Skip to content

Commit 8f5500a

Browse files
authored
feat(server): support for persist command #345 (#354)
fix(server): support for persist command #345 Co-authored-by: Boaz Sade <boaz@dragonflydb.io>
1 parent bfc073b commit 8f5500a

File tree

4 files changed

+62
-11
lines changed

4 files changed

+62
-11
lines changed

docs/api_status.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ with respect to Memcached and Redis APIs.
177177
- [X] EVAL
178178
- [X] EVALSHA
179179
- [ ] OBJECT
180-
- [ ] PERSIST
180+
- [x] PERSIST
181181
- [X] PTTL
182182
- [ ] RESTORE
183183
- [X] SCRIPT LOAD/EXISTS

src/server/generic_family.cc

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ using namespace facade;
2929

3030
namespace {
3131

32+
OpStatus OpPersist(const OpArgs& op_args, string_view key);
33+
3234
class Renamer {
3335
public:
3436
Renamer(ShardId source_id) : src_sid_(source_id) {
@@ -177,6 +179,22 @@ struct ScanOpts {
177179
unsigned bucket_id = UINT_MAX;
178180
};
179181

182+
OpStatus OpPersist(const OpArgs& op_args, string_view key) {
183+
auto& db_slice = op_args.shard->db_slice();
184+
auto [it, expire_it] = db_slice.FindExt(op_args.db_cntx, key);
185+
186+
if (!IsValid(it)) {
187+
return OpStatus::KEY_NOTFOUND;
188+
} else {
189+
if (IsValid(expire_it)) {
190+
// The SKIPPED not really used, just placeholder for error
191+
return db_slice.UpdateExpire(op_args.db_cntx.db_index, it, 0) ? OpStatus::OK
192+
: OpStatus::SKIPPED;
193+
}
194+
return OpStatus::OK; // fall though - this is the default
195+
}
196+
}
197+
180198
bool ScanCb(const OpArgs& op_args, PrimeIterator it, const ScanOpts& opts, StringVec* res) {
181199
auto& db_slice = op_args.shard->db_slice();
182200
if (it->second.HasExpire()) {
@@ -348,6 +366,15 @@ void GenericFamily::Exists(CmdArgList args, ConnectionContext* cntx) {
348366
return (*cntx)->SendLong(result.load(memory_order_release));
349367
}
350368

369+
void GenericFamily::Persist(CmdArgList args, ConnectionContext* cntx) {
370+
string_view key = ArgS(args, 1);
371+
372+
auto cb = [&](Transaction* t, EngineShard* shard) { return OpPersist(t->GetOpArgs(shard), key); };
373+
374+
OpStatus status = cntx->transaction->ScheduleSingleHop(move(cb));
375+
(*cntx)->SendLong(status == OpStatus::OK);
376+
}
377+
351378
void GenericFamily::Expire(CmdArgList args, ConnectionContext* cntx) {
352379
string_view key = ArgS(args, 1);
353380
string_view sec = ArgS(args, 2);
@@ -1036,6 +1063,7 @@ void GenericFamily::Register(CommandRegistry* registry) {
10361063
<< CI{"EXISTS", CO::READONLY | CO::FAST, -2, 1, -1, 1}.HFUNC(Exists)
10371064
<< CI{"EXPIRE", CO::WRITE | CO::FAST, 3, 1, 1, 1}.HFUNC(Expire)
10381065
<< CI{"EXPIREAT", CO::WRITE | CO::FAST, 3, 1, 1, 1}.HFUNC(ExpireAt)
1066+
<< CI{"PERSIST", CO::WRITE | CO::FAST, 2, 1, 1, 1}.HFUNC(Persist)
10391067
<< CI{"KEYS", CO::READONLY, 2, 0, 0, 0}.HFUNC(Keys)
10401068
<< CI{"PEXPIREAT", CO::WRITE | CO::FAST, 3, 1, 1, 1}.HFUNC(PexpireAt)
10411069
<< CI{"RENAME", CO::WRITE, 3, 1, 2, 1}.HFUNC(Rename)

src/server/generic_family.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class GenericFamily {
4646
static void Exists(CmdArgList args, ConnectionContext* cntx);
4747
static void Expire(CmdArgList args, ConnectionContext* cntx);
4848
static void ExpireAt(CmdArgList args, ConnectionContext* cntx);
49+
static void Persist(CmdArgList args, ConnectionContext* cntx);
4950
static void Keys(CmdArgList args, ConnectionContext* cntx);
5051
static void PexpireAt(CmdArgList args, ConnectionContext* cntx);
5152
static void Stick(CmdArgList args, ConnectionContext* cntx);

src/server/generic_family_test.cc

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -282,31 +282,41 @@ TEST_F(GenericFamilyTest, Sort) {
282282
// numeric
283283
ASSERT_THAT(Run({"sort", "list-1"}).GetVec(), ElementsAre("1.2", "2.20", "3.5", "10.1", "200"));
284284
// string
285-
ASSERT_THAT(Run({"sort", "list-1", "ALPHA"}).GetVec(), ElementsAre("1.2", "10.1", "2.20", "200", "3.5"));
285+
ASSERT_THAT(Run({"sort", "list-1", "ALPHA"}).GetVec(),
286+
ElementsAre("1.2", "10.1", "2.20", "200", "3.5"));
286287
// desc numeric
287-
ASSERT_THAT(Run({"sort", "list-1", "DESC"}).GetVec(), ElementsAre("200", "10.1", "3.5", "2.20", "1.2"));
288+
ASSERT_THAT(Run({"sort", "list-1", "DESC"}).GetVec(),
289+
ElementsAre("200", "10.1", "3.5", "2.20", "1.2"));
288290
// desc strig
289-
ASSERT_THAT(Run({"sort", "list-1", "DESC", "ALPHA"}).GetVec(), ElementsAre("3.5", "200", "2.20", "10.1", "1.2"));
291+
ASSERT_THAT(Run({"sort", "list-1", "DESC", "ALPHA"}).GetVec(),
292+
ElementsAre("3.5", "200", "2.20", "10.1", "1.2"));
290293
// limits
291-
ASSERT_THAT(Run({"sort", "list-1", "LIMIT", "0", "5"}).GetVec(), ElementsAre("1.2", "2.20", "3.5", "10.1", "200"));
292-
ASSERT_THAT(Run({"sort", "list-1", "LIMIT", "0", "10"}).GetVec(), ElementsAre("1.2", "2.20", "3.5", "10.1", "200"));
294+
ASSERT_THAT(Run({"sort", "list-1", "LIMIT", "0", "5"}).GetVec(),
295+
ElementsAre("1.2", "2.20", "3.5", "10.1", "200"));
296+
ASSERT_THAT(Run({"sort", "list-1", "LIMIT", "0", "10"}).GetVec(),
297+
ElementsAre("1.2", "2.20", "3.5", "10.1", "200"));
293298
ASSERT_THAT(Run({"sort", "list-1", "LIMIT", "2", "2"}).GetVec(), ElementsAre("3.5", "10.1"));
294299
ASSERT_THAT(Run({"sort", "list-1", "LIMIT", "1", "1"}), "2.20");
295300
ASSERT_THAT(Run({"sort", "list-1", "LIMIT", "4", "2"}), "200");
296301
ASSERT_THAT(Run({"sort", "list-1", "LIMIT", "5", "2"}), ArrLen(0));
297302
// limits desc
298-
ASSERT_THAT(Run({"sort", "list-1", "DESC", "LIMIT", "0", "5"}).GetVec(), ElementsAre("200", "10.1", "3.5", "2.20", "1.2"));
299-
ASSERT_THAT(Run({"sort", "list-1", "DESC", "LIMIT", "2", "2"}).GetVec(), ElementsAre("3.5", "2.20"));
303+
ASSERT_THAT(Run({"sort", "list-1", "DESC", "LIMIT", "0", "5"}).GetVec(),
304+
ElementsAre("200", "10.1", "3.5", "2.20", "1.2"));
305+
ASSERT_THAT(Run({"sort", "list-1", "DESC", "LIMIT", "2", "2"}).GetVec(),
306+
ElementsAre("3.5", "2.20"));
300307
ASSERT_THAT(Run({"sort", "list-1", "DESC", "LIMIT", "1", "1"}), "10.1");
301308
ASSERT_THAT(Run({"sort", "list-1", "DESC", "LIMIT", "5", "2"}), ArrLen(0));
302309

303310
// Test set sort
304311
Run({"del", "set-1"});
305312
Run({"sadd", "set-1", "5.3", "4.4", "60", "99.9", "100", "9"});
306313
ASSERT_THAT(Run({"sort", "set-1"}).GetVec(), ElementsAre("4.4", "5.3", "9", "60", "99.9", "100"));
307-
ASSERT_THAT(Run({"sort", "set-1", "ALPHA"}).GetVec(), ElementsAre("100", "4.4", "5.3", "60", "9", "99.9"));
308-
ASSERT_THAT(Run({"sort", "set-1", "DESC"}).GetVec(), ElementsAre("100", "99.9", "60", "9", "5.3", "4.4"));
309-
ASSERT_THAT(Run({"sort", "set-1", "DESC", "ALPHA"}).GetVec(), ElementsAre("99.9", "9", "60", "5.3", "4.4", "100"));
314+
ASSERT_THAT(Run({"sort", "set-1", "ALPHA"}).GetVec(),
315+
ElementsAre("100", "4.4", "5.3", "60", "9", "99.9"));
316+
ASSERT_THAT(Run({"sort", "set-1", "DESC"}).GetVec(),
317+
ElementsAre("100", "99.9", "60", "9", "5.3", "4.4"));
318+
ASSERT_THAT(Run({"sort", "set-1", "DESC", "ALPHA"}).GetVec(),
319+
ElementsAre("99.9", "9", "60", "5.3", "4.4", "100"));
310320

311321
// Test intset sort
312322
Run({"del", "intset-1"});
@@ -354,4 +364,16 @@ TEST_F(GenericFamilyTest, Time) {
354364
}
355365
}
356366

367+
TEST_F(GenericFamilyTest, Persist) {
368+
auto resp = Run({"set", "mykey", "somevalue"});
369+
EXPECT_EQ(resp, "OK");
370+
// Key without expiration time - return 1
371+
EXPECT_EQ(1, CheckedInt({"persist", "mykey"}));
372+
// set expiration time and try again
373+
resp = Run({"EXPIRE", "mykey", "10"});
374+
EXPECT_EQ(10, CheckedInt({"TTL", "mykey"}));
375+
EXPECT_EQ(1, CheckedInt({"persist", "mykey"}));
376+
EXPECT_EQ(-1, CheckedInt({"TTL", "mykey"}));
377+
}
378+
357379
} // namespace dfly

0 commit comments

Comments
 (0)