commit e55cf9bcb7d28697d15cd5cf4f86ef83f25b27b5
parent 8b52de576b74dc75e6de40a1c7a3d96515b3a7e8
Author: lash <dev@holbrook.no>
Date: Mon, 7 Apr 2025 15:34:13 +0100
Add logdb decoder
Diffstat:
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)
+ }
}