From 79fdda6a1d98ed35d6157f2c7e3e2eb0b968fcca Mon Sep 17 00:00:00 2001 From: Brian Stafford Date: Sun, 23 Feb 2025 05:04:19 -0600 Subject: [PATCH] add lexi kv interface type --- dex/lexi/db_test.go | 7 +++---- dex/lexi/index.go | 35 +++++------------------------------ dex/lexi/lexi.go | 29 +++++++++++++++++++++-------- dex/lexi/table.go | 12 ++++++------ tatanka/db/bonds.go | 2 +- tatanka/db/db.go | 11 +++++------ tatanka/db/reputation.go | 2 +- 7 files changed, 42 insertions(+), 56 deletions(-) diff --git a/dex/lexi/db_test.go b/dex/lexi/db_test.go index d78c132707..f7de64e7c6 100644 --- a/dex/lexi/db_test.go +++ b/dex/lexi/db_test.go @@ -2,7 +2,6 @@ package lexi import ( "bytes" - "encoding" "os" "path/filepath" "strings" @@ -66,11 +65,11 @@ func (v *tValue) MarshalBinary() ([]byte, error) { return v.v, nil } -func valueIndex(k, v encoding.BinaryMarshaler) ([]byte, error) { +func valueIndex(k, v KV) ([]byte, error) { return v.(*tValue).idx, nil } -func valueKey(k, v encoding.BinaryMarshaler) ([]byte, error) { +func valueKey(k, v KV) ([]byte, error) { return v.(*tValue).k, nil } @@ -109,7 +108,7 @@ func TestIndex(t *testing.T) { indexKey = append(prefix, indexKey...) v := &tValue{k: indexKey, v: encode.RandomBytes(10), idx: []byte{byte(i)}} vs[i] = v - if err := tbl.Set(B(k), v); err != nil { + if err := tbl.Set(k, v); err != nil { t.Fatalf("Error setting table entry: %v", err) } } diff --git a/dex/lexi/index.go b/dex/lexi/index.go index 13dc56f9b6..6f018ff75f 100644 --- a/dex/lexi/index.go +++ b/dex/lexi/index.go @@ -5,11 +5,8 @@ package lexi import ( "bytes" - "encoding" - "encoding/binary" "errors" "fmt" - "time" "decred.org/dcrdex/dex" "github.com/dgraph-io/badger" @@ -29,13 +26,13 @@ type Index struct { name string table *Table prefix keyPrefix - f func(k, v encoding.BinaryMarshaler) ([]byte, error) + f func(k, v KV) ([]byte, error) defaultIterationOptions iteratorOpts } // AddIndex adds an index to a Table. Once an Index is added, every datum // Set in the Table will generate an entry in the Index too. -func (t *Table) AddIndex(name string, f func(k, v encoding.BinaryMarshaler) ([]byte, error)) (*Index, error) { +func (t *Table) AddIndex(name string, f func(k, v KV) ([]byte, error)) (*Index, error) { p, err := t.prefixForName(t.name + "__idx__" + name) if err != nil { return nil, err @@ -51,7 +48,7 @@ func (t *Table) AddIndex(name string, f func(k, v encoding.BinaryMarshaler) ([]b return idx, nil } -func (idx *Index) add(txn *badger.Txn, k, v encoding.BinaryMarshaler, dbID DBID) ([]byte, error) { +func (idx *Index) add(txn *badger.Txn, k, v KV, dbID DBID) ([]byte, error) { idxB, err := idx.f(k, v) if err != nil { return nil, fmt.Errorf("error getting index value: %w", err) @@ -170,32 +167,10 @@ func (i *Iter) Delete() error { return i.idx.table.deleteDatum(i.txn, i.dbID, d) } -// IndexBucket is any one of a number of common types whose binary encoding is -// straight-forward. An IndexBucket restricts Iterate to the entries in the -// index that have the bytes decoded from the IndexBucket as the prefix. -type IndexBucket interface{} - -func parseIndexBucket(i IndexBucket) (b []byte, err error) { - switch it := i.(type) { - case []byte: - b = it - case uint32: - b = make([]byte, 4) - binary.BigEndian.PutUint32(b[:], it) - case time.Time: - b = make([]byte, 8) - binary.BigEndian.PutUint64(b[:], uint64(it.UnixMilli())) - case nil: - default: - err = fmt.Errorf("unknown IndexBucket type %T", it) - } - return -} - // Iterate iterates the index, providing access to the index entry, datum, and // datum key via the Iter. -func (idx *Index) Iterate(prefixI IndexBucket, f func(*Iter) error, iterOpts ...IterationOption) error { - prefix, err := parseIndexBucket(prefixI) +func (idx *Index) Iterate(prefixI KV, f func(*Iter) error, iterOpts ...IterationOption) error { + prefix, err := parseKV(prefixI) if err != nil { return err } diff --git a/dex/lexi/lexi.go b/dex/lexi/lexi.go index 63909d9ec9..2bb97e6823 100644 --- a/dex/lexi/lexi.go +++ b/dex/lexi/lexi.go @@ -227,12 +227,25 @@ func (db *DB) deleteDBID(txn *badger.Txn, dbID DBID) error { return nil } -// B is a byte slice that implements encoding.BinaryMarshaler. -type B []byte - -var _ encoding.BinaryMarshaler = B{} - -// MarshalBinary implements encoding.BinaryMarshaler for the B. -func (b B) MarshalBinary() ([]byte, error) { - return b, nil +// KV is any one of a number of common types whose binary encoding is +// straight-forward. +type KV interface{} + +func parseKV(i KV) (b []byte, err error) { + switch it := i.(type) { + case []byte: + b = it + case uint32: + b = make([]byte, 4) + binary.BigEndian.PutUint32(b[:], it) + case time.Time: + b = make([]byte, 8) + binary.BigEndian.PutUint64(b[:], uint64(it.UnixMilli())) + case encoding.BinaryMarshaler: + b, err = it.MarshalBinary() + case nil: + default: + err = fmt.Errorf("unknown IndexBucket type %T", it) + } + return } diff --git a/dex/lexi/table.go b/dex/lexi/table.go index fb828b4cd0..eac7624412 100644 --- a/dex/lexi/table.go +++ b/dex/lexi/table.go @@ -36,8 +36,8 @@ func (db *DB) Table(name string) (*Table, error) { } // GetRaw retrieves a value from the Table as raw bytes. -func (t *Table) GetRaw(k encoding.BinaryMarshaler) (b []byte, err error) { - kB, err := k.MarshalBinary() +func (t *Table) GetRaw(k KV) (b []byte, err error) { + kB, err := parseKV(k) if err != nil { return nil, fmt.Errorf("error marshaling key: %w", err) } @@ -57,7 +57,7 @@ func (t *Table) GetRaw(k encoding.BinaryMarshaler) (b []byte, err error) { } // Get retrieves a value from the Table. -func (t *Table) Get(k encoding.BinaryMarshaler, thing encoding.BinaryUnmarshaler) error { +func (t *Table) Get(k KV, thing encoding.BinaryUnmarshaler) error { b, err := t.GetRaw(k) if err != nil { return err @@ -113,8 +113,8 @@ func (t *Table) UseDefaultSetOptions(setOpts ...SetOption) { } // Set inserts a new value for the key, and creates index entries. -func (t *Table) Set(k, v encoding.BinaryMarshaler, setOpts ...SetOption) error { - kB, err := k.MarshalBinary() +func (t *Table) Set(k, v KV, setOpts ...SetOption) error { + kB, err := parseKV(k) if err != nil { return fmt.Errorf("error marshaling key: %w", err) } @@ -123,7 +123,7 @@ func (t *Table) Set(k, v encoding.BinaryMarshaler, setOpts ...SetOption) error { if len(kB) == 0 { return errors.New("no zero-length keys allowed") } - vB, err := v.MarshalBinary() + vB, err := parseKV(v) if err != nil { return fmt.Errorf("error marshaling value: %w", err) } diff --git a/tatanka/db/bonds.go b/tatanka/db/bonds.go index d9cfe0946e..ed5f359afd 100644 --- a/tatanka/db/bonds.go +++ b/tatanka/db/bonds.go @@ -50,7 +50,7 @@ func (bond *dbBond) UnmarshalBinary(b []byte) error { } func (d *DB) StoreBond(newBond *tanka.Bond) error { - return d.bonds.Set(lexi.B(newBond.CoinID), &dbBond{newBond}, lexi.WithReplace()) + return d.bonds.Set(newBond.CoinID[:], &dbBond{newBond}, lexi.WithReplace()) } func (d *DB) GetBonds(peerID tanka.PeerID) ([]*tanka.Bond, error) { diff --git a/tatanka/db/db.go b/tatanka/db/db.go index 39ab621917..f5b0b18c63 100644 --- a/tatanka/db/db.go +++ b/tatanka/db/db.go @@ -5,7 +5,6 @@ package db import ( "context" - "encoding" "encoding/binary" "errors" "fmt" @@ -51,12 +50,12 @@ func New(dir string, log dex.Logger) (*DB, error) { if err != nil { return nil, fmt.Errorf("error initializing meta table: %w", err) } - verB, err := metaTable.GetRaw(lexi.B(versionKey)) + verB, err := metaTable.GetRaw(versionKey) if err != nil { if errors.Is(err, lexi.ErrKeyNotFound) { // fresh install verB = []byte{DBVersion} - metaTable.Set(lexi.B(versionKey), lexi.B(verB)) + metaTable.Set(versionKey, verB) } else { return nil, fmt.Errorf("error getting version") } @@ -78,7 +77,7 @@ func New(dir string, log dex.Logger) (*DB, error) { return nil, fmt.Errorf("error constructing reputation table: %w", err) } // Scored peer index with timestamp sorting. - scoredIdx, err := scoreTable.AddIndex("scored-stamp", func(_, v encoding.BinaryMarshaler) ([]byte, error) { + scoredIdx, err := scoreTable.AddIndex("scored-stamp", func(_, v lexi.KV) ([]byte, error) { s, is := v.(*dbScore) if !is { return nil, fmt.Errorf("wrong type %T", v) @@ -98,7 +97,7 @@ func New(dir string, log dex.Logger) (*DB, error) { return nil, fmt.Errorf("error initializing bonds table: %w", err) } // Retrieve bonds by peer ID. - bonderIdx, err := bondsTable.AddIndex("bonder", func(_, v encoding.BinaryMarshaler) ([]byte, error) { + bonderIdx, err := bondsTable.AddIndex("bonder", func(_, v lexi.KV) ([]byte, error) { b, is := v.(*dbBond) if !is { return nil, fmt.Errorf("wrong type %T", v) @@ -109,7 +108,7 @@ func New(dir string, log dex.Logger) (*DB, error) { return nil, fmt.Errorf("error initializing bonder index: %w", err) } // We'll periodically prune expired bonds. - bondStampIdx, err := bondsTable.AddIndex("bond-stamp", func(_, v encoding.BinaryMarshaler) ([]byte, error) { + bondStampIdx, err := bondsTable.AddIndex("bond-stamp", func(_, v lexi.KV) ([]byte, error) { b, is := v.(*dbBond) if !is { return nil, fmt.Errorf("wrong type %T", v) diff --git a/tatanka/db/reputation.go b/tatanka/db/reputation.go index 9a222338b3..7c09b60906 100644 --- a/tatanka/db/reputation.go +++ b/tatanka/db/reputation.go @@ -30,7 +30,7 @@ func (d *DB) SetScore(scored, scorer tanka.PeerID, score int8, stamp time.Time) score: score, stamp: stamp, } - return d.scores.Set(lexi.B(k), s, lexi.WithReplace()) + return d.scores.Set(k, s, lexi.WithReplace()) } func (d *DB) Reputation(scored tanka.PeerID) (*tanka.Reputation, error) {