@@ -14,6 +14,7 @@ extern "C" {
14
14
15
15
#include " base/flags.h"
16
16
#include " base/logging.h"
17
+ #include " core/qlist.h"
17
18
#include " server/blocking_controller.h"
18
19
#include " server/command_registry.h"
19
20
#include " server/conn_context.h"
@@ -59,6 +60,8 @@ ABSL_FLAG(int32_t, list_max_listpack_size, -2, "Maximum listpack size, default i
59
60
*/
60
61
61
62
ABSL_FLAG (int32_t , list_compress_depth, 0 , " Compress depth of the list. Default is no compression" );
63
+ ABSL_FLAG (bool , list_experimental_v2, false ,
64
+ " Compress depth of the list. Default is no compression" );
62
65
63
66
namespace dfly {
64
67
@@ -73,6 +76,10 @@ quicklist* GetQL(const PrimeValue& mv) {
73
76
return (quicklist*)mv.RObjPtr ();
74
77
}
75
78
79
+ QList* GetQLV2 (const PrimeValue& mv) {
80
+ return (QList*)mv.RObjPtr ();
81
+ }
82
+
76
83
void * listPopSaver (unsigned char * data, size_t sz) {
77
84
return new string ((char *)data, sz);
78
85
}
@@ -265,26 +272,46 @@ OpResult<uint32_t> OpPush(const OpArgs& op_args, std::string_view key, ListDir d
265
272
res = std::move (*op_res);
266
273
}
267
274
268
- quicklist* ql = nullptr ;
275
+ size_t len = 0 ;
269
276
DVLOG (1 ) << " OpPush " << key << " new_key " << res.is_new ;
277
+ quicklist* ql = nullptr ;
278
+ QList* ql_v2 = nullptr ;
270
279
271
280
if (res.is_new ) {
272
- ql = quicklistCreate ();
273
- quicklistSetOptions (ql, GetFlag (FLAGS_list_max_listpack_size),
274
- GetFlag (FLAGS_list_compress_depth));
275
- res.it ->second .InitRobj (OBJ_LIST, OBJ_ENCODING_QUICKLIST, ql);
281
+ if (absl::GetFlag (FLAGS_list_experimental_v2)) {
282
+ ql_v2 = CompactObj::AllocateMR<QList>(GetFlag (FLAGS_list_max_listpack_size),
283
+ GetFlag (FLAGS_list_compress_depth));
284
+ res.it ->second .InitRobj (OBJ_LIST, kEncodingQL2 , ql_v2);
285
+ } else {
286
+ ql = quicklistCreate ();
287
+ quicklistSetOptions (ql, GetFlag (FLAGS_list_max_listpack_size),
288
+ GetFlag (FLAGS_list_compress_depth));
289
+ res.it ->second .InitRobj (OBJ_LIST, OBJ_ENCODING_QUICKLIST, ql);
290
+ }
276
291
} else {
277
292
if (res.it ->second .ObjType () != OBJ_LIST)
278
293
return OpStatus::WRONG_TYPE;
279
- ql = GetQL (res.it ->second );
294
+ if (res.it ->second .Encoding () == kEncodingQL2 ) {
295
+ ql_v2 = GetQLV2 (res.it ->second );
296
+ } else {
297
+ ql = GetQL (res.it ->second );
298
+ }
280
299
}
281
300
282
- // Left push is LIST_HEAD.
283
- int pos = (dir == ListDir::LEFT) ? QUICKLIST_HEAD : QUICKLIST_TAIL;
284
-
285
- for (string_view v : vals) {
286
- auto vsds = WrapSds (v);
287
- quicklistPush (ql, vsds, sdslen (vsds), pos);
301
+ if (ql) {
302
+ // Left push is LIST_HEAD.
303
+ int pos = (dir == ListDir::LEFT) ? QUICKLIST_HEAD : QUICKLIST_TAIL;
304
+ for (string_view v : vals) {
305
+ auto vsds = WrapSds (v);
306
+ quicklistPush (ql, vsds, sdslen (vsds), pos);
307
+ }
308
+ len = quicklistCount (ql);
309
+ } else {
310
+ QList::Where where = (dir == ListDir::LEFT) ? QList::HEAD : QList::TAIL;
311
+ for (string_view v : vals) {
312
+ ql_v2->Push (v, where);
313
+ }
314
+ len = ql_v2->Size ();
288
315
}
289
316
290
317
if (res.is_new ) {
@@ -305,7 +332,7 @@ OpResult<uint32_t> OpPush(const OpArgs& op_args, std::string_view key, ListDir d
305
332
RecordJournal (op_args, command, mapped, 2 );
306
333
}
307
334
308
- return quicklistCount (ql) ;
335
+ return len ;
309
336
}
310
337
311
338
OpResult<StringVec> OpPop (const OpArgs& op_args, string_view key, ListDir dir, uint32_t count,
@@ -320,26 +347,26 @@ OpResult<StringVec> OpPop(const OpArgs& op_args, string_view key, ListDir dir, u
320
347
321
348
auto it = it_res->it ;
322
349
quicklist* ql = GetQL (it->second );
323
-
350
+ auto prev_len = quicklistCount (ql);
324
351
StringVec res;
325
- if (quicklistCount (ql) < count) {
326
- count = quicklistCount (ql) ;
352
+ if (prev_len < count) {
353
+ count = prev_len ;
327
354
}
328
- res.reserve (count);
329
355
330
356
if (return_results) {
331
- for (unsigned i = 0 ; i < count; ++i) {
332
- res.push_back (ListPop (dir, ql));
333
- }
334
- } else {
335
- for (unsigned i = 0 ; i < count; ++i) {
336
- ListPop (dir, ql);
357
+ res.reserve (count);
358
+ }
359
+
360
+ for (unsigned i = 0 ; i < count; ++i) {
361
+ string val = ListPop (dir, ql);
362
+ if (return_results) {
363
+ res.push_back (std::move (val));
337
364
}
338
365
}
339
366
340
367
it_res->post_updater .Run ();
341
368
342
- if (quicklistCount (ql) == 0 ) {
369
+ if (count == prev_len ) {
343
370
CHECK (db_slice.Del (op_args.db_cntx , it));
344
371
}
345
372
@@ -418,31 +445,43 @@ OpResult<uint32_t> OpLen(const OpArgs& op_args, std::string_view key) {
418
445
if (!res)
419
446
return res.status ();
420
447
421
- quicklist* ql = GetQL (res.value ()->second );
448
+ if (res.value ()->second .Encoding () == kEncodingQL2 ) {
449
+ QList* ql = GetQLV2 (res.value ()->second );
450
+ return ql->Size ();
451
+ }
422
452
453
+ quicklist* ql = GetQL (res.value ()->second );
423
454
return quicklistCount (ql);
424
455
}
425
456
426
457
OpResult<string> OpIndex (const OpArgs& op_args, std::string_view key, long index) {
427
458
auto res = op_args.GetDbSlice ().FindReadOnly (op_args.db_cntx , key, OBJ_LIST);
428
459
if (!res)
429
460
return res.status ();
430
- quicklist* ql = GetQL (res.value ()->second );
431
- quicklistEntry entry = container_utils::QLEntry ();
432
- quicklistIter* iter = quicklistGetIteratorAtIdx (ql, AL_START_TAIL, index);
433
- if (!iter)
434
- return OpStatus::KEY_NOTFOUND;
435
461
436
- quicklistNext (iter, &entry);
437
462
string str;
438
-
439
- if (entry.value ) {
440
- str.assign (reinterpret_cast <char *>(entry.value ), entry.sz );
463
+ if (res.value ()->second .Encoding () == kEncodingQL2 ) {
464
+ QList* ql = GetQLV2 (res.value ()->second );
465
+ auto it = ql->GetIterator (index);
466
+ if (!it.Next ())
467
+ return OpStatus::KEY_NOTFOUND;
468
+ str = it.Get ().to_string ();
441
469
} else {
442
- str = absl::StrCat (entry.longval );
443
- }
444
- quicklistReleaseIterator (iter);
470
+ quicklist* ql = GetQL (res.value ()->second );
471
+ quicklistEntry entry = container_utils::QLEntry ();
472
+ quicklistIter* iter = quicklistGetIteratorAtIdx (ql, AL_START_TAIL, index);
473
+ if (!iter)
474
+ return OpStatus::KEY_NOTFOUND;
475
+
476
+ quicklistNext (iter, &entry);
445
477
478
+ if (entry.value ) {
479
+ str.assign (reinterpret_cast <char *>(entry.value ), entry.sz );
480
+ } else {
481
+ str = absl::StrCat (entry.longval );
482
+ }
483
+ quicklistReleaseIterator (iter);
484
+ }
446
485
return str;
447
486
}
448
487
0 commit comments