summaryrefslogtreecommitdiffstats
path: root/searchlib
diff options
context:
space:
mode:
authorTor Egge <Tor.Egge@broadpark.no>2016-11-25 12:09:49 +0000
committerGitHub <noreply@github.com>2016-11-25 12:09:49 +0000
commit2446929eead5959e5ac84e3947907d16a2853200 (patch)
tree2573e875da44217303295163a48dbac6adafd432 /searchlib
parentd2e8f70a1962fe67c68ed96aab64474108961feb (diff)
parent72188280d37fecfa154da4ac18549a095fbdacd4 (diff)
Merge pull request #1179 from yahoo/geirst/optimize-array-store-for-huge-page-size
Geirst/optimize array store for huge page size
Diffstat (limited to 'searchlib')
-rw-r--r--searchlib/CMakeLists.txt1
-rw-r--r--searchlib/src/tests/attribute/multi_value_mapping2/multi_value_mapping2_test.cpp7
-rw-r--r--searchlib/src/tests/datastore/array_store/array_store_test.cpp2
-rw-r--r--searchlib/src/tests/datastore/array_store_config/CMakeLists.txt8
-rw-r--r--searchlib/src/tests/datastore/array_store_config/FILES1
-rw-r--r--searchlib/src/tests/datastore/array_store_config/array_store_config_test.cpp73
-rw-r--r--searchlib/src/vespa/searchlib/attribute/multi_value_mapping2.h9
-rw-r--r--searchlib/src/vespa/searchlib/attribute/multi_value_mapping2.hpp21
-rw-r--r--searchlib/src/vespa/searchlib/attribute/multivalueattribute.hpp12
-rw-r--r--searchlib/src/vespa/searchlib/datastore/CMakeLists.txt1
-rw-r--r--searchlib/src/vespa/searchlib/datastore/array_store.h14
-rw-r--r--searchlib/src/vespa/searchlib/datastore/array_store.hpp39
-rw-r--r--searchlib/src/vespa/searchlib/datastore/array_store_config.cpp66
-rw-r--r--searchlib/src/vespa/searchlib/datastore/array_store_config.h66
14 files changed, 286 insertions, 34 deletions
diff --git a/searchlib/CMakeLists.txt b/searchlib/CMakeLists.txt
index 7a5b654e2c0..bc342c594d1 100644
--- a/searchlib/CMakeLists.txt
+++ b/searchlib/CMakeLists.txt
@@ -104,6 +104,7 @@ vespa_define_module(
src/tests/common/sequencedtaskexecutor
src/tests/common/summaryfeatures
src/tests/datastore/array_store
+ src/tests/datastore/array_store_config
src/tests/datastore/datastore
src/tests/diskindex/bitvector
src/tests/diskindex/diskindex
diff --git a/searchlib/src/tests/attribute/multi_value_mapping2/multi_value_mapping2_test.cpp b/searchlib/src/tests/attribute/multi_value_mapping2/multi_value_mapping2_test.cpp
index 01cc4fd7154..6f0b7fe5e49 100644
--- a/searchlib/src/tests/attribute/multi_value_mapping2/multi_value_mapping2_test.cpp
+++ b/searchlib/src/tests/attribute/multi_value_mapping2/multi_value_mapping2_test.cpp
@@ -11,6 +11,8 @@ LOG_SETUP("multivaluemapping2_test");
#include <vespa/searchlib/util/rand48.h>
#include <vespa/vespalib/stllike/hash_set.h>
+using search::datastore::ArrayStoreConfig;
+
template <typename EntryT>
void
assertArray(const std::vector<EntryT> &exp, vespalib::ConstArrayRef<EntryT> values)
@@ -64,17 +66,18 @@ protected:
using MvMapping = search::attribute::MultiValueMapping2<EntryT>;
MvMapping _mvMapping;
MyAttribute<MvMapping> _attr;
+ using RefType = typename MvMapping::RefType;
using generation_t = vespalib::GenerationHandler::generation_t;
public:
using ConstArrayRef = vespalib::ConstArrayRef<EntryT>;
Fixture(uint32_t maxSmallArraySize)
- : _mvMapping(maxSmallArraySize),
+ : _mvMapping(ArrayStoreConfig(maxSmallArraySize, ArrayStoreConfig::AllocSpec(0, RefType::offsetSize(), 8 * 1024))),
_attr(_mvMapping)
{
}
Fixture(uint32_t maxSmallArraySize, size_t minClusters, size_t maxClusters, size_t numClustersForNewBuffer)
- : _mvMapping(maxSmallArraySize, minClusters, maxClusters, numClustersForNewBuffer),
+ : _mvMapping(ArrayStoreConfig(maxSmallArraySize, ArrayStoreConfig::AllocSpec(minClusters, maxClusters, numClustersForNewBuffer))),
_attr(_mvMapping)
{
}
diff --git a/searchlib/src/tests/datastore/array_store/array_store_test.cpp b/searchlib/src/tests/datastore/array_store/array_store_test.cpp
index 161df30f3cc..39cd458a1da 100644
--- a/searchlib/src/tests/datastore/array_store/array_store_test.cpp
+++ b/searchlib/src/tests/datastore/array_store/array_store_test.cpp
@@ -53,7 +53,7 @@ struct Fixture
ReferenceStore refStore;
generation_t generation;
Fixture(uint32_t maxSmallArraySize)
- : store(maxSmallArraySize),
+ : store(ArrayStoreConfig(maxSmallArraySize, ArrayStoreConfig::AllocSpec(16, RefT::offsetSize(), 8 * 1024))),
refStore(),
generation(1)
{}
diff --git a/searchlib/src/tests/datastore/array_store_config/CMakeLists.txt b/searchlib/src/tests/datastore/array_store_config/CMakeLists.txt
new file mode 100644
index 00000000000..465e697553a
--- /dev/null
+++ b/searchlib/src/tests/datastore/array_store_config/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(searchlib_array_store_config_test_app TEST
+ SOURCES
+ array_store_config_test.cpp
+ DEPENDS
+ searchlib
+)
+vespa_add_test(NAME searchlib_array_store_config_test_app COMMAND searchlib_array_store_config_test_app)
diff --git a/searchlib/src/tests/datastore/array_store_config/FILES b/searchlib/src/tests/datastore/array_store_config/FILES
new file mode 100644
index 00000000000..71f4e3f5b8c
--- /dev/null
+++ b/searchlib/src/tests/datastore/array_store_config/FILES
@@ -0,0 +1 @@
+array_store_config_test.cpp
diff --git a/searchlib/src/tests/datastore/array_store_config/array_store_config_test.cpp b/searchlib/src/tests/datastore/array_store_config/array_store_config_test.cpp
new file mode 100644
index 00000000000..bc7a446b3b4
--- /dev/null
+++ b/searchlib/src/tests/datastore/array_store_config/array_store_config_test.cpp
@@ -0,0 +1,73 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/fastos/fastos.h>
+#include <vespa/log/log.h>
+LOG_SETUP("array_store_config_test");
+#include <vespa/vespalib/testkit/testapp.h>
+#include <vespa/searchlib/datastore/entryref.h>
+#include <vespa/searchlib/datastore/array_store_config.h>
+
+using namespace search::datastore;
+using AllocSpec = ArrayStoreConfig::AllocSpec;
+
+struct Fixture
+{
+ using EntryRefType = EntryRefT<18>;
+ ArrayStoreConfig cfg;
+
+ Fixture(uint32_t maxSmallArraySize,
+ const AllocSpec &defaultSpec)
+ : cfg(maxSmallArraySize, defaultSpec) {}
+
+ Fixture(uint32_t maxSmallArraySize,
+ size_t hugePageSize,
+ size_t smallPageSize,
+ size_t minNumArraysForNewBuffer)
+ : cfg(ArrayStoreConfig::optimizeForHugePage(maxSmallArraySize, hugePageSize, smallPageSize,
+ sizeof(int), EntryRefType::offsetSize(),
+ minNumArraysForNewBuffer)) { }
+ void assertSpec(size_t arraySize, uint32_t numArraysForNewBuffer) {
+ assertSpec(arraySize, AllocSpec(0, EntryRefType::offsetSize(), numArraysForNewBuffer));
+ }
+ void assertSpec(size_t arraySize, const AllocSpec &expSpec) {
+ const ArrayStoreConfig::AllocSpec &actSpec = cfg.specForSize(arraySize);
+ EXPECT_EQUAL(expSpec.minArraysInBuffer, actSpec.minArraysInBuffer);
+ EXPECT_EQUAL(expSpec.maxArraysInBuffer, actSpec.maxArraysInBuffer);
+ EXPECT_EQUAL(expSpec.numArraysForNewBuffer, actSpec.numArraysForNewBuffer);
+ }
+};
+
+constexpr size_t KB = 1024;
+constexpr size_t MB = KB * KB;
+
+TEST_F("require that default allocation spec is given for all array sizes", Fixture(3, AllocSpec(4, 32, 8)))
+{
+ EXPECT_EQUAL(3, f.cfg.maxSmallArraySize());
+ TEST_DO(f.assertSpec(0, AllocSpec(4, 32, 8)));
+ TEST_DO(f.assertSpec(1, AllocSpec(4, 32, 8)));
+ TEST_DO(f.assertSpec(2, AllocSpec(4, 32, 8)));
+ TEST_DO(f.assertSpec(3, AllocSpec(4, 32, 8)));
+}
+
+TEST_F("require that we can generate config optimized for a given huge page", Fixture(1024,
+ 2 * MB,
+ 4 * KB,
+ 8 * KB))
+{
+ EXPECT_EQUAL(1024, f.cfg.maxSmallArraySize());
+ TEST_DO(f.assertSpec(0, 8 * KB)); // large arrays
+ TEST_DO(f.assertSpec(1, 256 * KB));
+ TEST_DO(f.assertSpec(2, 256 * KB));
+ TEST_DO(f.assertSpec(3, 168 * KB));
+ TEST_DO(f.assertSpec(4, 128 * KB));
+ TEST_DO(f.assertSpec(5, 100 * KB));
+ TEST_DO(f.assertSpec(6, 84 * KB));
+
+ TEST_DO(f.assertSpec(32, 16 * KB));
+ TEST_DO(f.assertSpec(33, 12 * KB));
+ TEST_DO(f.assertSpec(42, 12 * KB));
+ TEST_DO(f.assertSpec(43, 8 * KB));
+ TEST_DO(f.assertSpec(1022, 8 * KB));
+ TEST_DO(f.assertSpec(1023, 8 * KB));
+}
+
+TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/searchlib/src/vespa/searchlib/attribute/multi_value_mapping2.h b/searchlib/src/vespa/searchlib/attribute/multi_value_mapping2.h
index 471bce229bd..417ed17720f 100644
--- a/searchlib/src/vespa/searchlib/attribute/multi_value_mapping2.h
+++ b/searchlib/src/vespa/searchlib/attribute/multi_value_mapping2.h
@@ -25,9 +25,7 @@ private:
ArrayStore _store;
public:
- MultiValueMapping2(uint32_t maxSmallArraySize,
- const GrowStrategy &gs = GrowStrategy());
- MultiValueMapping2(uint32_t maxSmallArraySize, size_t minClusters, size_t maxClusters, size_t numClustersForNewBuffer,
+ MultiValueMapping2(const datastore::ArrayStoreConfig &storeCfg,
const GrowStrategy &gs = GrowStrategy());
virtual ~MultiValueMapping2();
ConstArrayRef get(uint32_t docId) const { return _store.get(_indices[docId]); }
@@ -55,6 +53,11 @@ public:
bool enoughCapacity(const Histogram &) { return true; }
void performCompaction(Histogram &) { }
void reset(uint32_t, const Histogram &) { }
+
+ static datastore::ArrayStoreConfig optimizedConfigForHugePage(size_t maxSmallArraySize,
+ size_t hugePageSize,
+ size_t smallPageSize,
+ size_t minNumArraysForNewBuffer);
};
} // namespace search::attribute
diff --git a/searchlib/src/vespa/searchlib/attribute/multi_value_mapping2.hpp b/searchlib/src/vespa/searchlib/attribute/multi_value_mapping2.hpp
index b5653c3a046..85a199968db 100644
--- a/searchlib/src/vespa/searchlib/attribute/multi_value_mapping2.hpp
+++ b/searchlib/src/vespa/searchlib/attribute/multi_value_mapping2.hpp
@@ -8,16 +8,9 @@ namespace search {
namespace attribute {
template <typename EntryT, typename RefT>
-MultiValueMapping2<EntryT,RefT>::MultiValueMapping2(uint32_t maxSmallArraySize, const GrowStrategy &gs)
+MultiValueMapping2<EntryT,RefT>::MultiValueMapping2(const datastore::ArrayStoreConfig &storeCfg, const GrowStrategy &gs)
: MultiValueMapping2Base(gs, _store.getGenerationHolder()),
- _store(maxSmallArraySize)
-{
-}
-
-template <typename EntryT, typename RefT>
-MultiValueMapping2<EntryT,RefT>::MultiValueMapping2(uint32_t maxSmallArraySize, size_t minClusters, size_t maxClusters, size_t numClustersForNewBuffer, const GrowStrategy &gs)
- : MultiValueMapping2Base(gs, _store.getGenerationHolder()),
- _store(maxSmallArraySize, minClusters, maxClusters, numClustersForNewBuffer)
+ _store(storeCfg)
{
}
@@ -75,5 +68,15 @@ MultiValueMapping2<EntryT, RefT>::getAddressSpaceUsage() const {
return _store.addressSpaceUsage();
}
+template <typename EntryT, typename RefT>
+datastore::ArrayStoreConfig
+MultiValueMapping2<EntryT, RefT>::optimizedConfigForHugePage(size_t maxSmallArraySize,
+ size_t hugePageSize,
+ size_t smallPageSize,
+ size_t minNumArraysForNewBuffer)
+{
+ return ArrayStore::optimizedConfigForHugePage(maxSmallArraySize, hugePageSize, smallPageSize, minNumArraysForNewBuffer);
+}
+
} // namespace search::attribute
} // namespace search
diff --git a/searchlib/src/vespa/searchlib/attribute/multivalueattribute.hpp b/searchlib/src/vespa/searchlib/attribute/multivalueattribute.hpp
index c0a7ce76de3..aa048563ff1 100644
--- a/searchlib/src/vespa/searchlib/attribute/multivalueattribute.hpp
+++ b/searchlib/src/vespa/searchlib/attribute/multivalueattribute.hpp
@@ -6,12 +6,22 @@
namespace search {
+namespace multivalueattribute {
+
+constexpr size_t HUGE_MEMORY_PAGE_SIZE = 2 * 1024 * 1024;
+constexpr size_t SMALL_MEMORY_PAGE_SIZE = 4 * 1024;
+
+}
+
template <typename B, typename M>
MultiValueAttribute<B, M>::
MultiValueAttribute(const vespalib::string &baseFileName,
const AttributeVector::Config &cfg)
: B(baseFileName, cfg),
- _mvMapping(1023, cfg.getGrowStrategy())
+ _mvMapping(MultiValueMapping::optimizedConfigForHugePage(1023,
+ multivalueattribute::HUGE_MEMORY_PAGE_SIZE,
+ multivalueattribute::SMALL_MEMORY_PAGE_SIZE,
+ 8 * 1024), cfg.getGrowStrategy())
{
}
diff --git a/searchlib/src/vespa/searchlib/datastore/CMakeLists.txt b/searchlib/src/vespa/searchlib/datastore/CMakeLists.txt
index 3b67548d719..a54cbc7c479 100644
--- a/searchlib/src/vespa/searchlib/datastore/CMakeLists.txt
+++ b/searchlib/src/vespa/searchlib/datastore/CMakeLists.txt
@@ -1,6 +1,7 @@
# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
vespa_add_library(searchlib_datastore OBJECT
SOURCES
+ array_store_config.cpp
buffer_type.cpp
bufferstate.cpp
datastore.cpp
diff --git a/searchlib/src/vespa/searchlib/datastore/array_store.h b/searchlib/src/vespa/searchlib/datastore/array_store.h
index 0ed5c627cc0..94a656f960d 100644
--- a/searchlib/src/vespa/searchlib/datastore/array_store.h
+++ b/searchlib/src/vespa/searchlib/datastore/array_store.h
@@ -2,6 +2,7 @@
#pragma once
+#include "array_store_config.h"
#include "buffer_type.h"
#include "bufferstate.h"
#include "datastore.h"
@@ -31,6 +32,7 @@ public:
using DataStoreType = DataStoreT<RefT>;
using SmallArrayType = BufferType<EntryT>;
using LargeArray = vespalib::Array<EntryT>;
+ using AllocSpec = ArrayStoreConfig::AllocSpec;
private:
class LargeArrayType : public BufferType<LargeArray> {
@@ -39,7 +41,7 @@ private:
using ParentType::_emptyEntry;
using CleanContext = typename ParentType::CleanContext;
public:
- LargeArrayType();
+ LargeArrayType(const AllocSpec &spec);
virtual void cleanHold(void *buffer, uint64_t offset, uint64_t len, CleanContext cleanCtx) override;
};
@@ -51,7 +53,7 @@ private:
uint32_t _largeArrayTypeId;
using generation_t = vespalib::GenerationHandler::generation_t;
- void initArrayTypes(size_t minClusters, size_t maxClusters, size_t numClustersForNewBuffer);
+ void initArrayTypes(const ArrayStoreConfig &cfg);
// 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; }
@@ -61,8 +63,7 @@ private:
ConstArrayRef getLargeArray(RefT ref) const;
public:
- ArrayStore(uint32_t maxSmallArraySize);
- ArrayStore(uint32_t maxSmallArraySize, size_t minClusters, size_t maxClusters, size_t numClustersForNewBuffer);
+ ArrayStore(const ArrayStoreConfig &cfg);
~ArrayStore();
EntryRef add(const ConstArrayRef &array);
ConstArrayRef get(EntryRef ref) const;
@@ -84,6 +85,11 @@ public:
// Should only be used for unit testing
const BufferState &bufferState(EntryRef ref) const;
+
+ static ArrayStoreConfig optimizedConfigForHugePage(size_t maxSmallArraySize,
+ size_t hugePageSize,
+ size_t smallPageSize,
+ size_t minNumArraysForNewBuffer);
};
}
diff --git a/searchlib/src/vespa/searchlib/datastore/array_store.hpp b/searchlib/src/vespa/searchlib/datastore/array_store.hpp
index 1e98f3a4702..ba437fb265d 100644
--- a/searchlib/src/vespa/searchlib/datastore/array_store.hpp
+++ b/searchlib/src/vespa/searchlib/datastore/array_store.hpp
@@ -12,8 +12,8 @@ namespace datastore {
constexpr size_t MIN_BUFFER_CLUSTERS = 8192;
template <typename EntryT, typename RefT>
-ArrayStore<EntryT, RefT>::LargeArrayType::LargeArrayType()
- : BufferType<LargeArray>(1, MIN_BUFFER_CLUSTERS, RefT::offsetSize())
+ArrayStore<EntryT, RefT>::LargeArrayType::LargeArrayType(const AllocSpec &spec)
+ : BufferType<LargeArray>(1, spec.minArraysInBuffer, spec.maxArraysInBuffer, spec.numArraysForNewBuffer)
{
}
@@ -31,32 +31,28 @@ ArrayStore<EntryT, RefT>::LargeArrayType::cleanHold(void *buffer, uint64_t offse
template <typename EntryT, typename RefT>
void
-ArrayStore<EntryT, RefT>::initArrayTypes(size_t minClusters, size_t maxClusters, size_t numClustersForNewBuffer)
+ArrayStore<EntryT, RefT>::initArrayTypes(const ArrayStoreConfig &cfg)
{
_largeArrayTypeId = _store.addType(&_largeArrayType);
assert(_largeArrayTypeId == 0);
for (uint32_t arraySize = 1; arraySize <= _maxSmallArraySize; ++arraySize) {
- _smallArrayTypes.push_back(std::make_unique<SmallArrayType>(arraySize, minClusters, maxClusters, numClustersForNewBuffer));
+ const AllocSpec &spec = cfg.specForSize(arraySize);
+ _smallArrayTypes.push_back(std::make_unique<SmallArrayType>
+ (arraySize, spec.minArraysInBuffer, spec.maxArraysInBuffer, spec.numArraysForNewBuffer));
uint32_t typeId = _store.addType(_smallArrayTypes.back().get());
assert(typeId == arraySize); // Enforce 1-to-1 mapping between type ids and sizes for small arrays
}
}
template <typename EntryT, typename RefT>
-ArrayStore<EntryT, RefT>::ArrayStore(uint32_t maxSmallArraySize)
- : ArrayStore<EntryT,RefT>(maxSmallArraySize, 0, RefT::offsetSize(), MIN_BUFFER_CLUSTERS)
-{
-}
-
-template <typename EntryT, typename RefT>
-ArrayStore<EntryT, RefT>::ArrayStore(uint32_t maxSmallArraySize, size_t minClusters, size_t maxClusters, size_t numClustersForNewBuffer)
+ArrayStore<EntryT, RefT>::ArrayStore(const ArrayStoreConfig &cfg)
: _store(),
- _maxSmallArraySize(maxSmallArraySize),
+ _maxSmallArraySize(cfg.maxSmallArraySize()),
_smallArrayTypes(),
- _largeArrayType(),
+ _largeArrayType(cfg.specForSize(0)),
_largeArrayTypeId()
{
- initArrayTypes(minClusters, maxClusters, numClustersForNewBuffer);
+ initArrayTypes(cfg);
_store.initActiveBuffers();
}
@@ -228,5 +224,20 @@ ArrayStore<EntryT, RefT>::bufferState(EntryRef ref) const
return _store.getBufferState(internalRef.bufferId());
}
+template <typename EntryT, typename RefT>
+ArrayStoreConfig
+ArrayStore<EntryT, RefT>::optimizedConfigForHugePage(size_t maxSmallArraySize,
+ size_t hugePageSize,
+ size_t smallPageSize,
+ size_t minNumArraysForNewBuffer)
+{
+ return ArrayStoreConfig::optimizeForHugePage(maxSmallArraySize,
+ hugePageSize,
+ smallPageSize,
+ sizeof(EntryT),
+ RefT::offsetSize(),
+ minNumArraysForNewBuffer);
+}
+
}
}
diff --git a/searchlib/src/vespa/searchlib/datastore/array_store_config.cpp b/searchlib/src/vespa/searchlib/datastore/array_store_config.cpp
new file mode 100644
index 00000000000..1710e41069b
--- /dev/null
+++ b/searchlib/src/vespa/searchlib/datastore/array_store_config.cpp
@@ -0,0 +1,66 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/fastos/fastos.h>
+#include "array_store_config.h"
+
+namespace search {
+namespace datastore {
+
+ArrayStoreConfig::ArrayStoreConfig(size_t maxSmallArraySize, const AllocSpec &defaultSpec)
+ : _allocSpecs()
+{
+ for (size_t i = 0; i < (maxSmallArraySize + 1); ++i) {
+ _allocSpecs.push_back(defaultSpec);
+ }
+}
+
+ArrayStoreConfig::ArrayStoreConfig(const AllocSpecVector &allocSpecs)
+ : _allocSpecs(allocSpecs)
+{
+}
+
+const ArrayStoreConfig::AllocSpec &
+ArrayStoreConfig::specForSize(size_t arraySize) const
+{
+ assert(arraySize < _allocSpecs.size());
+ return _allocSpecs[arraySize];
+}
+
+namespace {
+
+size_t
+capToLimits(size_t value, size_t minLimit, size_t maxLimit)
+{
+ size_t result = std::max(value, minLimit);
+ return std::min(result, maxLimit);
+}
+
+size_t
+alignToSmallPageSize(size_t value, size_t minLimit, size_t smallPageSize)
+{
+ return ((value - minLimit) / smallPageSize) * smallPageSize + minLimit;
+}
+
+}
+
+ArrayStoreConfig
+ArrayStoreConfig::optimizeForHugePage(size_t maxSmallArraySize,
+ size_t hugePageSize,
+ size_t smallPageSize,
+ size_t entrySize,
+ size_t maxEntryRefOffset,
+ size_t minNumArraysForNewBuffer)
+{
+ AllocSpecVector allocSpecs;
+ allocSpecs.emplace_back(0, maxEntryRefOffset, minNumArraysForNewBuffer); // large array spec;
+ for (size_t arraySize = 1; arraySize <= maxSmallArraySize; ++arraySize) {
+ size_t numArraysForNewBuffer = hugePageSize / (entrySize * arraySize);
+ numArraysForNewBuffer = capToLimits(numArraysForNewBuffer, minNumArraysForNewBuffer, maxEntryRefOffset);
+ numArraysForNewBuffer = alignToSmallPageSize(numArraysForNewBuffer, minNumArraysForNewBuffer, smallPageSize);
+ allocSpecs.emplace_back(0, maxEntryRefOffset, numArraysForNewBuffer);
+ }
+ return ArrayStoreConfig(allocSpecs);
+}
+
+}
+}
diff --git a/searchlib/src/vespa/searchlib/datastore/array_store_config.h b/searchlib/src/vespa/searchlib/datastore/array_store_config.h
new file mode 100644
index 00000000000..6ada8cdae05
--- /dev/null
+++ b/searchlib/src/vespa/searchlib/datastore/array_store_config.h
@@ -0,0 +1,66 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+namespace search {
+namespace datastore {
+
+/**
+ * Config specifying layout and buffer allocation strategy for an array store.
+ */
+class ArrayStoreConfig
+{
+public:
+ /**
+ * Specification of buffer allocation strategy for arrays of a given size.
+ */
+ struct AllocSpec {
+ // Minimum number of arrays to allocate in a buffer.
+ size_t minArraysInBuffer;
+ // Maximum number of arrays to allocate in a buffer.
+ size_t maxArraysInBuffer;
+ // Number of arrays needed before allocating a new buffer instead of just resizing the first one.
+ size_t numArraysForNewBuffer;
+ AllocSpec(size_t minArraysInBuffer_,
+ size_t maxArraysInBuffer_,
+ size_t numArraysForNewBuffer_)
+ : minArraysInBuffer(minArraysInBuffer_),
+ maxArraysInBuffer(maxArraysInBuffer_),
+ numArraysForNewBuffer(numArraysForNewBuffer_) {}
+ };
+
+ using AllocSpecVector = std::vector<AllocSpec>;
+
+private:
+ AllocSpecVector _allocSpecs;
+
+ /**
+ * 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.
+ * 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
+ * with the given default allocation spec. Larger arrays are heap allocated.
+ */
+ ArrayStoreConfig(size_t maxSmallArraySize, const AllocSpec &defaultSpec);
+
+ size_t maxSmallArraySize() const { return _allocSpecs.size() - 1; }
+ const AllocSpec &specForSize(size_t arraySize) const;
+
+ /**
+ * Generate a config that is optimized for the given memory huge page size.
+ */
+ static ArrayStoreConfig optimizeForHugePage(size_t maxSmallArraySize,
+ size_t hugePageSize,
+ size_t smallPageSize,
+ size_t entrySize,
+ size_t maxEntryRefOffset,
+ size_t minNumArraysForNewBuffer);
+};
+
+}
+}