Skip to content

Commit

Permalink
add lexi kv interface type
Browse files Browse the repository at this point in the history
  • Loading branch information
buck54321 committed Feb 23, 2025
1 parent 2b683d5 commit 79fdda6
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 56 deletions.
7 changes: 3 additions & 4 deletions dex/lexi/db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package lexi

import (
"bytes"
"encoding"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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)
}
}
Expand Down
35 changes: 5 additions & 30 deletions dex/lexi/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,8 @@ package lexi

import (
"bytes"
"encoding"
"encoding/binary"
"errors"
"fmt"
"time"

"decred.org/dcrdex/dex"
"github.com/dgraph-io/badger"
Expand All @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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
}
Expand Down
29 changes: 21 additions & 8 deletions dex/lexi/lexi.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
12 changes: 6 additions & 6 deletions dex/lexi/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -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
Expand Down Expand Up @@ -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)
}
Expand All @@ -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)
}
Expand Down
2 changes: 1 addition & 1 deletion tatanka/db/bonds.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
11 changes: 5 additions & 6 deletions tatanka/db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package db

import (
"context"
"encoding"
"encoding/binary"
"errors"
"fmt"
Expand Down Expand Up @@ -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")
}
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion tatanka/db/reputation.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down

0 comments on commit 79fdda6

Please sign in to comment.