Skip to content

Commit 53d3195

Browse files
committed
feat: zipmap support migrate
1 parent 7814efd commit 53d3195

File tree

2 files changed

+42
-14
lines changed

2 files changed

+42
-14
lines changed

internal/benchmark/main.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func main() {
3737
flag.StringVar(&c, "obj", "hashmap", "")
3838
flag.IntVar(&n, "n", 512, "")
3939
flag.Parse()
40-
fmt.Println(c)
40+
fmt.Println(c, n)
4141

4242
start := time.Now()
4343
m := map[int]any{}
@@ -77,6 +77,8 @@ func main() {
7777
}
7878
m[i] = zs
7979
}
80+
default:
81+
panic("unknown flags")
8082
}
8183

8284
cost := time.Since(start)

internal/hash/zipmap.go

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,29 @@ import (
55
"encoding/binary"
66
"github.com/cockroachdb/swiss"
77
"github.com/xgzlucario/rotom/internal/iface"
8+
"github.com/xgzlucario/rotom/internal/pool"
89
"github.com/xgzlucario/rotom/internal/resp"
910
)
1011

12+
const (
13+
migrateThresholdRate = 0.5
14+
migrateThresholdSize = 1024
15+
)
16+
1117
var _ iface.MapI = (*ZipMap)(nil)
1218

19+
var (
20+
bpool = pool.NewBufferPool()
21+
)
22+
1323
type ZipMap struct {
14-
unused uint32
24+
unused int
1525
data []byte
1626
index *swiss.Map[string, uint32]
1727
}
1828

1929
func New() *ZipMap {
2030
return &ZipMap{
21-
data: make([]byte, 0, 64),
2231
index: swiss.New[string, uint32](8),
2332
}
2433
}
@@ -34,22 +43,27 @@ func (zm *ZipMap) Get(key string) ([]byte, bool) {
3443

3544
func (zm *ZipMap) Set(key string, val []byte) bool {
3645
pos, ok := zm.index.Get(key)
37-
// update inplace
46+
// update inplaced
3847
if ok {
3948
oldVal, n := zm.readVal(pos)
4049
if len(oldVal) == len(val) {
4150
copy(oldVal, val)
4251
return false
4352
}
4453
// mem trash
45-
zm.unused += uint32(n)
54+
zm.unused += n
55+
zm.Migrate()
4656
}
47-
zm.index.Put(key, uint32(len(zm.data)))
48-
zm.data = binary.AppendUvarint(zm.data, uint64(len(val)))
49-
zm.data = append(zm.data, val...)
57+
zm.data = zm.appendKeyVal(zm.data, key, val)
5058
return !ok
5159
}
5260

61+
func (zm *ZipMap) appendKeyVal(dst []byte, key string, val []byte) []byte {
62+
zm.index.Put(key, uint32(len(dst)))
63+
dst = binary.AppendUvarint(dst, uint64(len(val)))
64+
return append(dst, val...)
65+
}
66+
5367
func (zm *ZipMap) readVal(pos uint32) ([]byte, int) {
5468
data := zm.data[pos:]
5569
vlen, n := binary.Uvarint(data)
@@ -62,7 +76,9 @@ func (zm *ZipMap) Remove(key string) bool {
6276
if ok {
6377
zm.index.Delete(key)
6478
_, n := zm.readVal(pos)
65-
zm.unused += uint32(n)
79+
// mem trash
80+
zm.unused += n
81+
zm.Migrate()
6682
}
6783
return ok
6884
}
@@ -75,13 +91,23 @@ func (zm *ZipMap) Scan(fn func(string, []byte)) {
7591
})
7692
}
7793

78-
func (zm *ZipMap) Len() int {
79-
return zm.index.Len()
94+
func (zm *ZipMap) Migrate() {
95+
if zm.unused < migrateThresholdSize {
96+
return
97+
}
98+
if float64(zm.unused)/float64(len(zm.data)) < migrateThresholdRate {
99+
return
100+
}
101+
newData := bpool.Get(len(zm.data))
102+
zm.Scan(func(key string, val []byte) {
103+
newData = zm.appendKeyVal(newData, key, val)
104+
})
105+
bpool.Put(zm.data)
106+
zm.data = newData
107+
zm.unused = 0
80108
}
81109

82-
func (zm *ZipMap) Compress() {
83-
84-
}
110+
func (zm *ZipMap) Len() int { return zm.index.Len() }
85111

86112
func (zm *ZipMap) Encode(writer *resp.Writer) error {
87113
writer.WriteArrayHead(zm.Len())

0 commit comments

Comments
 (0)