diff options
author | Henning Baldersheim <balder@yahoo-inc.com> | 2022-10-10 18:01:28 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-10 18:01:28 +0200 |
commit | 26d9e5da4de4425cbb75cd8fff4374053073b19d (patch) | |
tree | bab1c9ca156af7d94b3583d6244a1c09c72e2a81 /vespalib | |
parent | 08f7a121fff008dd1307b106bd1b7d7a84433fe6 (diff) | |
parent | ab10d27bd029f73d82dabd1f3fdb839edae29e61 (diff) |
Merge pull request #24380 from vespa-engine/geirst/generation-holder-new-implv8.66.20
Implement GenerationHolder in terms of the generic generation hold list.
Diffstat (limited to 'vespalib')
13 files changed, 81 insertions, 213 deletions
diff --git a/vespalib/CMakeLists.txt b/vespalib/CMakeLists.txt index 532ec870ce9..8edd7fb2c5d 100644 --- a/vespalib/CMakeLists.txt +++ b/vespalib/CMakeLists.txt @@ -182,7 +182,6 @@ vespa_define_module( src/tests/util/cgroup_resource_limits src/tests/util/file_area_freelist src/tests/util/generation_hold_list - src/tests/util/generation_holder src/tests/util/generationhandler src/tests/util/generationhandler_stress src/tests/util/hamming diff --git a/vespalib/src/tests/datastore/fixed_size_hash_map/fixed_size_hash_map_test.cpp b/vespalib/src/tests/datastore/fixed_size_hash_map/fixed_size_hash_map_test.cpp index 599cb209e6c..ad10bc5c7e6 100644 --- a/vespalib/src/tests/datastore/fixed_size_hash_map/fixed_size_hash_map_test.cpp +++ b/vespalib/src/tests/datastore/fixed_size_hash_map/fixed_size_hash_map_test.cpp @@ -90,11 +90,11 @@ DataStoreFixedSizeHashTest::commit() { _store.transferHoldLists(_generation_handler.getCurrentGeneration()); _hash_map->transfer_hold_lists(_generation_handler.getCurrentGeneration()); - _generation_holder.transferHoldLists(_generation_handler.getCurrentGeneration()); + _generation_holder.assign_generation(_generation_handler.getCurrentGeneration()); _generation_handler.incGeneration(); _store.trimHoldLists(_generation_handler.getFirstUsedGeneration()); _hash_map->trim_hold_lists(_generation_handler.getFirstUsedGeneration()); - _generation_holder.trimHoldLists(_generation_handler.getFirstUsedGeneration()); + _generation_holder.reclaim(_generation_handler.getFirstUsedGeneration()); } size_t diff --git a/vespalib/src/tests/util/generation_hold_list/generation_hold_list_test.cpp b/vespalib/src/tests/util/generation_hold_list/generation_hold_list_test.cpp index 0490a99f1e0..8305b711d5f 100644 --- a/vespalib/src/tests/util/generation_hold_list/generation_hold_list_test.cpp +++ b/vespalib/src/tests/util/generation_hold_list/generation_hold_list_test.cpp @@ -3,12 +3,13 @@ #include <vespa/vespalib/gtest/gtest.h> #include <vespa/vespalib/util/generation_hold_list.hpp> #include <vespa/vespalib/util/generationholder.h> +#include <iostream> using vespalib::GenerationHeldBase; using vespalib::GenerationHoldList; using MyElem = GenerationHeldBase; -using MyHoldList = GenerationHoldList<MyElem::UP, true>; +using MyHoldList = GenerationHoldList<MyElem::UP, true, false>; TEST(GenerationHoldListTest, holding_of_unique_ptr_elements_with_tracking_of_held_bytes) { diff --git a/vespalib/src/tests/util/generation_holder/CMakeLists.txt b/vespalib/src/tests/util/generation_holder/CMakeLists.txt deleted file mode 100644 index 8acf9fadaff..00000000000 --- a/vespalib/src/tests/util/generation_holder/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -vespa_add_executable(vespalib_generation_holder_test_app TEST - SOURCES - generation_holder_test.cpp - DEPENDS - vespalib - GTest::GTest -) -vespa_add_test(NAME vespalib_generation_holder_test_app COMMAND vespalib_generation_holder_test_app) diff --git a/vespalib/src/tests/util/generation_holder/generation_holder_test.cpp b/vespalib/src/tests/util/generation_holder/generation_holder_test.cpp deleted file mode 100644 index 97c3330ac9e..00000000000 --- a/vespalib/src/tests/util/generation_holder/generation_holder_test.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - -#include <vespa/vespalib/gtest/gtest.h> -#include <vespa/vespalib/util/generationholder.h> - -using vespalib::GenerationHolder; -using MyHeld = vespalib::GenerationHeldBase; - -TEST(GenerationHolderTest, basic_tracking) -{ - GenerationHolder gh; - gh.hold(std::make_unique<MyHeld>(sizeof(int32_t))); - gh.transferHoldLists(0); - gh.hold(std::make_unique<MyHeld>(sizeof(int32_t))); - gh.transferHoldLists(1); - gh.hold(std::make_unique<MyHeld>(sizeof(int32_t))); - gh.transferHoldLists(2); - gh.hold(std::make_unique<MyHeld>(sizeof(int32_t))); - gh.transferHoldLists(4); - EXPECT_EQ(4u * sizeof(int32_t), gh.getHeldBytes()); - gh.trimHoldLists(0); - EXPECT_EQ(4u * sizeof(int32_t), gh.getHeldBytes()); - gh.trimHoldLists(1); - EXPECT_EQ(3u * sizeof(int32_t), gh.getHeldBytes()); - gh.trimHoldLists(2); - EXPECT_EQ(2u * sizeof(int32_t), gh.getHeldBytes()); - gh.hold(std::make_unique<MyHeld>(sizeof(int32_t))); - gh.transferHoldLists(6); - EXPECT_EQ(3u * sizeof(int32_t), gh.getHeldBytes()); - gh.trimHoldLists(6); - EXPECT_EQ(1u * sizeof(int32_t), gh.getHeldBytes()); - gh.trimHoldLists(7); - EXPECT_EQ(0u * sizeof(int32_t), gh.getHeldBytes()); - gh.trimHoldLists(7); - EXPECT_EQ(0u * sizeof(int32_t), gh.getHeldBytes()); -} - -GTEST_MAIN_RUN_ALL_TESTS() diff --git a/vespalib/src/tests/util/rcuvector/rcuvector_test.cpp b/vespalib/src/tests/util/rcuvector/rcuvector_test.cpp index eb2b00f9e20..c23065b7468 100644 --- a/vespalib/src/tests/util/rcuvector/rcuvector_test.cpp +++ b/vespalib/src/tests/util/rcuvector/rcuvector_test.cpp @@ -102,15 +102,15 @@ TEST(RcuVectorTest, resize) RcuVectorBase<int8_t> v(growStrategy(16, 1.0, 0), g); v.push_back(1); v.push_back(2); - g.transferHoldLists(0); - g.trimHoldLists(1); + g.assign_generation(0); + g.reclaim(1); const int8_t *old = &v[0]; EXPECT_EQ(16u, v.capacity()); EXPECT_EQ(2u, v.size()); v.ensure_size(32, 3); v[0] = 3; v[1] = 3; - g.transferHoldLists(1); + g.assign_generation(1); EXPECT_EQ(1, old[0]); EXPECT_EQ(2, old[1]); EXPECT_EQ(3, v[0]); @@ -119,7 +119,7 @@ TEST(RcuVectorTest, resize) EXPECT_EQ(3, v[31]); EXPECT_EQ(64u, v.capacity()); EXPECT_EQ(32u, v.size()); - g.trimHoldLists(2); + g.reclaim(2); } } @@ -197,11 +197,11 @@ void verify_shrink_with_buffer_copying(size_t initial_size, size_t absolute_mini v.push_back(2); v.push_back(3); v.push_back(4); - g.transferHoldLists(0); - g.trimHoldLists(1); + g.assign_generation(0); + g.reclaim(1); MemoryUsage mu; mu = v.getMemoryUsage(); - mu.incAllocatedBytesOnHold(g.getHeldBytes()); + mu.incAllocatedBytesOnHold(g.get_held_bytes()); EXPECT_TRUE(assertUsage(MemoryUsage(initial_capacity, 4, 0, 0), mu)); EXPECT_EQ(4u, v.size()); EXPECT_EQ(initial_capacity, v.capacity()); @@ -211,18 +211,18 @@ void verify_shrink_with_buffer_copying(size_t initial_size, size_t absolute_mini EXPECT_EQ(4, v[3]); const int8_t *old = &v[0]; v.shrink(2); - g.transferHoldLists(1); + g.assign_generation(1); EXPECT_EQ(2u, v.size()); EXPECT_EQ(minimal_capacity, v.capacity()); EXPECT_EQ(1, v[0]); EXPECT_EQ(2, v[1]); EXPECT_EQ(1, old[0]); EXPECT_EQ(2, old[1]); - g.trimHoldLists(2); + g.reclaim(2); EXPECT_EQ(1, v[0]); EXPECT_EQ(2, v[1]); mu = v.getMemoryUsage(); - mu.incAllocatedBytesOnHold(g.getHeldBytes()); + mu.incAllocatedBytesOnHold(g.get_held_bytes()); EXPECT_TRUE(assertUsage(MemoryUsage(minimal_capacity, 2, 0, 0), mu)); } @@ -256,7 +256,7 @@ struct ShrinkFixture { EXPECT_EQ(oldPtr, &vec[0]); } void assertEmptyHoldList() { - EXPECT_EQ(0u, g.getHeldBytes()); + EXPECT_EQ(0u, g.get_held_bytes()); } static size_t page_ints() { return round_up_to_page_size(1) / sizeof(int); } }; @@ -294,8 +294,8 @@ TEST(RcuVectorTest, small_expand) v.push_back(2); EXPECT_EQ(2u, v.capacity()); EXPECT_EQ(2u, v.size()); - g.transferHoldLists(1); - g.trimHoldLists(2); + g.assign_generation(1); + g.reclaim(2); } struct FixtureBase { @@ -325,10 +325,10 @@ struct Fixture : public FixtureBase { Fixture(); ~Fixture(); - void transfer_and_trim(generation_t transfer_gen, generation_t trim_gen) + void assign_and_reclaim(generation_t assign_gen, generation_t reclaim_gen) { - g.transferHoldLists(transfer_gen); - g.trimHoldLists(trim_gen); + g.assign_generation(assign_gen); + g.reclaim(reclaim_gen); } }; @@ -345,7 +345,7 @@ TEST(RcuVectorTest, memory_allocator_can_be_set) { Fixture f; EXPECT_EQ(AllocStats(2, 0), f.stats); - f.transfer_and_trim(1, 2); + f.assign_and_reclaim(1, 2); EXPECT_EQ(AllocStats(2, 1), f.stats); } @@ -355,7 +355,7 @@ TEST(RcuVectorTest, memory_allocator_is_preserved_across_reset) f.arr.reset(); f.arr.reserve(100); EXPECT_EQ(AllocStats(4, 1), f.stats); - f.transfer_and_trim(1, 2); + f.assign_and_reclaim(1, 2); EXPECT_EQ(AllocStats(4, 3), f.stats); } @@ -366,7 +366,7 @@ TEST(RcuVectorTest, created_replacement_vector_uses_same_memory_allocator) EXPECT_EQ(AllocStats(2, 0), f.stats); arr2.reserve(100); EXPECT_EQ(AllocStats(3, 0), f.stats); - f.transfer_and_trim(1, 2); + f.assign_and_reclaim(1, 2); EXPECT_EQ(AllocStats(3, 1), f.stats); } @@ -377,7 +377,7 @@ TEST(RcuVectorTest, ensure_size_and_shrink_use_same_memory_allocator) EXPECT_EQ(AllocStats(3, 0), f.stats); f.arr.shrink(1000); EXPECT_EQ(AllocStats(4, 0), f.stats); - f.transfer_and_trim(1, 2); + f.assign_and_reclaim(1, 2); EXPECT_EQ(AllocStats(4, 3), f.stats); } @@ -432,10 +432,10 @@ void StressFixture::commit() { auto current_gen = generation_handler.getCurrentGeneration(); - g.transferHoldLists(current_gen); + g.assign_generation(current_gen); generation_handler.incGeneration(); auto first_used_gen = generation_handler.getFirstUsedGeneration(); - g.trimHoldLists(first_used_gen); + g.reclaim(first_used_gen); } void diff --git a/vespalib/src/vespa/vespalib/datastore/datastorebase.cpp b/vespalib/src/vespa/vespalib/datastore/datastorebase.cpp index dd6c767e9c6..5962e6cf2f7 100644 --- a/vespalib/src/vespa/vespalib/datastore/datastorebase.cpp +++ b/vespalib/src/vespa/vespalib/datastore/datastorebase.cpp @@ -232,7 +232,7 @@ DataStoreBase::transferElemHoldList(generation_t generation) void DataStoreBase::transferHoldLists(generation_t generation) { - _genHolder.transferHoldLists(generation); + _genHolder.assign_generation(generation); if (hasElemHold1()) { transferElemHoldList(generation); } @@ -250,7 +250,7 @@ void DataStoreBase::trimHoldLists(generation_t usedGen) { trimElemHoldList(usedGen); // Trim entries before trimming buffers - _genHolder.trimHoldLists(usedGen); + _genHolder.reclaim(usedGen); } void @@ -258,7 +258,7 @@ DataStoreBase::clearHoldLists() { transferElemHoldList(0); clearElemHoldList(); - _genHolder.clearHoldLists(); + _genHolder.reclaim_all(); } void @@ -268,7 +268,7 @@ DataStoreBase::dropBuffers() for (uint32_t bufferId = 0; bufferId < numBuffers; ++bufferId) { _states[bufferId].dropBuffer(bufferId, _buffers[bufferId].get_atomic_buffer()); } - _genHolder.clearHoldLists(); + _genHolder.reclaim_all(); } vespalib::MemoryUsage @@ -289,7 +289,7 @@ DataStoreBase::holdBuffer(uint32_t bufferId) _states[bufferId].onHold(bufferId); size_t holdBytes = 0u; // getMemStats() still accounts held buffers auto hold = std::make_unique<BufferHold>(holdBytes, *this, bufferId); - _genHolder.hold(std::move(hold)); + _genHolder.insert(std::move(hold)); } void @@ -356,7 +356,7 @@ DataStoreBase::getMemStats() const LOG_ABORT("should not be reached"); } } - size_t genHolderHeldBytes = _genHolder.getHeldBytes(); + size_t genHolderHeldBytes = _genHolder.get_held_bytes(); stats._holdBytes += genHolderHeldBytes; stats._allocBytes += genHolderHeldBytes; stats._usedBytes += genHolderHeldBytes; @@ -428,7 +428,7 @@ DataStoreBase::fallbackResize(uint32_t bufferId, size_t elemsNeeded) state.getTypeHandler(), state.getTypeId()); if (!_initializing) { - _genHolder.hold(std::move(hold)); + _genHolder.insert(std::move(hold)); } } diff --git a/vespalib/src/vespa/vespalib/datastore/sharded_hash_map.cpp b/vespalib/src/vespa/vespalib/datastore/sharded_hash_map.cpp index 2ae22084472..102aa1cefb3 100644 --- a/vespalib/src/vespa/vespalib/datastore/sharded_hash_map.cpp +++ b/vespalib/src/vespa/vespalib/datastore/sharded_hash_map.cpp @@ -32,7 +32,7 @@ ShardedHashMap::ShardedHashMap(std::unique_ptr<const EntryComparator> comp) ShardedHashMap::~ShardedHashMap() { - _gen_holder.clearHoldLists(); + _gen_holder.reclaim_all(); for (size_t i = 0; i < num_shards; ++i) { auto map = _maps[i].load(std::memory_order_relaxed); delete map; @@ -58,7 +58,7 @@ ShardedHashMap::hold_shard(std::unique_ptr<const FixedSizeHashMap> map) { auto usage = map->get_memory_usage(); auto hold = std::make_unique<ShardedHashMapShardHeld>(usage.allocatedBytes(), std::move(map)); - _gen_holder.hold(std::move(hold)); + _gen_holder.insert(std::move(hold)); } ShardedHashMap::KvType& @@ -115,7 +115,7 @@ ShardedHashMap::transfer_hold_lists(generation_t generation) map->transfer_hold_lists(generation); } } - _gen_holder.transferHoldLists(generation); + _gen_holder.assign_generation(generation); } void @@ -127,7 +127,7 @@ ShardedHashMap::trim_hold_lists(generation_t first_used) map->trim_hold_lists(first_used); } } - _gen_holder.trimHoldLists(first_used); + _gen_holder.reclaim(first_used); } size_t @@ -153,7 +153,7 @@ ShardedHashMap::get_memory_usage() const memory_usage.merge(map->get_memory_usage()); } } - size_t gen_holder_held_bytes = _gen_holder.getHeldBytes(); + size_t gen_holder_held_bytes = _gen_holder.get_held_bytes(); memory_usage.incAllocatedBytes(gen_holder_held_bytes); memory_usage.incAllocatedBytesOnHold(gen_holder_held_bytes); return memory_usage; @@ -222,7 +222,7 @@ ShardedHashMap::foreach_value(std::function<void(const std::vector<EntryRef>&)> bool ShardedHashMap::has_held_buffers() const { - return _gen_holder.getHeldBytes() != 0; + return _gen_holder.get_held_bytes() != 0; } void diff --git a/vespalib/src/vespa/vespalib/util/generation_hold_list.h b/vespalib/src/vespa/vespalib/util/generation_hold_list.h index 5e12cb72bbd..b2f90934e84 100644 --- a/vespalib/src/vespa/vespalib/util/generation_hold_list.h +++ b/vespalib/src/vespa/vespalib/util/generation_hold_list.h @@ -14,7 +14,7 @@ namespace vespalib { * * This class must be used in accordance with a GenerationHandler. */ -template <typename T, bool track_bytes_held> +template <typename T, bool track_bytes_held, bool use_deque> class GenerationHoldList { private: using generation_t = vespalib::GenerationHandler::generation_t; @@ -30,7 +30,9 @@ private: }; using ElemList = std::vector<T>; - using ElemWithGenList = std::deque<ElemWithGen>; + using ElemWithGenList = std::conditional_t<use_deque, + std::deque<ElemWithGen>, + std::vector<ElemWithGen>>; ElemList _phase_1_list; ElemWithGenList _phase_2_list; @@ -46,6 +48,7 @@ private: public: GenerationHoldList(); + ~GenerationHoldList(); /** * Insert the given data element on this hold list. diff --git a/vespalib/src/vespa/vespalib/util/generation_hold_list.hpp b/vespalib/src/vespa/vespalib/util/generation_hold_list.hpp index e7eee2b0aef..ed4a99c4753 100644 --- a/vespalib/src/vespa/vespalib/util/generation_hold_list.hpp +++ b/vespalib/src/vespa/vespalib/util/generation_hold_list.hpp @@ -1,12 +1,15 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#pragma once + #include "generation_hold_list.h" +#include <cassert> namespace vespalib { -template <typename T, bool track_bytes_held> +template <typename T, bool track_bytes_held, bool use_deque> void -GenerationHoldList<T, track_bytes_held>::assign_generation_internal(generation_t current_gen) +GenerationHoldList<T, track_bytes_held, use_deque>::assign_generation_internal(generation_t current_gen) { for (auto& elem : _phase_1_list) { _phase_2_list.push_back(ElemWithGen(std::move(elem), current_gen)); @@ -14,9 +17,9 @@ GenerationHoldList<T, track_bytes_held>::assign_generation_internal(generation_t _phase_1_list.clear(); } -template <typename T, bool track_bytes_held> +template <typename T, bool track_bytes_held, bool use_deque> void -GenerationHoldList<T, track_bytes_held>::reclaim_internal(generation_t oldest_used_gen) +GenerationHoldList<T, track_bytes_held, use_deque>::reclaim_internal(generation_t oldest_used_gen) { auto itr = _phase_2_list.begin(); auto ite = _phase_2_list.end(); @@ -33,17 +36,25 @@ GenerationHoldList<T, track_bytes_held>::reclaim_internal(generation_t oldest_us } } -template <typename T, bool track_bytes_held> -GenerationHoldList<T, track_bytes_held>::GenerationHoldList() +template <typename T, bool track_bytes_held, bool use_deque> +GenerationHoldList<T, track_bytes_held, use_deque>::GenerationHoldList() : _phase_1_list(), _phase_2_list(), _held_bytes() { } -template <typename T, bool track_bytes_held> +template <typename T, bool track_bytes_held, bool use_deque> +GenerationHoldList<T, track_bytes_held, use_deque>::~GenerationHoldList() +{ + assert(_phase_1_list.empty()); + assert(_phase_2_list.empty()); + assert(get_held_bytes() == 0); +} + +template <typename T, bool track_bytes_held, bool use_deque> void -GenerationHoldList<T, track_bytes_held>::insert(T data) +GenerationHoldList<T, track_bytes_held, use_deque>::insert(T data) { _phase_1_list.push_back(std::move(data)); if (track_bytes_held) { @@ -51,9 +62,9 @@ GenerationHoldList<T, track_bytes_held>::insert(T data) } } -template <typename T, bool track_bytes_held> +template <typename T, bool track_bytes_held, bool use_deque> void -GenerationHoldList<T, track_bytes_held>::reclaim_all() +GenerationHoldList<T, track_bytes_held, use_deque>::reclaim_all() { _phase_1_list.clear(); _phase_2_list.clear(); diff --git a/vespalib/src/vespa/vespalib/util/generationholder.cpp b/vespalib/src/vespa/vespalib/util/generationholder.cpp index f2b10ff3af1..5f31f610c68 100644 --- a/vespalib/src/vespa/vespalib/util/generationholder.cpp +++ b/vespalib/src/vespa/vespalib/util/generationholder.cpp @@ -1,66 +1,15 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "generationholder.h" -#include <cassert> +#include "generation_hold_list.hpp" namespace vespalib { GenerationHeldBase::~GenerationHeldBase() = default; GenerationHolder::GenerationHolder() - : _hold1List(), - _hold2List(), - _heldBytes(0) -{ } - -GenerationHolder::~GenerationHolder() -{ - assert(_hold1List.empty()); - assert(_hold2List.empty()); - assert(getHeldBytes() == 0); -} - -void -GenerationHolder::hold(GenerationHeldBase::UP data) -{ - _hold1List.push_back(std::move(data)); - _heldBytes.store(getHeldBytes() + _hold1List.back()->byte_size(), std::memory_order_relaxed); -} - -void -GenerationHolder::transferHoldListsSlow(generation_t generation) -{ - HoldList::iterator it(_hold1List.begin()); - HoldList::iterator ite(_hold1List.end()); - HoldList &hold2List = _hold2List; - for (; it != ite; ++it) { - assert((*it)->_generation == 0u); - (*it)->_generation = generation; - hold2List.push_back(std::move(*it)); - } - _hold1List.clear(); -} - -void -GenerationHolder::trimHoldListsSlow(generation_t usedGen) -{ - for (;;) { - if (_hold2List.empty()) - break; - GenerationHeldBase &first = *_hold2List.front(); - if (static_cast<sgeneration_t>(first._generation - usedGen) >= 0) - break; - _heldBytes.store(getHeldBytes() - first.byte_size(), std::memory_order_relaxed); - _hold2List.erase(_hold2List.begin()); - } -} - -void -GenerationHolder::clearHoldLists() + : GenerationHoldList<GenerationHeldBase::UP, true, false>() { - _hold1List.clear(); - _hold2List.clear(); - _heldBytes = 0; } } diff --git a/vespalib/src/vespa/vespalib/util/generationholder.h b/vespalib/src/vespa/vespalib/util/generationholder.h index df44f39ebff..ec2cded2e84 100644 --- a/vespalib/src/vespa/vespalib/util/generationholder.h +++ b/vespalib/src/vespa/vespalib/util/generationholder.h @@ -2,8 +2,8 @@ #pragma once +#include "generation_hold_list.h" #include "generationhandler.h" -#include <vector> #include <memory> namespace vespalib { @@ -11,79 +11,31 @@ namespace vespalib { class GenerationHeldBase { public: - typedef GenerationHandler::generation_t generation_t; - typedef std::unique_ptr<GenerationHeldBase> UP; - typedef std::shared_ptr<GenerationHeldBase> SP; + using generation_t = GenerationHandler::generation_t; + using UP = std::unique_ptr<GenerationHeldBase>; + using SP = std::shared_ptr<GenerationHeldBase>; - generation_t _generation; private: size_t _byte_size; public: GenerationHeldBase(size_t byte_size_in) - : _generation(0u), - _byte_size(byte_size_in) + : _byte_size(byte_size_in) { } virtual ~GenerationHeldBase(); size_t byte_size() const { return _byte_size; } }; +template class GenerationHoldList<GenerationHeldBase::UP, true, false>; + /* * GenerationHolder is meant to hold large elements until readers can * no longer access them. */ -class GenerationHolder -{ -private: - typedef GenerationHandler::generation_t generation_t; - typedef GenerationHandler::sgeneration_t sgeneration_t; - - typedef std::vector<GenerationHeldBase::UP> HoldList; - - HoldList _hold1List; - HoldList _hold2List; - std::atomic<size_t> _heldBytes; - - /** - * Transfer holds from hold1 to hold2 lists, assigning generation. - */ - void transferHoldListsSlow(generation_t generation); - - /** - * Remove all data elements from this holder where generation < usedGen. - **/ - void trimHoldListsSlow(generation_t usedGen); - +class GenerationHolder : public GenerationHoldList<GenerationHeldBase::UP, true, false> { public: GenerationHolder(); - ~GenerationHolder(); - - /** - * Add the given data pointer to this holder. - **/ - void hold(GenerationHeldBase::UP data); - - /** - * Transfer holds from hold1 to hold2 lists, assigning generation. - */ - void transferHoldLists(generation_t generation) { - if (!_hold1List.empty()) { - transferHoldListsSlow(generation); - } - } - - /** - * Remove all data elements from this holder where generation < usedGen. - **/ - void trimHoldLists(generation_t usedGen) { - if (!_hold2List.empty() && static_cast<sgeneration_t>(_hold2List.front()->_generation - usedGen) < 0) { - trimHoldListsSlow(usedGen); - } - } - - void clearHoldLists(); - size_t getHeldBytes() const { return _heldBytes.load(std::memory_order_relaxed); } }; } diff --git a/vespalib/src/vespa/vespalib/util/rcuvector.hpp b/vespalib/src/vespa/vespalib/util/rcuvector.hpp index 97a73a73cc9..e551bb17db0 100644 --- a/vespalib/src/vespa/vespalib/util/rcuvector.hpp +++ b/vespalib/src/vespa/vespalib/util/rcuvector.hpp @@ -80,7 +80,7 @@ RcuVectorBase<T>::replaceVector(ArrayType replacement) { replacement.swap(_data); // atomic switch of underlying data size_t holdSize = replacement.capacity() * sizeof(T); auto hold = std::make_unique<RcuVectorHeld<ArrayType>>(holdSize, std::move(replacement)); - _genHolder.hold(std::move(hold)); + _genHolder.insert(std::move(hold)); onReallocation(); } @@ -116,7 +116,7 @@ RcuVectorBase<T>::shrink(size_t newSize) tmpData.swap(_data); // atomic switch of underlying data size_t holdSize = tmpData.capacity() * sizeof(T); auto hold = std::make_unique<RcuVectorHeld<ArrayType>>(holdSize, std::move(tmpData)); - _genHolder.hold(std::move(hold)); + _genHolder.insert(std::move(hold)); onReallocation(); } } @@ -162,7 +162,7 @@ template <typename T> void RcuVector<T>::onReallocation() { RcuVectorBase<T>::onReallocation(); - _genHolderStore.transferHoldLists(_generation); + _genHolderStore.assign_generation(_generation); } template <typename T> @@ -182,14 +182,14 @@ RcuVector<T>::RcuVector(GrowStrategy growStrategy) template <typename T> RcuVector<T>::~RcuVector() { - _genHolderStore.clearHoldLists(); + _genHolderStore.reclaim_all(); } template <typename T> void RcuVector<T>::removeOldGenerations(generation_t firstUsed) { - _genHolderStore.trimHoldLists(firstUsed); + _genHolderStore.reclaim(firstUsed); } template <typename T> @@ -197,7 +197,7 @@ MemoryUsage RcuVector<T>::getMemoryUsage() const { MemoryUsage retval(RcuVectorBase<T>::getMemoryUsage()); - retval.mergeGenerationHeldBytes(_genHolderStore.getHeldBytes()); + retval.mergeGenerationHeldBytes(_genHolderStore.get_held_bytes()); return retval; } |