// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #pragma once #include "generationhandler.h" #include #include #include namespace vespalib { /** * Class used to hold data elements until they can be safely reclaimed when they are no longer accessed by readers. * * This class must be used in accordance with a GenerationHandler. */ template class GenerationHoldList { private: using generation_t = vespalib::GenerationHandler::generation_t; struct ElemWithGen { T elem; generation_t gen; ElemWithGen(T elem_in, generation_t gen_in) : elem(std::move(elem_in)), gen(gen_in) {} size_t byte_size() const { return elem->byte_size(); } }; using ElemList = std::vector; using ElemWithGenList = std::conditional_t, std::vector>; ElemList _phase_1_list; ElemWithGenList _phase_2_list; std::atomic _held_bytes; /** * Transfer elements from phase 1 to phase 2 list, assigning the current generation. */ void assign_generation_internal(generation_t current_gen); void reclaim_internal(generation_t oldest_used_gen); public: GenerationHoldList(); ~GenerationHoldList(); /** * Insert the given data element on this hold list. */ void insert(T data); /** * Assign the current generation to all data elements inserted on the hold list * since the last time this function was called. */ void assign_generation(generation_t current_gen) { if (!_phase_1_list.empty()) { assign_generation_internal(current_gen); } } /** * Reclaim all data elements where the assigned generation < oldest used generation. **/ void reclaim(generation_t oldest_used_gen) { if (!_phase_2_list.empty() && (_phase_2_list.front().gen < oldest_used_gen)) { reclaim_internal(oldest_used_gen); } } /** * Reclaim all data elements from this hold list. */ void reclaim_all(); size_t get_held_bytes() const { return _held_bytes.load(std::memory_order_relaxed); } }; }