From 9b32b8b8f29a4079fcb76554599a79779dd7c191 Mon Sep 17 00:00:00 2001 From: edipretoro Date: Tue, 21 Jul 2026 21:36:14 +0200 Subject: [PATCH] Adding the challenge 0103 --- 0103/kv.go | 21 ++++++++++++++ 0103/kv_entry.go | 51 ++++++++++++++++++++++++++++++++ 0103/kv_test.go | 75 ++++++++++++++++++++++++++++++++++++++++++++++++ 0103/log.go | 38 ++++++++++++++++++++++++ 4 files changed, 185 insertions(+) create mode 100644 0103/kv.go create mode 100644 0103/kv_entry.go create mode 100644 0103/kv_test.go create mode 100644 0103/log.go diff --git a/0103/kv.go b/0103/kv.go new file mode 100644 index 0000000..f4bcdcb --- /dev/null +++ b/0103/kv.go @@ -0,0 +1,21 @@ +package db0103 + +type KV struct { + log Log + mem map[string][]byte +} + +func (kv *KV) Open() error + +func (kv *KV) Close() error { return kv.log.Close() } + +func (kv *KV) Get(key []byte) (val []byte, ok bool, err error) { + val, ok = kv.mem[string(key)] + return +} + +func (kv *KV) Set(key []byte, val []byte) (updated bool, err error) + +func (kv *KV) Del(key []byte) (deleted bool, err error) + +// QzBQWVJJOUhU https://trialofcode.org/ diff --git a/0103/kv_entry.go b/0103/kv_entry.go new file mode 100644 index 0000000..2dbfca0 --- /dev/null +++ b/0103/kv_entry.go @@ -0,0 +1,51 @@ +package db0103 + +import ( + "encoding/binary" + "io" +) + +type Entry struct { + key []byte + val []byte + deleted bool +} + +func (ent *Entry) Encode() []byte { + data := make([]byte, 4+4+1+len(ent.key)+len(ent.val)) + binary.LittleEndian.PutUint32(data[0:4], uint32(len(ent.key))) + copy(data[9:], ent.key) + if ent.deleted { + data[8] = 1 + } else { + binary.LittleEndian.PutUint32(data[4:8], uint32(len(ent.val))) + copy(data[9+len(ent.key):], ent.val) + } + return data +} + +func (ent *Entry) Decode(r io.Reader) error { + var header [9]byte + if _, err := io.ReadFull(r, header[:]); err != nil { + return err + } + klen := int(binary.LittleEndian.Uint32(header[0:4])) + vlen := int(binary.LittleEndian.Uint32(header[4:8])) + deleted := header[8] + + data := make([]byte, klen+vlen) + if _, err := io.ReadFull(r, data); err != nil { + return err + } + + ent.key = data[:klen] + if deleted != 0 { + ent.deleted = true + } else { + ent.deleted = false + ent.val = data[klen:] + } + return nil +} + +// QzBQWVJJOUhU https://trialofcode.org/ diff --git a/0103/kv_test.go b/0103/kv_test.go new file mode 100644 index 0000000..a1d52eb --- /dev/null +++ b/0103/kv_test.go @@ -0,0 +1,75 @@ +package db0103 + +import ( + "bytes" + "os" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestKVBasic(t *testing.T) { + kv := KV{} + kv.log.FileName = ".test_db" + defer os.Remove(kv.log.FileName) + + os.Remove(kv.log.FileName) + err := kv.Open() + assert.Nil(t, err) + defer kv.Close() + + updated, err := kv.Set([]byte("k1"), []byte("v1")) + assert.True(t, updated && err == nil) + + val, ok, err := kv.Get([]byte("k1")) + assert.True(t, string(val) == "v1" && ok && err == nil) + + _, ok, err = kv.Get([]byte("xxx")) + assert.True(t, !ok && err == nil) + + updated, err = kv.Del([]byte("xxx")) + assert.True(t, !updated && err == nil) + + updated, err = kv.Del([]byte("k1")) + assert.True(t, updated && err == nil) + + _, ok, err = kv.Get([]byte("xxx")) + assert.True(t, !ok && err == nil) + + updated, err = kv.Set([]byte("k2"), []byte("v2")) + assert.True(t, updated && err == nil) + + // reopen + kv.Close() + err = kv.Open() + assert.Nil(t, err) + + _, ok, err = kv.Get([]byte("k1")) + assert.True(t, !ok && err == nil) + val, ok, err = kv.Get([]byte("k2")) + assert.True(t, string(val) == "v2" && ok && err == nil) +} + +func TestEntryEncode(t *testing.T) { + ent := Entry{key: []byte("k1"), val: []byte("xxx")} + data := []byte{2, 0, 0, 0, 3, 0, 0, 0, 0, 'k', '1', 'x', 'x', 'x'} + + assert.Equal(t, data, ent.Encode()) + + decoded := Entry{} + err := decoded.Decode(bytes.NewBuffer(data)) + assert.Nil(t, err) + assert.Equal(t, ent, decoded) + + ent = Entry{key: []byte("k1"), deleted: true} + data = []byte{2, 0, 0, 0, 0, 0, 0, 0, 1, 'k', '1'} + + assert.Equal(t, data, ent.Encode()) + + decoded = Entry{} + err = decoded.Decode(bytes.NewBuffer(data)) + assert.Nil(t, err) + assert.Equal(t, ent, decoded) +} + +// QzBQWVJJOUhU https://trialofcode.org/ diff --git a/0103/log.go b/0103/log.go new file mode 100644 index 0000000..98714de --- /dev/null +++ b/0103/log.go @@ -0,0 +1,38 @@ +package db0103 + +import ( + "io" + "os" +) + +type Log struct { + FileName string + fp *os.File +} + +func (log *Log) Open() (err error) { + log.fp, err = os.OpenFile(log.FileName, os.O_RDWR|os.O_CREATE, 0o644) + return err +} + +func (log *Log) Close() error { + return log.fp.Close() +} + +func (log *Log) Write(ent *Entry) error { + _, err := log.fp.Write(ent.Encode()) + return err +} + +func (log *Log) Read(ent *Entry) (eof bool, err error) { + err = ent.Decode(log.fp) + if err == io.EOF { + return true, nil + } else if err != nil { + return false, err + } else { + return false, nil + } +} + +// QzBQWVJJOUhU https://trialofcode.org/