Skip to content

Commit

Permalink
perf: encode entry in zipmap
Browse files Browse the repository at this point in the history
  • Loading branch information
xgzlucario committed Jul 15, 2024
1 parent c7df670 commit 5db120f
Showing 1 changed file with 56 additions and 23 deletions.
79 changes: 56 additions & 23 deletions internal/hash/zipmap.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package hash

import (
"encoding/binary"
"unsafe"

"github.com/xgzlucario/rotom/internal/list"
)

var _ MapI = (*ZipMap)(nil)

// ZipMap store datas as [key1, val1, key2, val2...] in listpack.
// ZipMap store datas as [entry1, entry2, entry3...] in listpack.
type ZipMap struct {
m *list.ListPack
}
Expand All @@ -17,57 +18,87 @@ func NewZipMap() *ZipMap {
return &ZipMap{list.NewListPack()}
}

// encodeEntry encode data to [vlen, val, key].
func encodeEntry(key string, val []byte) []byte {
buf := make([]byte, 0, len(key)+len(val)+1)
buf = binary.AppendUvarint(buf, uint64(len(val)))
buf = append(buf, val...)
return append(buf, key...)
}

func decodeEntry(buf []byte) (key string, val []byte) {
vlen, n := binary.Uvarint(buf)
val = buf[n : n+int(vlen)]
key = b2s(buf[n+int(vlen):])
return
}

func (zm *ZipMap) Set(key string, val []byte) (newField bool) {
it := zm.m.Iterator().SeekLast()
b := key[len(key)-1]
newEntry := b2s(encodeEntry(key, val))

for !it.IsFirst() {
it.Prev()
keyBytes := it.Prev()
if key == b2s(keyBytes) {
// update val
it.Next()
it.ReplaceNext(b2s(val))
entry := it.Prev()
// fast equal
if entry[len(entry)-1] != b {
continue
}

kb, _ := decodeEntry(entry)
if key == kb {
it.ReplaceNext(newEntry)
return false
}
}
zm.m.RPush(key, b2s(val))
zm.m.RPush(newEntry)
return true
}

func (zm *ZipMap) Get(key string) ([]byte, bool) {
it := zm.m.Iterator().SeekLast()
b := key[len(key)-1]

for !it.IsFirst() {
valBytes := it.Prev()
keyBytes := it.Prev()
if key == b2s(keyBytes) {
return valBytes, true
entry := it.Prev()
// fast equal
if entry[len(entry)-1] != b {
continue
}

kb, vb := decodeEntry(entry)
if key == kb {
return vb, true
}
}
return nil, false
}

func (zm *ZipMap) Remove(key string) bool {
it := zm.m.Iterator().SeekLast()
b := key[len(key)-1]

for !it.IsFirst() {
it.Prev()
keyBytes := it.Prev()
if key == b2s(keyBytes) {
it.RemoveNexts(2)
entry := it.Prev()
// fast equal
if entry[len(entry)-1] != b {
continue
}

kb, _ := decodeEntry(entry)
if key == kb {
it.RemoveNext()
return true
}
}
return false
}

func (zm *ZipMap) Len() int {
return zm.m.Size() / 2
}

func (zm *ZipMap) Scan(fn func(string, []byte)) {
it := zm.m.Iterator().SeekLast()
for !it.IsFirst() {
valBytes := it.Prev()
keyBytes := it.Prev()
fn(b2s(keyBytes), valBytes)
kb, vb := decodeEntry(it.Prev())
fn(kb, vb)
}
}

Expand All @@ -79,6 +110,8 @@ func (zm *ZipMap) ToMap() *Map {
return m
}

func (zm *ZipMap) Len() int { return zm.m.Size() }

func (zm *ZipMap) Compress() { zm.m.Compress() }

func (zm *ZipMap) Decompress() { zm.m.Decompress() }
Expand Down

0 comments on commit 5db120f

Please sign in to comment.