From d77f08c140d29025c3e6097c3f4b737a9b7139af Mon Sep 17 00:00:00 2001 From: li <1312513963@qq.com> Date: Tue, 14 Feb 2023 14:23:40 +0800 Subject: [PATCH] ADD EXPIRETIME and EXPIRETIME command --- cluster/router.go | 2 ++ database/keys.go | 36 +++++++++++++++++++++++++++++ database/keys_test.go | 54 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+) diff --git a/cluster/router.go b/cluster/router.go index 677d02c..34c3ac0 100644 --- a/cluster/router.go +++ b/cluster/router.go @@ -16,8 +16,10 @@ func makeRouter() map[string]CmdFunc { routerMap["expire"] = defaultFunc routerMap["expireat"] = defaultFunc + routerMap["expiretime"] = defaultFunc routerMap["pexpire"] = defaultFunc routerMap["pexpireat"] = defaultFunc + routerMap["pexpiretime"] = defaultFunc routerMap["ttl"] = defaultFunc routerMap["pttl"] = defaultFunc routerMap["persist"] = defaultFunc diff --git a/database/keys.go b/database/keys.go index d503acb..7328dc5 100644 --- a/database/keys.go +++ b/database/keys.go @@ -185,6 +185,23 @@ func execExpireAt(db *DB, args [][]byte) redis.Reply { return protocol.MakeIntReply(1) } +// execExpireTime returns the absolute Unix expiration timestamp in seconds at which the given key will expire. +func execExpireTime(db *DB, args [][]byte) redis.Reply { + key := string(args[0]) + _, exists := db.GetEntity(key) + if !exists { + return protocol.MakeIntReply(-2) + } + + raw, exists := db.ttlMap.Get(key) + if !exists { + return protocol.MakeIntReply(-1) + } + rawExpireTime, _ := raw.(time.Time) + expireTime := rawExpireTime.Unix() + return protocol.MakeIntReply(expireTime) +} + // execPExpire sets a key's time to live in milliseconds func execPExpire(db *DB, args [][]byte) redis.Reply { key := string(args[0]) @@ -227,6 +244,23 @@ func execPExpireAt(db *DB, args [][]byte) redis.Reply { return protocol.MakeIntReply(1) } +// execPExpireTime returns the absolute Unix expiration timestamp in milliseconds at which the given key will expire. +func execPExpireTime(db *DB, args [][]byte) redis.Reply { + key := string(args[0]) + _, exists := db.GetEntity(key) + if !exists { + return protocol.MakeIntReply(-2) + } + + raw, exists := db.ttlMap.Get(key) + if !exists { + return protocol.MakeIntReply(-1) + } + rawExpireTime, _ := raw.(time.Time) + expireTime := rawExpireTime.UnixMilli() + return protocol.MakeIntReply(expireTime) +} + // execTTL returns a key's time to live in seconds func execTTL(db *DB, args [][]byte) redis.Reply { key := string(args[0]) @@ -379,8 +413,10 @@ func init() { RegisterCommand("Del", execDel, writeAllKeys, undoDel, -2, flagWrite) RegisterCommand("Expire", execExpire, writeFirstKey, undoExpire, 3, flagWrite) RegisterCommand("ExpireAt", execExpireAt, writeFirstKey, undoExpire, 3, flagWrite) + RegisterCommand("ExpireTime", execExpireTime, readFirstKey, nil, 2, flagReadOnly) RegisterCommand("PExpire", execPExpire, writeFirstKey, undoExpire, 3, flagWrite) RegisterCommand("PExpireAt", execPExpireAt, writeFirstKey, undoExpire, 3, flagWrite) + RegisterCommand("PExpireTime", execPExpireTime, readFirstKey, nil, 2, flagReadOnly) RegisterCommand("TTL", execTTL, readFirstKey, nil, 2, flagReadOnly) RegisterCommand("PTTL", execPTTL, readFirstKey, nil, 2, flagReadOnly) RegisterCommand("Persist", execPersist, writeFirstKey, undoExpire, 2, flagWrite) diff --git a/database/keys_test.go b/database/keys_test.go index 37b83cd..0e1508e 100644 --- a/database/keys_test.go +++ b/database/keys_test.go @@ -191,6 +191,60 @@ func TestExpireAt(t *testing.T) { } } +func TestExpiredTime(t *testing.T) { + //测试ExpireTime + testDB.Flush() + key := utils.RandString(10) + value := utils.RandString(10) + testDB.Exec(nil, utils.ToCmdLine("set", key, value)) + + result := testDB.Exec(nil, utils.ToCmdLine("ttl", key)) + asserts.AssertIntReply(t, result, -1) + result = testDB.Exec(nil, utils.ToCmdLine("EXPIRETIME", key)) + asserts.AssertIntReply(t, result, -1) + result = testDB.Exec(nil, utils.ToCmdLine("PEXPIRETIME", key)) + asserts.AssertIntReply(t, result, -1) + + testDB.Exec(nil, utils.ToCmdLine("EXPIRE", key, "2")) + //tt := time.Now() + result = testDB.Exec(nil, utils.ToCmdLine("ttl", key)) + asserts.AssertIntReply(t, result, 2) + result = testDB.Exec(nil, utils.ToCmdLine("EXPIRETIME", key)) + asserts.AssertIntReply(t, result, int(time.Now().Add(2*time.Second).Unix())) + intResult, ok := result.(*protocol.IntReply) + if !ok { + t.Error(fmt.Sprintf("expected int protocol, actually %s", result.ToBytes())) + return + } + if intResult.Code <= 0 { + t.Errorf("expected ttl more than 0, actual: %d", intResult.Code) + return + } + + result = testDB.Exec(nil, utils.ToCmdLine("PEXPIRETIME", key)) + asserts.AssertIntReply(t, result, int(time.Now().Add(2*time.Second).UnixMilli())) + intResult, ok = result.(*protocol.IntReply) + if !ok { + t.Error(fmt.Sprintf("expected int protocol, actually %s", result.ToBytes())) + return + } + if intResult.Code <= 0 { + t.Errorf("expected ttl more than 0, actual: %d", intResult.Code) + return + } + + time.Sleep(3 * time.Second) + result = testDB.Exec(nil, utils.ToCmdLine("ttl", key)) + asserts.AssertIntReply(t, result, -2) + result = testDB.Exec(nil, utils.ToCmdLine("EXPIRETIME", key)) + asserts.AssertIntReply(t, result, -2) + intResult, ok = result.(*protocol.IntReply) + result = testDB.Exec(nil, utils.ToCmdLine("PEXPIRETIME", key)) + asserts.AssertIntReply(t, result, -2) + intResult, ok = result.(*protocol.IntReply) + +} + func TestKeys(t *testing.T) { testDB.Flush() key := utils.RandString(10)