From acafbc6f4fb0b71e70010de15dd73294d8a22f6c Mon Sep 17 00:00:00 2001 From: b0bleet <83914374+b0bleet@users.noreply.github.com> Date: Sun, 6 Nov 2022 15:07:41 -0500 Subject: [PATCH] feat(server) implement pexpire command (#464) Signed-off-by: b0bleet b0bleet@placeq.com --- docs/api_status.md | 2 +- src/server/generic_family.cc | 24 ++++++++++++++++++++++++ src/server/generic_family.h | 1 + src/server/generic_family_test.cc | 17 +++++++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/docs/api_status.md b/docs/api_status.md index 276aaa83d..cb198e1f3 100644 --- a/docs/api_status.md +++ b/docs/api_status.md @@ -172,7 +172,7 @@ with respect to Memcached and Redis APIs. - [X] Generic Family - [X] SCAN - [X] PEXPIREAT - - [ ] PEXPIRE + - [X] PEXPIRE - [x] DUMP - [X] EVAL - [X] EVALSHA diff --git a/src/server/generic_family.cc b/src/server/generic_family.cc index d7af80fa9..c743966a3 100644 --- a/src/server/generic_family.cc +++ b/src/server/generic_family.cc @@ -778,6 +778,29 @@ void GenericFamily::PexpireAt(CmdArgList args, ConnectionContext* cntx) { } } +void GenericFamily::Pexpire(CmdArgList args, ConnectionContext* cntx) { + string_view key = ArgS(args, 1); + string_view msec = ArgS(args, 2); + int64_t int_arg; + + if (!absl::SimpleAtoi(msec, &int_arg)) { + return (*cntx)->SendError(kInvalidIntErr); + } + int_arg = std::max(int_arg, 0L); + DbSlice::ExpireParams params{.value = int_arg, .unit = TimeUnit::MSEC}; + + auto cb = [&](Transaction* t, EngineShard* shard) { + return OpExpire(t->GetOpArgs(shard), key, params); + }; + OpStatus status = cntx->transaction->ScheduleSingleHop(std::move(cb)); + + if (status == OpStatus::OUT_OF_RANGE) { + return (*cntx)->SendError(kExpiryOutOfRange); + } else { + (*cntx)->SendLong(status == OpStatus::OK); + } +} + void GenericFamily::Stick(CmdArgList args, ConnectionContext* cntx) { Transaction* transaction = cntx->transaction; VLOG(1) << "Stick " << ArgS(args, 1); @@ -1411,6 +1434,7 @@ void GenericFamily::Register(CommandRegistry* registry) { << CI{"PERSIST", CO::WRITE | CO::FAST, 2, 1, 1, 1}.HFUNC(Persist) << CI{"KEYS", CO::READONLY, 2, 0, 0, 0}.HFUNC(Keys) << CI{"PEXPIREAT", CO::WRITE | CO::FAST, 3, 1, 1, 1}.HFUNC(PexpireAt) + << CI{"PEXPIRE", CO::WRITE | CO::FAST, 3, 1, 1, 1}.HFUNC(Pexpire) << CI{"RENAME", CO::WRITE, 3, 1, 2, 1}.HFUNC(Rename) << CI{"RENAMENX", CO::WRITE, 3, 1, 2, 1}.HFUNC(RenameNx) << CI{"SELECT", kSelectOpts, 2, 0, 0, 0}.HFUNC(Select) diff --git a/src/server/generic_family.h b/src/server/generic_family.h index 0ebc7ca54..ba0e55b76 100644 --- a/src/server/generic_family.h +++ b/src/server/generic_family.h @@ -40,6 +40,7 @@ class GenericFamily { static void Persist(CmdArgList args, ConnectionContext* cntx); static void Keys(CmdArgList args, ConnectionContext* cntx); static void PexpireAt(CmdArgList args, ConnectionContext* cntx); + static void Pexpire(CmdArgList args, ConnectionContext* cntx); static void Stick(CmdArgList args, ConnectionContext* cntx); static void Sort(CmdArgList args, ConnectionContext* cntx); static void Move(CmdArgList args, ConnectionContext* cntx); diff --git a/src/server/generic_family_test.cc b/src/server/generic_family_test.cc index 2a1fc3e01..e43d334bb 100644 --- a/src/server/generic_family_test.cc +++ b/src/server/generic_family_test.cc @@ -52,6 +52,23 @@ TEST_F(GenericFamilyTest, Expire) { AdvanceTime(1); resp = Run({"get", "key"}); EXPECT_THAT(resp, ArgType(RespExpr::NIL)); + + // pexpire test + Run({"set", "key", "val"}); + resp = Run({"pexpire", "key", absl::StrCat(2000)}); + EXPECT_THAT(resp, IntArg(1)); + + // expire time override + resp = Run({"pexpire", "key", absl::StrCat(3000)}); + EXPECT_THAT(resp, IntArg(1)); + + AdvanceTime(2999); + resp = Run({"get", "key"}); + EXPECT_THAT(resp, "val"); + + AdvanceTime(1); + resp = Run({"get", "key"}); + EXPECT_THAT(resp, ArgType(RespExpr::NIL)); } TEST_F(GenericFamilyTest, Del) {