mirror of
https://github.com/dragonflydb/dragonfly.git
synced 2024-12-15 17:51:06 +00:00
chore: add defrag logic for sets (#3833)
* add defrag logic for sets * add small test --------- Signed-off-by: kostas <kostas@dragonflydb.io>
This commit is contained in:
parent
beb2ec2b29
commit
a3abf41f4e
2 changed files with 89 additions and 21 deletions
|
@ -138,39 +138,74 @@ inline void FreeObjZset(unsigned encoding, void* ptr) {
|
|||
}
|
||||
}
|
||||
|
||||
pair<void*, bool> DefragStrMap2(StringMap* sm, float ratio) {
|
||||
bool realloced = false;
|
||||
|
||||
for (auto it = sm->begin(); it != sm->end(); ++it)
|
||||
realloced |= it.ReallocIfNeeded(ratio);
|
||||
|
||||
return {sm, realloced};
|
||||
}
|
||||
|
||||
pair<void*, bool> DefragListPack(uint8_t* lp, float ratio) {
|
||||
if (!zmalloc_page_is_underutilized(lp, ratio))
|
||||
return {lp, false};
|
||||
|
||||
size_t lp_bytes = lpBytes(lp);
|
||||
uint8_t* replacement = lpNew(lpBytes(lp));
|
||||
memcpy(replacement, lp, lp_bytes);
|
||||
lpFree(lp);
|
||||
|
||||
return {replacement, true};
|
||||
}
|
||||
|
||||
pair<void*, bool> DefragIntSet(intset* is, float ratio) {
|
||||
if (!zmalloc_page_is_underutilized(is, ratio))
|
||||
return {is, false};
|
||||
|
||||
const size_t blob_len = intsetBlobLen(is);
|
||||
intset* replacement = (intset*)zmalloc(blob_len);
|
||||
memcpy(replacement, is, blob_len);
|
||||
|
||||
zfree(is);
|
||||
return {replacement, true};
|
||||
}
|
||||
|
||||
// Iterates over allocations of internal hash data structures and re-allocates
|
||||
// them if their pages are underutilized.
|
||||
// Returns pointer to new object ptr and whether any re-allocations happened.
|
||||
pair<void*, bool> DefragHash(MemoryResource* mr, unsigned encoding, void* ptr, float ratio) {
|
||||
pair<void*, bool> DefragHash(unsigned encoding, void* ptr, float ratio) {
|
||||
switch (encoding) {
|
||||
// Listpack is stored as a single contiguous array
|
||||
case kEncodingListPack: {
|
||||
uint8_t* lp = (uint8_t*)ptr;
|
||||
if (!zmalloc_page_is_underutilized(lp, ratio))
|
||||
return {lp, false};
|
||||
|
||||
size_t lp_bytes = lpBytes(lp);
|
||||
uint8_t* replacement = lpNew(lpBytes(lp));
|
||||
memcpy(replacement, lp, lp_bytes);
|
||||
lpFree(lp);
|
||||
|
||||
return {replacement, true};
|
||||
};
|
||||
return DefragListPack((uint8_t*)ptr, ratio);
|
||||
}
|
||||
|
||||
// StringMap supports re-allocation of it's internal nodes
|
||||
case kEncodingStrMap2: {
|
||||
bool realloced = false;
|
||||
|
||||
StringMap* sm = (StringMap*)ptr;
|
||||
for (auto it = sm->begin(); it != sm->end(); ++it)
|
||||
realloced |= it.ReallocIfNeeded(ratio);
|
||||
|
||||
return {sm, realloced};
|
||||
return DefragStrMap2((StringMap*)ptr, ratio);
|
||||
}
|
||||
|
||||
default:
|
||||
ABSL_UNREACHABLE();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pair<void*, bool> DefragSet(unsigned encoding, void* ptr, float ratio) {
|
||||
switch (encoding) {
|
||||
// Int sets have flat storage
|
||||
case kEncodingIntSet: {
|
||||
return DefragIntSet((intset*)ptr, ratio);
|
||||
}
|
||||
|
||||
// StringMap supports re-allocation of it's internal nodes
|
||||
case kEncodingStrMap2: {
|
||||
return DefragStrMap2((StringMap*)ptr, ratio);
|
||||
}
|
||||
|
||||
default:
|
||||
ABSL_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
inline void FreeObjStream(void* ptr) {
|
||||
|
@ -391,7 +426,11 @@ bool RobjWrapper::DefragIfNeeded(float ratio) {
|
|||
return true;
|
||||
}
|
||||
} else if (type() == OBJ_HASH) {
|
||||
auto [new_ptr, realloced] = DefragHash(tl.local_mr, encoding_, inner_obj_, ratio);
|
||||
auto [new_ptr, realloced] = DefragHash(encoding_, inner_obj_, ratio);
|
||||
inner_obj_ = new_ptr;
|
||||
return realloced;
|
||||
} else if (type() == OBJ_SET) {
|
||||
auto [new_ptr, realloced] = DefragSet(encoding_, inner_obj_, ratio);
|
||||
inner_obj_ = new_ptr;
|
||||
return realloced;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
#include "facade/facade_test.h"
|
||||
#include "server/command_registry.h"
|
||||
#include "server/test_utils.h"
|
||||
extern "C" {
|
||||
#include "redis/intset.h"
|
||||
#include "redis/zmalloc.h"
|
||||
}
|
||||
|
||||
using namespace testing;
|
||||
using namespace std;
|
||||
|
@ -349,4 +353,29 @@ TEST_F(SetFamilyTest, SScan) {
|
|||
EXPECT_THAT(vec.size(), 0);
|
||||
}
|
||||
|
||||
TEST_F(SetFamilyTest, IntSetMemcpy) {
|
||||
// This logic is used in CompactObject::DefragIntSet
|
||||
intset* original = intsetNew();
|
||||
uint8_t success = 0;
|
||||
for (int i = 0; i < 250; ++i) {
|
||||
original = intsetAdd(original, i, &success);
|
||||
ASSERT_THAT(success, 1);
|
||||
}
|
||||
const size_t blob_len = intsetBlobLen(original);
|
||||
intset* replacement = (intset*)zmalloc(blob_len);
|
||||
memcpy(replacement, original, blob_len);
|
||||
|
||||
ASSERT_THAT(original->encoding, replacement->encoding);
|
||||
ASSERT_THAT(original->length, replacement->length);
|
||||
|
||||
for (int i = 0; i < 250; ++i) {
|
||||
int64_t value;
|
||||
ASSERT_THAT(intsetGet(replacement, i, &value), 1);
|
||||
ASSERT_THAT(value, i);
|
||||
}
|
||||
|
||||
zfree(original);
|
||||
zfree(replacement);
|
||||
}
|
||||
|
||||
} // namespace dfly
|
||||
|
|
Loading…
Reference in a new issue