go-vise

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

commit e55cf9bcb7d28697d15cd5cf4f86ef83f25b27b5
parent 8b52de576b74dc75e6de40a1c7a3d96515b3a7e8
Author: lash <dev@holbrook.no>
Date:   Mon,  7 Apr 2025 15:34:13 +0100

Add logdb decoder

Diffstat:
Mdb/log/log.go | 45++++++++++++++++++++++++++++++++++++++++++---
Mdb/log/log_test.go | 39+++++++++++++++++++++++++++++++++++++++
2 files changed, 81 insertions(+), 3 deletions(-)

diff --git a/db/log/log.go b/db/log/log.go @@ -20,6 +20,14 @@ type logDb struct { logDb db.Db } +type LogEntry struct { + Key []byte + Val []byte + SessionId string + When time.Time + Pfx uint8 +} + // NewLogDb creates a wrapper for the main Db in the first argument, which write an entry for every Put to the second database. // // All interface methods operate like normal on the main Db. @@ -33,7 +41,7 @@ type logDb struct { // The value is stored as: // // `varint(length(key)) | key | value` -func NewLogDb(mainDb db.Db, subDb db.Db) db.Db { +func NewLogDb(mainDb db.Db, subDb db.Db) *logDb { subDb.Base().AllowUnknownPrefix() return &logDb{ Db: mainDb, @@ -111,8 +119,8 @@ func (ldb *logDb) toLogDbEntry(ctx context.Context, key []byte, val []byte) ([]b } l = make([]byte, 8) - binary.PutUvarint(l, uint64(len(innerValKey))) - innerValKey = append(l, innerValKey...) + c := binary.PutUvarint(l, uint64(len(innerValKey))) + innerValKey = append(l[:c], innerValKey...) innerValKey = append(innerValKey, val...) innerKey = make([]byte, 8) @@ -121,6 +129,37 @@ func (ldb *logDb) toLogDbEntry(ctx context.Context, key []byte, val []byte) ([]b return innerKey, append(innerValKey, innerValVal...) } +// ToLogDbEntry decodes a logdb entry to a structure containing the relevant metadata aswell as the original key and value pass by the client. +func (ldb *logDb) ToLogDbEntry(ctx context.Context, key []byte, val []byte) (LogEntry, error) { + var err error + + key = key[1:] + tb := key[len(key)-8:] + nsecs := binary.BigEndian.Uint64(tb[:8]) + nsecPart := int64(nsecs % 1000000000) + secPart := int64(nsecs / 1000000000) + t := time.Unix(secPart, nsecPart) + + sessionId := key[:len(key)-8] + + l, c := binary.Uvarint(val) + lk := val[c:uint64(c)+l] + v := val[uint64(c)+l:] + pfx := lk[0] + k, err := ldb.Base().DecodeKey(ctx, lk) + if err != nil { + return LogEntry{}, err + } + sessionId = lk[1:len(lk)-len(k)-1] + return LogEntry{ + Key: k, + Val: v, + SessionId: string(sessionId), + When: t, + Pfx: pfx, + }, nil +} + // Put implements Db. func (ldb *logDb) Put(ctx context.Context, key []byte, val []byte) error { ldb.logDb.SetPrefix(db.DATATYPE_UNKNOWN) diff --git a/db/log/log_test.go b/db/log/log_test.go @@ -65,5 +65,44 @@ func TestLogDb(t *testing.T) { if tn >= tExpect { t.Fatalf("expected %v should be before %v", tn, tExpect) } +} +func TestLogDbConvert(t *testing.T) { + sessionId := "xyzzy" + ctx := context.Background() + main := mem.NewMemDb() + sub := mem.NewMemDb() + store := NewLogDb(main, sub) + err := store.Connect(ctx, "main") + if err != nil { + t.Fatal(err) + } + + k := []byte("foo") + v := []byte("bar") + store.SetPrefix(db.DATATYPE_USERDATA) + store.SetSession(sessionId) + err = store.Put(ctx, k, v) + if err != nil { + t.Fatal(err) + } + + dump, err := sub.Dump(ctx, []byte{db.DATATYPE_UNKNOWN}) + if err != nil { + t.Fatal(err) + } + rk, rv := dump.Next(ctx) + entry, err := store.ToLogDbEntry(ctx, rk, rv) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(entry.Key, k) { + t.Fatalf("expected %x, got %x", k, entry.Key) + } + if !bytes.Equal(entry.Val, v) { + t.Fatalf("expected %x, got %x", v, entry.Val) + } + if entry.SessionId != sessionId { + t.Fatalf("expected %x, got %x", sessionId, entry.SessionId) + } }