mirror of
https://github.com/dragonflydb/dragonfly.git
synced 2024-12-14 11:58:02 +00:00
chore: support rdb loading and container utils with QList. (#4109)
generic_family_test and rdb_test pass with qlist enabled. Signed-off-by: Roman Gershman <roman@dragonflydb.io>
This commit is contained in:
parent
745db2c82f
commit
79aa5d490d
3 changed files with 88 additions and 54 deletions
|
@ -82,7 +82,8 @@ size_t NodeNegFillLimit(int fill) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8_t* uint_ptr(string_view sv) {
|
const uint8_t* uint_ptr(string_view sv) {
|
||||||
return reinterpret_cast<const uint8_t*>(sv.data());
|
static uint8_t empty = 0;
|
||||||
|
return sv.empty() ? &empty : reinterpret_cast<const uint8_t*>(sv.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsLargeElement(size_t sz, int fill) {
|
bool IsLargeElement(size_t sz, int fill) {
|
||||||
|
@ -136,10 +137,6 @@ quicklistNode* CreateNode() {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t* LP_FromElem(string_view elem) {
|
|
||||||
return lpPrepend(lpNew(0), uint_ptr(elem), elem.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t* LP_Insert(uint8_t* lp, string_view elem, uint8_t* pos, int lp_where) {
|
uint8_t* LP_Insert(uint8_t* lp, string_view elem, uint8_t* pos, int lp_where) {
|
||||||
return lpInsertString(lp, uint_ptr(elem), elem.size(), pos, lp_where, NULL);
|
return lpInsertString(lp, uint_ptr(elem), elem.size(), pos, lp_where, NULL);
|
||||||
}
|
}
|
||||||
|
@ -155,15 +152,16 @@ uint8_t* LP_Prepend(uint8_t* lp, string_view elem) {
|
||||||
quicklistNode* CreateNode(int container, string_view value) {
|
quicklistNode* CreateNode(int container, string_view value) {
|
||||||
quicklistNode* new_node = CreateNode();
|
quicklistNode* new_node = CreateNode();
|
||||||
new_node->container = container;
|
new_node->container = container;
|
||||||
new_node->sz = value.size();
|
new_node->count = 1;
|
||||||
new_node->count++;
|
|
||||||
|
|
||||||
if (container == QUICKLIST_NODE_CONTAINER_PLAIN) {
|
if (container == QUICKLIST_NODE_CONTAINER_PLAIN) {
|
||||||
DCHECK(!value.empty());
|
DCHECK(!value.empty());
|
||||||
new_node->entry = (uint8_t*)zmalloc(new_node->sz);
|
new_node->entry = (uint8_t*)zmalloc(new_node->sz);
|
||||||
memcpy(new_node->entry, value.data(), new_node->sz);
|
memcpy(new_node->entry, value.data(), new_node->sz);
|
||||||
|
new_node->sz = value.size();
|
||||||
} else {
|
} else {
|
||||||
new_node->entry = LP_FromElem(value);
|
new_node->entry = LP_Prepend(lpNew(0), value);
|
||||||
|
new_node->sz = lpBytes(new_node->entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new_node;
|
return new_node;
|
||||||
|
@ -467,13 +465,10 @@ bool QList::PushHead(string_view value) {
|
||||||
count_++;
|
count_++;
|
||||||
|
|
||||||
if (ABSL_PREDICT_TRUE(NodeAllowInsert(head_, fill_, sz))) {
|
if (ABSL_PREDICT_TRUE(NodeAllowInsert(head_, fill_, sz))) {
|
||||||
head_->entry = lpPrepend(head_->entry, uint_ptr(value), sz);
|
head_->entry = LP_Prepend(head_->entry, value);
|
||||||
NodeUpdateSz(head_);
|
NodeUpdateSz(head_);
|
||||||
} else {
|
} else {
|
||||||
quicklistNode* node = CreateNode();
|
quicklistNode* node = CreateNode(QUICKLIST_NODE_CONTAINER_PACKED, value);
|
||||||
node->entry = LP_FromElem(value);
|
|
||||||
|
|
||||||
NodeUpdateSz(node);
|
|
||||||
InsertNode(head_, node, BEFORE);
|
InsertNode(head_, node, BEFORE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -492,16 +487,16 @@ bool QList::PushTail(string_view value) {
|
||||||
|
|
||||||
count_++;
|
count_++;
|
||||||
if (ABSL_PREDICT_TRUE(NodeAllowInsert(orig, fill_, sz))) {
|
if (ABSL_PREDICT_TRUE(NodeAllowInsert(orig, fill_, sz))) {
|
||||||
orig->entry = lpAppend(orig->entry, uint_ptr(value), sz);
|
orig->entry = LP_Append(orig->entry, value);
|
||||||
NodeUpdateSz(orig);
|
NodeUpdateSz(orig);
|
||||||
} else {
|
orig->count++;
|
||||||
quicklistNode* node = CreateNode();
|
return false;
|
||||||
node->entry = LP_FromElem(value);
|
|
||||||
NodeUpdateSz(node);
|
|
||||||
InsertNode(orig, node, AFTER);
|
|
||||||
}
|
}
|
||||||
tail_->count++;
|
|
||||||
return (orig != tail_);
|
quicklistNode* node = CreateNode(QUICKLIST_NODE_CONTAINER_PACKED, value);
|
||||||
|
InsertNode(orig, node, AFTER);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QList::InsertPlainNode(quicklistNode* old_node, string_view value, InsertOpt insert_opt) {
|
void QList::InsertPlainNode(quicklistNode* old_node, string_view value, InsertOpt insert_opt) {
|
||||||
|
@ -559,10 +554,9 @@ void QList::Insert(Iterator it, std::string_view elem, InsertOpt insert_opt) {
|
||||||
InsertPlainNode(tail_, elem, insert_opt);
|
InsertPlainNode(tail_, elem, insert_opt);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
new_node = CreateNode();
|
|
||||||
new_node->entry = LP_FromElem(elem);
|
new_node = CreateNode(QUICKLIST_NODE_CONTAINER_PACKED, elem);
|
||||||
InsertNode(NULL, new_node, insert_opt);
|
InsertNode(NULL, new_node, insert_opt);
|
||||||
new_node->count++;
|
|
||||||
count_++;
|
count_++;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -636,10 +630,7 @@ void QList::Insert(Iterator it, std::string_view elem, InsertOpt insert_opt) {
|
||||||
} else if (full && ((at_tail && !avail_next && after) || (at_head && !avail_prev && !after))) {
|
} else if (full && ((at_tail && !avail_next && after) || (at_head && !avail_prev && !after))) {
|
||||||
/* If we are: full, and our prev/next has no available space, then:
|
/* If we are: full, and our prev/next has no available space, then:
|
||||||
* - create new node and attach to qlist */
|
* - create new node and attach to qlist */
|
||||||
new_node = CreateNode();
|
new_node = CreateNode(QUICKLIST_NODE_CONTAINER_PACKED, elem);
|
||||||
new_node->entry = LP_FromElem(elem);
|
|
||||||
new_node->count++;
|
|
||||||
NodeUpdateSz(new_node);
|
|
||||||
InsertNode(node, new_node, insert_opt);
|
InsertNode(node, new_node, insert_opt);
|
||||||
} else if (full) {
|
} else if (full) {
|
||||||
/* else, node is full we need to split it. */
|
/* else, node is full we need to split it. */
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "base/flags.h"
|
#include "base/flags.h"
|
||||||
#include "base/logging.h"
|
#include "base/logging.h"
|
||||||
|
#include "core/qlist.h"
|
||||||
#include "core/sorted_map.h"
|
#include "core/sorted_map.h"
|
||||||
#include "core/string_map.h"
|
#include "core/string_map.h"
|
||||||
#include "core/string_set.h"
|
#include "core/string_set.h"
|
||||||
|
@ -152,6 +153,9 @@ quicklistEntry QLEntry() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IterateList(const PrimeValue& pv, const IterateFunc& func, long start, long end) {
|
bool IterateList(const PrimeValue& pv, const IterateFunc& func, long start, long end) {
|
||||||
|
bool success = true;
|
||||||
|
|
||||||
|
if (pv.Encoding() == OBJ_ENCODING_QUICKLIST) {
|
||||||
quicklist* ql = static_cast<quicklist*>(pv.RObjPtr());
|
quicklist* ql = static_cast<quicklist*>(pv.RObjPtr());
|
||||||
long llen = quicklistCount(ql);
|
long llen = quicklistCount(ql);
|
||||||
if (end < 0 || end >= llen)
|
if (end < 0 || end >= llen)
|
||||||
|
@ -161,7 +165,6 @@ bool IterateList(const PrimeValue& pv, const IterateFunc& func, long start, long
|
||||||
quicklistEntry entry = QLEntry();
|
quicklistEntry entry = QLEntry();
|
||||||
long lrange = end - start + 1;
|
long lrange = end - start + 1;
|
||||||
|
|
||||||
bool success = true;
|
|
||||||
while (success && quicklistNext(qiter, &entry) && lrange-- > 0) {
|
while (success && quicklistNext(qiter, &entry) && lrange-- > 0) {
|
||||||
if (entry.value) {
|
if (entry.value) {
|
||||||
success = func(ContainerEntry{reinterpret_cast<char*>(entry.value), entry.sz});
|
success = func(ContainerEntry{reinterpret_cast<char*>(entry.value), entry.sz});
|
||||||
|
@ -172,6 +175,21 @@ bool IterateList(const PrimeValue& pv, const IterateFunc& func, long start, long
|
||||||
quicklistReleaseIterator(qiter);
|
quicklistReleaseIterator(qiter);
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
DCHECK_EQ(pv.Encoding(), kEncodingQL2);
|
||||||
|
QList* ql = static_cast<QList*>(pv.RObjPtr());
|
||||||
|
|
||||||
|
ql->Iterate(
|
||||||
|
[&](const QList::Entry& entry) {
|
||||||
|
if (entry.is_int()) {
|
||||||
|
success = func(ContainerEntry{entry.ival()});
|
||||||
|
} else {
|
||||||
|
success = func(ContainerEntry{entry.view().data(), entry.view().size()});
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
},
|
||||||
|
start, end);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
bool IterateSet(const PrimeValue& pv, const IterateFunc& func) {
|
bool IterateSet(const PrimeValue& pv, const IterateFunc& func) {
|
||||||
bool success = true;
|
bool success = true;
|
||||||
|
|
|
@ -32,6 +32,7 @@ extern "C" {
|
||||||
#include "base/logging.h"
|
#include "base/logging.h"
|
||||||
#include "core/bloom.h"
|
#include "core/bloom.h"
|
||||||
#include "core/json/json_object.h"
|
#include "core/json/json_object.h"
|
||||||
|
#include "core/qlist.h"
|
||||||
#include "core/sorted_map.h"
|
#include "core/sorted_map.h"
|
||||||
#include "core/string_map.h"
|
#include "core/string_map.h"
|
||||||
#include "core/string_set.h"
|
#include "core/string_set.h"
|
||||||
|
@ -57,7 +58,7 @@ extern "C" {
|
||||||
ABSL_DECLARE_FLAG(int32_t, list_max_listpack_size);
|
ABSL_DECLARE_FLAG(int32_t, list_max_listpack_size);
|
||||||
ABSL_DECLARE_FLAG(int32_t, list_compress_depth);
|
ABSL_DECLARE_FLAG(int32_t, list_compress_depth);
|
||||||
ABSL_DECLARE_FLAG(uint32_t, dbnum);
|
ABSL_DECLARE_FLAG(uint32_t, dbnum);
|
||||||
|
ABSL_DECLARE_FLAG(bool, list_experimental_v2);
|
||||||
namespace dfly {
|
namespace dfly {
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
@ -709,20 +710,34 @@ void RdbLoaderBase::OpaqueObjLoader::CreateHMap(const LoadTrace* ltrace) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RdbLoaderBase::OpaqueObjLoader::CreateList(const LoadTrace* ltrace) {
|
void RdbLoaderBase::OpaqueObjLoader::CreateList(const LoadTrace* ltrace) {
|
||||||
quicklist* ql;
|
quicklist* ql = nullptr;
|
||||||
|
QList* qlv2 = nullptr;
|
||||||
if (config_.append) {
|
if (config_.append) {
|
||||||
if (!EnsureObjEncoding(OBJ_LIST, OBJ_ENCODING_QUICKLIST)) {
|
if (pv_->ObjType() != OBJ_LIST) {
|
||||||
|
ec_ = RdbError(errc::invalid_rdb_type);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (pv_->Encoding() == OBJ_ENCODING_QUICKLIST) {
|
||||||
ql = static_cast<quicklist*>(pv_->RObjPtr());
|
ql = static_cast<quicklist*>(pv_->RObjPtr());
|
||||||
|
} else {
|
||||||
|
DCHECK_EQ(pv_->Encoding(), kEncodingQL2);
|
||||||
|
qlv2 = static_cast<QList*>(pv_->RObjPtr());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (absl::GetFlag(FLAGS_list_experimental_v2)) {
|
||||||
|
qlv2 = CompactObj::AllocateMR<QList>(GetFlag(FLAGS_list_max_listpack_size),
|
||||||
|
GetFlag(FLAGS_list_compress_depth));
|
||||||
} else {
|
} else {
|
||||||
ql = quicklistNew(GetFlag(FLAGS_list_max_listpack_size), GetFlag(FLAGS_list_compress_depth));
|
ql = quicklistNew(GetFlag(FLAGS_list_max_listpack_size), GetFlag(FLAGS_list_compress_depth));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto cleanup = absl::Cleanup([&] {
|
auto cleanup = absl::Cleanup([&] {
|
||||||
if (!config_.append) {
|
if (!config_.append) {
|
||||||
|
if (ql)
|
||||||
quicklistRelease(ql);
|
quicklistRelease(ql);
|
||||||
|
else
|
||||||
|
CompactObj::DeleteMR<QList>(qlv2);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -737,7 +752,11 @@ void RdbLoaderBase::OpaqueObjLoader::CreateList(const LoadTrace* ltrace) {
|
||||||
if (container == QUICKLIST_NODE_CONTAINER_PLAIN) {
|
if (container == QUICKLIST_NODE_CONTAINER_PLAIN) {
|
||||||
lp = (uint8_t*)zmalloc(sv.size());
|
lp = (uint8_t*)zmalloc(sv.size());
|
||||||
::memcpy(lp, (uint8_t*)sv.data(), sv.size());
|
::memcpy(lp, (uint8_t*)sv.data(), sv.size());
|
||||||
|
if (ql)
|
||||||
quicklistAppendPlainNode(ql, lp, sv.size());
|
quicklistAppendPlainNode(ql, lp, sv.size());
|
||||||
|
else
|
||||||
|
qlv2->AppendPlain(lp, sv.size());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -774,13 +793,16 @@ void RdbLoaderBase::OpaqueObjLoader::CreateList(const LoadTrace* ltrace) {
|
||||||
lp = lpShrinkToFit(lp);
|
lp = lpShrinkToFit(lp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ql)
|
||||||
quicklistAppendListpack(ql, lp);
|
quicklistAppendListpack(ql, lp);
|
||||||
|
else
|
||||||
|
qlv2->AppendListpack(lp);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (ec_)
|
if (ec_)
|
||||||
return;
|
return;
|
||||||
if (quicklistCount(ql) == 0) {
|
if ((ql && quicklistCount(ql) == 0) || (qlv2 && qlv2->Size() == 0)) {
|
||||||
ec_ = RdbError(errc::empty_key);
|
ec_ = RdbError(errc::empty_key);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -788,7 +810,10 @@ void RdbLoaderBase::OpaqueObjLoader::CreateList(const LoadTrace* ltrace) {
|
||||||
std::move(cleanup).Cancel();
|
std::move(cleanup).Cancel();
|
||||||
|
|
||||||
if (!config_.append) {
|
if (!config_.append) {
|
||||||
|
if (ql)
|
||||||
pv_->InitRobj(OBJ_LIST, OBJ_ENCODING_QUICKLIST, ql);
|
pv_->InitRobj(OBJ_LIST, OBJ_ENCODING_QUICKLIST, ql);
|
||||||
|
else
|
||||||
|
pv_->InitRobj(OBJ_LIST, kEncodingQL2, qlv2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue