diff --git a/ledis/const.go b/ledis/const.go index 156f439..64473ad 100644 --- a/ledis/const.go +++ b/ledis/const.go @@ -15,6 +15,10 @@ const ( zScoreType ) +const ( + defaultScanCount int = 20 +) + const ( //we don't support too many databases MaxDBNumber uint8 = 16 diff --git a/ledis/t_kv.go b/ledis/t_kv.go index d2acc50..fa31b90 100644 --- a/ledis/t_kv.go +++ b/ledis/t_kv.go @@ -35,6 +35,17 @@ func (db *DB) decodeKVKey(ek []byte) ([]byte, error) { return ek[2:], nil } +func (db *DB) encodeKVMinKey() []byte { + ek := db.encodeKVKey(nil) + return ek +} + +func (db *DB) encodeKVMaxKey() []byte { + ek := db.encodeKVKey(nil) + ek[len(ek)-1] = kvType + 1 + return ek +} + func (db *DB) incr(key []byte, delta int64) (int64, error) { if err := checkKeySize(key); err != nil { return 0, err @@ -265,13 +276,8 @@ func (db *DB) KvFlush() (drop int64, err error) { t.Lock() defer t.Unlock() - minKey := make([]byte, 2) - minKey[0] = db.index - minKey[1] = kvType - - maxKey := make([]byte, 2) - maxKey[0] = db.index - maxKey[1] = kvType + 1 + minKey := db.encodeKVMinKey() + maxKey := db.encodeKVMaxKey() it := db.db.Iterator(minKey, maxKey, leveldb.RangeROpen, 0, -1) for ; it.Valid(); it.Next() { @@ -282,3 +288,37 @@ func (db *DB) KvFlush() (drop int64, err error) { err = t.Commit() return } + +func (db *DB) Scan(cursor int, count int) ([]interface{}, error) { + minKey := db.encodeKVMinKey() + maxKey := db.encodeKVMaxKey() + + if count <= 0 { + count = defaultScanCount + } + + v := make([]interface{}, 2) + r := make([]interface{}, 0, count) + + var num int = 0 + it := db.db.Iterator(minKey, maxKey, leveldb.RangeROpen, cursor, count) + for ; it.Valid(); it.Next() { + num++ + + if key, err := db.decodeKVKey(it.Key()); err != nil { + continue + } else { + r = append(r, key) + } + } + + if num < count { + v[0] = int64(0) + } else { + v[0] = int64(cursor + count) + } + + v[1] = r + + return v, nil +} diff --git a/server/cmd_kv.go b/server/cmd_kv.go index a6bdcbd..11ec4c6 100644 --- a/server/cmd_kv.go +++ b/server/cmd_kv.go @@ -2,6 +2,7 @@ package server import ( "github.com/siddontang/ledisdb/ledis" + "strings" ) func getCommand(c *client) error { @@ -203,6 +204,40 @@ func mgetCommand(c *client) error { return nil } +func scanCommand(c *client) error { + args := c.args + + if len(args) != 1 && len(args) != 3 { + return ErrCmdParams + } + var offset int64 + var count int64 + var err error + + if offset, err = ledis.StrInt64(args[0], nil); err != nil { + return err + } + + //now we only support count + if len(args) == 3 { + if strings.ToLower(ledis.String(args[1])) != "count" { + return ErrCmdParams + } + + if count, err = ledis.StrInt64(args[2], nil); err != nil { + return err + } + } + + if v, err := c.db.Scan(int(offset), int(count)); err != nil { + return err + } else { + c.writeArray(v) + } + + return nil +} + func init() { register("decr", decrCommand) register("decrby", decrbyCommand) @@ -216,4 +251,5 @@ func init() { register("mset", msetCommand) register("set", setCommand) register("setnx", setnxCommand) + register("scan", scanCommand) }