diff --git a/src/v/storage/spill_key_index.cc b/src/v/storage/spill_key_index.cc index a492676e0d9d..0406c22e83f0 100644 --- a/src/v/storage/spill_key_index.cc +++ b/src/v/storage/spill_key_index.cc @@ -85,10 +85,10 @@ ss::future<> spill_key_index::index( ss::future<> spill_key_index::add_key(compaction_key b, value_type v) { auto f = ss::now(); - auto const key_size = b.size(); - auto const expected_size = idx_mem_usage() + _keys_mem_usage + key_size; + auto const entry_size = entry_mem_usage(b); + auto const expected_size = idx_mem_usage() + _keys_mem_usage + entry_size; - auto take_result = _resources.compaction_index_take_bytes(key_size); + auto take_result = _resources.compaction_index_take_bytes(entry_size); if (_mem_units.count() == 0) { _mem_units = std::move(take_result.units); } else { @@ -104,8 +104,8 @@ ss::future<> spill_key_index::add_key(compaction_key b, value_type v) { (take_result.checkpoint_hint && expected_size > min_index_size) || expected_size >= _max_mem) { f = ss::do_until( - [this, key_size, min_index_size] { - size_t total_mem = idx_mem_usage() + _keys_mem_usage + key_size; + [this, entry_size, min_index_size] { + size_t total_mem = idx_mem_usage() + _keys_mem_usage + entry_size; // Instance-local capacity check bool local_ok = total_mem < _max_mem; @@ -136,9 +136,9 @@ ss::future<> spill_key_index::add_key(compaction_key b, value_type v) { }); } - return f.then([this, b = std::move(b), v]() mutable { + return f.then([this, entry_size, b = std::move(b), v]() mutable { // convert iobuf to key - _keys_mem_usage += b.size(); + _keys_mem_usage += entry_size; // No update to _mem_units here: we already took units at top // of add_key before starting the write. @@ -241,8 +241,9 @@ ss::future<> spill_key_index::drain_all_keys() { }, [this] { auto node = _midx.extract(_midx.begin()); - _keys_mem_usage -= node.key().size(); - _mem_units.return_units(node.key().size()); + auto mem_usage = entry_mem_usage(node.key()); + _keys_mem_usage -= mem_usage; + _mem_units.return_units(mem_usage); return ss::do_with( node.key(), node.mapped(), [this](const bytes& k, value_type o) { return spill(compacted_index::entry_type::key, k, o); diff --git a/src/v/storage/spill_key_index.h b/src/v/storage/spill_key_index.h index 076c4c1dde29..9c3ca1514e1f 100644 --- a/src/v/storage/spill_key_index.h +++ b/src/v/storage/spill_key_index.h @@ -91,6 +91,15 @@ class spill_key_index final : public compacted_index_writer::impl { HashtableDebugAccess; return debug::AllocatedByteSize(_midx); } + + size_t entry_mem_usage(const compaction_key& k) const { + // One entry in a node hash map: key and value + // are allocated together, and the key is a basic_sstring with + // internal buffer that may be spilled if key was longer. + auto is_external = k.size() > bytes_inline_size; + return (is_external ? sizeof(k) + k.size() : sizeof(k)) + value_sz; + } + ss::future<> drain_all_keys(); ss::future<> add_key(compaction_key, value_type); ss::future<> spill(compacted_index::entry_type, bytes_view, value_type);