diff --git a/src/commands/cmd_key.cc b/src/commands/cmd_key.cc index 8a75b2db616..efd0cc57927 100644 --- a/src/commands/cmd_key.cc +++ b/src/commands/cmd_key.cc @@ -115,13 +115,13 @@ class CommandExists : public Commander { class CommandExpire : public Commander { public: Status Parse(const std::vector &args) override { - seconds_ = GET_OR_RET(ParseInt(args[2], 10)) + Util::GetTimeStamp(); + ttl_ = GET_OR_RET(ParseInt(args[2], 10)); return Status::OK(); } Status Execute(Server *svr, Connection *conn, std::string *output) override { Redis::Database redis(svr->storage_, conn->GetNamespace()); - auto s = redis.Expire(args_[1], seconds_ * 1000); + auto s = redis.Expire(args_[1], ttl_ * 1000 + Util::GetTimeStampMS()); if (s.ok()) { *output = Redis::Integer(1); } else { @@ -131,7 +131,7 @@ class CommandExpire : public Commander { } private: - uint64_t seconds_ = 0; + uint64_t ttl_ = 0; }; class CommandPExpire : public Commander { diff --git a/src/storage/redis_db.cc b/src/storage/redis_db.cc index c347caa485f..6d2a2d1bb02 100644 --- a/src/storage/redis_db.cc +++ b/src/storage/redis_db.cc @@ -324,13 +324,13 @@ rocksdb::Status Database::RandomKey(const std::string &cursor, std::string *key) std::string end_cursor; std::vector keys; - auto s = Scan(cursor, 60, "", &keys, &end_cursor); + auto s = Scan(cursor, RANDOM_KEY_SCAN_LIMIT, "", &keys, &end_cursor); if (!s.ok()) { return s; } if (keys.empty() && !cursor.empty()) { // if reach the end, restart from beginning - s = Scan("", 60, "", &keys, &end_cursor); + s = Scan("", RANDOM_KEY_SCAN_LIMIT, "", &keys, &end_cursor); if (!s.ok()) { return s; } diff --git a/src/storage/redis_db.h b/src/storage/redis_db.h index 18012bf5aee..437ef82572e 100644 --- a/src/storage/redis_db.h +++ b/src/storage/redis_db.h @@ -31,6 +31,8 @@ namespace Redis { class Database { public: + static constexpr uint64_t RANDOM_KEY_SCAN_LIMIT = 60; + explicit Database(Engine::Storage *storage, std::string ns = ""); rocksdb::Status GetMetadata(RedisType type, const Slice &ns_key, Metadata *metadata); rocksdb::Status GetRawMetadata(const Slice &ns_key, std::string *bytes); diff --git a/src/storage/redis_metadata.cc b/src/storage/redis_metadata.cc index 73580abd406..aa5b26fe25f 100644 --- a/src/storage/redis_metadata.cc +++ b/src/storage/redis_metadata.cc @@ -233,7 +233,8 @@ uint64_t Metadata::ExpireMsToS(uint64_t ms) { return 1; } - return ms / 1000; + // We use rounding to get closer to the original value + return (ms + 499) / 1000; } bool Metadata::Is64BitEncoded() const { return flags & METADATA_64BIT_ENCODING_MASK; } diff --git a/tests/cppunit/types/string_test.cc b/tests/cppunit/types/string_test.cc index b2b4b26a295..61755b9b27a 100644 --- a/tests/cppunit/types/string_test.cc +++ b/tests/cppunit/types/string_test.cc @@ -179,7 +179,7 @@ TEST_F(RedisStringTest, MSetXX) { EXPECT_EQ(ret, 1); int64_t ttl = 0; string->TTL(key_, &ttl); - EXPECT_TRUE(ttl >= 2000 && ttl <= 3000); + EXPECT_TRUE(ttl >= 2000 && ttl <= 4000); string->Del(key_); } @@ -214,7 +214,7 @@ TEST_F(RedisStringTest, MSetNXWithTTL) { string->SetNX(key_, "test-value", 3000, &ret); int64_t ttl = 0; string->TTL(key_, &ttl); - EXPECT_TRUE(ttl >= 2000 && ttl <= 3000); + EXPECT_TRUE(ttl >= 2000 && ttl <= 4000); string->Del(key_); } @@ -222,7 +222,7 @@ TEST_F(RedisStringTest, SetEX) { string->SetEX(key_, "test-value", 3000); int64_t ttl = 0; string->TTL(key_, &ttl); - EXPECT_TRUE(ttl >= 2000 && ttl <= 3000); + EXPECT_TRUE(ttl >= 2000 && ttl <= 4000); string->Del(key_); } @@ -277,7 +277,7 @@ TEST_F(RedisStringTest, CAS) { int64_t ttl = 0; string->TTL(key, &ttl); - EXPECT_TRUE(ttl >= 9000 && ttl <= 10000); + EXPECT_TRUE(ttl >= 9000 && ttl <= 11000); string->Del(key); } diff --git a/tests/gocase/unit/expire/expire_test.go b/tests/gocase/unit/expire/expire_test.go index d35b84d8801..8a6919661af 100644 --- a/tests/gocase/unit/expire/expire_test.go +++ b/tests/gocase/unit/expire/expire_test.go @@ -168,7 +168,7 @@ func TestExpire(t *testing.T) { t.Run("PTTL returns time to live in milliseconds", func(t *testing.T) { require.NoError(t, rdb.Del(ctx, "x").Err()) require.NoError(t, rdb.SetEx(ctx, "x", "somevalue", 2*time.Second).Err()) - util.BetweenValues(t, rdb.PTTL(ctx, "x").Val(), 50*time.Millisecond, 2000*time.Millisecond) + util.BetweenValues(t, rdb.PTTL(ctx, "x").Val(), 500*time.Millisecond, 2500*time.Millisecond) }) t.Run("TTL / PTTL return -1 if key has no expire", func(t *testing.T) {