1
0
Fork 0
mirror of https://github.com/dragonflydb/dragonfly.git synced 2024-12-14 11:58:02 +00:00

switch back to dict implementation for set due to sscan command

This commit is contained in:
Roman Gershman 2022-03-22 20:53:54 +02:00
parent 5bce920308
commit c533ffb692
4 changed files with 76 additions and 54 deletions

View file

@ -20,7 +20,6 @@ extern "C" {
#include "base/logging.h" #include "base/logging.h"
#include "base/pod_array.h" #include "base/pod_array.h"
#include "core/flat_set.h"
#if defined(__aarch64__) #if defined(__aarch64__)
#include "base/sse2neon.h" #include "base/sse2neon.h"
@ -52,10 +51,7 @@ size_t DictMallocSize(dict* d) {
inline void FreeObjSet(unsigned encoding, void* ptr, pmr::memory_resource* mr) { inline void FreeObjSet(unsigned encoding, void* ptr, pmr::memory_resource* mr) {
switch (encoding) { switch (encoding) {
case kEncodingStrMap: { case kEncodingStrMap: {
pmr::polymorphic_allocator<FlatSet> pa(mr); dictRelease((dict*)ptr);
pa.destroy((FlatSet*)ptr);
pa.deallocate((FlatSet*)ptr, 1);
break; break;
} }
case kEncodingIntSet: case kEncodingIntSet:
@ -66,6 +62,24 @@ inline void FreeObjSet(unsigned encoding, void* ptr, pmr::memory_resource* mr) {
} }
} }
bool dictContains(const dict* d, string_view key) {
uint64_t h = dictGenHashFunction(key.data(), key.size());
for (unsigned table = 0; table <= 1; table++) {
uint64_t idx = h & DICTHT_SIZE_MASK(d->ht_size_exp[table]);
dictEntry* he = d->ht_table[table][idx];
while (he) {
sds dkey = (sds)he->key;
if (sdslen(dkey) == key.size() && (key.empty() || memcmp(dkey, key.data(), key.size()) == 0))
return true;
he = he->next;
}
if (!dictIsRehashing(d))
break;
}
return false;
}
bool IsMemberSet(unsigned encoding, std::string_view key, void* set) { bool IsMemberSet(unsigned encoding, std::string_view key, void* set) {
long long llval; long long llval;
@ -78,13 +92,14 @@ bool IsMemberSet(unsigned encoding, std::string_view key, void* set) {
return intsetFind(is, llval); return intsetFind(is, llval);
} }
case kEncodingStrMap: { case kEncodingStrMap: {
const FlatSet* fs = (FlatSet*)set; const dict* ds = (dict*)set;
return fs->Contains(key); return dictContains(ds, key);
} }
default: default:
LOG(FATAL) << "Unexpected encoding " << encoding; LOG(FATAL) << "Unexpected encoding " << encoding;
} }
} }
size_t MallocUsedSet(unsigned encoding, void* ptr) { size_t MallocUsedSet(unsigned encoding, void* ptr) {
switch (encoding) { switch (encoding) {
case kEncodingStrMap /*OBJ_ENCODING_HT*/: case kEncodingStrMap /*OBJ_ENCODING_HT*/:
@ -116,8 +131,7 @@ size_t MallocUsedZSet(unsigned encoding, void* ptr) {
case OBJ_ENCODING_SKIPLIST: { case OBJ_ENCODING_SKIPLIST: {
zset* zs = (zset*)ptr; zset* zs = (zset*)ptr;
return DictMallocSize(zs->dict); return DictMallocSize(zs->dict);
} } break;
break;
default: default:
LOG(FATAL) << "Unknown set encoding type " << encoding; LOG(FATAL) << "Unknown set encoding type " << encoding;
} }
@ -269,8 +283,8 @@ size_t RobjWrapper::Size() const {
return intsetLen(is); return intsetLen(is);
} }
case kEncodingStrMap: { case kEncodingStrMap: {
const FlatSet* fs = (FlatSet*)inner_obj_; dict* d = (dict*)inner_obj_;
return fs->Size(); return dictSize(d);
} }
default: default:
LOG(FATAL) << "Unexpected encoding " << encoding_; LOG(FATAL) << "Unexpected encoding " << encoding_;
@ -997,4 +1011,8 @@ size_t CompactObj::DecodedLen(size_t sz) const {
return ascii_len(sz) - ((mask_ & ASCII1_ENC_BIT) ? 1 : 0); return ascii_len(sz) - ((mask_ & ASCII1_ENC_BIT) ? 1 : 0);
} }
pmr::memory_resource* CompactObj::memory_resource() {
return tl.local_mr;
}
} // namespace dfly } // namespace dfly

View file

