diff --git a/command.go b/command.go index f62ea1e..6b4f7b7 100644 --- a/command.go +++ b/command.go @@ -104,7 +104,7 @@ func setCommand(writer *RESPWriter, args []RESP) { writer.WriteError(errParseInteger) return } - ttl = time.Now().Add(time.Second * time.Duration(n)).UnixNano() + ttl = dict.GetNanoTime() + int64(time.Second)*int64(n) extra = extra[2:] // PX @@ -114,7 +114,7 @@ func setCommand(writer *RESPWriter, args []RESP) { writer.WriteError(errParseInteger) return } - ttl = time.Now().Add(time.Millisecond * time.Duration(n)).UnixNano() + ttl = dict.GetNanoTime() + int64(time.Millisecond)*int64(n) extra = extra[2:] // KEEPTTL diff --git a/command_test.go b/command_test.go index 27beb31..02a5c89 100644 --- a/command_test.go +++ b/command_test.go @@ -353,6 +353,18 @@ func TestCommand(t *testing.T) { res, _ := rdb.ZRem(ctx, "rank", "player1", "player2", "player999").Result() assert.Equal(res, int64(2)) + + // err wrong type + rdb.Set(ctx, "key", "value", 0) + + _, err := rdb.ZAdd(ctx, "key", redis.Z{}).Result() + assert.Equal(err.Error(), errWrongType.Error()) + + _, err = rdb.ZRank(ctx, "key", "member1").Result() + assert.Equal(err.Error(), errWrongType.Error()) + + _, err = rdb.ZRem(ctx, "key", "member1").Result() + assert.Equal(err.Error(), errWrongType.Error()) }) t.Run("flushdb", func(t *testing.T) { diff --git a/go.mod b/go.mod index ca04cf0..c3bdbe3 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.22 require ( github.com/chen3feng/stl4go v0.1.1 github.com/deckarep/golang-set/v2 v2.6.0 - github.com/dolthub/swiss v0.2.1 github.com/influxdata/tdigest v0.0.1 github.com/redis/go-redis/v9 v9.5.2 github.com/rs/zerolog v1.33.0 @@ -18,7 +17,6 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/dolthub/maphash v0.1.0 // indirect github.com/edsrzf/mmap-go v1.1.0 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/kr/pretty v0.3.0 // indirect diff --git a/go.sum b/go.sum index 603c4fb..8fb972a 100644 --- a/go.sum +++ b/go.sum @@ -14,10 +14,6 @@ github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80N github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/dolthub/maphash v0.1.0 h1:bsQ7JsF4FkkWyrP3oCnFJgrCUAFbFf3kOl4L/QxPDyQ= -github.com/dolthub/maphash v0.1.0/go.mod h1:gkg4Ch4CdCDu5h6PMriVLawB7koZ+5ijb9puGMV50a4= -github.com/dolthub/swiss v0.2.1 h1:gs2osYs5SJkAaH5/ggVJqXQxRXtWshF6uE0lgR/Y3Gw= -github.com/dolthub/swiss v0.2.1/go.mod h1:8AhKZZ1HK7g18j7v7k6c5cYIGEZJcPn0ARsai8cUrh0= github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ= github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= diff --git a/internal/dict/benchmark/main.go b/internal/dict/benchmark/main.go index 5bdaef2..768f367 100644 --- a/internal/dict/benchmark/main.go +++ b/internal/dict/benchmark/main.go @@ -7,7 +7,6 @@ import ( "runtime/debug" "time" - "github.com/dolthub/swiss" "github.com/influxdata/tdigest" "github.com/xgzlucario/rotom/internal/dict" ) @@ -60,15 +59,6 @@ func main() { m[k] = v td.Add(float64(time.Since(start)), 1) } - - case "swiss": - m := swiss.NewMap[string, any](8) - for i := 0; i < entries; i++ { - k, v := genKV(i) - start := time.Now() - m.Put(k, v) - td.Add(float64(time.Since(start)), 1) - } } cost := time.Since(start) diff --git a/internal/dict/dict.go b/internal/dict/dict.go index ecc838c..29ab9cc 100644 --- a/internal/dict/dict.go +++ b/internal/dict/dict.go @@ -3,8 +3,6 @@ package dict import ( "sync/atomic" "time" - - "github.com/dolthub/swiss" ) const ( @@ -34,33 +32,33 @@ func GetNanoTime() int64 { // Dict is the hashmap for Rotom. type Dict struct { - data *swiss.Map[string, any] - expire *swiss.Map[string, int64] + data map[string]any + expire map[string]int64 } func New() *Dict { return &Dict{ - data: swiss.NewMap[string, any](64), - expire: swiss.NewMap[string, int64](64), + data: make(map[string]any, 64), + expire: make(map[string]int64, 64), } } func (dict *Dict) Get(key string) (any, int) { - data, ok := dict.data.Get(key) + data, ok := dict.data[key] if !ok { // key not exist return nil, KEY_NOT_EXIST } - nsec, ok := dict.expire.Get(key) + nsec, ok := dict.expire[key] if !ok { return data, TTL_FOREVER } // key expired if nsec < _nsec.Load() { - dict.data.Delete(key) - dict.expire.Delete(key) + delete(dict.data, key) + delete(dict.expire, key) return nil, KEY_NOT_EXIST } @@ -68,23 +66,23 @@ func (dict *Dict) Get(key string) (any, int) { } func (dict *Dict) Set(key string, data any) { - dict.data.Put(key, data) + dict.data[key] = data } func (dict *Dict) SetWithTTL(key string, data any, ttl int64) { if ttl > 0 { - dict.expire.Put(key, ttl) + dict.expire[key] = ttl } - dict.data.Put(key, data) + dict.data[key] = data } func (dict *Dict) Delete(key string) bool { - _, ok := dict.data.Get(key) + _, ok := dict.data[key] if !ok { return false } - dict.data.Delete(key) - dict.expire.Delete(key) + delete(dict.data, key) + delete(dict.expire, key) return true } @@ -92,35 +90,37 @@ func (dict *Dict) Delete(key string) bool { // return `0` if key not exist or expired. // return `1` if set successed. func (dict *Dict) SetTTL(key string, ttl int64) int { - _, ok := dict.data.Get(key) + _, ok := dict.data[key] if !ok { // key not exist return 0 } // check key if already expired - nsec, ok := dict.expire.Get(key) + nsec, ok := dict.expire[key] if ok && nsec < _nsec.Load() { - dict.data.Delete(key) - dict.expire.Delete(key) + delete(dict.data, key) + delete(dict.expire, key) return 0 } // set ttl - dict.expire.Put(key, ttl) + dict.expire[key] = ttl return 1 } func (dict *Dict) EvictExpired() { var count int - dict.expire.Iter(func(key string, nsec int64) bool { + for key, nsec := range dict.expire { if _nsec.Load() > nsec { - dict.expire.Delete(key) - dict.data.Delete(key) + delete(dict.expire, key) + delete(dict.data, key) } count++ - return count > 20 - }) + if count > 20 { + return + } + } } func nsec2duration(nsec int64) (second int) { diff --git a/internal/hash/map.go b/internal/hash/map.go index fcb7a66..95b4985 100644 --- a/internal/hash/map.go +++ b/internal/hash/map.go @@ -1,9 +1,5 @@ package hash -import ( - "github.com/dolthub/swiss" -) - type MapI interface { Set(key string, val []byte) bool Get(key string) ([]byte, bool) @@ -15,34 +11,36 @@ type MapI interface { var _ MapI = (*Map)(nil) type Map struct { - data *swiss.Map[string, []byte] + data map[string][]byte } func NewMap() *Map { - return &Map{swiss.NewMap[string, []byte](256)} + return &Map{make(map[string][]byte, 256)} } func (m *Map) Get(key string) ([]byte, bool) { - return m.data.Get(key) + val, ok := m.data[key] + return val, ok } func (m *Map) Set(key string, val []byte) bool { - _, ok := m.data.Get(key) - m.data.Put(key, val) + _, ok := m.data[key] + m.data[key] = val return !ok } func (m *Map) Remove(key string) bool { - return m.data.Delete(key) + _, ok := m.data[key] + delete(m.data, key) + return ok } func (m *Map) Len() int { - return m.data.Count() + return len(m.data) } func (m *Map) Scan(fn func(key string, val []byte)) { - m.data.Iter(func(key string, val []byte) (stop bool) { + for key, val := range m.data { fn(key, val) - return false - }) + } } diff --git a/internal/zset/zset.go b/internal/zset/zset.go index 192b656..5b2ed65 100644 --- a/internal/zset/zset.go +++ b/internal/zset/zset.go @@ -4,7 +4,6 @@ import ( "cmp" "github.com/chen3feng/stl4go" - "github.com/dolthub/swiss" ) type node struct { @@ -20,23 +19,24 @@ func nodeCompare(a, b node) int { } type ZSet struct { - m *swiss.Map[string, float64] + m map[string]float64 skl *stl4go.SkipList[node, struct{}] } func NewZSet() *ZSet { return &ZSet{ - m: swiss.NewMap[string, float64](8), + m: make(map[string]float64), skl: stl4go.NewSkipListFunc[node, struct{}](nodeCompare), } } func (z *ZSet) Get(key string) (float64, bool) { - return z.m.Get(key) + val, ok := z.m[key] + return val, ok } func (z *ZSet) Set(key string, score float64) bool { - old, ok := z.m.Get(key) + old, ok := z.m[key] if ok { // same if score == old { @@ -44,17 +44,17 @@ func (z *ZSet) Set(key string, score float64) bool { } z.skl.Remove(node{key, old}) } - z.m.Put(key, score) + z.m[key] = score z.skl.Insert(node{key, score}, struct{}{}) return !ok } func (z *ZSet) Remove(key string) bool { - score, ok := z.m.Get(key) + score, ok := z.m[key] if !ok { return false } - z.m.Delete(key) + delete(z.m, key) z.skl.Remove(node{key, score}) return true } @@ -65,13 +65,13 @@ func (z *ZSet) PopMin() (key string, score float64) { score = n.score return false }) - z.m.Delete(key) + delete(z.m, key) z.skl.Remove(node{key, score}) return } func (z *ZSet) Rank(key string) (int, float64) { - score, ok := z.m.Get(key) + score, ok := z.m[key] if !ok { return -1, 0 } @@ -95,5 +95,5 @@ func (z *ZSet) Range(start, stop int, fn func(key string, score float64)) { } func (z *ZSet) Len() int { - return z.m.Count() + return len(z.m) } diff --git a/rotom.go b/rotom.go index 8cea3c3..cf1d00e 100644 --- a/rotom.go +++ b/rotom.go @@ -119,7 +119,7 @@ READ: client.recvx += n if readSize == 0 { - log.Warn().Msgf("client %d read query empty, now free", fd) + log.Info().Msgf("client %d read query empty, now free", fd) freeClient(client) return }