Skip to content

Commit

Permalink
chore: add QList class (#4078)
Browse files Browse the repository at this point in the history
This class will consolidate list functionality across multiple layers, and eventually replace the original quicklist code.
Right now we added the skeleton files and defined most of the interface.
The implementation is not done yet.

Signed-off-by: Roman Gershman <[email protected]>
  • Loading branch information
romange authored Nov 7, 2024
1 parent c19af2b commit c756832
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 5 deletions.
9 changes: 5 additions & 4 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ add_subdirectory(json)

set(SEARCH_LIB query_parser)

add_library(dfly_core bloom.cc compact_object.cc dragonfly_core.cc extent_tree.cc
interpreter.cc mi_memory_resource.cc sds_utils.cc
add_library(dfly_core allocation_tracker.cc bloom.cc compact_object.cc dense_set.cc
dragonfly_core.cc extent_tree.cc
interpreter.cc mi_memory_resource.cc qlist.cc sds_utils.cc
segment_allocator.cc score_map.cc small_string.cc sorted_map.cc task_queue.cc
tx_queue.cc dense_set.cc allocation_tracker.cc
string_set.cc string_map.cc detail/bitpacking.cc)
tx_queue.cc string_set.cc string_map.cc detail/bitpacking.cc)

cxx_link(dfly_core base absl::flat_hash_map absl::str_format redis_lib TRDP::lua lua_modules
fibers2 ${SEARCH_LIB} jsonpath OpenSSL::Crypto TRDP::dconv)
Expand All @@ -29,3 +29,4 @@ cxx_test(score_map_test dfly_core LABELS DFLY)
cxx_test(flatbuffers_test dfly_core TRDP::flatbuffers LABELS DFLY)
cxx_test(bloom_test dfly_core LABELS DFLY)
cxx_test(allocation_tracker_test dfly_core absl::random_random LABELS DFLY)
cxx_test(qlist_test dfly_core LABELS DFLY)
99 changes: 99 additions & 0 deletions src/core/qlist.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright 2024, DragonflyDB authors. All rights reserved.
// See LICENSE for licensing terms.
//

#include "core/qlist.h"

extern "C" {
#include "redis/zmalloc.h"
}

#include "base/logging.h"

using namespace std;

namespace dfly {

QList::QList() : fill_(-2), compress_(0), bookmark_count_(0) {
}

QList::QList(int fill, int compress) : fill_(fill), compress_(compress), bookmark_count_(0) {
}

QList::~QList() {
unsigned long len;
quicklistNode *current, *next;

current = head_;
len = len_;
while (len--) {
next = current->next;

zfree(current->entry);
count_ -= current->count;

zfree(current);

len_--;
current = next;
}
}

void QList::Push(string_view value, Where where) {
/* The head and tail should never be compressed (we don't attempt to decompress them) */
if (head_)
DCHECK(head_->encoding != QUICKLIST_NODE_ENCODING_LZF);
if (tail_)
DCHECK(tail_->encoding != QUICKLIST_NODE_ENCODING_LZF);

if (where == HEAD) {
PushHead(value);
} else {
DCHECK_EQ(TAIL, where);
PushTail(value);
}
}

void QList::AppendListpack(unsigned char* zl) {
}

void QList::AppendPlain(unsigned char* zl) {
}

void QList::Insert(std::string_view pivot, std::string_view elem, InsertOpt opt) {
}

size_t QList::MallocUsed() const {
// Approximation since does not account for listpacks.
size_t res = len_ * sizeof(quicklistNode) + znallocx(sizeof(quicklist));
return res + count_ * 16; // we account for each member 16 bytes.
}

string QList::Peek(Where where) const {
return {};
}

optional<string> QList::Get(long index) const {
return nullopt;
}

void QList::Iterate(IterateFunc cb, long start, long end) const {
}

bool QList::PushHead(string_view value) {
return false;
}

// Returns false if used existing head, true if new head created.
bool QList::PushTail(string_view value) {
return false;
}

void InsertPlainNode(quicklistNode* old_node, string_view, bool after) {
}

void InsertNode(quicklist* quicklist, quicklistNode* old_node, quicklistNode* new_node,
bool after) {
}

} // namespace dfly
76 changes: 76 additions & 0 deletions src/core/qlist.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright 2024, DragonflyDB authors. All rights reserved.
// See LICENSE for licensing terms.
//

#pragma once

extern "C" {
#include "redis/quicklist.h"
}

#include <functional>
#include <optional>
#include <string>

namespace dfly {

class QList {
public:
enum Where { TAIL, HEAD };

struct Entry {
Entry(const char* value, size_t length) : value{value}, length{length} {
}
Entry(long long longval) : value{nullptr}, longval{longval} {
}

const char* value;
union {
size_t length;
long long longval;
};
};

using IterateFunc = std::function<bool(Entry)>;
enum InsertOpt { BEFORE, AFTER };

QList();
QList(int fill, int compress);
~QList();

size_t Size() const {
return count_;
}

void Push(std::string_view value, Where where);
void AppendListpack(unsigned char* zl);
void AppendPlain(unsigned char* zl);
void Insert(std::string_view pivot, std::string_view elem, InsertOpt opt);

size_t MallocUsed() const;

std::string Peek(Where where) const;
std::optional<std::string> Get(long index) const;

void Iterate(IterateFunc cb, long start, long end) const;

private:
// Returns false if used existing head, true if new head created.
bool PushHead(std::string_view value);

// Returns false if used existing head, true if new head created.
bool PushTail(std::string_view value);
void InsertPlainNode(quicklistNode* old_node, std::string_view, bool after);
void InsertNode(quicklist* quicklist, quicklistNode* old_node, quicklistNode* new_node,
bool after);

quicklistNode* head_ = nullptr;
quicklistNode* tail_ = nullptr;
uint32_t count_ = 0; /* total count of all entries in all listpacks */
uint32_t len_ = 0; /* number of quicklistNodes */
signed int fill_ : QL_FILL_BITS; /* fill factor for individual nodes */
unsigned int compress_ : QL_COMP_BITS; /* depth of end nodes not to compress;0=off */
unsigned int bookmark_count_ : QL_BM_BITS;
};

} // namespace dfly
35 changes: 35 additions & 0 deletions src/core/qlist_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2024, DragonflyDB authors. All rights reserved.
// See LICENSE for licensing terms.
//

#include "core/qlist.h"

#include "base/gtest.h"
#include "core/mi_memory_resource.h"

extern "C" {
#include "redis/zmalloc.h"
}

namespace dfly {

class QListTest : public ::testing::Test {
protected:
QListTest() : mr_(mi_heap_get_backing()) {
}

static void SetUpTestSuite() {
// configure redis lib zmalloc which requires mimalloc heap to work.
auto* tlh = mi_heap_get_backing();
init_zmalloc_threadlocal(tlh);
}

MiMemoryResource mr_;
QList ql_;
};

TEST_F(QListTest, Basic) {
EXPECT_EQ(0, ql_.Size());
}

}; // namespace dfly
2 changes: 1 addition & 1 deletion src/core/sorted_map_test.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2023, Roman Gershman. All rights reserved.
// Copyright 2024, DragonflyDB authors. All rights reserved.
// See LICENSE for licensing terms.
//

Expand Down
1 change: 1 addition & 0 deletions src/redis/quicklist.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
*/

#include <stdint.h> // for UINTPTR_MAX
#include <stddef.h>

#ifndef __QUICKLIST_H__
#define __QUICKLIST_H__
Expand Down

0 comments on commit c756832

Please sign in to comment.