Skip to content
This repository was archived by the owner on Jun 23, 2025. It is now read-only.

#632: Feature: KeepAlive and Timeout Support #745

Closed
wants to merge 12 commits into from
Closed
4 changes: 2 additions & 2 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ var baseConfig = Config{
}{
Addr: DefaultHost,
Port: DefaultPort,
KeepAlive: int32(300),
Timeout: int32(300),
KeepAlive: int32(30),
Timeout: int32(30),
MaxConn: int32(0),
ShardCronFrequency: 1 * time.Second,
MultiplexerPollTimeout: 100 * time.Millisecond,
Expand Down
4 changes: 4 additions & 0 deletions internal/errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,21 @@ const (
ArityErr = "wrong number of arguments for '%s' command"
SyntaxErr = "syntax error"
ExpiryErr = "invalid expire time in '%s' command"
AuthErr = "AUTH failed"
IntOrOutOfRangeErr = "value is not an integer or out of range"
IntOrFloatErr = "value is not an integer or a float"
ValOutOfRangeErr = "value is out of range"
IncrDecrOverflowErr = "increment or decrement would overflow"
ElementPeekErr = "number of elements to peek should be a positive number less than %d"
NoKeyErr = "no such key"
ErrDefault = "-ERR %s"
WrongTypeErr = "-WRONGTYPE Operation against a key holding the wrong kind of value"
WrongTypeHllErr = "-WRONGTYPE Key is not a valid HyperLogLog string value."
InvalidHllErr = "-INVALIDOBJ Corrupted HLL object detected"
WorkerNotFoundErr = "worker with ID %s not found"
JSONPathNotExistErr = "-ERR Path '%s' does not exist"
JSONPathValueTypeErr = "-WRONGTYPE wrong type of path value - expected string but found integer"
InvalidExpireTime = "-ERR invalid expire time"
HashValueNotIntegerErr = "hash value is not an integer"
InternalServerError = "-ERR: Internal server error, unable to process command"
InvalidFloatErr = "-ERR value is not a valid float"
Expand Down
42 changes: 21 additions & 21 deletions internal/eval/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -621,10 +621,10 @@ var (
KeySpecs: KeySpecs{BeginIndex: 1},
}
hkeysCmdMeta = DiceCmdMeta{
Name: "HKEYS",
Info: `HKEYS command is used to retrieve all the keys(or field names) within a hash. Complexity is O(n) where n is the size of the hash.`,
Eval: evalHKEYS,
Arity: 1,
Name: "HKEYS",
Info: `HKEYS command is used to retrieve all the keys(or field names) within a hash. Complexity is O(n) where n is the size of the hash.`,
Eval: evalHKEYS,
Arity: 1,
KeySpecs: KeySpecs{BeginIndex: 1},
}
hsetnxCmdMeta = DiceCmdMeta{
Expand Down Expand Up @@ -918,27 +918,27 @@ var (
Arity: 3,
KeySpecs: KeySpecs{BeginIndex: 1},
}
dumpkeyCMmdMeta=DiceCmdMeta{
Name: "DUMP",
Info: `Serialize the value stored at key in a Redis-specific format and return it to the user.
dumpkeyCMmdMeta = DiceCmdMeta{
Name: "DUMP",
Info: `Serialize the value stored at key in a Redis-specific format and return it to the user.
The returned value can be synthesized back into a Redis key using the RESTORE command.`,
Eval: evalDUMP,
Arity: 1,
KeySpecs: KeySpecs{BeginIndex: 1},
Eval: evalDUMP,
Arity: 1,
KeySpecs: KeySpecs{BeginIndex: 1},
}
restorekeyCmdMeta=DiceCmdMeta{
Name: "RESTORE",
Info: `Serialize the value stored at key in a Redis-specific format and return it to the user.
restorekeyCmdMeta = DiceCmdMeta{
Name: "RESTORE",
Info: `Serialize the value stored at key in a Redis-specific format and return it to the user.
The returned value can be synthesized back into a Redis key using the RESTORE command.`,
Eval: evalRestore,
Arity: 2,
Eval: evalRestore,
Arity: 2,
KeySpecs: KeySpecs{BeginIndex: 1},
}
typeCmdMeta = DiceCmdMeta{
Name: "TYPE",
Info: `Returns the string representation of the type of the value stored at key. The different types that can be returned are: string, list, set, zset, hash and stream.`,
Eval: evalTYPE,
Arity: 1,
Name: "TYPE",
Info: `Returns the string representation of the type of the value stored at key. The different types that can be returned are: string, list, set, zset, hash and stream.`,
Eval: evalTYPE,
Arity: 1,

KeySpecs: KeySpecs{BeginIndex: 1},
}
Expand Down Expand Up @@ -1053,8 +1053,8 @@ func init() {
DiceCmds["PING"] = pingCmdMeta
DiceCmds["ECHO"] = echoCmdMeta
DiceCmds["AUTH"] = authCmdMeta
DiceCmds["DUMP"]=dumpkeyCMmdMeta
DiceCmds["RESTORE"]=restorekeyCmdMeta
DiceCmds["DUMP"] = dumpkeyCMmdMeta
DiceCmds["RESTORE"] = restorekeyCmdMeta
DiceCmds["SET"] = setCmdMeta
DiceCmds["GET"] = getCmdMeta
DiceCmds["MSET"] = msetCmdMeta
Expand Down
132 changes: 66 additions & 66 deletions internal/eval/dump_restore.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,21 @@ import (
)

func evalDUMP(args []string, store *dstore.Store) []byte {
if len(args) < 1 {
return diceerrors.NewErrArity("DUMP")
}
key := args[0]
obj := store.Get(key)
if obj == nil {
return diceerrors.NewErrWithFormattedMessage("nil")
}
serializedValue, err := rdbSerialize(obj)
if err != nil {
return diceerrors.NewErrWithMessage("serialization failed")
}
if len(args) < 1 {
return diceerrors.NewErrArity("DUMP")
}
key := args[0]
obj := store.Get(key)
if obj == nil {
return diceerrors.NewErrWithFormattedMessage("nil")
}

serializedValue, err := rdbSerialize(obj)
if err != nil {
return diceerrors.NewErrWithMessage("serialization failed")
}
encodedResult := base64.StdEncoding.EncodeToString(serializedValue)
return clientio.Encode(encodedResult, false)
return clientio.Encode(encodedResult, false)
}

func evalRestore(args []string, store *dstore.Store) []byte {
Expand All @@ -38,9 +38,9 @@ func evalRestore(args []string, store *dstore.Store) []byte {
}

key := args[0]
ttlStr:=args[1]
ttlStr := args[1]
ttl, _ := strconv.ParseInt(ttlStr, 10, 64)

encodedValue := args[2]
serializedData, err := base64.StdEncoding.DecodeString(encodedValue)
if err != nil {
Expand All @@ -52,23 +52,23 @@ func evalRestore(args []string, store *dstore.Store) []byte {
return diceerrors.NewErrWithMessage("deserialization failed: " + err.Error())
}

newobj:=store.NewObj(obj.Value,ttl,obj.TypeEncoding,obj.TypeEncoding)
var keepttl=true
newobj := store.NewObj(obj.Value, ttl, obj.TypeEncoding, obj.TypeEncoding)
var keepttl = true

if(ttl>0){
if ttl > 0 {
store.Put(key, newobj, dstore.WithKeepTTL(keepttl))
}else{
store.Put(key,obj)
} else {
store.Put(key, obj)
}

return clientio.RespOK
}

func rdbDeserialize(data []byte) (*object.Obj, error) {
if len(data) < 3 {
return nil, errors.New("insufficient data for deserialization")
}
objType := data[1]
objType := data[1]
switch objType {
case 0x00:
return readString(data[2:])
Expand Down Expand Up @@ -104,55 +104,55 @@ func readInt(data []byte) (*object.Obj, error) {
}

func rdbSerialize(obj *object.Obj) ([]byte, error) {
var buf bytes.Buffer
buf.WriteByte(0x09)

switch object.GetType(obj.TypeEncoding) {
case object.ObjTypeString:
str, ok := obj.Value.(string)
if !ok {
return nil, errors.New("invalid string value")
}
buf.WriteByte(0x00)
if err := writeString(&buf, str); err != nil {
return nil, err
}

case object.ObjTypeInt:
intVal, ok := obj.Value.(int64)
if !ok {
return nil, errors.New("invalid integer value")
}
buf.WriteByte(0xC0)
writeInt(&buf, intVal);

default:
return nil, errors.New("unsupported object type")
}

buf.WriteByte(0xFF) // End marker

return appendChecksum(buf.Bytes()), nil
var buf bytes.Buffer
buf.WriteByte(0x09)

switch object.GetType(obj.TypeEncoding) {
case object.ObjTypeString:
str, ok := obj.Value.(string)
if !ok {
return nil, errors.New("invalid string value")
}
buf.WriteByte(0x00)
if err := writeString(&buf, str); err != nil {
return nil, err
}

case object.ObjTypeInt:
intVal, ok := obj.Value.(int64)
if !ok {
return nil, errors.New("invalid integer value")
}
buf.WriteByte(0xC0)
writeInt(&buf, intVal)

default:
return nil, errors.New("unsupported object type")
}

buf.WriteByte(0xFF) // End marker

return appendChecksum(buf.Bytes()), nil
}

func writeString(buf *bytes.Buffer, str string) error {
strLen := uint32(len(str))
if err := binary.Write(buf, binary.BigEndian, strLen); err != nil {
return err
}
buf.WriteString(str)
return nil
strLen := uint32(len(str))
if err := binary.Write(buf, binary.BigEndian, strLen); err != nil {
return err
}
buf.WriteString(str)
return nil
}

func writeInt(buf *bytes.Buffer, intVal int64){
tempBuf := make([]byte, 8)
binary.BigEndian.PutUint64(tempBuf, uint64(intVal))
buf.Write(tempBuf)
func writeInt(buf *bytes.Buffer, intVal int64) {
tempBuf := make([]byte, 8)
binary.BigEndian.PutUint64(tempBuf, uint64(intVal))
buf.Write(tempBuf)
}

func appendChecksum(data []byte) []byte {
checksum := crc64.Checksum(data, crc64.MakeTable(crc64.ECMA))
checksumBuf := make([]byte, 8)
binary.BigEndian.PutUint64(checksumBuf, checksum)
return append(data, checksumBuf...)
checksum := crc64.Checksum(data, crc64.MakeTable(crc64.ECMA))
checksumBuf := make([]byte, 8)
binary.BigEndian.PutUint64(checksumBuf, checksum)
return append(data, checksumBuf...)
}
2 changes: 1 addition & 1 deletion internal/eval/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -3174,7 +3174,7 @@ func evalHGET(args []string, store *dstore.Store) []byte {
// evalHMGET returns an array of values associated with the given fields,
// in the same order as they are requested.
// If a field does not exist, returns a corresponding nil value in the array.
// If the key does not exist, returns an array of nil values.
// If the key does not exist, returns an array of nil values.
func evalHMGET(args []string, store *dstore.Store) []byte {
if len(args) < 2 {
return diceerrors.NewErrArity("HMGET")
Expand Down
2 changes: 1 addition & 1 deletion internal/server/utils/redisCmdAdapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func ParseHTTPRequest(r *http.Request) (*cmd.DiceDBCmd, error) {

var args []string

//Handle subcommand and multiple arguments
// Handle subcommand and multiple arguments
if subcommand != "" {
args = append(args, subcommand)
}
Expand Down
Loading
Loading