go-vise

Constrained Size Output Virtual Machine
Info | Log | Files | Refs | README | LICENSE

commit 5348e19880454920c387b3c1191716898cc5e79a
parent b588301738ed0626da50abb85dcc6b916598676f
Author: lash <dev@holbrook.no>
Date:   Sat,  2 Nov 2024 20:05:56 +0000

Add dumper db implementation for gdbm

Diffstat:
Mdb/db.go | 1+
Adb/dump.go | 42++++++++++++++++++++++++++++++++++++++++++
Adb/fs/dump.go | 12++++++++++++
Adb/gdbm/dump.go | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adb/gdbm/dump_test.go | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdb/gdbm/gdbm.go | 3+++
Adb/mem/dump.go | 12++++++++++++
Adb/postgres/dump.go | 12++++++++++++
8 files changed, 231 insertions(+), 0 deletions(-)

diff --git a/db/db.go b/db/db.go @@ -75,6 +75,7 @@ type Db interface { SetLanguage(*lang.Language) // Prefix returns the current active datatype prefix Prefix() uint8 + Dump(context.Context, []byte) (*Dumper, error) } type LookupKey struct { diff --git a/db/dump.go b/db/dump.go @@ -0,0 +1,42 @@ +package db + +import ( + "context" +) + +type DumperFunc func(ctx context.Context) ([]byte, []byte) + +type Dumper struct { + fn DumperFunc + k []byte + v []byte + nexted bool +} + +func NewDumper(fn DumperFunc) *Dumper { + return &Dumper{ + fn: fn, + } +} + +func(d *Dumper) WithFirst(k []byte, v []byte) *Dumper { + if d.nexted { + panic("already started") + } + d.k = k + d.v = v + d.nexted = true + return d +} + +func(d *Dumper) Next(ctx context.Context) ([]byte, []byte) { + d.nexted = true + k := d.k + v := d.v + if k == nil { + return nil, nil + } + d.k, d.v = d.fn(ctx) + logg.TraceCtxf(ctx, "next value is", "k", d.k, "v", d.v) + return k, v +} diff --git a/db/fs/dump.go b/db/fs/dump.go @@ -0,0 +1,12 @@ +package fs + +import ( + "context" + "errors" + + "git.defalsify.org/vise.git/db" +) + +func(fdb *fsDb) Dump(ctx context.Context, key []byte) (*db.Dumper, error) { + return nil, errors.New("unimplemented") +} diff --git a/db/gdbm/dump.go b/db/gdbm/dump.go @@ -0,0 +1,84 @@ +package gdbm + +import ( + "bytes" + "context" + "errors" + + gdbm "github.com/graygnuorg/go-gdbm" + + "git.defalsify.org/vise.git/db" +) + +func(gdb *gdbmDb) Dump(ctx context.Context, key []byte) (*db.Dumper, error) { + gdb.it = gdb.conn.Iterator() + for true { + k, err := gdb.it() + if err != nil { + if errors.Is(err, gdbm.ErrItemNotFound) { + err = db.NewErrNotFound(key) + } + gdb.it = nil + return nil, err + } + logg.TraceCtxf(ctx, "dump trace", "k", k) + if !bytes.HasPrefix(k[1:], key) { + continue + } + v, err := gdb.Get(ctx, k[1:]) + if err != nil { + gdb.it = nil + return nil, err + } + gdb.itBase = key + return db.NewDumper(gdb.dumpFunc).WithFirst(k, v), nil + } + gdb.it = nil + return nil, db.NewErrNotFound(key) +} + +func(gdb *gdbmDb) dumpFunc(ctx context.Context) ([]byte, []byte) { + var k []byte + var match bool + var err error + + for true { + k, err = gdb.it() + if err != nil { + gdb.it = nil + return nil, nil + } + if bytes.HasPrefix(k[1:], gdb.itBase) { + match = true + break + } + } + if !match { + gdb.it = nil + return nil, nil + } + v, err := gdb.Get(ctx, k[1:]) + if err != nil { + return nil, nil + } + return k, v +} + +//func(gdb *gdbmDb) After(ctx context.Context, keyPart []byte) ([]byte, []byte) { +// if keyPart == nil { +// gdb.it = gdb.conn.Iterator() +// return nil, nil +// } +// k, err := gdb.it() +// if err != nil { +// if !errors.Is(err, gdbm.ErrItemNotFound) { +// panic(err) +// } +// gdb.it = gdb.conn.Iterator() +// } +// v, err := gdb.Get(ctx, k) +// if err != nil { +// panic(err) +// } +// return k, v +//} diff --git a/db/gdbm/dump_test.go b/db/gdbm/dump_test.go @@ -0,0 +1,65 @@ +package gdbm + +import ( + "bytes" + "context" + "io/ioutil" + "testing" + + "git.defalsify.org/vise.git/db" +) + +func TestDumpGdbm(t *testing.T) { + ctx := context.Background() + + store := NewGdbmDb() + f, err := ioutil.TempFile("", "vise-db-gdbm-*") + if err != nil { + t.Fatal(err) + } + err = store.Connect(ctx, f.Name()) + if err != nil { + t.Fatal(err) + } + + store.SetPrefix(db.DATATYPE_USERDATA) + err = store.Put(ctx, []byte("bar"), []byte("inky")) + if err != nil { + t.Fatal(err) + } + err = store.Put(ctx, []byte("foobar"), []byte("pinky")) + if err != nil { + t.Fatal(err) + } + err = store.Put(ctx, []byte("foobarbaz"), []byte("blinky")) + if err != nil { + t.Fatal(err) + } + err = store.Put(ctx, []byte("xyzzy"), []byte("clyde")) + if err != nil { + t.Fatal(err) + } + + o, err := store.Dump(ctx, []byte("foo")) + if err != nil { + t.Fatal(err) + } + k, v := o.Next(ctx) + if !bytes.Equal(k, append([]byte{db.DATATYPE_USERDATA}, []byte("foobar")...)) { + t.Fatalf("expected key 'foobar', got %s", k) + } + if !bytes.Equal(v, []byte("pinky")) { + t.Fatalf("expected val 'pinky', got %s", v) + } + k, v = o.Next(ctx) + if !bytes.Equal(k, append([]byte{db.DATATYPE_USERDATA}, []byte("foobarbaz")...)) { + t.Fatalf("expected key 'foobarbaz', got %s", k) + } + if !bytes.Equal(v, []byte("blinky")) { + t.Fatalf("expected val 'blinky', got %s", v) + } + k, v = o.Next(ctx) + if k != nil { + t.Fatalf("expected nil, got %s", k) + } +} diff --git a/db/gdbm/gdbm.go b/db/gdbm/gdbm.go @@ -17,6 +17,8 @@ type gdbmDb struct { conn *gdbm.Database readOnly bool prefix uint8 + it gdbm.DatabaseIterator + itBase []byte } // Creates a new gdbm backed Db implementation. @@ -118,6 +120,7 @@ func(gdb *gdbmDb) Get(ctx context.Context, key []byte) ([]byte, error) { return v, nil } v, err = gdb.conn.Fetch(lk.Default) + logg.TraceCtxf(ctx, "gdbm get", "key", key, "lk", lk.Default) if err != nil { if errors.Is(gdbm.ErrItemNotFound, err) { return nil, db.NewErrNotFound(key) diff --git a/db/mem/dump.go b/db/mem/dump.go @@ -0,0 +1,12 @@ +package mem + +import ( + "context" + "errors" + + "git.defalsify.org/vise.git/db" +) + +func(mdb *memDb) Dump(ctx context.Context, key []byte) (*db.Dumper, error) { + return nil, errors.New("unimplemented") +} diff --git a/db/postgres/dump.go b/db/postgres/dump.go @@ -0,0 +1,12 @@ +package postgres + +import ( + "context" + "errors" + + "git.defalsify.org/vise.git/db" +) + +func(pdb *pgDb) Dump(ctx context.Context, key []byte) (*db.Dumper, error) { + return nil, errors.New("unimplemented") +}