Skip to content

Commit 2bfead5

Browse files
authored
Merge pull request #8 from youzan/more-cmd-support
More bit cmd support
2 parents 088d166 + d3685bc commit 2bfead5

File tree

9 files changed

+218
-8
lines changed

9 files changed

+218
-8
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
language: go
22
go:
3-
- 1.8.x
43
- 1.9.x
4+
- 1.10.x
55
env:
66
- GOARCH=amd64 TEST_RACE=false
77
- GOARCH=amd64 TEST_RACE=true

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ CGO_CFLAGS="-I/path/to/rocksdb/include" CGO_LDFLAGS="-L/path/to/rocksdb -lrocksd
3838

3939
use the `dep ensure` to install other dependencies
4040

41-
Build zankv and placedriver from the source (only support go version 1.8+, gcc 4.9+ or xcode-command-line-tools on Mac):
41+
Build zankv and placedriver from the source (only support go version 1.9+, gcc 4.9+ or xcode-command-line-tools on Mac):
4242
<pre>
4343
make
4444
</pre>

node/keys.go

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package node
22

33
import (
4+
"fmt"
45
"strconv"
56
"time"
67

7-
"github.com/youzan/ZanRedisDB/common"
88
"github.com/absolute8511/redcon"
9+
"github.com/youzan/ZanRedisDB/common"
10+
"github.com/youzan/ZanRedisDB/rockredis"
911
)
1012

