aboutsummaryrefslogtreecommitdiffstats
path: root/vespalib
diff options
context:
space:
mode:
authorGeir Storli <geirst@yahooinc.com>2022-09-29 12:37:54 +0000
committerGeir Storli <geirst@yahooinc.com>2022-09-29 12:37:54 +0000
commit2381228f5f732282510adfe03f51d52341c618dd (patch)
treebc6dee336e6f5300f9c1c800200df2da62827f1f /vespalib
parent8b463cd632fa4dac1d5809b950d96c51a1101275 (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')
-rw-r--r--vespalib/src/tests/datastore/array_store/array_store_test.cpp4
-rw-r--r--vespalib/src/tests/datastore/array_store_config/array_store_config_test.cpp24
-rw-r--r--vespalib/src/vespa/vespalib/datastore/array_store.h40
-rw-r--r--vespalib/src/vespa/vespalib/datastore/array_store.hpp109
-rw-r--r--vespalib/src/vespa/vespalib/datastore/array_store_config.cpp16
-rw-r--r--vespalib/src/vespa/vespalib/datastore/array_store_config.h17
-rw-r--r--vespalib/src/vespa/vespalib/datastore/array_store_type_mapper.h28
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; }
+};
+
+}