From e2250d7dc092f8b012f37a8b381ac88941798daa Mon Sep 17 00:00:00 2001 From: qishenonly <1050026498@qq.com> Date: Wed, 24 Jan 2024 23:44:14 +0800 Subject: [PATCH 1/7] Compatible with redis protocol(RESP) --- go.mod | 8 +++-- go.sum | 8 +++-- lib/redis/client.go | 60 +++++++++++++++++++++++++++++++++++ lib/redis/cmd/flydb_server.go | 32 +++++++++++++++++++ lib/redis/hash.go | 44 +++++++++++++++++++++++++ lib/redis/server.go | 40 +++++++++++++++++++++++ lib/redis/string.go | 40 +++++++++++++++++++++++ structure/string.go | 4 +++ 8 files changed, 231 insertions(+), 5 deletions(-) create mode 100644 lib/redis/client.go create mode 100644 lib/redis/cmd/flydb_server.go create mode 100644 lib/redis/hash.go create mode 100644 lib/redis/server.go create mode 100644 lib/redis/string.go diff --git a/go.mod b/go.mod index 8f28b68..fe021ba 100644 --- a/go.mod +++ b/go.mod @@ -21,9 +21,12 @@ require ( github.com/spaolacci/murmur3 v1.1.0 github.com/stretchr/testify v1.8.2 github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c + github.com/tidwall/redcon v1.6.2 go.etcd.io/bbolt v1.3.7 go.uber.org/zap v1.24.0 golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 + golang.org/x/net v0.8.0 + golang.org/x/sys v0.6.0 google.golang.org/grpc v1.55.0 google.golang.org/protobuf v1.31.0 ) @@ -47,13 +50,12 @@ require ( github.com/kr/pretty v0.3.0 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.16 // indirect - github.com/panjf2000/ants v1.3.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/tidwall/btree v1.1.0 // indirect + github.com/tidwall/match v1.1.1 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/sys v0.6.0 // indirect golang.org/x/text v0.8.0 // indirect google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect diff --git a/go.sum b/go.sum index 8c568fd..b394ae7 100644 --- a/go.sum +++ b/go.sum @@ -140,8 +140,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= -github.com/panjf2000/ants v1.3.0 h1:8pQ+8leaLc9lys2viEEr8md0U4RN6uOSUCE9bOYjQ9M= -github.com/panjf2000/ants v1.3.0/go.mod h1:AaACblRPzq35m1g3enqYcxspbbiOJJYaxU2wMpm1cXY= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -190,6 +188,12 @@ github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= +github.com/tidwall/btree v1.1.0 h1:5P+9WU8ui5uhmcg3SoPyTwoI0mVyZ1nps7YQzTZFkYM= +github.com/tidwall/btree v1.1.0/go.mod h1:TzIRzen6yHbibdSfK6t8QimqbUnoxUSrZfeW7Uob0q4= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/redcon v1.6.2 h1:5qfvrrybgtO85jnhSravmkZyC0D+7WstbfCs3MmPhow= +github.com/tidwall/redcon v1.6.2/go.mod h1:p5Wbsgeyi2VSTBWOcA5vRXrOb9arFTcU2+ZzFjqV75Y= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= diff --git a/lib/redis/client.go b/lib/redis/client.go new file mode 100644 index 0000000..c776f9d --- /dev/null +++ b/lib/redis/client.go @@ -0,0 +1,60 @@ +package redis + +import ( + "fmt" + _const "github.com/ByteStorage/FlyDB/lib/const" + "strings" + + "github.com/tidwall/redcon" +) + +type FlyDBClient struct { + DB map[int]interface{} + Server *FlyDBServer +} + +func NewWrongNumberOfArgsError(cmd string) error { + return fmt.Errorf("ERR wrong number of arguments for '%s' command", cmd) +} + +type CmdHandler func(cli *FlyDBClient, args [][]byte) (interface{}, error) + +var FlyDBSupportCommands = map[string]CmdHandler{ + // string + "use-string": UseString, + "set": Set, + "get": Get, + + // hash + "use-hash": UseHash, + "hset": HSet, + "hget": HGet, +} + +func ClientCommands(conn redcon.Conn, cmd redcon.Command) { + command := strings.ToLower(string(cmd.Args[0])) + cmdFunc, ok := FlyDBSupportCommands[command] + if !ok { + conn.WriteError("Err unsupported command: '" + command + "'") + return + } + + cli, _ := conn.Context().(*FlyDBClient) + switch command { + case "ping": + conn.WriteString("PONG") + case "quit": + _ = conn.Close() + default: + res, err := cmdFunc(cli, cmd.Args[1:]) + if err != nil { + if err == _const.ErrKeyNotFound { + conn.WriteNull() + } else { + conn.WriteError(err.Error()) + } + return + } + conn.WriteAny(res) + } +} diff --git a/lib/redis/cmd/flydb_server.go b/lib/redis/cmd/flydb_server.go new file mode 100644 index 0000000..0f18076 --- /dev/null +++ b/lib/redis/cmd/flydb_server.go @@ -0,0 +1,32 @@ +package main + +import ( + "github.com/ByteStorage/FlyDB/config" + "github.com/ByteStorage/FlyDB/lib/redis" + flydb_stru "github.com/ByteStorage/FlyDB/structure" + "github.com/tidwall/redcon" +) + +func main() { + // 打开 Redis 数据结构服务 + stringStructure, err := flydb_stru.NewStringStructure(config.DefaultOptions) + if err != nil { + panic(err) + } + hashStructure, err := flydb_stru.NewHashStructure(config.DefaultOptions) + if err != nil { + panic(err) + } + + // 初始化 FlyDBServer + flydbServer := &redis.FlyDBServer{ + Dbs: make(map[int]interface{}), + } + flydbServer.Dbs[0] = stringStructure + flydbServer.Dbs[1] = hashStructure + + // 初始化一个 Redis 服务端 + flydbServer.Server = redcon.NewServer(config.DefaultAddr, + redis.ClientCommands, flydbServer.Accept, nil) + flydbServer.Listen() +} diff --git a/lib/redis/hash.go b/lib/redis/hash.go new file mode 100644 index 0000000..4c195a9 --- /dev/null +++ b/lib/redis/hash.go @@ -0,0 +1,44 @@ +package redis + +import ( + "github.com/ByteStorage/FlyDB/structure" + "github.com/tidwall/redcon" +) + +func HSet(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 3 { + return nil, NewWrongNumberOfArgsError("hset") + } + + var ok = 0 + key, field, value := args[0], args[1], args[2] + res, err := cli.DB[1].(*structure.HashStructure).HSet(string(key), field, value) + if err != nil { + return nil, err + } + if res { + ok = 1 + } + return redcon.SimpleInt(ok), nil +} + +func HGet(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 2 { + return nil, NewWrongNumberOfArgsError("hget") + } + + value, err := cli.DB[1].(*structure.HashStructure).HGet(string(args[0]), args[1]) + if err != nil { + return nil, err + } + return value, nil +} + +func UseHash(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 0 { + return nil, NewWrongNumberOfArgsError("use-hash") + } + + cli.DB[0].(*structure.StringStructure).Close() + return redcon.SimpleString("OK"), nil +} diff --git a/lib/redis/server.go b/lib/redis/server.go new file mode 100644 index 0000000..7a0a937 --- /dev/null +++ b/lib/redis/server.go @@ -0,0 +1,40 @@ +package redis + +import ( + "github.com/ByteStorage/FlyDB/structure" + "log" + "sync" + + "github.com/tidwall/redcon" +) + +type FlyDBServer struct { + Dbs map[int]interface{} + Server *redcon.Server + lock sync.RWMutex +} + +func (svr *FlyDBServer) Listen() { + log.Println("FlyDB-Redis Server running, ready to accept connections...") + _ = svr.Server.ListenAndServe() +} + +func (svr *FlyDBServer) Accept(conn redcon.Conn) bool { + svr.lock.Lock() + defer svr.lock.Unlock() + + cli := new(FlyDBClient) + cli.Server = svr + cli.DB = svr.Dbs + conn.SetContext(cli) + return true +} + +func (svr *FlyDBServer) Close() error { + if db, ok := svr.Dbs[0].(*structure.StringStructure); ok { + db.Clean() + } else if dbh, ok := svr.Dbs[1].(*structure.HashStructure); ok { + dbh.Clean() + } + return svr.Server.Close() +} diff --git a/lib/redis/string.go b/lib/redis/string.go new file mode 100644 index 0000000..45159f6 --- /dev/null +++ b/lib/redis/string.go @@ -0,0 +1,40 @@ +package redis + +import ( + "github.com/ByteStorage/FlyDB/structure" + "github.com/tidwall/redcon" +) + +func Set(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 2 { + return nil, NewWrongNumberOfArgsError("set") + } + + key, value := args[0], args[1] + if err := cli.DB[0].(*structure.StringStructure).Set(string(key), string(value), 0); err != nil { + return nil, err + } + return redcon.SimpleString("OK"), nil +} + +func Get(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 1 { + return nil, NewWrongNumberOfArgsError("get") + } + + value, err := cli.DB[0].(*structure.StringStructure).Get(string(args[0])) + if err != nil { + return nil, err + } + return value, nil +} + +func UseString(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 0 { + return nil, NewWrongNumberOfArgsError("use-string") + } + + cli.DB[1].(*structure.HashStructure).Stop() + + return redcon.SimpleString("OK"), nil +} diff --git a/structure/string.go b/structure/string.go index 3fe24a8..b2d7915 100644 --- a/structure/string.go +++ b/structure/string.go @@ -627,3 +627,7 @@ func (s *StringStructure) Stop() error { func (s *StringStructure) Clean() { s.db.Clean() } + +func (s *StringStructure) Close() { + s.db.Close() +} From ea5ad968d3e2251d92ed06cb966a910fc5fa0af2 Mon Sep 17 00:00:00 2001 From: qishenonly <1050026498@qq.com> Date: Thu, 25 Jan 2024 22:12:43 +0800 Subject: [PATCH 2/7] Fixed a bug where switching data structures made it impossible to read data --- config/options.go | 9 +++++++++ lib/redis/client.go | 6 +++--- lib/redis/cmd/flydb_server.go | 8 ++++++-- lib/redis/hash.go | 2 -- lib/redis/string.go | 5 +---- structure/hash.go | 3 +-- structure/list.go | 3 +-- structure/string.go | 8 +++++--- 8 files changed, 26 insertions(+), 18 deletions(-) diff --git a/config/options.go b/config/options.go index 5a33c3e..28db9fb 100644 --- a/config/options.go +++ b/config/options.go @@ -3,6 +3,7 @@ package config import ( "github.com/ByteStorage/FlyDB/lib/wal" "os" + "path/filepath" ) // Options is a comprehensive configuration struct that @@ -140,3 +141,11 @@ var DefaultDbMemoryOptions = DbMemoryOptions{ ColumnName: "default", Wal: nil, } + +var ( + RedisStringDirPath = filepath.Join(os.TempDir(), "flydb/redis/string") + RedisHashDirPath = filepath.Join(os.TempDir(), "flydb/redis/hash") + RedisListDirPath = filepath.Join(os.TempDir(), "flydb/redis/list") + RedisSetDirPath = filepath.Join(os.TempDir(), "flydb/redis/set") + RedisZSetDirPath = filepath.Join(os.TempDir(), "flydb/redis/zset") +) diff --git a/lib/redis/client.go b/lib/redis/client.go index c776f9d..4871682 100644 --- a/lib/redis/client.go +++ b/lib/redis/client.go @@ -21,9 +21,9 @@ type CmdHandler func(cli *FlyDBClient, args [][]byte) (interface{}, error) var FlyDBSupportCommands = map[string]CmdHandler{ // string - "use-string": UseString, - "set": Set, - "get": Get, + "use-str": UseString, + "set": Set, + "get": Get, // hash "use-hash": UseHash, diff --git a/lib/redis/cmd/flydb_server.go b/lib/redis/cmd/flydb_server.go index 0f18076..1e0e210 100644 --- a/lib/redis/cmd/flydb_server.go +++ b/lib/redis/cmd/flydb_server.go @@ -9,11 +9,15 @@ import ( func main() { // 打开 Redis 数据结构服务 - stringStructure, err := flydb_stru.NewStringStructure(config.DefaultOptions) + options := config.DefaultOptions + options.DirPath = config.RedisStringDirPath + stringStructure, err := flydb_stru.NewStringStructure(options) if err != nil { panic(err) } - hashStructure, err := flydb_stru.NewHashStructure(config.DefaultOptions) + + options.DirPath = config.RedisHashDirPath + hashStructure, err := flydb_stru.NewHashStructure(options) if err != nil { panic(err) } diff --git a/lib/redis/hash.go b/lib/redis/hash.go index 4c195a9..9287f30 100644 --- a/lib/redis/hash.go +++ b/lib/redis/hash.go @@ -38,7 +38,5 @@ func UseHash(cli *FlyDBClient, args [][]byte) (interface{}, error) { if len(args) != 0 { return nil, NewWrongNumberOfArgsError("use-hash") } - - cli.DB[0].(*structure.StringStructure).Close() return redcon.SimpleString("OK"), nil } diff --git a/lib/redis/string.go b/lib/redis/string.go index 45159f6..81acee4 100644 --- a/lib/redis/string.go +++ b/lib/redis/string.go @@ -31,10 +31,7 @@ func Get(cli *FlyDBClient, args [][]byte) (interface{}, error) { func UseString(cli *FlyDBClient, args [][]byte) (interface{}, error) { if len(args) != 0 { - return nil, NewWrongNumberOfArgsError("use-string") + return nil, NewWrongNumberOfArgsError("use-str") } - - cli.DB[1].(*structure.HashStructure).Stop() - return redcon.SimpleString("OK"), nil } diff --git a/structure/hash.go b/structure/hash.go index d1fa3ff..14de042 100644 --- a/structure/hash.go +++ b/structure/hash.go @@ -1402,8 +1402,7 @@ func (hs *HashStructure) findHashMeta(key string, dataType DataStructure) (*Hash } func (hs *HashStructure) Stop() error { - err := hs.db.Close() - return err + return hs.db.Close() } func (hs *HashStructure) Clean() { diff --git a/structure/list.go b/structure/list.go index 81b5fc4..0f8c180 100644 --- a/structure/list.go +++ b/structure/list.go @@ -728,8 +728,7 @@ func (l *ListStructure) decodeList(value []byte) (*DecodedList, error) { } func (s *ListStructure) Stop() error { - err := s.db.Close() - return err + return s.db.Close() } func (l *ListStructure) Size(key string) (string, error) { diff --git a/structure/string.go b/structure/string.go index b2d7915..1646ebd 100644 --- a/structure/string.go +++ b/structure/string.go @@ -620,8 +620,7 @@ func decodeStringValue(value []byte) ([]byte, int64, error) { } func (s *StringStructure) Stop() error { - err := s.db.Close() - return err + return s.db.Close() } func (s *StringStructure) Clean() { @@ -629,5 +628,8 @@ func (s *StringStructure) Clean() { } func (s *StringStructure) Close() { - s.db.Close() + err := s.db.Close() + if err != nil { + return + } } From 9c5c2908935d9f39f48b281c4c7312378428a6e8 Mon Sep 17 00:00:00 2001 From: qishenonly <1050026498@qq.com> Date: Thu, 25 Jan 2024 22:37:54 +0800 Subject: [PATCH 3/7] Complete the string data structure service --- lib/redis/client.go | 16 +++ lib/redis/cmd/flydb_server.go | 6 +- lib/redis/hash.go | 3 + lib/redis/server.go | 3 + lib/redis/string.go | 194 ++++++++++++++++++++++++++++++++++ 5 files changed, 219 insertions(+), 3 deletions(-) diff --git a/lib/redis/client.go b/lib/redis/client.go index 4871682..c773790 100644 --- a/lib/redis/client.go +++ b/lib/redis/client.go @@ -19,11 +19,26 @@ func NewWrongNumberOfArgsError(cmd string) error { type CmdHandler func(cli *FlyDBClient, args [][]byte) (interface{}, error) +// FlyDBSupportCommands is the map of all supported redis commands var FlyDBSupportCommands = map[string]CmdHandler{ // string "use-str": UseString, "set": Set, "get": Get, + "del": Del, + "getset": GetSet, + "append": Append, + "strlen": Strlen, + "incr": Incr, + "decr": Decr, + "incrby": IncrBy, + "decrby": DecrBy, + "keys": Keys, + "exists": Exists, + "expire": Expire, + "persist": Persist, + "ttl": TTL, + "size": Size, // hash "use-hash": UseHash, @@ -31,6 +46,7 @@ var FlyDBSupportCommands = map[string]CmdHandler{ "hget": HGet, } +// ClientCommands is the handler for all redis commands func ClientCommands(conn redcon.Conn, cmd redcon.Command) { command := strings.ToLower(string(cmd.Args[0])) cmdFunc, ok := FlyDBSupportCommands[command] diff --git a/lib/redis/cmd/flydb_server.go b/lib/redis/cmd/flydb_server.go index 1e0e210..3349ead 100644 --- a/lib/redis/cmd/flydb_server.go +++ b/lib/redis/cmd/flydb_server.go @@ -8,7 +8,7 @@ import ( ) func main() { - // 打开 Redis 数据结构服务 + // open Redis data structure service options := config.DefaultOptions options.DirPath = config.RedisStringDirPath stringStructure, err := flydb_stru.NewStringStructure(options) @@ -22,14 +22,14 @@ func main() { panic(err) } - // 初始化 FlyDBServer + // initialize FlyDBServer flydbServer := &redis.FlyDBServer{ Dbs: make(map[int]interface{}), } flydbServer.Dbs[0] = stringStructure flydbServer.Dbs[1] = hashStructure - // 初始化一个 Redis 服务端 + // initialize a Redis server flydbServer.Server = redcon.NewServer(config.DefaultAddr, redis.ClientCommands, flydbServer.Accept, nil) flydbServer.Listen() diff --git a/lib/redis/hash.go b/lib/redis/hash.go index 9287f30..51d234f 100644 --- a/lib/redis/hash.go +++ b/lib/redis/hash.go @@ -5,6 +5,7 @@ import ( "github.com/tidwall/redcon" ) +// Set key value func HSet(cli *FlyDBClient, args [][]byte) (interface{}, error) { if len(args) != 3 { return nil, NewWrongNumberOfArgsError("hset") @@ -22,6 +23,7 @@ func HSet(cli *FlyDBClient, args [][]byte) (interface{}, error) { return redcon.SimpleInt(ok), nil } +// HGet key field func HGet(cli *FlyDBClient, args [][]byte) (interface{}, error) { if len(args) != 2 { return nil, NewWrongNumberOfArgsError("hget") @@ -34,6 +36,7 @@ func HGet(cli *FlyDBClient, args [][]byte) (interface{}, error) { return value, nil } +// UseHash change to hash db func UseHash(cli *FlyDBClient, args [][]byte) (interface{}, error) { if len(args) != 0 { return nil, NewWrongNumberOfArgsError("use-hash") diff --git a/lib/redis/server.go b/lib/redis/server.go index 7a0a937..832ab25 100644 --- a/lib/redis/server.go +++ b/lib/redis/server.go @@ -14,11 +14,13 @@ type FlyDBServer struct { lock sync.RWMutex } +// Listen starts listening for incoming connections. func (svr *FlyDBServer) Listen() { log.Println("FlyDB-Redis Server running, ready to accept connections...") _ = svr.Server.ListenAndServe() } +// Accept is called when a new client connects. func (svr *FlyDBServer) Accept(conn redcon.Conn) bool { svr.lock.Lock() defer svr.lock.Unlock() @@ -30,6 +32,7 @@ func (svr *FlyDBServer) Accept(conn redcon.Conn) bool { return true } +// Close closes the server. func (svr *FlyDBServer) Close() error { if db, ok := svr.Dbs[0].(*structure.StringStructure); ok { db.Clean() diff --git a/lib/redis/string.go b/lib/redis/string.go index 81acee4..a80a052 100644 --- a/lib/redis/string.go +++ b/lib/redis/string.go @@ -1,10 +1,12 @@ package redis import ( + "encoding/binary" "github.com/ByteStorage/FlyDB/structure" "github.com/tidwall/redcon" ) +// Set key value func Set(cli *FlyDBClient, args [][]byte) (interface{}, error) { if len(args) != 2 { return nil, NewWrongNumberOfArgsError("set") @@ -17,6 +19,7 @@ func Set(cli *FlyDBClient, args [][]byte) (interface{}, error) { return redcon.SimpleString("OK"), nil } +// Get key func Get(cli *FlyDBClient, args [][]byte) (interface{}, error) { if len(args) != 1 { return nil, NewWrongNumberOfArgsError("get") @@ -29,6 +32,197 @@ func Get(cli *FlyDBClient, args [][]byte) (interface{}, error) { return value, nil } +// Del key +func Del(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 1 { + return nil, NewWrongNumberOfArgsError("del") + } + + if err := cli.DB[0].(*structure.StringStructure).Del(string(args[0])); err != nil { + return nil, err + } + return redcon.SimpleString("OK"), nil +} + +// GetSet key value +func GetSet(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 2 { + return nil, NewWrongNumberOfArgsError("getset") + } + + value, err := cli.DB[0].(*structure.StringStructure).GetSet(string(args[0]), string(args[1]), 0) + if err != nil { + return nil, err + } + return value, nil +} + +// Append key value +func Append(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 2 { + return nil, NewWrongNumberOfArgsError("append") + } + + if err := cli.DB[0].(*structure.StringStructure).Append(string(args[0]), + string(args[1]), 0); err != nil { + return nil, err + } + + return redcon.SimpleString("OK"), nil +} + +// Strlen key +func Strlen(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 1 { + return nil, NewWrongNumberOfArgsError("strlen") + } + + length, err := cli.DB[0].(*structure.StringStructure).StrLen(string(args[0])) + if err != nil { + return nil, err + } + return redcon.SimpleInt(length), nil +} + +// Incr key +func Incr(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 1 { + return nil, NewWrongNumberOfArgsError("incr") + } + + if err := cli.DB[0].(*structure.StringStructure).Incr(string(args[0]), + int64(binary.BigEndian.Uint64(args[1]))); err != nil { + return nil, err + } + + return redcon.SimpleString("OK"), nil +} + +// IncrBy key increment +func IncrBy(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 2 { + return nil, NewWrongNumberOfArgsError("incrby") + } + + if err := cli.DB[0].(*structure.StringStructure).Incr(string(args[0]), + int64(binary.BigEndian.Uint64(args[1]))); err != nil { + return nil, err + } + + return redcon.SimpleString("OK"), nil +} + +// Decr key +func Decr(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 1 { + return nil, NewWrongNumberOfArgsError("decr") + } + + if err := cli.DB[0].(*structure.StringStructure).Decr(string(args[0]), + int64(binary.BigEndian.Uint64(args[1]))); err != nil { + return nil, err + } + + return redcon.SimpleString("OK"), nil +} + +// DecrBy key decrement +func DecrBy(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 2 { + return nil, NewWrongNumberOfArgsError("decrby") + } + + if err := cli.DB[0].(*structure.StringStructure).Decr(string(args[0]), + int64(binary.BigEndian.Uint64(args[1]))); err != nil { + return nil, err + } + + return redcon.SimpleString("OK"), nil +} + +// Keys pattern +func Keys(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 1 { + return nil, NewWrongNumberOfArgsError("keys") + } + + keys, err := cli.DB[0].(*structure.StringStructure).Keys(string(args[0])) + if err != nil { + return nil, err + } + return keys, nil +} + +// Exists key +func Exists(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 1 { + return nil, NewWrongNumberOfArgsError("exists") + } + + ok, err := cli.DB[0].(*structure.StringStructure).Exists(string(args[0])) + if err != nil { + return nil, err + } + + if ok { + return redcon.SimpleInt(1), nil + } else { + return redcon.SimpleInt(0), nil + } +} + +// Expire key seconds +func Expire(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 2 { + return nil, NewWrongNumberOfArgsError("expire") + } + + if err := cli.DB[0].(*structure.StringStructure).Expire(string(args[0]), + int64(binary.BigEndian.Uint64(args[1]))); err != nil { + return nil, err + } + return redcon.SimpleInt(1), nil +} + +// Persist key +func Persist(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 1 { + return nil, NewWrongNumberOfArgsError("persist") + } + + if err := cli.DB[0].(*structure.StringStructure).Persist(string(args[0])); err != nil { + return nil, err + } + return redcon.SimpleInt(1), nil +} + +// TTL key +func TTL(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 1 { + return nil, NewWrongNumberOfArgsError("ttl") + } + + ttl, err := cli.DB[0].(*structure.StringStructure).TTL(string(args[0])) + if err != nil { + return nil, err + } + return redcon.SimpleInt(ttl), nil +} + +// Size key +func Size(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 1 { + return nil, NewWrongNumberOfArgsError("size") + } + + size, err := cli.DB[0].(*structure.StringStructure).Size(string(args[0])) + if err != nil { + return nil, err + } + return redcon.SimpleString(size), nil +} + +// UseString change to string db func UseString(cli *FlyDBClient, args [][]byte) (interface{}, error) { if len(args) != 0 { return nil, NewWrongNumberOfArgsError("use-str") From ce0f02647a71c4313aadab732114a0e4d69b8bfc Mon Sep 17 00:00:00 2001 From: qishenonly <1050026498@qq.com> Date: Fri, 26 Jan 2024 18:42:10 +0800 Subject: [PATCH 4/7] move redis service to flydb service --- cmd/server/server.go | 35 ++++++++++++++++++++++++-------- config/options.go | 4 +++- db/grpc/base.go | 5 +++-- lib/redis/cmd/flydb_server.go | 36 --------------------------------- lib/redis/server.go | 38 ++++++++++++++++++++++++++++++++--- 5 files changed, 68 insertions(+), 50 deletions(-) delete mode 100644 lib/redis/cmd/flydb_server.go diff --git a/cmd/server/server.go b/cmd/server/server.go index 48a9244..d271f12 100644 --- a/cmd/server/server.go +++ b/cmd/server/server.go @@ -4,18 +4,37 @@ import ( "fmt" "github.com/ByteStorage/FlyDB/config" base "github.com/ByteStorage/FlyDB/db/grpc" + "github.com/ByteStorage/FlyDB/lib/redis" "os" + "sync" ) func StartServer() { - options := config.DefaultOptions - options.FIOType = config.MmapIOType - service, err := base.NewService(options, config.DefaultAddr) - if err != nil { - fmt.Println("flydb start error: ", err) - return - } - service.StartGrpcServer() + var wg sync.WaitGroup + + // start flydb server + wg.Add(1) + go func() { + defer wg.Done() + options := config.DefaultOptions + options.FIOType = config.MmapIOType + service, err := base.NewService(options, config.DefaultAddr) + if err != nil { + fmt.Println("flydb start error: ", err) + return + } + service.StartGrpcServer() + }() + + // start flydb-redis server + wg.Add(1) + go func() { + defer wg.Done() + redis.StartRedisServer() + }() + + // wait for signal + wg.Wait() } func CleanServer() { diff --git a/config/options.go b/config/options.go index 28db9fb..31fa2f2 100644 --- a/config/options.go +++ b/config/options.go @@ -110,7 +110,8 @@ const ( ) const ( - DefaultAddr = "127.0.0.1:8999" + DefaultAddr = "127.0.0.1:8999" + DefaultRedisAddr = "127.0.0.1:8998" ) var DefaultOptions = Options{ @@ -142,6 +143,7 @@ var DefaultDbMemoryOptions = DbMemoryOptions{ Wal: nil, } +// Redis var ( RedisStringDirPath = filepath.Join(os.TempDir(), "flydb/redis/string") RedisHashDirPath = filepath.Join(os.TempDir(), "flydb/redis/hash") diff --git a/db/grpc/base.go b/db/grpc/base.go index 728e745..4e235b4 100644 --- a/db/grpc/base.go +++ b/db/grpc/base.go @@ -12,6 +12,7 @@ import ( "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/health" "google.golang.org/grpc/health/grpc_health_v1" + "log" "net" "os" "os/signal" @@ -102,7 +103,7 @@ func (s *base) StartGrpcServer() { } break } - fmt.Println("flydb start success on ", s.addr) + log.Println("FlyDB Server Start Success On: ", s.addr) // graceful shutdown signal.Notify(s.sig, syscall.SIGINT, syscall.SIGKILL) @@ -114,7 +115,7 @@ func (s *base) StartGrpcServer() { return } } - fmt.Println("flydb stop success on ", s.addr) + log.Println("FlyDB Server Stop Success On: ", s.addr) } func (s *base) StopGrpcServer() { diff --git a/lib/redis/cmd/flydb_server.go b/lib/redis/cmd/flydb_server.go deleted file mode 100644 index 3349ead..0000000 --- a/lib/redis/cmd/flydb_server.go +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - "github.com/ByteStorage/FlyDB/config" - "github.com/ByteStorage/FlyDB/lib/redis" - flydb_stru "github.com/ByteStorage/FlyDB/structure" - "github.com/tidwall/redcon" -) - -func main() { - // open Redis data structure service - options := config.DefaultOptions - options.DirPath = config.RedisStringDirPath - stringStructure, err := flydb_stru.NewStringStructure(options) - if err != nil { - panic(err) - } - - options.DirPath = config.RedisHashDirPath - hashStructure, err := flydb_stru.NewHashStructure(options) - if err != nil { - panic(err) - } - - // initialize FlyDBServer - flydbServer := &redis.FlyDBServer{ - Dbs: make(map[int]interface{}), - } - flydbServer.Dbs[0] = stringStructure - flydbServer.Dbs[1] = hashStructure - - // initialize a Redis server - flydbServer.Server = redcon.NewServer(config.DefaultAddr, - redis.ClientCommands, flydbServer.Accept, nil) - flydbServer.Listen() -} diff --git a/lib/redis/server.go b/lib/redis/server.go index 832ab25..c73d726 100644 --- a/lib/redis/server.go +++ b/lib/redis/server.go @@ -1,6 +1,7 @@ package redis import ( + "github.com/ByteStorage/FlyDB/config" "github.com/ByteStorage/FlyDB/structure" "log" "sync" @@ -16,7 +17,7 @@ type FlyDBServer struct { // Listen starts listening for incoming connections. func (svr *FlyDBServer) Listen() { - log.Println("FlyDB-Redis Server running, ready to accept connections...") + log.Println("FlyDB-Redis Server Start Success On: ", config.DefaultRedisAddr) _ = svr.Server.ListenAndServe() } @@ -33,11 +34,42 @@ func (svr *FlyDBServer) Accept(conn redcon.Conn) bool { } // Close closes the server. -func (svr *FlyDBServer) Close() error { +func (svr *FlyDBServer) Close(conn redcon.Conn, err error) { if db, ok := svr.Dbs[0].(*structure.StringStructure); ok { db.Clean() } else if dbh, ok := svr.Dbs[1].(*structure.HashStructure); ok { dbh.Clean() } - return svr.Server.Close() + _ = svr.Server.Close() + log.Println("FlyDB-Redis Server Stop Success On: ", config.DefaultRedisAddr) + return +} + +// StartRedisServer starts a Redis server. +func StartRedisServer() { + // open Redis data structure service + options := config.DefaultOptions + options.DirPath = config.RedisStringDirPath + stringStructure, err := structure.NewStringStructure(options) + if err != nil { + panic(err) + } + + options.DirPath = config.RedisHashDirPath + hashStructure, err := structure.NewHashStructure(options) + if err != nil { + panic(err) + } + + // initialize FlyDBServer + flydbServer := FlyDBServer{ + Dbs: make(map[int]interface{}), + } + flydbServer.Dbs[0] = stringStructure + flydbServer.Dbs[1] = hashStructure + + // initialize a Redis server + flydbServer.Server = redcon.NewServer(config.DefaultRedisAddr, + ClientCommands, flydbServer.Accept, flydbServer.Close) + flydbServer.Listen() } From d50b12d501aca332cbc36157c8a8d24a09a1cd55 Mon Sep 17 00:00:00 2001 From: qishenonly <1050026498@qq.com> Date: Fri, 26 Jan 2024 20:02:58 +0800 Subject: [PATCH 5/7] Complete the hash data service --- lib/redis/client.go | 13 ++++ lib/redis/hash.go | 173 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+) diff --git a/lib/redis/client.go b/lib/redis/client.go index c773790..bf5c9a2 100644 --- a/lib/redis/client.go +++ b/lib/redis/client.go @@ -44,6 +44,19 @@ var FlyDBSupportCommands = map[string]CmdHandler{ "use-hash": UseHash, "hset": HSet, "hget": HGet, + "hdel": HDel, + "hdelall": HDelAll, + "hexists": HExists, + "hexpire": HExpire, + "hlen": HLen, + "hupdate": HUpdate, + "hkeys": HKeys, + "hstrlen": HStrlen, + "hmove": HMove, + "hsize": HSize, + "httl": HTTL, + "hincrby": HIncrBy, + "hdecrby": HDecrBy, } // ClientCommands is the handler for all redis commands diff --git a/lib/redis/hash.go b/lib/redis/hash.go index 51d234f..8d41e2e 100644 --- a/lib/redis/hash.go +++ b/lib/redis/hash.go @@ -1,6 +1,7 @@ package redis import ( + "encoding/binary" "github.com/ByteStorage/FlyDB/structure" "github.com/tidwall/redcon" ) @@ -36,6 +37,178 @@ func HGet(cli *FlyDBClient, args [][]byte) (interface{}, error) { return value, nil } +// HDel key field +func HDel(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 2 { + return nil, NewWrongNumberOfArgsError("hdel") + } + + if _, err := cli.DB[1].(*structure.HashStructure).HDel(string(args[0]), args[1]); err != nil { + return nil, err + } + return redcon.SimpleString("OK"), nil +} + +// HDelAll key +func HDelAll(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 1 { + return nil, NewWrongNumberOfArgsError("hdelall") + } + + if _, err := cli.DB[1].(*structure.HashStructure).HDelAll(string(args[0])); err != nil { + return nil, err + } + return redcon.SimpleString("OK"), nil +} + +// HExists key field +func HExists(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 2 { + return nil, NewWrongNumberOfArgsError("hexists") + } + + var ok = 0 + res, err := cli.DB[1].(*structure.HashStructure).HExists(string(args[0]), args[1]) + if err != nil { + return nil, err + } + if res { + ok = 1 + } + return redcon.SimpleInt(ok), nil +} + +// HExpire key seconds +func HExpire(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 2 { + return nil, NewWrongNumberOfArgsError("hexpire") + } + + if _, err := cli.DB[1].(*structure.HashStructure).HExpire(string(args[0]), + int64(binary.BigEndian.Uint64(args[1]))); err != nil { + return nil, err + } + return redcon.SimpleString("OK"), nil +} + +// HLen key +func HLen(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 1 { + return nil, NewWrongNumberOfArgsError("hlen") + } + + length, err := cli.DB[1].(*structure.HashStructure).HLen(string(args[0])) + if err != nil { + return nil, err + } + return redcon.SimpleInt(length), nil +} + +// HUpdate key field value +func HUpdate(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 1 { + return nil, NewWrongNumberOfArgsError("hupdate") + } + + if _, err := cli.DB[1].(*structure.HashStructure).HUpdate(string(args[0]), args[1], args[2]); err != nil { + return nil, err + } + return redcon.SimpleString("OK"), nil +} + +// HKeys key +func HKeys(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 1 { + return nil, NewWrongNumberOfArgsError("hkeys") + } + + keys, err := cli.DB[1].(*structure.HashStructure).Keys(string(args[0])) + if err != nil { + return nil, err + } + return keys, nil +} + +// HStrlen key field +func HStrlen(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 2 { + return nil, NewWrongNumberOfArgsError("hstrlen") + } + + length, err := cli.DB[1].(*structure.HashStructure).HStrLen(string(args[0]), args[1]) + if err != nil { + return nil, err + } + return redcon.SimpleInt(length), nil +} + +// HMove source destination field +func HMove(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 3 { + return nil, NewWrongNumberOfArgsError("hmove") + } + + if _, err := cli.DB[1].(*structure.HashStructure).HMove(string(args[0]), string(args[1]), + int64(binary.BigEndian.Uint64(args[2]))); err != nil { + return nil, err + } + return redcon.SimpleString("OK"), nil +} + +// HSize key +func HSize(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 1 { + return nil, NewWrongNumberOfArgsError("hsize") + } + + size, err := cli.DB[1].(*structure.HashStructure).Size(string(args[0])) + if err != nil { + return nil, err + } + return redcon.SimpleString(size), nil +} + +// HTTL key +func HTTL(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 1 { + return nil, NewWrongNumberOfArgsError("httl") + } + + ttl, err := cli.DB[1].(*structure.HashStructure).TTL(string(args[0])) + if err != nil { + return nil, err + } + return redcon.SimpleInt(ttl), nil +} + +// HIncrBy key field increment +func HIncrBy(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 3 { + return nil, NewWrongNumberOfArgsError("hincrby") + } + + value, err := cli.DB[1].(*structure.HashStructure).HIncrBy(string(args[0]), args[1], + int64(binary.BigEndian.Uint64(args[2]))) + if err != nil { + return nil, err + } + return redcon.SimpleInt(value), nil +} + +// HDecrBy key field decrement +func HDecrBy(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 3 { + return nil, NewWrongNumberOfArgsError("hdecrby") + } + + value, err := cli.DB[1].(*structure.HashStructure).HDecrBy(string(args[0]), args[1], + int64(binary.BigEndian.Uint64(args[2]))) + if err != nil { + return nil, err + } + return redcon.SimpleInt(value), nil +} + // UseHash change to hash db func UseHash(cli *FlyDBClient, args [][]byte) (interface{}, error) { if len(args) != 0 { From 4af813115a6e4753493181949416b54b689fe1fd Mon Sep 17 00:00:00 2001 From: qishenonly <1050026498@qq.com> Date: Fri, 26 Jan 2024 20:38:29 +0800 Subject: [PATCH 6/7] fix link --- lib/redis/server.go | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/redis/server.go b/lib/redis/server.go index c73d726..5c326db 100644 --- a/lib/redis/server.go +++ b/lib/redis/server.go @@ -42,7 +42,6 @@ func (svr *FlyDBServer) Close(conn redcon.Conn, err error) { } _ = svr.Server.Close() log.Println("FlyDB-Redis Server Stop Success On: ", config.DefaultRedisAddr) - return } // StartRedisServer starts a Redis server. From af18024679de3322f1f56da844f5421986760d2f Mon Sep 17 00:00:00 2001 From: qishenonly <1050026498@qq.com> Date: Sun, 4 Feb 2024 19:26:53 +0800 Subject: [PATCH 7/7] Complete the list data service --- lib/redis/client.go | 15 ++++ lib/redis/list.go | 182 ++++++++++++++++++++++++++++++++++++++++++++ lib/redis/server.go | 13 ++++ structure/list.go | 4 + 4 files changed, 214 insertions(+) create mode 100644 lib/redis/list.go diff --git a/lib/redis/client.go b/lib/redis/client.go index bf5c9a2..5ddb475 100644 --- a/lib/redis/client.go +++ b/lib/redis/client.go @@ -57,6 +57,21 @@ var FlyDBSupportCommands = map[string]CmdHandler{ "httl": HTTL, "hincrby": HIncrBy, "hdecrby": HDecrBy, + + // list + "use-list": UseList, + "lpush": LPush, + "rpush": RPush, + "lpop": LPop, + "rpop": RPop, + "lrange": LRange, + "llen": LLen, + "lindex": LIndex, + "lset": LSet, + "lrem": LRem, + "ltrim": LTrim, + "lkeys": LKeys, + "lsize": LSize, } // ClientCommands is the handler for all redis commands diff --git a/lib/redis/list.go b/lib/redis/list.go new file mode 100644 index 0000000..494cea9 --- /dev/null +++ b/lib/redis/list.go @@ -0,0 +1,182 @@ +package redis + +import ( + "encoding/binary" + "github.com/ByteStorage/FlyDB/structure" + "github.com/tidwall/redcon" +) + +// LPush key value +func LPush(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) < 2 { + return nil, NewWrongNumberOfArgsError("lpush") + } + + key := string(args[0]) + values := make([]string, len(args)-1) + for i, v := range args[1:] { + values[i] = string(v) + } + + if err := cli.DB[2].(*structure.ListStructure).LPush(key, values, 0); err != nil { + return nil, err + } + return redcon.SimpleInt(int64(len(values))), nil +} + +// RPush key value +func RPush(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) < 2 { + return nil, NewWrongNumberOfArgsError("rpush") + } + + key := string(args[0]) + values := make([]string, len(args)-1) + for i, v := range args[1:] { + values[i] = string(v) + } + + if err := cli.DB[2].(*structure.ListStructure).RPush(key, values, 0); err != nil { + return nil, err + } + return redcon.SimpleInt(int64(len(values))), nil +} + +// LPop key +func LPop(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 1 { + return nil, NewWrongNumberOfArgsError("lpop") + } + + value, err := cli.DB[2].(*structure.ListStructure).LPop(string(args[0])) + if err != nil { + return nil, err + } + return value, nil +} + +// RPop key +func RPop(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 1 { + return nil, NewWrongNumberOfArgsError("rpop") + } + + value, err := cli.DB[2].(*structure.ListStructure).RPop(string(args[0])) + if err != nil { + return nil, err + } + return value, nil +} + +// LIndex key index +func LIndex(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 2 { + return nil, NewWrongNumberOfArgsError("lindex") + } + + value, err := cli.DB[2].(*structure.ListStructure).LIndex(string(args[0]), int(binary.BigEndian.Uint64(args[1]))) + if err != nil { + return nil, err + } + return value, nil +} + +// LRange key start stop +func LRange(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 3 { + return nil, NewWrongNumberOfArgsError("lrange") + } + + values, err := cli.DB[2].(*structure.ListStructure).LRange(string(args[0]), int(binary.BigEndian.Uint64(args[1])), int(binary.BigEndian.Uint64(args[2]))) + if err != nil { + return nil, err + } + return values, nil +} + +// LRem key count value +func LRem(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 3 { + return nil, NewWrongNumberOfArgsError("lrem") + } + + count := int(binary.BigEndian.Uint64(args[1])) + if err := cli.DB[2].(*structure.ListStructure).LRem(string(args[0]), + count, string(args[2])); err != nil { + return nil, err + } + + return redcon.SimpleString("OK"), nil +} + +// LLen key +func LLen(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 1 { + return nil, NewWrongNumberOfArgsError("llen") + } + + length, err := cli.DB[2].(*structure.ListStructure).LLen(string(args[0])) + if err != nil { + return nil, err + } + return redcon.SimpleInt(int64(length)), nil +} + +// LSet key index value +func LSet(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 3 { + return nil, NewWrongNumberOfArgsError("lset") + } + + index := int(binary.BigEndian.Uint64(args[1])) + if err := cli.DB[2].(*structure.ListStructure).LSet(string(args[0]), index, string(args[2]), 0); err != nil { + return nil, err + } + return redcon.SimpleString("OK"), nil +} + +// LTrim key start stop +func LTrim(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 3 { + return nil, NewWrongNumberOfArgsError("ltrim") + } + + if err := cli.DB[2].(*structure.ListStructure).LTrim(string(args[0]), int(binary.BigEndian.Uint64(args[1])), int(binary.BigEndian.Uint64(args[2]))); err != nil { + return nil, err + } + return redcon.SimpleString("OK"), nil +} + +// LKeys key +func LKeys(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 1 { + return nil, NewWrongNumberOfArgsError("lkeys") + } + + keys, err := cli.DB[2].(*structure.ListStructure).Keys(string(args[0])) + if err != nil { + return nil, err + } + return keys, nil +} + +// LSize key +func LSize(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 1 { + return nil, NewWrongNumberOfArgsError("lsize") + } + + size, err := cli.DB[2].(*structure.ListStructure).Size(string(args[0])) + if err != nil { + return nil, err + } + return redcon.SimpleString(size), nil +} + +// UseList change to list db +func UseList(cli *FlyDBClient, args [][]byte) (interface{}, error) { + if len(args) != 0 { + return nil, NewWrongNumberOfArgsError("use-list") + } + return redcon.SimpleString("OK"), nil +} diff --git a/lib/redis/server.go b/lib/redis/server.go index 5c326db..9e85098 100644 --- a/lib/redis/server.go +++ b/lib/redis/server.go @@ -39,6 +39,8 @@ func (svr *FlyDBServer) Close(conn redcon.Conn, err error) { db.Clean() } else if dbh, ok := svr.Dbs[1].(*structure.HashStructure); ok { dbh.Clean() + } else if dbl, ok := svr.Dbs[2].(*structure.ListStructure); ok { + dbl.Clean() } _ = svr.Server.Close() log.Println("FlyDB-Redis Server Stop Success On: ", config.DefaultRedisAddr) @@ -48,24 +50,35 @@ func (svr *FlyDBServer) Close(conn redcon.Conn, err error) { func StartRedisServer() { // open Redis data structure service options := config.DefaultOptions + + // Redis String Service options.DirPath = config.RedisStringDirPath stringStructure, err := structure.NewStringStructure(options) if err != nil { panic(err) } + // Redis Hash Service options.DirPath = config.RedisHashDirPath hashStructure, err := structure.NewHashStructure(options) if err != nil { panic(err) } + // Redis List Service + options.DirPath = config.RedisListDirPath + listStructure, err := structure.NewListStructure(options) + if err != nil { + panic(err) + } + // initialize FlyDBServer flydbServer := FlyDBServer{ Dbs: make(map[int]interface{}), } flydbServer.Dbs[0] = stringStructure flydbServer.Dbs[1] = hashStructure + flydbServer.Dbs[2] = listStructure // initialize a Redis server flydbServer.Server = redcon.NewServer(config.DefaultRedisAddr, diff --git a/structure/list.go b/structure/list.go index 0f8c180..445a68b 100644 --- a/structure/list.go +++ b/structure/list.go @@ -767,3 +767,7 @@ func (l *ListStructure) Size(key string) (string, error) { return size, nil } + +func (s *ListStructure) Clean() { + s.db.Clean() +}