1113
func (nd *KVNode) Lookup(key []byte) ([]byte, error) {
@@ -32,6 +34,51 @@ func (nd *KVNode) existsCommand(cmd redcon.Command) (interface{}, error) {
3234
return val, err
3335
}
3436

37+
func (nd *KVNode) getbitCommand(conn redcon.Conn, cmd redcon.Command) {
38+
if len(cmd.Args) < 3 {
39+
conn.WriteError(errWrongNumberArgs.Error())
40+
return
41+
}
42+
offset, err := strconv.ParseInt(string(cmd.Args[2]), 10, 64)
43+
if err != nil {
44+
conn.WriteError(err.Error())
45+
return
46+
}
47+
val, err := nd.store.BitGet(cmd.Args[1], offset)
48+
if err != nil {
49+
conn.WriteError(err.Error())
50+
return
51+
}
52+
conn.WriteInt64(val)
53+
}
54+
55+
func (nd *KVNode) bitcountCommand(conn redcon.Conn, cmd redcon.Command) {
56+
if len(cmd.Args) != 2 && len(cmd.Args) != 4 {
57+
conn.WriteError(errWrongNumberArgs.Error())
58+
return
59+
}
60+
start, end := int64(0), int64(-1)
61+
var err error
62+
if len(cmd.Args) == 4 {
63+
start, err = strconv.ParseInt(string(cmd.Args[2]), 10, 64)
64+
if err != nil {
65+
conn.WriteError(err.Error())
66+
return
67+
}
68+
end, err = strconv.ParseInt(string(cmd.Args[3]), 10, 64)
69+
if err != nil {
70+
conn.WriteError(err.Error())
71+
return
72+
}
73+
}
74+
val, err := nd.store.BitCount(cmd.Args[1], int(start), int(end))
75+
if err != nil {
76+
conn.WriteError(err.Error())
77+
return
78+
}
79+
conn.WriteInt64(val)
80+
}
81+
3582
func (nd *KVNode) mgetCommand(conn redcon.Conn, cmd redcon.Command) {
3683
vals, _ := nd.store.MGet(cmd.Args[1:]...)
3784
conn.WriteArray(len(vals))
@@ -67,6 +114,42 @@ func (nd *KVNode) setnxCommand(conn redcon.Conn, cmd redcon.Command, v interface
67114
}
68115
}
69116

117+
func (nd *KVNode) setbitCommand(conn redcon.Conn, cmd redcon.Command) {
118+
if len(cmd.Args) != 4 {
119+
conn.WriteError(errWrongNumberArgs.Error())
120+
return
121+
}
122+
123+
offset, err := strconv.ParseInt(string(cmd.Args[2]), 10, 64)
124+
if err != nil {
125+
conn.WriteError(err.Error())
126+
return
127+
}
128+
on, err := strconv.ParseInt(string(cmd.Args[3]), 10, 64)
129+
if err != nil {
130+
conn.WriteError(err.Error())
131+
return
132+
}
133+
if offset > rockredis.MaxBitOffset {
134+
conn.WriteError(rockredis.ErrBitOverflow.Error())
135+
return
136+
}
137+
if (on & ^1) != 0 {
138+
conn.WriteError(fmt.Errorf("bit should be 0 or 1, got %d", on).Error())
139+
return
140+
}
141+
142+
_, v, ok := rebuildFirstKeyAndPropose(nd, conn, cmd)
143+
if !ok {
144+
return
145+
}
146+
if rsp, ok := v.(int64); ok {
147+
conn.WriteInt64(rsp)
148+
} else {
149+
conn.WriteError(errInvalidResponse.Error())
150+
}
151+
}
152+
70153
func (nd *KVNode) msetCommand(cmd redcon.Command, v interface{}) (interface{}, error) {
71154
return nil, nil
72155
}
@@ -158,3 +241,15 @@ func (kvsm *kvStoreSM) localPFAddCommand(cmd redcon.Command, ts int64) (interfac
158241
v, err := kvsm.store.PFAdd(ts, cmd.Args[1], cmd.Args[2:]...)
159242
return v, err
160243
}
244+
245+
func (kvsm *kvStoreSM) localBitSetCommand(cmd redcon.Command, ts int64) (interface{}, error) {
246+
offset, err := strconv.ParseInt(string(cmd.Args[2]), 10, 64)
247+
if err != nil {
248+
return 0, err
249+
}
250+
on, err := strconv.ParseInt(string(cmd.Args[3]), 10, 64)
251+
if err != nil {
252+
return 0, err
253+
}
254+
return kvsm.store.BitSet(ts, cmd.Args[1], offset, int(on))
255+
}

node/keys_test.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ import (
1111
"testing"
1212
"time"
1313

14+
"github.com/absolute8511/redcon"
15+
"github.com/stretchr/testify/assert"
1416
"github.com/youzan/ZanRedisDB/common"
1517
"github.com/youzan/ZanRedisDB/rockredis"
1618
"github.com/youzan/ZanRedisDB/stats"
1719
"github.com/youzan/ZanRedisDB/transport/rafthttp"
18-
"github.com/absolute8511/redcon"
19-
"github.com/stretchr/testify/assert"
2020
)
2121

2222
func getTestKVNode(t *testing.T) (*KVNode, string, chan struct{}) {
@@ -150,6 +150,7 @@ func TestKVNode_kvCommand(t *testing.T) {
150150
testKey2 := []byte("default:test:2")
151151
testKey2Value := []byte("2")
152152
testPFKey := []byte("default:test:pf1")
153+
testBitKey := []byte("default:test:bit1")
153154
tests := []struct {
154155
name string
155156
args redcon.Command
@@ -169,6 +170,9 @@ func TestKVNode_kvCommand(t *testing.T) {
169170
{"exists", buildCommand([][]byte{[]byte("exists"), testKey})},
170171
{"pfadd", buildCommand([][]byte{[]byte("pfadd"), testPFKey, testKeyValue})},
171172
{"pfcount", buildCommand([][]byte{[]byte("pfcount"), testPFKey})},
173+
{"setbit", buildCommand([][]byte{[]byte("setbit"), testBitKey, []byte("1"), []byte("1")})},
174+
{"getbit", buildCommand([][]byte{[]byte("getbit"), testBitKey, []byte("1")})},
175+
{"bitcount", buildCommand([][]byte{[]byte("bitcount"), testBitKey, []byte("1"), []byte("2")})},
172176
}
173177
defer os.RemoveAll(dataDir)
174178
defer nd.Stop()

node/namespace.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,10 +337,20 @@ func (nsm *NamespaceMgr) InitNamespaceNode(conf *NamespaceConfig, raftID uint64,
337337
if err != nil {
338338
return nil, err
339339
}
340-
if _, ok := nsm.nsMetas[conf.BaseName]; !ok {
340+
if oldMeta, ok := nsm.nsMetas[conf.BaseName]; !ok {
341341
nsm.nsMetas[conf.BaseName] = NamespaceMeta{
342342
PartitionNum: conf.PartitionNum,
343343
}
344+
nodeLog.Infof("namespace meta init: %v", conf)
345+
} else {
346+
if oldMeta.PartitionNum != conf.PartitionNum {
347+
nodeLog.Errorf("namespace meta mismatch: %v, old: %v", conf, oldMeta)
348+
// update the meta if mismatch, it may happen if create the same namespace with different
349+
// config for old deleted namespace
350+
nsm.nsMetas[conf.BaseName] = NamespaceMeta{
351+
PartitionNum: conf.PartitionNum,
352+
}
353+
}
344354
}
345355

346356
n := &NamespaceNode{

node/node.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ var (
3131
errUnknownData = errors.New("unknown request data type")
3232
errTooMuchBatchSize = errors.New("the batch size exceed the limit")
3333
errRaftNotReadyForWrite = errors.New("ERR_CLUSTER_CHANGED: the raft is not ready for write")
34+
errWrongNumberArgs = errors.New("ERR wrong number of arguments for redis command")
3435
)
3536

3637
const (

node/node_cmd_reg.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ func (kvsm *kvStoreSM) registerHandlers() {
55
// kv
66
kvsm.router.RegisterInternal("del", kvsm.localDelCommand)
77
kvsm.router.RegisterInternal("set", kvsm.localSetCommand)
8+
kvsm.router.RegisterInternal("setbit", kvsm.localBitSetCommand)
89
kvsm.router.RegisterInternal("setnx", kvsm.localSetnxCommand)
910
kvsm.router.RegisterInternal("mset", kvsm.localMSetCommand)
1011
kvsm.router.RegisterInternal("incr", kvsm.localIncrCommand)
@@ -72,8 +73,11 @@ func (nd *KVNode) registerHandler() {
7273
}
7374
// for kv
7475
nd.router.Register(false, "get", wrapReadCommandK(nd.getCommand))
76+
nd.router.Register(false, "getbit", wrapReadCommandKAnySubkeyN(nd.getbitCommand, 1))
77+
nd.router.Register(false, "bitcount", wrapReadCommandKAnySubkey(nd.bitcountCommand))
7578
nd.router.Register(false, "mget", wrapReadCommandKK(nd.mgetCommand))
7679
nd.router.Register(true, "set", wrapWriteCommandKV(nd, nd.setCommand))
80+
nd.router.Register(true, "setbit", nd.setbitCommand)
7781
nd.router.Register(true, "setnx", wrapWriteCommandKV(nd, nd.setnxCommand))
7882
nd.router.Register(true, "incr", wrapWriteCommandK(nd, nd.incrCommand))
7983
nd.router.Register(true, "incrby", wrapWriteCommandKV(nd, nd.incrbyCommand))

rockredis/t_kv.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const (
1919

2020
var errKVKey = errors.New("invalid encode kv key")
2121
var errInvalidDBValue = errors.New("invalide db value")
22-
var errBitOverflow = errors.New("bit offset overflowed")
22+
var ErrBitOverflow = errors.New("bit offset overflowed")
2323

2424
func convertRedisKeyToDBKVKey(key []byte) ([]byte, []byte, error) {
2525
table, _, _ := extractTableFromRedisKey(key)
@@ -530,7 +530,7 @@ func (db *RockDB) BitSet(ts int64, key []byte, offset int64, on int) (int64, err
530530
return 0, err
531531
}
532532
if offset > MaxBitOffset {
533-
return 0, errBitOverflow
533+
return 0, ErrBitOverflow
534534
}
535535

536536
if (on & ^1) != 0 {
@@ -625,6 +625,9 @@ func (db *RockDB) BitCount(key []byte, start, end int) (int64, error) {
625625
return 0, err
626626
}
627627
start, end = getRange(start, end, len(v))
628+
if start > end {
629+
return 0, nil
630+
}
628631
v = v[start : end+1]
629632
return popcountBytes(v), nil
630633
}

server/redis_api_test.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,81 @@ func TestKVIncrDecr(t *testing.T) {
332332
}
333333
}
334334

335+
func TestKVBitOp(t *testing.T) {
336+
c := getTestConn(t)
337+
defer c.Close()
338+
339+
key := "default:test:kv_bitop"
340+
if n, err := goredis.Int64(c.Do("bitcount", key)); err != nil {
341+
t.Fatal(err)
342+
} else if n != 0 {
343+
t.Fatal(n)
344+
}
345+
346+
if n, err := goredis.Int64(c.Do("getbit", key, 1)); err != nil {
347+
t.Fatal(err)
348+
} else if n != 0 {
349+
t.Fatal(n)
350+
}
351+
352+
if n, err := goredis.Int64(c.Do("setbit", key, 100, 1)); err != nil {
353+
t.Fatal(err)
354+
} else if n != 0 {
355+
t.Fatal(n)
356+
}
357+
358+
if n, err := goredis.Int64(c.Do("getbit", key, 100)); err != nil {
359+
t.Fatal(err)
360+
} else if n != 1 {
361+
t.Fatal(n)
362+
}
363+
if n, err := goredis.Int64(c.Do("bitcount", key)); err != nil {
364+
t.Fatal(err)
365+
} else if n != 1 {
366+
t.Fatal(n)
367+
}
368+
if n, err := goredis.Int64(c.Do("setbit", key, 1, 1)); err != nil {
369+
t.Fatal(err)
370+
} else if n != 0 {
371+
t.Fatal(n)
372+
}
373+
if n, err := goredis.Int64(c.Do("bitcount", key)); err != nil {
374+
t.Fatal(err)
375+
} else if n != 2 {
376+
t.Fatal(n)
377+
}
378+
if n, err := goredis.Int64(c.Do("bitcount", key, 0, 0)); err != nil {
379+
t.Fatal(err)
380+
} else if n != 1 {
381+
t.Fatal(n)
382+
}
383+
if n, err := goredis.Int64(c.Do("setbit", key, 8, 1)); err != nil {
384+
t.Fatal(err)
385+
} else if n != 0 {
386+
t.Fatal(n)
387+
}
388+
if n, err := goredis.Int64(c.Do("bitcount", key, 0, 0)); err != nil {
389+
t.Fatal(err)
390+
} else if n != 1 {
391+
t.Fatal(n)
392+
}
393+
if n, err := goredis.Int64(c.Do("setbit", key, 7, 1)); err != nil {
394+
t.Fatal(err)
395+
} else if n != 0 {
396+
t.Fatal(n)
397+
}
398+
if n, err := goredis.Int64(c.Do("bitcount", key, 0, 0)); err != nil {
399+
t.Fatal(err)
400+
} else if n != 2 {
401+
t.Fatal(n)
402+
}
403+
if n, err := goredis.Int64(c.Do("bitcount", key, 0, 1)); err != nil {
404+
t.Fatal(err)
405+
} else if n != 3 {
406+
t.Fatal(n)
407+
}
408+
}
409+
335410
func TestKVBatch(t *testing.T) {
336411

337412
var wg sync.WaitGroup
@@ -546,6 +621,24 @@ func TestKVErrorParams(t *testing.T) {
546621

547622
_, err = c.Do("mget")
548623
assert.NotNil(t, err)
624+
625+
_, err = c.Do("getbit")
626+
assert.NotNil(t, err)
627+
628+
_, err = c.Do("getbit", key1)
629+
assert.NotNil(t, err)
630+
631+
_, err = c.Do("setbit", key1)
632+
assert.NotNil(t, err)
633+
634+
_, err = c.Do("setbit")
635+
assert.NotNil(t, err)
636+
637+
_, err = c.Do("bitcount")
638+
assert.NotNil(t, err)
639+
640+
_, err = c.Do("bitcount", key1, "0")
641+
assert.NotNil(t, err)
549642
}
550643

551644
func TestPFOp(t *testing.T) {

0 commit comments

Comments
 (0)