diff options
author | Geir Storli <geirst@yahooinc.com> | 2022-09-29 12:37:54 +0000 |
---|---|---|
committer | Geir Storli <geirst@yahooinc.com> | 2022-09-29 12:37:54 +0000 |
commit | 2381228f5f732282510adfe03f51d52341c618dd (patch) | |
tree | bc6dee336e6f5300f9c1c800200df2da62827f1f /vespalib | |
parent | 8b463cd632fa4dac1d5809b950d96c51a1101275 (diff) |
Refactor ArrayStore to support generic type id to array size mappers.
The default type mapper uses a 1-to-1 mapping between type id and array size for small arrays.
Diffstat (limited to 'vespalib')
7 files changed, 156 insertions, 82 deletions
diff --git a/vespalib/src/tests/datastore/array_store/array_store_test.cpp b/vespalib/src/tests/datastore/array_store/array_store_test.cpp index e9dd5860ece..3b15c90c4af 100644 --- a/vespalib/src/tests/datastore/array_store/array_store_test.cpp +++ b/vespalib/src/tests/datastore/array_store/array_store_test.cpp @@ -167,10 +167,10 @@ TEST_F("control static sizes", NumberFixture(3)) { EXPECT_EQUAL(440u, sizeof(f.store)); EXPECT_EQUAL(296u, sizeof(NumberFixture::ArrayStoreType::DataStoreType)); #else - EXPECT_EQUAL(472u, sizeof(f.store)); + EXPECT_EQUAL(488u, sizeof(f.store)); EXPECT_EQUAL(328u, sizeof(NumberFixture::ArrayStoreType::DataStoreType)); #endif - EXPECT_EQUAL(96u, sizeof(NumberFixture::ArrayStoreType::SmallArrayType)); + EXPECT_EQUAL(112u, sizeof(NumberFixture::ArrayStoreType::SmallBufferType)); MemoryUsage usage = f.store.getMemoryUsage(); EXPECT_EQUAL(960u, usage.allocatedBytes()); EXPECT_EQUAL(32u, usage.usedBytes()); diff --git a/vespalib/src/tests/datastore/array_store_config/array_store_config_test.cpp b/vespalib/src/tests/datastore/array_store_config/array_store_config_test.cpp index f5cfea0c327..fcf1acd5cd3 100644 --- a/vespalib/src/tests/datastore/array_store_config/array_store_config_test.cpp +++ b/vespalib/src/tests/datastore/array_store_config/array_store_config_test.cpp @@ -15,24 +15,26 @@ struct Fixture using EntryRefType = EntryRefT<18>; ArrayStoreConfig cfg; - Fixture(uint32_t maxSmallArraySize, + Fixture(uint32_t maxSmallArrayTypeId, const AllocSpec &defaultSpec) - : cfg(maxSmallArraySize, defaultSpec) {} + : cfg(maxSmallArrayTypeId, defaultSpec) {} - Fixture(uint32_t maxSmallArraySize, + Fixture(uint32_t maxSmallArrayTypeId, size_t hugePageSize, size_t smallPageSize, size_t minNumArraysForNewBuffer) - : cfg(ArrayStoreConfig::optimizeForHugePage(maxSmallArraySize, hugePageSize, smallPageSize, + : cfg(ArrayStoreConfig::optimizeForHugePage(maxSmallArrayTypeId, + [](size_t type_id) noexcept { return type_id; }, + hugePageSize, smallPageSize, sizeof(int), EntryRefType::offsetSize(), minNumArraysForNewBuffer, ALLOC_GROW_FACTOR)) { } - void assertSpec(size_t arraySize, uint32_t numArraysForNewBuffer) { - assertSpec(arraySize, AllocSpec(0, EntryRefType::offsetSize(), - numArraysForNewBuffer, ALLOC_GROW_FACTOR)); + void assertSpec(uint32_t type_id, uint32_t numArraysForNewBuffer) { + assertSpec(type_id, AllocSpec(0, EntryRefType::offsetSize(), + numArraysForNewBuffer, ALLOC_GROW_FACTOR)); } - void assertSpec(size_t arraySize, const AllocSpec &expSpec) { - const ArrayStoreConfig::AllocSpec &actSpec = cfg.specForSize(arraySize); + void assertSpec(uint32_t type_id, const AllocSpec &expSpec) { + const auto& actSpec = cfg.spec_for_type_id(type_id); EXPECT_EQUAL(expSpec.minArraysInBuffer, actSpec.minArraysInBuffer); EXPECT_EQUAL(expSpec.maxArraysInBuffer, actSpec.maxArraysInBuffer); EXPECT_EQUAL(expSpec.numArraysForNewBuffer, actSpec.numArraysForNewBuffer); @@ -53,7 +55,7 @@ constexpr size_t MB = KB * KB; TEST_F("require that default allocation spec is given for all array sizes", Fixture(3, makeSpec(4, 32, 8))) { - EXPECT_EQUAL(3u, f.cfg.maxSmallArraySize()); + EXPECT_EQUAL(3u, f.cfg.maxSmallArrayTypeId()); TEST_DO(f.assertSpec(0, makeSpec(4, 32, 8))); TEST_DO(f.assertSpec(1, makeSpec(4, 32, 8))); TEST_DO(f.assertSpec(2, makeSpec(4, 32, 8))); @@ -65,7 +67,7 @@ TEST_F("require that we can generate config optimized for a given huge page", Fi 4 * KB, 8 * KB)) { - EXPECT_EQUAL(1_Ki, f.cfg.maxSmallArraySize()); + EXPECT_EQUAL(1_Ki, f.cfg.maxSmallArrayTypeId()); TEST_DO(f.assertSpec(0, 8 * KB)); // large arrays TEST_DO(f.assertSpec(1, 256 * KB)); TEST_DO(f.assertSpec(2, 256 * KB)); diff --git a/vespalib/src/vespa/vespalib/datastore/array_store.h b/vespalib/src/vespa/vespalib/datastore/array_store.h index 7bf24194ce2..fd0271915dd 100644 --- a/vespalib/src/vespa/vespalib/datastore/array_store.h +++ b/vespalib/src/vespa/vespalib/datastore/array_store.h @@ -2,6 +2,7 @@ #pragma once +#include "array_store_type_mapper.h" #include "array_store_config.h" #include "buffer_type.h" #include "bufferstate.h" @@ -19,33 +20,36 @@ namespace vespalib::datastore { * Datastore for storing arrays of type EntryT that is accessed via a 32-bit EntryRef. * * The default EntryRef type uses 19 bits for offset (524288 values) and 13 bits for buffer id (8192 buffers). - * Arrays of size [1,maxSmallArraySize] are stored in buffers with arrays of equal size. - * Arrays of size >maxSmallArraySize are stored in buffers with vespalib::Array instances that are heap allocated. * - * The max value of maxSmallArraySize is (2^bufferBits - 1). + * Buffer type ids [1,maxSmallArrayTypeId] are used to allocate small arrays in datastore buffers. + * The default type mapper uses a 1-to-1 mapping between type id and array size. + * Buffer type id 0 is used to heap allocate large arrays as vespalib::Array instances. + * + * The max value of maxSmallArrayTypeId is (2^bufferBits - 1). */ -template <typename EntryT, typename RefT = EntryRefT<19> > +template <typename EntryT, typename RefT = EntryRefT<19>, typename TypeMapperT = ArrayStoreTypeMapper<EntryT> > class ArrayStore { public: + using AllocSpec = ArrayStoreConfig::AllocSpec; using ArrayRef = vespalib::ArrayRef<EntryT>; using ConstArrayRef = vespalib::ConstArrayRef<EntryT>; using DataStoreType = DataStoreT<RefT>; - using SmallArrayType = BufferType<EntryT>; using LargeArray = vespalib::Array<EntryT>; - using AllocSpec = ArrayStoreConfig::AllocSpec; + using LargeBufferType = typename TypeMapperT::LargeBufferType; + using SmallBufferType = typename TypeMapperT::SmallBufferType; + using TypeMapper = TypeMapperT; private: uint32_t _largeArrayTypeId; - uint32_t _maxSmallArraySize; + uint32_t _maxSmallArrayTypeId; + size_t _maxSmallArraySize; DataStoreType _store; - std::vector<SmallArrayBufferType<EntryT>> _smallArrayTypes; - LargeArrayBufferType<EntryT> _largeArrayType; + TypeMapper _mapper; + std::vector<SmallBufferType> _smallArrayTypes; + LargeBufferType _largeArrayType; using generation_t = vespalib::GenerationHandler::generation_t; void initArrayTypes(const ArrayStoreConfig &cfg, std::shared_ptr<alloc::MemoryAllocator> memory_allocator); - // 1-to-1 mapping between type ids and sizes for small arrays is enforced during initialization. - uint32_t getTypeId(size_t arraySize) const { return arraySize; } - size_t getArraySize(uint32_t typeId) const { return typeId; } EntryRef addSmallArray(const ConstArrayRef &array); EntryRef addLargeArray(const ConstArrayRef &array); ConstArrayRef getSmallArray(RefT ref, size_t arraySize) const { @@ -59,6 +63,7 @@ private: public: ArrayStore(const ArrayStoreConfig &cfg, std::shared_ptr<alloc::MemoryAllocator> memory_allocator); + ArrayStore(const ArrayStoreConfig &cfg, std::shared_ptr<alloc::MemoryAllocator> memory_allocator, TypeMapper&& mapper); ~ArrayStore(); EntryRef add(const ConstArrayRef &array); ConstArrayRef get(EntryRef ref) const { @@ -68,7 +73,7 @@ public: RefT internalRef(ref); uint32_t typeId = _store.getTypeId(internalRef.bufferId()); if (typeId != _largeArrayTypeId) { - size_t arraySize = getArraySize(typeId); + size_t arraySize = _mapper.get_array_size(typeId); return getSmallArray(internalRef, arraySize); } else { return getLargeArray(internalRef); @@ -113,7 +118,14 @@ public: bool has_free_lists_enabled() const { return _store.has_free_lists_enabled(); } bool has_held_buffers() const noexcept { return _store.has_held_buffers(); } - static ArrayStoreConfig optimizedConfigForHugePage(size_t maxSmallArraySize, + static ArrayStoreConfig optimizedConfigForHugePage(uint32_t maxSmallArrayTypeId, + size_t hugePageSize, + size_t smallPageSize, + size_t minNumArraysForNewBuffer, + float allocGrowFactor); + + static ArrayStoreConfig optimizedConfigForHugePage(uint32_t maxSmallArrayTypeId, + const TypeMapper& mapper, size_t hugePageSize, size_t smallPageSize, size_t minNumArraysForNewBuffer, diff --git a/vespalib/src/vespa/vespalib/datastore/array_store.hpp b/vespalib/src/vespa/vespalib/datastore/array_store.hpp index f452d0f9b57..c1623b4322a 100644 --- a/vespalib/src/vespa/vespalib/datastore/array_store.hpp +++ b/vespalib/src/vespa/vespalib/datastore/array_store.hpp @@ -13,30 +13,38 @@ namespace vespalib::datastore { -template <typename EntryT, typename RefT> +template <typename EntryT, typename RefT, typename TypeMapperT> void -ArrayStore<EntryT, RefT>::initArrayTypes(const ArrayStoreConfig &cfg, std::shared_ptr<alloc::MemoryAllocator> memory_allocator) +ArrayStore<EntryT, RefT, TypeMapperT>::initArrayTypes(const ArrayStoreConfig &cfg, std::shared_ptr<alloc::MemoryAllocator> memory_allocator) { _largeArrayTypeId = _store.addType(&_largeArrayType); assert(_largeArrayTypeId == 0); - _smallArrayTypes.reserve(_maxSmallArraySize); - for (uint32_t arraySize = 1; arraySize <= _maxSmallArraySize; ++arraySize) { - const AllocSpec &spec = cfg.specForSize(arraySize); + _smallArrayTypes.reserve(_maxSmallArrayTypeId); + for (uint32_t type_id = 1; type_id <= _maxSmallArrayTypeId; ++type_id) { + const AllocSpec &spec = cfg.spec_for_type_id(type_id); + size_t arraySize = _mapper.get_array_size(type_id); _smallArrayTypes.emplace_back(arraySize, spec, memory_allocator); + uint32_t act_type_id = _store.addType(&_smallArrayTypes.back()); + assert(type_id == act_type_id); } - for (auto & type : _smallArrayTypes) { - uint32_t typeId = _store.addType(&type); - assert(typeId == type.getArraySize()); // Enforce 1-to-1 mapping between type ids and sizes for small arrays - } } -template <typename EntryT, typename RefT> -ArrayStore<EntryT, RefT>::ArrayStore(const ArrayStoreConfig &cfg, std::shared_ptr<alloc::MemoryAllocator> memory_allocator) +template <typename EntryT, typename RefT, typename TypeMapperT> +ArrayStore<EntryT, RefT, TypeMapperT>::ArrayStore(const ArrayStoreConfig &cfg, std::shared_ptr<alloc::MemoryAllocator> memory_allocator) + : ArrayStore(cfg, memory_allocator, TypeMapper()) +{ +} + +template <typename EntryT, typename RefT, typename TypeMapperT> +ArrayStore<EntryT, RefT, TypeMapperT>::ArrayStore(const ArrayStoreConfig &cfg, std::shared_ptr<alloc::MemoryAllocator> memory_allocator, + TypeMapper&& mapper) : _largeArrayTypeId(0), - _maxSmallArraySize(cfg.maxSmallArraySize()), + _maxSmallArrayTypeId(cfg.maxSmallArrayTypeId()), + _maxSmallArraySize(mapper.get_array_size(_maxSmallArrayTypeId)), _store(), + _mapper(std::move(mapper)), _smallArrayTypes(), - _largeArrayType(cfg.specForSize(0), memory_allocator) + _largeArrayType(cfg.spec_for_type_id(0), memory_allocator) { initArrayTypes(cfg, std::move(memory_allocator)); _store.init_primary_buffers(); @@ -45,16 +53,16 @@ ArrayStore<EntryT, RefT>::ArrayStore(const ArrayStoreConfig &cfg, std::shared_pt } } -template <typename EntryT, typename RefT> -ArrayStore<EntryT, RefT>::~ArrayStore() +template <typename EntryT, typename RefT, typename TypeMapperT> +ArrayStore<EntryT, RefT, TypeMapperT>::~ArrayStore() { _store.clearHoldLists(); _store.dropBuffers(); } -template <typename EntryT, typename RefT> +template <typename EntryT, typename RefT, typename TypeMapperT> EntryRef -ArrayStore<EntryT, RefT>::add(const ConstArrayRef &array) +ArrayStore<EntryT, RefT, TypeMapperT>::add(const ConstArrayRef &array) { if (array.size() == 0) { return EntryRef(); @@ -66,18 +74,18 @@ ArrayStore<EntryT, RefT>::add(const ConstArrayRef &array) } } -template <typename EntryT, typename RefT> +template <typename EntryT, typename RefT, typename TypeMapperT> EntryRef -ArrayStore<EntryT, RefT>::addSmallArray(const ConstArrayRef &array) +ArrayStore<EntryT, RefT, TypeMapperT>::addSmallArray(const ConstArrayRef &array) { - uint32_t typeId = getTypeId(array.size()); + uint32_t typeId = _mapper.get_type_id(array.size()); using NoOpReclaimer = DefaultReclaimer<EntryT>; return _store.template freeListAllocator<EntryT, NoOpReclaimer>(typeId).allocArray(array).ref; } -template <typename EntryT, typename RefT> +template <typename EntryT, typename RefT, typename TypeMapperT> EntryRef -ArrayStore<EntryT, RefT>::addLargeArray(const ConstArrayRef &array) +ArrayStore<EntryT, RefT, TypeMapperT>::addLargeArray(const ConstArrayRef &array) { using NoOpReclaimer = DefaultReclaimer<LargeArray>; auto handle = _store.template freeListAllocator<LargeArray, NoOpReclaimer>(_largeArrayTypeId) @@ -87,15 +95,15 @@ ArrayStore<EntryT, RefT>::addLargeArray(const ConstArrayRef &array) return handle.ref; } -template <typename EntryT, typename RefT> +template <typename EntryT, typename RefT, typename TypeMapperT> void -ArrayStore<EntryT, RefT>::remove(EntryRef ref) +ArrayStore<EntryT, RefT, TypeMapperT>::remove(EntryRef ref) { if (ref.valid()) { RefT internalRef(ref); uint32_t typeId = _store.getTypeId(internalRef.bufferId()); if (typeId != _largeArrayTypeId) { - size_t arraySize = getArraySize(typeId); + size_t arraySize = _mapper.get_array_size(typeId); _store.holdElem(ref, arraySize); } else { _store.holdElem(ref, 1, sizeof(EntryT) * get(ref).size()); @@ -105,10 +113,10 @@ ArrayStore<EntryT, RefT>::remove(EntryRef ref) namespace arraystore { -template <typename EntryT, typename RefT> +template <typename EntryT, typename RefT, typename TypeMapperT> class CompactionContext : public ICompactionContext { private: - using ArrayStoreType = ArrayStore<EntryT, RefT>; + using ArrayStoreType = ArrayStore<EntryT, RefT, TypeMapperT>; DataStoreBase &_dataStore; ArrayStoreType &_store; std::vector<uint32_t> _bufferIdsToCompact; @@ -141,39 +149,58 @@ public: } -template <typename EntryT, typename RefT> +template <typename EntryT, typename RefT, typename TypeMapperT> ICompactionContext::UP -ArrayStore<EntryT, RefT>::compactWorst(CompactionSpec compaction_spec, const CompactionStrategy &compaction_strategy) +ArrayStore<EntryT, RefT, TypeMapperT>::compactWorst(CompactionSpec compaction_spec, const CompactionStrategy &compaction_strategy) { std::vector<uint32_t> bufferIdsToCompact = _store.startCompactWorstBuffers(compaction_spec, compaction_strategy); - return std::make_unique<arraystore::CompactionContext<EntryT, RefT>> + return std::make_unique<arraystore::CompactionContext<EntryT, RefT, TypeMapperT>> (_store, *this, std::move(bufferIdsToCompact)); } -template <typename EntryT, typename RefT> +template <typename EntryT, typename RefT, typename TypeMapperT> vespalib::AddressSpace -ArrayStore<EntryT, RefT>::addressSpaceUsage() const +ArrayStore<EntryT, RefT, TypeMapperT>::addressSpaceUsage() const { return _store.getAddressSpaceUsage(); } -template <typename EntryT, typename RefT> +template <typename EntryT, typename RefT, typename TypeMapperT> const BufferState & -ArrayStore<EntryT, RefT>::bufferState(EntryRef ref) const +ArrayStore<EntryT, RefT, TypeMapperT>::bufferState(EntryRef ref) const { RefT internalRef(ref); return _store.getBufferState(internalRef.bufferId()); } -template <typename EntryT, typename RefT> +template <typename EntryT, typename RefT, typename TypeMapperT> +ArrayStoreConfig +ArrayStore<EntryT, RefT, TypeMapperT>::optimizedConfigForHugePage(uint32_t maxSmallArrayTypeId, + size_t hugePageSize, + size_t smallPageSize, + size_t minNumArraysForNewBuffer, + float allocGrowFactor) +{ + TypeMapper mapper; + return optimizedConfigForHugePage(maxSmallArrayTypeId, + mapper, + hugePageSize, + smallPageSize, + minNumArraysForNewBuffer, + allocGrowFactor); +} + +template <typename EntryT, typename RefT, typename TypeMapperT> ArrayStoreConfig -ArrayStore<EntryT, RefT>::optimizedConfigForHugePage(size_t maxSmallArraySize, - size_t hugePageSize, - size_t smallPageSize, - size_t minNumArraysForNewBuffer, - float allocGrowFactor) +ArrayStore<EntryT, RefT, TypeMapperT>::optimizedConfigForHugePage(uint32_t maxSmallArrayTypeId, + const TypeMapper& mapper, + size_t hugePageSize, + size_t smallPageSize, + size_t minNumArraysForNewBuffer, + float allocGrowFactor) { - return ArrayStoreConfig::optimizeForHugePage(maxSmallArraySize, + return ArrayStoreConfig::optimizeForHugePage(maxSmallArrayTypeId, + [&](uint32_t type_id) noexcept { return mapper.get_array_size(type_id); }, hugePageSize, smallPageSize, sizeof(EntryT), diff --git a/vespalib/src/vespa/vespalib/datastore/array_store_config.cpp b/vespalib/src/vespa/vespalib/datastore/array_store_config.cpp index ec51f5813ac..d5587841745 100644 --- a/vespalib/src/vespa/vespalib/datastore/array_store_config.cpp +++ b/vespalib/src/vespa/vespalib/datastore/array_store_config.cpp @@ -5,11 +5,11 @@ namespace vespalib::datastore { -ArrayStoreConfig::ArrayStoreConfig(size_t maxSmallArraySize, const AllocSpec &defaultSpec) +ArrayStoreConfig::ArrayStoreConfig(uint32_t maxSmallArrayTypeId, const AllocSpec &defaultSpec) : _allocSpecs(), _enable_free_lists(false) { - for (size_t i = 0; i < (maxSmallArraySize + 1); ++i) { + for (uint32_t type_id = 0; type_id < (maxSmallArrayTypeId + 1); ++type_id) { _allocSpecs.push_back(defaultSpec); } } @@ -21,10 +21,10 @@ ArrayStoreConfig::ArrayStoreConfig(const AllocSpecVector &allocSpecs) } const ArrayStoreConfig::AllocSpec & -ArrayStoreConfig::specForSize(size_t arraySize) const +ArrayStoreConfig::spec_for_type_id(uint32_t type_id) const { - assert(arraySize < _allocSpecs.size()); - return _allocSpecs[arraySize]; + assert(type_id < _allocSpecs.size()); + return _allocSpecs[type_id]; } namespace { @@ -45,7 +45,8 @@ alignToSmallPageSize(size_t value, size_t minLimit, size_t smallPageSize) } ArrayStoreConfig -ArrayStoreConfig::optimizeForHugePage(size_t maxSmallArraySize, +ArrayStoreConfig::optimizeForHugePage(uint32_t maxSmallArrayTypeId, + std::function<size_t(uint32_t)> type_id_to_array_size, size_t hugePageSize, size_t smallPageSize, size_t entrySize, @@ -55,7 +56,8 @@ ArrayStoreConfig::optimizeForHugePage(size_t maxSmallArraySize, { AllocSpecVector allocSpecs; allocSpecs.emplace_back(0, maxEntryRefOffset, minNumArraysForNewBuffer, allocGrowFactor); // large array spec; - for (size_t arraySize = 1; arraySize <= maxSmallArraySize; ++arraySize) { + for (uint32_t type_id = 1; type_id <= maxSmallArrayTypeId; ++type_id) { + size_t arraySize = type_id_to_array_size(type_id); size_t numArraysForNewBuffer = hugePageSize / (entrySize * arraySize); numArraysForNewBuffer = capToLimits(numArraysForNewBuffer, minNumArraysForNewBuffer, maxEntryRefOffset); numArraysForNewBuffer = alignToSmallPageSize(numArraysForNewBuffer, minNumArraysForNewBuffer, smallPageSize); diff --git a/vespalib/src/vespa/vespalib/datastore/array_store_config.h b/vespalib/src/vespa/vespalib/datastore/array_store_config.h index 36f52154b7b..a326c00d042 100644 --- a/vespalib/src/vespa/vespalib/datastore/array_store_config.h +++ b/vespalib/src/vespa/vespalib/datastore/array_store_config.h @@ -3,6 +3,8 @@ #pragma once #include <cstddef> +#include <cstdint> +#include <functional> #include <vector> namespace vespalib::datastore { @@ -42,21 +44,21 @@ private: bool _enable_free_lists; /** - * Setup an array store with arrays of size [1-(allocSpecs.size()-1)] allocated in buffers and - * larger arrays are heap allocated. The allocation spec for a given array size is found in the given vector. + * Setup an array store where buffer type ids [1-(allocSpecs.size()-1)] are used to allocate small arrays in datastore buffers and + * larger arrays are heap allocated. The allocation spec for a given buffer type is found in the given vector. * Allocation spec for large arrays is located at position 0. */ ArrayStoreConfig(const AllocSpecVector &allocSpecs); public: /** - * Setup an array store with arrays of size [1-maxSmallArraySize] allocated in buffers + * Setup an array store where buffer type ids [1-maxSmallArrayTypeId] are used to allocate small arrays in datastore buffers * with the given default allocation spec. Larger arrays are heap allocated. */ - ArrayStoreConfig(size_t maxSmallArraySize, const AllocSpec &defaultSpec); + ArrayStoreConfig(uint32_t maxSmallArrayTypeId, const AllocSpec &defaultSpec); - size_t maxSmallArraySize() const { return _allocSpecs.size() - 1; } - const AllocSpec &specForSize(size_t arraySize) const; + uint32_t maxSmallArrayTypeId() const { return _allocSpecs.size() - 1; } + const AllocSpec &spec_for_type_id(uint32_t type_id) const; ArrayStoreConfig& enable_free_lists(bool enable) & noexcept { _enable_free_lists = enable; return *this; @@ -70,7 +72,8 @@ public: /** * Generate a config that is optimized for the given memory huge page size. */ - static ArrayStoreConfig optimizeForHugePage(size_t maxSmallArraySize, + static ArrayStoreConfig optimizeForHugePage(uint32_t maxSmallArrayTypeId, + std::function<size_t(uint32_t)> type_id_to_array_size, size_t hugePageSize, size_t smallPageSize, size_t entrySize, diff --git a/vespalib/src/vespa/vespalib/datastore/array_store_type_mapper.h b/vespalib/src/vespa/vespalib/datastore/array_store_type_mapper.h new file mode 100644 index 00000000000..0fc1073d577 --- /dev/null +++ b/vespalib/src/vespa/vespalib/datastore/array_store_type_mapper.h @@ -0,0 +1,28 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#pragma once + +#include "large_array_buffer_type.h" +#include "small_array_buffer_type.h" + +namespace vespalib::datastore { + +/** + * This class provides a 1-to-1 mapping between type ids and array sizes for small arrays in an array store. + * + * This means that buffers for type id 1 stores arrays of size 1, buffers for type id 2 stores arrays of size 2, and so on. + * Type id 0 is always reserved for large arrays allocated on the heap. + * + * A more complex mapping can be used by creating a custom mapper and BufferType implementations. + */ +template <typename EntryT> +class ArrayStoreTypeMapper { +public: + using SmallBufferType = SmallArrayBufferType<EntryT>; + using LargeBufferType = LargeArrayBufferType<EntryT>; + + uint32_t get_type_id(size_t array_size) const { return array_size; } + size_t get_array_size(uint32_t type_id) const { return type_id; } +}; + +} |