Skip to content

Commit cc16036

Browse files
dranikpgkostasrim
authored andcommitted
fix: fix defrag stats (#1740)
* fix: fix defrag stats Signed-off-by: Vladislav <[email protected]>
1 parent 2ff8c71 commit cc16036

File tree

5 files changed

+36
-20
lines changed

5 files changed

+36
-20
lines changed

src/core/compact_object.cc

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -141,31 +141,34 @@ inline void FreeObjZset(unsigned encoding, void* ptr) {
141141
}
142142
}
143143

144-
// Iterates over allocations of internal hash data structed and re-allocates
144+
// Iterates over allocations of internal hash data structures and re-allocates
145145
// them if their pages are underutilized.
146-
void* DefragHash(MemoryResource* mr, unsigned encoding, void* ptr, float ratio) {
146+
// Returns pointer to new object ptr and whether any re-allocations happened.
147+
pair<void*, bool> DefragHash(MemoryResource* mr, unsigned encoding, void* ptr, float ratio) {
147148
switch (encoding) {
148149
// Listpack is stored as a single contiguous array
149150
case kEncodingListPack: {
150151
uint8_t* lp = (uint8_t*)ptr;
151152
if (!zmalloc_page_is_underutilized(lp, ratio))
152-
return lp;
153+
return {lp, false};
153154

154155
size_t lp_bytes = lpBytes(lp);
155156
uint8_t* replacement = lpNew(lpBytes(lp));
156157
memcpy(replacement, lp, lp_bytes);
157158
lpFree(lp);
158159

159-
return replacement;
160+
return {replacement, true};
160161
};
161162

162163
// StringMap supports re-allocation of it's internal nodes
163164
case kEncodingStrMap2: {
165+
bool realloced = false;
166+
164167
StringMap* sm = (StringMap*)ptr;
165168
for (auto it = sm->begin(); it != sm->end(); ++it)
166-
it.ReallocIfNeeded(ratio);
169+
realloced |= it.ReallocIfNeeded(ratio);
167170

168-
return sm;
171+
return {sm, realloced};
169172
}
170173

171174
default:
@@ -394,10 +397,13 @@ void RobjWrapper::SetString(string_view s, MemoryResource* mr) {
394397
bool RobjWrapper::DefragIfNeeded(float ratio) {
395398
if (type() == OBJ_STRING) {
396399
if (zmalloc_page_is_underutilized(inner_obj(), ratio)) {
397-
return Reallocate(tl.local_mr);
400+
ReallocateString(tl.local_mr);
401+
return true;
398402
}
399403
} else if (type() == OBJ_HASH) {
400-
inner_obj_ = DefragHash(tl.local_mr, encoding_, inner_obj_, ratio);
404+
auto [new_ptr, realloced] = DefragHash(tl.local_mr, encoding_, inner_obj_, ratio);
405+
inner_obj_ = new_ptr;
406+
return realloced;
401407
}
402408
return false;
403409
}
@@ -487,12 +493,12 @@ int RobjWrapper::ZsetAdd(double score, sds ele, int in_flags, int* out_flags, do
487493
return ss->Add(score, ele, in_flags, out_flags, newscore);
488494
}
489495

490-
bool RobjWrapper::Reallocate(MemoryResource* mr) {
496+
void RobjWrapper::ReallocateString(MemoryResource* mr) {
497+
DCHECK_EQ(type(), OBJ_STRING);
491498
void* old_ptr = inner_obj_;
492499
inner_obj_ = mr->allocate(sz_, kAlignSize);
493500
memcpy(inner_obj_, old_ptr, sz_);
494501
mr->deallocate(old_ptr, 0, kAlignSize);
495-
return true;
496502
}
497503

498504
void RobjWrapper::Init(unsigned type, unsigned encoding, void* inner) {

src/core/compact_object.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,16 @@ class RobjWrapper {
5959
return std::string_view{reinterpret_cast<char*>(inner_obj_), sz_};
6060
}
6161

62+
// Try reducing memory fragmentation by re-allocating values from underutilized pages.
63+
// Returns true if re-allocated.
6264
bool DefragIfNeeded(float ratio);
6365

6466
// as defined in zset.h
6567
int ZsetAdd(double score, char* ele, int in_flags, int* out_flags, double* newscore);
6668

6769
private:
68-
bool Reallocate(MemoryResource* mr);
70+
void ReallocateString(MemoryResource* mr);
71+
6972
size_t InnerObjMallocUsed() const;
7073
void MakeInnerRoom(size_t current_cap, size_t desired, MemoryResource* mr);
7174

src/core/compact_object_test.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -634,11 +634,11 @@ TEST_F(CompactObjectTest, DefragHash) {
634634

635635
// Trigger re-allocation
636636
cobj_.InitRobj(OBJ_HASH, kEncodingListPack, target_lp);
637-
cobj_.DefragIfNeeded(0.8);
637+
ASSERT_TRUE(cobj_.DefragIfNeeded(0.8));
638638

639639
// Check the pointer changes as the listpack needed defragmentation
640640
auto lp = (uint8_t*)cobj_.RObjPtr();
641-
CHECK_NE(lp, target_lp);
641+
EXPECT_NE(lp, target_lp) << "must have changed due to realloc";
642642

643643
uint8_t* fptr = lpFirst(lp);
644644
for (size_t i = 0; i < 100; i++) {

src/core/string_map.cc

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,16 @@ sds StringMap::Find(std::string_view key) {
101101
return GetValue(str);
102102
}
103103

104-
sds StringMap::ReallocIfNeeded(void* obj, float ratio) {
104+
pair<sds, bool> StringMap::ReallocIfNeeded(void* obj, float ratio) {
105105
sds key = (sds)obj;
106106
size_t key_len = sdslen(key);
107107

108108
auto* value_ptr = key + key_len + 1;
109109
uint64_t value_tag = absl::little_endian::Load64(value_ptr);
110110
sds value = (sds)(uint64_t(value_tag) & kValMask);
111111

112+
bool realloced_value = false;
113+
112114
// If the allocated value is underutilized, re-allocate it and update the pointer inside the key
113115
if (zmalloc_page_is_underutilized(value, ratio)) {
114116
size_t value_len = sdslen(value);
@@ -117,18 +119,19 @@ sds StringMap::ReallocIfNeeded(void* obj, float ratio) {
117119
uint64_t new_value_tag = (uint64_t(new_value) & kValMask) | (value_tag & ~kValMask);
118120
absl::little_endian::Store64(value_ptr, new_value_tag);
119121
sdsfree(value);
122+
realloced_value = true;
120123
}
121124

122125
if (!zmalloc_page_is_underutilized(key, ratio))
123-
return key;
126+
return {key, realloced_value};
124127

125128
size_t space_size = 8 /* value ptr */ + ((value_tag & kValTtlBit) ? 4 : 0) /* optional expiry */;
126129

127130
sds new_key = AllocSdsWithSpace(key_len, space_size);
128131
memcpy(new_key, key, key_len + 1 /* \0 */ + space_size);
129132
sdsfree(key);
130133

131-
return new_key;
134+
return {new_key, true};
132135
}
133136

134137
uint64_t StringMap::Hash(const void* obj, uint32_t cookie) const {

src/core/string_map.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,18 @@ class StringMap : public DenseSet {
6262
return BreakToPair(ptr);
6363
}
6464

65-
void ReallocIfNeeded(float ratio) {
65+
// Try reducing memory fragmentation of the value by re-allocating. Returns true if
66+
// re-allocation happened.
67+
bool ReallocIfNeeded(float ratio) {
6668
// Unwrap all links to correctly call SetObject()
6769
auto* ptr = curr_entry_;
6870
while (ptr->IsLink())
6971
ptr = ptr->AsLink();
7072

7173
auto* obj = ptr->GetObject();
72-
ptr->SetObject(static_cast<StringMap*>(owner_)->ReallocIfNeeded(obj, ratio));
74+
auto [new_obj, realloced] = static_cast<StringMap*>(owner_)->ReallocIfNeeded(obj, ratio);
75+
ptr->SetObject(new_obj);
76+
return realloced;
7377
}
7478

7579
iterator& operator++() {
@@ -115,8 +119,8 @@ class StringMap : public DenseSet {
115119

116120
private:
117121
// Reallocate key and/or value if their pages are underutilized.
118-
// Returns new object pointer (stays the same if utilization is enough).
119-
sds ReallocIfNeeded(void* obj, float ratio);
122+
// Returns new pointer (stays same if key utilization is enough) and if reallocation happened.
123+
std::pair<sds, bool> ReallocIfNeeded(void* obj, float ratio);
120124

121125
uint64_t Hash(const void* obj, uint32_t cookie) const final;
122126
bool ObjEqual(const void* left, const void* right, uint32_t right_cookie) const final;

0 commit comments

Comments
 (0)