Skip to content

Commit d13ab7b

Browse files
committed
fix: proper memory accounting for objects loaded via streaming
The bug: during the loading when appending to the existing object, ItAndUpdater scope did not account for the appended data, and as a result `object_used_memory` and its variation did not account for streamed objects. The fix: to extend the scope of the ItAndUpdater object to cover appends. Added a sanity DCHECK that ensures that object_used_memory is at least as the memory used by a single object. This dcheck fails pre-fix. Fixes #4773 Signed-off-by: Roman Gershman <[email protected]>
1 parent 8acf849 commit d13ab7b

File tree

2 files changed

+13
-4
lines changed

2 files changed

+13
-4
lines changed

src/server/db_slice.cc

+5
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ static_assert(kExpireSegmentSize == 23528);
6262

6363
void AccountObjectMemory(string_view key, unsigned type, int64_t size, DbTable* db) {
6464
DCHECK_NE(db, nullptr);
65+
if (size == 0)
66+
return;
67+
6568
DbTableStats& stats = db->stats;
6669
DCHECK_GE(static_cast<int64_t>(stats.obj_memory_usage) + size, 0)
6770
<< "Can't decrease " << size << " from " << stats.obj_memory_usage;
@@ -500,6 +503,8 @@ OpResult<DbSlice::ItAndUpdater> DbSlice::FindMutableInternal(const Context& cntx
500503
PreUpdateBlocking(cntx.db_index, it, key);
501504
// PreUpdate() might have caused a deletion of `it`
502505
if (res->it.IsOccupied()) {
506+
DCHECK_GE(db_arr_[cntx.db_index]->stats.obj_memory_usage, res->it->second.MallocUsed());
507+
503508
return {{it, exp_it,
504509
AutoUpdater({.action = AutoUpdater::DestructorAction::kRun,
505510
.db_slice = this,

src/server/rdb_load.cc

+8-4
Original file line numberDiff line numberDiff line change
@@ -2544,11 +2544,15 @@ void RdbLoader::CreateObjectOnShard(const DbContext& db_cntx, const Item* item,
25442544
item->val.rdb_type);
25452545
};
25462546

2547+
// The scope is important here, as we need to ensure that the object memory is properly
2548+
// accounted for.
2549+
DbSlice::ItAndUpdater append_res;
2550+
25472551
// If we're appending the item to an existing key, first load the
25482552
// object.
25492553
if (item->load_config.append) {
2550-
auto res = db_slice->FindMutable(db_cntx, item->key);
2551-
if (!IsValid(res.it)) {
2554+
append_res = db_slice->FindMutable(db_cntx, item->key);
2555+
if (!IsValid(append_res.it)) {
25522556
// If the item has expired we may not find the key. Note if the key
25532557
// is found, but expired since we started loading, we still append to
25542558
// avoid an inconsistent state where only part of the key is loaded.
@@ -2557,7 +2561,7 @@ void RdbLoader::CreateObjectOnShard(const DbContext& db_cntx, const Item* item,
25572561
}
25582562
return;
25592563
}
2560-
pv_ptr = &res.it->second;
2564+
pv_ptr = &append_res.it->second;
25612565
}
25622566

25632567
if (ec_ = FromOpaque(item->val, item->load_config, pv_ptr); ec_) {
@@ -2598,7 +2602,7 @@ void RdbLoader::CreateObjectOnShard(const DbContext& db_cntx, const Item* item,
25982602
return;
25992603
}
26002604

2601-
auto& res = *op_res;
2605+
DbSlice::ItAndUpdater& res = *op_res;
26022606
res.it->first.SetSticky(item->is_sticky);
26032607
if (item->has_mc_flags) {
26042608
res.it->second.SetFlag(true);

0 commit comments

Comments
 (0)