1
0
mirror of https://git.mills.io/kayos/bitraft.git synced 2024-06-20 22:08:48 +00:00

redis-cli compliant 'KEYS' command: fixes issue #39 (#44)

This commit is contained in:
Sebastien Leger 2021-02-17 07:57:12 +01:00 committed by GitHub
parent 4eb73c203a
commit 1eb412ca8b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 48 additions and 33 deletions

@ -45,7 +45,7 @@ Commands:
SET key value
GET key
DEL key [key ...]
KEYS [WITHVALUES]
KEYS pattern
FLUSHDB
SHUTDOWN
```

1
go.sum

@ -186,6 +186,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prologic/bitcask v0.3.9 h1:GuSlzUUiIwyCOV4za7LipfjJC9FV0BgHIGbwOEcssL0=
github.com/prologic/bitcask v0.3.9/go.mod h1:WQuqL23CGZcC83DhKuXH6KMHe1m25+Eb43s8yM3MnF0=
github.com/prologic/bitcask v0.3.10 h1:HXygU8zCvW5gLpZ8aQECPk5iV/YQ3hcqdg/zVeES6s0=
github.com/prologic/bitcask v0.3.10/go.mod h1:8RKJdbHLE7HFGLYSGu9slnYXSV7DMIucwVkaIYOk9GY=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=

@ -5,6 +5,10 @@ import (
"compress/gzip"
"encoding/binary"
"errors"
"github.com/prologic/bitcask"
log "github.com/sirupsen/logrus"
"github.com/tidwall/finn"
"github.com/tidwall/redcon"
"io"
"net"
"os"
@ -13,19 +17,47 @@ import (
"strings"
"sync"
"time"
"github.com/prologic/bitcask"
log "github.com/sirupsen/logrus"
"github.com/tidwall/finn"
"github.com/tidwall/redcon"
)
const defaultTCPKeepAlive = time.Minute * 5
var (
errSyntaxError = errors.New("syntax error")
errWrongNumberOfArguments = errors.New("wrong number of arguments")
)
func trimPattern(glob string) string {
escaped := false
pattern := ""
for _, char := range glob {
switch char {
case '\\':
escaped = !escaped
if !escaped {
pattern = pattern + string(char)
}
case '*':
if !escaped {
goto out
}
pattern = pattern + string(char)
case '?':
if !escaped {
goto out
}
pattern = pattern + string(char)
case '[':
if !escaped {
goto out
}
pattern = pattern + string(char)
default:
pattern = pattern + string(char)
}
}
out:
return pattern
}
func ListenAndServe(addr, join, dir, logdir string, consistency, durability finn.Level) error {
opts := finn.Options{
Backend: finn.FastLog,
@ -339,46 +371,28 @@ func (kvm *Machine) cmdDel(m finn.Applier, conn redcon.Conn, cmd redcon.Command)
}
func (kvm *Machine) cmdKeys(m finn.Applier, conn redcon.Conn, cmd redcon.Command) (interface{}, error) {
var withvalues bool
for i := 1; i < len(cmd.Args); i++ {
switch strings.ToLower(string(cmd.Args[i])) {
default:
return nil, errSyntaxError
case "withvalues":
withvalues = true
}
if len(cmd.Args) != 2 {
return nil, errWrongNumberOfArguments
}
pattern := string(cmd.Args[1])
scanPattern := trimPattern(pattern)
return m.Apply(conn, cmd, nil,
func(interface{}) (interface{}, error) {
kvm.mu.RLock()
defer kvm.mu.RUnlock()
var keys [][]byte
var values [][]byte
err := kvm.db.Fold(func(key []byte) error {
keys = append(keys, []byte(key))
if withvalues {
value, err := kvm.db.Get(key)
if err != nil {
return err
}
values = append(values, value)
err := kvm.db.Scan([]byte(scanPattern), func(key []byte) error {
if ok, _ := filepath.Match(pattern, string(key)); ok {
keys = append(keys, []byte(key))
}
return nil
})
if err != nil {
return nil, err
}
if withvalues {
conn.WriteArray(len(keys) * 2)
} else {
conn.WriteArray(len(keys))
}
conn.WriteArray(len(keys))
for i := 0; i < len(keys); i++ {
conn.WriteBulk(keys[i])
if withvalues {
conn.WriteBulk(values[i])
}
}
return nil, nil
},