package db0403 import ( "bytes" "slices" ) type KV struct { log Log keys [][]byte vals [][]byte } func (kv *KV) Open() error { if err := kv.log.Open(); err != nil { return err } entries := []Entry{} for { ent := Entry{} eof, err := kv.log.Read(&ent) if err != nil { return err } else if eof { break } entries = append(entries, ent) } slices.SortStableFunc(entries, func(a, b Entry) int { return bytes.Compare(a.key, b.key) }) kv.keys, kv.vals = kv.keys[:0], kv.vals[:0] for _, ent := range entries { n := len(kv.keys) if n > 0 && bytes.Equal(kv.keys[n-1], ent.key) { kv.keys, kv.vals = kv.keys[:n-1], kv.vals[:n-1] } if !ent.deleted { kv.keys = append(kv.keys, ent.key) kv.vals = append(kv.vals, ent.val) } } return nil } func (kv *KV) Close() error { return kv.log.Close() } func (kv *KV) Get(key []byte) (val []byte, ok bool, err error) { if idx, ok := slices.BinarySearchFunc(kv.keys, key, bytes.Compare); ok { return kv.vals[idx], true, nil } return nil, false, nil } type UpdateMode int const ( ModeUpsert UpdateMode = 0 // insert or update ModeInsert UpdateMode = 1 // insert new ModeUpdate UpdateMode = 2 // update existing ) func (kv *KV) SetEx(key []byte, val []byte, mode UpdateMode) (updated bool, err error) { idx, exist := slices.BinarySearchFunc(kv.keys, key, bytes.Compare) switch mode { case ModeUpsert: updated = !exist || !bytes.Equal(kv.vals[idx], val) case ModeInsert: updated = !exist case ModeUpdate: updated = exist && !bytes.Equal(kv.vals[idx], val) default: panic("unreachable") } if updated { if err = kv.log.Write(&Entry{key: key, val: val}); err != nil { return false, err } if exist { kv.vals[idx] = val } else { kv.keys = slices.Insert(kv.keys, idx, key) kv.vals = slices.Insert(kv.vals, idx, val) } } return } func (kv *KV) Set(key []byte, val []byte) (updated bool, err error) { return kv.SetEx(key, val, ModeUpsert) } func (kv *KV) Del(key []byte) (deleted bool, err error) { if idx, ok := slices.BinarySearchFunc(kv.keys, key, bytes.Compare); ok { if err = kv.log.Write(&Entry{key: key, deleted: true}); err != nil { return false, err } kv.keys = slices.Delete(kv.keys, idx, idx+1) kv.vals = slices.Delete(kv.vals, idx, idx+1) return true, nil } return false, nil } type KVIterator struct { keys [][]byte vals [][]byte pos int } func (kv *KV) Seek(key []byte) (*KVIterator, error) { pos, _ := slices.BinarySearchFunc(kv.keys, key, bytes.Compare) return &KVIterator{keys: kv.keys, vals: kv.vals, pos: pos}, nil } func (iter *KVIterator) Valid() bool { return 0 <= iter.pos && iter.pos < len(iter.keys) } func (iter *KVIterator) Key() []byte { check(iter.Valid()) return iter.keys[iter.pos] } func (iter *KVIterator) Val() []byte { check(iter.Valid()) return iter.vals[iter.pos] } func (iter *KVIterator) Next() error { if iter.pos < len(iter.keys) { iter.pos++ } return nil } func (iter *KVIterator) Prev() error { if iter.pos >= 0 { iter.pos-- } return nil } // QzBQWVJJOUhU https://trialofcode.org/