Add key prefix matching to KEYS command (#237)
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
Related to #234 and !236. This is the implementation that was requested in the original issue. I updated KEYS command to be redis-valid and implemented prefix search. There is also a rather interesting test, I could you use some feedback here. I noticed that it might not be possible to reduce the complexity of the KEYS command. Because even if you use Scan, you will have to store the counter of all found keys before you do WriteBulk of the actual keys. @prologic here is what you probably had in mind: ``` s.db.Scan([]byte(prefix), func(key []byte) error { conn.WriteBulk(key) return nil }) ``` But there is no way to call `conn.WriteArray(n)` with the number of keys until you iterate through all of them, hence the second loop over found keys. Co-authored-by: Ivan Elfimov <ielfimov@gmail.com> Co-authored-by: James Mills <james@mills.io> Reviewed-on: #237 Reviewed-by: James Mills <james@mills.io> Co-authored-by: biozz <biozz@noreply@mills.io> Co-committed-by: biozz <biozz@noreply@mills.io>scan_deadlock
parent
2279245b8c
commit
21a824e13e
@ -0,0 +1,102 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/tidwall/redcon"
|
||||
)
|
||||
|
||||
func TestHandleKeys(t *testing.T) {
|
||||
s, err := newServer(":61234", "./test.db")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to create server: %v", err)
|
||||
}
|
||||
s.db.Put([]byte("foo"), []byte("bar"))
|
||||
testCases := []TestCase{
|
||||
{
|
||||
Command: redcon.Command{
|
||||
Raw: []byte("KEYS *"),
|
||||
Args: [][]byte{[]byte("KEYS"), []byte("*")},
|
||||
},
|
||||
Expected: "1,foo",
|
||||
},
|
||||
{
|
||||
Command: redcon.Command{
|
||||
Raw: []byte("KEYS fo*"),
|
||||
Args: [][]byte{[]byte("KEYS"), []byte("fo*")},
|
||||
},
|
||||
Expected: "1,foo",
|
||||
},
|
||||
{
|
||||
Command: redcon.Command{
|
||||
Raw: []byte("KEYS ba*"),
|
||||
Args: [][]byte{[]byte("KEYS"), []byte("ba*")},
|
||||
},
|
||||
Expected: "0",
|
||||
},
|
||||
{
|
||||
Command: redcon.Command{
|
||||
Raw: []byte("KEYS *oo"),
|
||||
Args: [][]byte{[]byte("KEYS"), []byte("*oo")},
|
||||
},
|
||||
Expected: "0",
|
||||
},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
conn := DummyConn{}
|
||||
s.handleKeys(testCase.Command, &conn)
|
||||
if testCase.Expected != conn.Result {
|
||||
t.Fatalf("s.handleKeys failed: expected '%s', got '%s'", testCase.Expected, conn.Result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type TestCase struct {
|
||||
Command redcon.Command
|
||||
Expected string
|
||||
}
|
||||
|
||||
type DummyConn struct {
|
||||
Result string
|
||||
}
|
||||
|
||||
func (dc *DummyConn) RemoteAddr() string {
|
||||
return ""
|
||||
}
|
||||
func (dc *DummyConn) Close() error {
|
||||
return nil
|
||||
}
|
||||
func (dc *DummyConn) WriteError(msg string) {}
|
||||
func (dc *DummyConn) WriteString(str string) {}
|
||||
func (dc *DummyConn) WriteBulk(bulk []byte) {
|
||||
dc.Result += "," + string(bulk)
|
||||
}
|
||||
func (dc *DummyConn) WriteBulkString(bulk string) {}
|
||||
func (dc *DummyConn) WriteInt(num int) {}
|
||||
func (dc *DummyConn) WriteInt64(num int64) {}
|
||||
func (dc *DummyConn) WriteUint64(num uint64) {}
|
||||
func (dc *DummyConn) WriteArray(count int) {
|
||||
dc.Result = strconv.Itoa(count)
|
||||
}
|
||||
func (dc *DummyConn) WriteNull() {}
|
||||
func (dc *DummyConn) WriteRaw(data []byte) {}
|
||||
func (dc *DummyConn) WriteAny(any interface{}) {}
|
||||
func (dc *DummyConn) Context() interface{} {
|
||||
return nil
|
||||
}
|
||||
func (dc *DummyConn) SetContext(v interface{}) {}
|
||||
func (dc *DummyConn) SetReadBuffer(bytes int) {}
|
||||
func (dc *DummyConn) Detach() redcon.DetachedConn {
|
||||
return nil
|
||||
}
|
||||
func (dc *DummyConn) ReadPipeline() []redcon.Command {
|
||||
return nil
|
||||
}
|
||||
func (dc *DummyConn) PeekPipeline() []redcon.Command {
|
||||
return nil
|
||||
}
|
||||
func (dc *DummyConn) NetConn() net.Conn {
|
||||
return nil
|
||||
}
|
Loading…
Reference in new issue