@ -257,6 +257,7 @@ class CompactObj {
static Stats GetStats(); static Stats GetStats();
static void InitThreadLocal(std::pmr::memory_resource* mr); static void InitThreadLocal(std::pmr::memory_resource* mr);
static std::pmr::memory_resource* memory_resource(); // thread-local.
private: private:
size_t DecodedLen(size_t sz) const; size_t DecodedLen(size_t sz) const;

View file

@ -12,7 +12,6 @@ extern "C" {
} }
#include "base/logging.h" #include "base/logging.h"
#include "core/flat_set.h"
#include "server/command_registry.h" #include "server/command_registry.h"
#include "server/conn_context.h" #include "server/conn_context.h"
#include "server/engine_shard_set.h" #include "server/engine_shard_set.h"
@ -29,14 +28,7 @@ using SvArray = vector<std::string_view>;
namespace { namespace {
FlatSet* CreateFlatSet(pmr::memory_resource* mr) { void ConvertTo(intset* src, dict* dest) {
pmr::polymorphic_allocator<FlatSet> pa(mr);
FlatSet* fs = pa.allocate(1);
pa.construct(fs, mr);
return fs;
}
void ConvertTo(intset* src, FlatSet* dest) {
int64_t intele; int64_t intele;
char buf[32]; char buf[32];
@ -44,7 +36,8 @@ void ConvertTo(intset* src, FlatSet* dest) {
int ii = 0; int ii = 0;
while (intsetGet(src, ii++, &intele)) { while (intsetGet(src, ii++, &intele)) {
char* next = absl::numbers_internal::FastIntToBuffer(intele, buf); char* next = absl::numbers_internal::FastIntToBuffer(intele, buf);
dest->Add(string_view{buf, size_t(next - buf)}); sds s = sdsnewlen(buf, next - buf);
CHECK(dictAddRaw(dest, s, NULL));
} }
} }
@ -94,12 +87,14 @@ pair<unsigned, bool> RemoveSet(ArgSlice vals, CompactObj* set) {
isempty = (intsetLen(is) == 0); isempty = (intsetLen(is) == 0);
set->SetRObjPtr(is); set->SetRObjPtr(is);
} else { } else {
FlatSet* fs = (FlatSet*)set->RObjPtr(); dict* d = (dict*)set->RObjPtr();
for (auto val : vals) { auto* shard = EngineShard::tlocal();
removed += fs->Remove(val); for (auto member : vals) {
shard->tmp_str1 = sdscpylen(shard->tmp_str1, member.data(), member.size());
int result = dictDelete(d, shard->tmp_str1);
removed += (result == DICT_OK);
} }
isempty = fs->Empty(); isempty = (dictSize(d) == 0);
set->SetRObjPtr(fs);
} }
return make_pair(removed, isempty); return make_pair(removed, isempty);
} }
@ -116,12 +111,15 @@ template <typename F> void FillSet(const CompactObj& set, F&& f) {
f(string{buf, size_t(next - buf)}); f(string{buf, size_t(next - buf)});
} }
} else { } else {
FlatSet* fs = (FlatSet*)set.RObjPtr(); dict* ds = (dict*)set.RObjPtr();
string str; string str;
for (const auto& member : *fs) { dictIterator* di = dictGetIterator(ds);
member.GetString(&str); dictEntry* de = nullptr;
while ((de = dictNext(di))) {
str.assign((sds)de->key, sdslen((sds)de->key));
f(move(str)); f(move(str));
} }
dictReleaseIterator(di);
} }
} }
@ -269,8 +267,8 @@ OpResult<uint32_t> OpAdd(const OpArgs& op_args, std::string_view key, const ArgS
intset* is = intsetNew(); intset* is = intsetNew();
co.InitRobj(OBJ_SET, kEncodingIntSet, is); co.InitRobj(OBJ_SET, kEncodingIntSet, is);
} else { } else {
FlatSet* fs = CreateFlatSet(op_args.shard->memory_resource()); dict* ds = dictCreate(&setDictType);
co.InitRobj(OBJ_SET, kEncodingStrMap, fs); co.InitRobj(OBJ_SET, kEncodingStrMap, ds);
} }
} else { } else {
// We delibirately check only now because with othewrite=true // We delibirately check only now because with othewrite=true
@ -292,11 +290,11 @@ OpResult<uint32_t> OpAdd(const OpArgs& op_args, std::string_view key, const ArgS
res += added; res += added;
if (!success) { if (!success) {
FlatSet* fs = CreateFlatSet(op_args.shard->memory_resource()); dict* ds = dictCreate(&setDictType);
ConvertTo(is, fs); ConvertTo(is, ds);
co.SetRObjPtr(is); co.SetRObjPtr(is);
co.InitRobj(OBJ_SET, kEncodingStrMap, fs); co.InitRobj(OBJ_SET, kEncodingStrMap, ds);
inner_obj = fs; inner_obj = ds;
break; break;
} }
} }
@ -306,9 +304,15 @@ OpResult<uint32_t> OpAdd(const OpArgs& op_args, std::string_view key, const ArgS
} }
if (co.Encoding() == kEncodingStrMap) { if (co.Encoding() == kEncodingStrMap) {
FlatSet* fs = (FlatSet*)inner_obj; dict* ds = (dict*)inner_obj;
for (auto val : vals) {
res += fs->Add(val); for (auto member : vals) {
es->tmp_str1 = sdscpylen(es->tmp_str1, member.data(), member.size());
dictEntry* de = dictAddRaw(ds, es->tmp_str1, NULL);
if (de) {
de->key = sdsdup(es->tmp_str1);
++res;
}
} }
} }
@ -362,7 +366,7 @@ OpStatus Mover::OpFind(Transaction* t, EngineShard* es) {
ArgSlice largs = t->ShardArgsInShard(es->shard_id()); ArgSlice largs = t->ShardArgsInShard(es->shard_id());
// In case both src and dest are in the same shard, largs size will be 2. // In case both src and dest are in the same shard, largs size will be 2.
DCHECK_LT(largs.size(), 2u); DCHECK_LE(largs.size(), 2u);
for (auto k : largs) { for (auto k : largs) {
unsigned index = (k == src_) ? 0 : 1; unsigned index = (k == src_) ? 0 : 1;
@ -380,7 +384,7 @@ OpStatus Mover::OpFind(Transaction* t, EngineShard* es) {
OpStatus Mover::OpMutate(Transaction* t, EngineShard* es) { OpStatus Mover::OpMutate(Transaction* t, EngineShard* es) {
ArgSlice largs = t->ShardArgsInShard(es->shard_id()); ArgSlice largs = t->ShardArgsInShard(es->shard_id());
DCHECK_LT(largs.size(), 2u); DCHECK_LE(largs.size(), 2u);
OpArgs op_args{es, t->db_index()}; OpArgs op_args{es, t->db_index()};
for (auto k : largs) { for (auto k : largs) {
@ -899,9 +903,7 @@ OpResult<StringVec> SetFamily::OpPop(const OpArgs& op_args, std::string_view key
* The number of requested elements is greater than or equal to * The number of requested elements is greater than or equal to
* the number of elements inside the set: simply return the whole set. */ * the number of elements inside the set: simply return the whole set. */
if (count >= slen) { if (count >= slen) {
FillSet(it->second, [&result](string s) { FillSet(it->second, [&result](string s) { result.push_back(move(s)); });
result.push_back(move(s));
});
/* Delete the set as it is now empty */ /* Delete the set as it is now empty */
CHECK(es->db_slice().Del(op_args.db_ind, it)); CHECK(es->db_slice().Del(op_args.db_ind, it));
} else { } else {
@ -918,17 +920,16 @@ OpResult<StringVec> SetFamily::OpPop(const OpArgs& op_args, std::string_view key
is = intsetTrimTail(is, count); // now remove last count items is = intsetTrimTail(is, count); // now remove last count items
it->second.SetRObjPtr(is); it->second.SetRObjPtr(is);
} else { } else {
FlatSet* fs = (FlatSet*)it->second.RObjPtr(); dict* ds = (dict*)it->second.RObjPtr();
string str; string str;
dictIterator* di = dictGetSafeIterator(ds);
for (uint32_t i = 0; i < count; ++i) { for (uint32_t i = 0; i < count; ++i) {
auto it = fs->begin(); dictEntry* de = dictNext(di);
it->GetString(&str); DCHECK(de);
fs->Erase(it); result.emplace_back((sds)de->key, sdslen((sds)de->key));
result.push_back(move(str)); dictDelete(ds, de->key);
} }
dictReleaseIterator(di);
it->second.SetRObjPtr(fs);
} }
} }
return result; return result;
@ -947,9 +948,7 @@ OpResult<StringVec> SetFamily::OpInter(const Transaction* t, EngineShard* es, bo
if (!find_res) if (!find_res)
return find_res.status(); return find_res.status();
FillSet(find_res.value()->second, [&result](string s) { FillSet(find_res.value()->second, [&result](string s) { result.push_back(move(s)); });
result.push_back(move(s));
});
return result; return result;
} }

View file

@ -82,6 +82,10 @@ TEST_F(SetFamilyTest, SMove) {
Run({"sadd", "b", "3", "5", "6", "2"}); Run({"sadd", "b", "3", "5", "6", "2"});
resp = Run({"smove", "a", "b", "1"}); resp = Run({"smove", "a", "b", "1"});
EXPECT_THAT(resp[0], IntArg(1)); EXPECT_THAT(resp[0], IntArg(1));
Run({"sadd", "x", "a", "b", "c"});
Run({"sadd", "y", "c"});
EXPECT_THAT(Run({"smove", "x", "y", "c"}), ElementsAre(IntArg(1)));
} }
TEST_F(SetFamilyTest, SPop) { TEST_F(SetFamilyTest, SPop) {