Skip to content

Commit

Permalink
feat: add zipmap, zipset based on listpack
Browse files Browse the repository at this point in the history
  • Loading branch information
xgzlucario committed Jul 14, 2024
1 parent 2028de0 commit e9fcee0
Show file tree
Hide file tree
Showing 11 changed files with 165 additions and 77 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/re
RUN apk add --no-cache ca-certificates tzdata && \
update-ca-certificates

RUN apk --no-cache add redis
RUN apk --no-cache add redis bash

VOLUME /data
WORKDIR /data
Expand Down
4 changes: 2 additions & 2 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -410,15 +410,15 @@ func todoCommand(writer *RESPWriter, _ []RESP) {
}

func fetchMap(key string, setnx ...bool) (Map, error) {
return fetch(key, func() Map { return hash.NewMap() }, setnx...)
return fetch(key, func() Map { return hash.NewZipMap() }, setnx...)
}

func fetchList(key string, setnx ...bool) (List, error) {
return fetch(key, func() List { return list.New() }, setnx...)
}

func fetchSet(key string, setnx ...bool) (Set, error) {
return fetch(key, func() Set { return hash.NewSet() }, setnx...)
return fetch(key, func() Set { return hash.NewZipSet() }, setnx...)
}

func fetchZSet(key string, setnx ...bool) (ZSet, error) {
Expand Down
45 changes: 20 additions & 25 deletions internal/hash/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,44 +9,39 @@ func genKey(i int) string {
return fmt.Sprintf("%08x", i)
}

func genMap(m MapI, n int) MapI {
for i := 0; i < n; i++ {
k := genKey(i)
m.Set(k, []byte(k))
}
return m
}

func BenchmarkMap(b *testing.B) {
benchMapI("map", func() MapI { return NewMap() }, b)
benchMapI("zipmap", func() MapI { return NewZipMap() }, b)
}

func benchMapI(name string, newf func() MapI, b *testing.B) {
b.Run(name+"-set", func(b *testing.B) {
const N = 512
b.Run(name+"/set", func(b *testing.B) {
for i := 0; i < b.N; i++ {
m := newf()
for i := 0; i < 512; i++ {
k := genKey(i)
m.Set(k, []byte(k))
}
genMap(newf(), N)
}
})
b.Run(name+"-update", func(b *testing.B) {
b.Run(name+"/update", func(b *testing.B) {
m := genMap(newf(), N)
b.ResetTimer()
for i := 0; i < b.N; i++ {
m := newf()
for i := 0; i < 512; i++ {
k := genKey(0)
m.Set(k, []byte(k))
}
k := genKey(i % N)
m.Set(k, []byte(k))
}
})
}

func BenchmarkSet(b *testing.B) {
benchSetI("set", func() SetI { return NewSet() }, b)
benchSetI("zipset", func() SetI { return NewZipSet() }, b)
}

func benchSetI(name string, newf func() SetI, b *testing.B) {
b.Run(name+"-add", func(b *testing.B) {
b.Run(name+"/scan", func(b *testing.B) {
m := genMap(newf(), N)
b.ResetTimer()
for i := 0; i < b.N; i++ {
m := newf()
for i := 0; i < 512; i++ {
m.Add(genKey(i))
}
m.Scan(func(string, []byte) {})
}
})
}
12 changes: 6 additions & 6 deletions internal/hash/map.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import (
)

type MapI interface {
Set(key string, val []byte) (ok bool)
Get(key string) (val []byte, ok bool)
Remove(key string) (ok bool)
Set(key string, val []byte) bool
Get(key string) ([]byte, bool)
Remove(key string) bool
Len() int
Scan(iterator func(key string, val []byte))
Scan(fn func(key string, val []byte))
}

var _ MapI = (*Map)(nil)
Expand All @@ -19,7 +19,7 @@ type Map struct {
}

func NewMap() *Map {
return &Map{m: swiss.New[string, []byte](8)}
return &Map{m: swiss.New[string, []byte](64)}
}

func (m *Map) Get(key string) ([]byte, bool) {
Expand All @@ -42,7 +42,7 @@ func (m *Map) Len() int {
return m.m.Len()
}

func (m *Map) Scan(fn func(key string, value []byte)) {
func (m *Map) Scan(fn func(key string, val []byte)) {
m.m.All(func(key string, val []byte) (next bool) {
fn(key, val)
return true
Expand Down
15 changes: 15 additions & 0 deletions internal/hash/map_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,21 @@ func testMapI(m MapI, t *testing.T) {
assert.True(ok)
assert.Equal(string(val), "newval3")

// scan
count := 0
m.Scan(func(key string, val []byte) {
switch key {
case "key1":
assert.Equal(val, []byte("newval1"))
case "key2":
assert.Equal(val, []byte("newval2"))
case "key3":
assert.Equal(val, []byte("newval3"))
}
count++
})
assert.Equal(count, 3)

// remove
assert.True(m.Remove("key1"))
assert.True(m.Remove("key2"))
Expand Down
10 changes: 9 additions & 1 deletion internal/hash/set.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ type SetI interface {
Add(key string) (ok bool)
Remove(key string) (ok bool)
Pop() (key string, ok bool)
Scan(fn func(string))
Len() int
}

Expand All @@ -18,7 +19,7 @@ type Set struct {
}

func NewSet() *Set {
return &Set{mapset.NewThreadUnsafeSet[string]()}
return &Set{mapset.NewThreadUnsafeSetWithSize[string](64)}
}

func (s Set) Remove(key string) bool {
Expand All @@ -32,3 +33,10 @@ func (s Set) Remove(key string) bool {
func (s Set) Len() int {
return s.Cardinality()
}

func (s Set) Scan(fn func(string)) {
s.Set.Each(func(s string) bool {
fn(s)
return false
})
}
53 changes: 53 additions & 0 deletions internal/hash/set_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package hash

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestSet(t *testing.T) {
testSetI(NewSet(), t)
testSetI(NewZipSet(), t)
}

func testSetI(m SetI, t *testing.T) {
assert := assert.New(t)

// add
assert.True(m.Add("key1"))
assert.True(m.Add("key2"))
assert.True(m.Add("key3"))

// len
assert.Equal(m.Len(), 3)

// scan
count := 0
m.Scan(func(key string) {
switch key {
case "key1", "key2", "key3":
default:
panic("error")
}
count++
})
assert.Equal(count, 3)

// remove
assert.True(m.Remove("key1"))
assert.True(m.Remove("key2"))
assert.False(m.Remove("notexist"))

// pop
key, ok := m.Pop()
assert.Equal(key, "key3")
assert.True(ok)

key, ok = m.Pop()
assert.Equal(key, "")
assert.False(ok)

// len
assert.Equal(m.Len(), 0)
}
14 changes: 14 additions & 0 deletions internal/hash/zipmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,20 @@ func (zm *ZipMap) Len() int {
}

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)
}
}

func (zm *ZipMap) ToMap() *Map {
m := NewMap()
zm.Scan(func(key string, value []byte) {
m.Set(key, value)
})
return m
}

func b2s(b []byte) string {
Expand Down
15 changes: 15 additions & 0 deletions internal/hash/zipset.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,25 @@ func (zs *ZipSet) Remove(key string) bool {
return false
}

func (zs *ZipSet) Scan(fn func(string)) {
it := zs.m.Iterator().SeekLast()
for !it.IsFirst() {
fn(b2s(it.Prev()))
}
}

func (zs *ZipSet) Pop() (string, bool) {
return zs.m.RPop()
}

func (zs *ZipSet) Len() int {
return zs.m.Size()
}

func (zs *ZipSet) ToSet() *Set {
s := NewSet()
s.Scan(func(key string) {
s.Add(key)
})
return s
}
23 changes: 5 additions & 18 deletions internal/list/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,34 +31,20 @@ func BenchmarkList(b *testing.B) {
ls.RPop()
}
})
b.Run("range_all", func(b *testing.B) {
ls := genList(0, 1000)
b.Run("range", func(b *testing.B) {
ls := genList(0, 100)
b.ResetTimer()
for i := 0; i < b.N; i++ {
ls.Range(0, -1, func([]byte) {})
}
})
b.Run("range_100", func(b *testing.B) {
ls := genList(0, 1000)
b.ResetTimer()
for i := 0; i < b.N; i++ {
ls.Range(0, 100, func([]byte) {})
}
})
b.Run("revrange_all", func(b *testing.B) {
ls := genList(0, 1000)
b.Run("revrange", func(b *testing.B) {
ls := genList(0, 100)
b.ResetTimer()
for i := 0; i < b.N; i++ {
ls.RevRange(0, -1, func([]byte) {})
}
})
b.Run("revrange_100", func(b *testing.B) {
ls := genList(0, 1000)
b.ResetTimer()
for i := 0; i < b.N; i++ {
ls.RevRange(0, 100, func([]byte) {})
}
})
}

func BenchmarkListPack(b *testing.B) {
Expand Down Expand Up @@ -92,6 +78,7 @@ func BenchmarkListPack(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
it := lp.Iterator().SeekLast()
it.Prev()
it.ReplaceNext("abcde")
}
})
Expand Down
Loading

0 comments on commit e9fcee0

Please sign in to comment.