diff options
author | Geir Storli <geirstorli@yahoo.no> | 2016-11-23 09:43:57 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-11-23 09:43:57 +0100 |
commit | aae2ec4d391352dc7d9db692f6377f00ca26f99e (patch) | |
tree | bb6ec810f3df9ab2a9203241c7e06b73fb70813d /searchlib | |
parent | 7910e750249203f69df10838499ae0263e813f20 (diff) | |
parent | 24b30fcbca1afdfa2abc5ba0e4368b7fcf58c734 (diff) |
Merge pull request #1161 from yahoo/toregge/tweak-buffer-type-allocations
Toregge/tweak buffer type allocations
Diffstat (limited to 'searchlib')
14 files changed, 154 insertions, 67 deletions
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 54a643e689a..474f361d9c4 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 @@ -73,8 +73,8 @@ public: _attr(_mvMapping) { } - Fixture(uint32_t maxSmallArraySize, size_t minClusters, size_t maxClusters) - : _mvMapping(maxSmallArraySize, minClusters, maxClusters), + Fixture(uint32_t maxSmallArraySize, size_t minClusters, size_t maxClusters, size_t numClustersForNewBuffer) + : _mvMapping(maxSmallArraySize, minClusters, maxClusters, numClustersForNewBuffer), _attr(_mvMapping) { } @@ -146,8 +146,8 @@ public: _rnd.srand48(32); } - IntFixture(uint32_t maxSmallArraySize, size_t minClusters, size_t maxClusters) - : Fixture<int>(maxSmallArraySize, minClusters, maxClusters), + IntFixture(uint32_t maxSmallArraySize, size_t minClusters, size_t maxClusters, size_t numClustersForNewBuffer) + : Fixture<int>(maxSmallArraySize, minClusters, maxClusters, numClustersForNewBuffer), _rnd(), _refMapping(), _maxSmallArraySize(maxSmallArraySize) @@ -295,7 +295,7 @@ TEST_F("Test that replace works", Fixture<int>(3)) EXPECT_EQUAL(4u, f.getTotalValueCnt()); } -TEST_F("Test that compaction works", IntFixture(3, 64, 512)) +TEST_F("Test that compaction works", IntFixture(3, 64, 512, 129)) { uint32_t addDocs = 10; uint32_t bufferCountBefore = 0; diff --git a/searchlib/src/tests/datastore/datastore/datastore_test.cpp b/searchlib/src/tests/datastore/datastore/datastore_test.cpp index de673c8c0c9..5cfd88cc1da 100644 --- a/searchlib/src/tests/datastore/datastore/datastore_test.cpp +++ b/searchlib/src/tests/datastore/datastore/datastore_test.cpp @@ -5,6 +5,7 @@ LOG_SETUP("datastore_test"); #include <vespa/vespalib/testkit/testapp.h> #include <vespa/searchlib/datastore/datastore.h> #include <vespa/searchlib/datastore/datastore.hpp> +#include <vespa/vespalib/test/insertion_operators.h> namespace search { namespace datastore { @@ -59,6 +60,47 @@ public: size_t activeBufferId() const { return _activeBufferIds[0]; } }; + +using GrowthStats = std::vector<int>; + +class GrowStore +{ + using Store = DataStoreT<EntryRefT<22>>; + using RefType = Store::RefType; + Store _store; + BufferType<int> _type; + uint32_t _typeId; +public: + GrowStore(size_t minSwitch) + : _store(), + _type(1, 4, 64, minSwitch), + _typeId(0) + { + _typeId = _store.addType(&_type); + _store.initActiveBuffers(); + } + GrowStore() : GrowStore(0) { } + ~GrowStore() { _store.dropBuffers(); } + + GrowthStats getGrowthStats(size_t bufs) { + GrowthStats sizes; + int i = 0; + int prevBuffer = -1; + while (sizes.size() < bufs) { + RefType iRef = _store.allocNewEntry<int>(_typeId).first; + int buffer = iRef.bufferId(); + if (buffer != prevBuffer) { + if (prevBuffer >= 0) { + sizes.push_back(i); + } + prevBuffer = buffer; + } + ++i; + } + return sizes; + } +}; + typedef MyStore::RefType MyRef; class Test : public vespalib::TestApp { @@ -74,9 +116,8 @@ private: void requireThatWeCanUseFreeLists(); void requireThatMemoryStatsAreCalculated(); void requireThatMemoryUsageIsCalculated(); - - void - requireThatWecanDisableElemHoldList(void); + void requireThatWecanDisableElemHoldList(void); + void requireThatBufferGrowthWorks(); public: int Main(); }; @@ -406,6 +447,19 @@ Test::requireThatWecanDisableElemHoldList(void) s.trimHoldLists(101); } +void +Test::requireThatBufferGrowthWorks() +{ + // Always switch to new buffer + // Buffer sizes: 4, 8, 16, 32, 64, 64, 64, 64 + // First element in first buffer reserved + EXPECT_EQUAL(GrowthStats({ 3, 11, 27, 59, 123, 187,251, 315}), GrowStore().getGrowthStats(8)); + // Resize current buffer if new buffer size would be less than 32 + // Buffer sizes: 32, 36, 64, 64, 64, 64, 64, 64 + // First element in first buffer reserved + EXPECT_EQUAL(GrowthStats({ 31, 67, 131, 195, 259,323,387,451}), GrowStore(32).getGrowthStats(8)); +} + int Test::Main() { @@ -421,6 +475,7 @@ Test::Main() requireThatMemoryStatsAreCalculated(); requireThatMemoryUsageIsCalculated(); requireThatWecanDisableElemHoldList(); + requireThatBufferGrowthWorks(); TEST_DONE(); } diff --git a/searchlib/src/vespa/searchlib/attribute/enumstorebase.cpp b/searchlib/src/vespa/searchlib/attribute/enumstorebase.cpp index df3f9f18037..dbfd8744210 100644 --- a/searchlib/src/vespa/searchlib/attribute/enumstorebase.cpp +++ b/searchlib/src/vespa/searchlib/attribute/enumstorebase.cpp @@ -28,7 +28,7 @@ EnumStoreBase::EnumBufferType::EnumBufferType() } size_t -EnumStoreBase::EnumBufferType::calcClustersToAlloc(uint32_t bufferId, size_t sizeNeeded, uint64_t clusterRefSize, bool resizing) const +EnumStoreBase::EnumBufferType::calcClustersToAlloc(uint32_t bufferId, size_t sizeNeeded, bool resizing) const { (void) resizing; size_t reservedElements = getReservedElements(bufferId); @@ -39,7 +39,7 @@ EnumStoreBase::EnumBufferType::calcClustersToAlloc(uint32_t bufferId, size_t siz } assert((usedElems % _clusterSize) == 0); double growRatio = 1.5f; - uint64_t maxSize = clusterRefSize * _clusterSize; + uint64_t maxSize = static_cast<uint64_t>(_maxClusters) * _clusterSize; uint64_t newSize = usedElems - _deadElems + sizeNeeded; if (usedElems != 0) { newSize *= growRatio; @@ -54,9 +54,9 @@ EnumStoreBase::EnumBufferType::calcClustersToAlloc(uint32_t bufferId, size_t siz newSize = alignBufferSize(newSize); assert((newSize % _clusterSize) == 0); if (newSize <= maxSize) { - return clusterRefSize; + return _maxClusters; } - failNewSize(newSize, clusterRefSize * _clusterSize); + failNewSize(newSize, maxSize); return 0; } diff --git a/searchlib/src/vespa/searchlib/attribute/enumstorebase.h b/searchlib/src/vespa/searchlib/attribute/enumstorebase.h index 08d17728bbf..cda6ab465b7 100644 --- a/searchlib/src/vespa/searchlib/attribute/enumstorebase.h +++ b/searchlib/src/vespa/searchlib/attribute/enumstorebase.h @@ -324,7 +324,7 @@ protected: public: EnumBufferType(); - virtual size_t calcClustersToAlloc(uint32_t bufferId, size_t sizeNeeded, uint64_t clusterRefSize, bool resizing) const override; + virtual size_t calcClustersToAlloc(uint32_t bufferId, size_t sizeNeeded, bool resizing) const override; void setSizeNeededAndDead(uint64_t sizeNeeded, uint64_t deadElems) { _minSizeNeeded = sizeNeeded; diff --git a/searchlib/src/vespa/searchlib/attribute/multi_value_mapping2.h b/searchlib/src/vespa/searchlib/attribute/multi_value_mapping2.h index 91be1143ab6..3a5d9c98c6f 100644 --- a/searchlib/src/vespa/searchlib/attribute/multi_value_mapping2.h +++ b/searchlib/src/vespa/searchlib/attribute/multi_value_mapping2.h @@ -27,7 +27,7 @@ private: public: MultiValueMapping2(uint32_t maxSmallArraySize, const GrowStrategy &gs = GrowStrategy()); - MultiValueMapping2(uint32_t maxSmallArraySize, size_t minClusters, size_t maxClusters, + MultiValueMapping2(uint32_t maxSmallArraySize, size_t minClusters, size_t maxClusters, size_t numClustersForNewBuffer, const GrowStrategy &gs = GrowStrategy()); virtual ~MultiValueMapping2(); ConstArrayRef get(uint32_t docId) const { return _store.get(_indices[docId]); } diff --git a/searchlib/src/vespa/searchlib/attribute/multi_value_mapping2.hpp b/searchlib/src/vespa/searchlib/attribute/multi_value_mapping2.hpp index 9cfaba960b3..b5653c3a046 100644 --- a/searchlib/src/vespa/searchlib/attribute/multi_value_mapping2.hpp +++ b/searchlib/src/vespa/searchlib/attribute/multi_value_mapping2.hpp @@ -15,9 +15,9 @@ MultiValueMapping2<EntryT,RefT>::MultiValueMapping2(uint32_t maxSmallArraySize, } template <typename EntryT, typename RefT> -MultiValueMapping2<EntryT,RefT>::MultiValueMapping2(uint32_t maxSmallArraySize, size_t minClusters, size_t maxClusters, const GrowStrategy &gs) +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) + _store(maxSmallArraySize, minClusters, maxClusters, numClustersForNewBuffer) { } diff --git a/searchlib/src/vespa/searchlib/datastore/array_store.h b/searchlib/src/vespa/searchlib/datastore/array_store.h index 3a2d8b72988..45a9319b84b 100644 --- a/searchlib/src/vespa/searchlib/datastore/array_store.h +++ b/searchlib/src/vespa/searchlib/datastore/array_store.h @@ -51,7 +51,7 @@ private: uint32_t _largeArrayTypeId; using generation_t = vespalib::GenerationHandler::generation_t; - void initArrayTypes(size_t minClusters, size_t maxClusters); + void initArrayTypes(size_t minClusters, size_t maxClusters, size_t numClustersForNewBuffer); // 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; } @@ -62,7 +62,7 @@ private: public: ArrayStore(uint32_t maxSmallArraySize); - ArrayStore(uint32_t maxSmallArraySize, size_t minClusters, size_t maxClusters); + ArrayStore(uint32_t maxSmallArraySize, size_t minClusters, size_t maxClusters, size_t numClustersForNewBuffer); ~ArrayStore(); EntryRef add(const ConstArrayRef &array); ConstArrayRef get(EntryRef ref) const; diff --git a/searchlib/src/vespa/searchlib/datastore/array_store.hpp b/searchlib/src/vespa/searchlib/datastore/array_store.hpp index ad341a2f297..125d9dce0ff 100644 --- a/searchlib/src/vespa/searchlib/datastore/array_store.hpp +++ b/searchlib/src/vespa/searchlib/datastore/array_store.hpp @@ -31,12 +31,12 @@ 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) +ArrayStore<EntryT, RefT>::initArrayTypes(size_t minClusters, size_t maxClusters, size_t numClustersForNewBuffer) { _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)); + _smallArrayTypes.push_back(std::make_unique<SmallArrayType>(arraySize, minClusters, maxClusters, numClustersForNewBuffer)); uint32_t typeId = _store.addType(_smallArrayTypes.back().get()); assert(typeId == arraySize); // Enforce 1-to-1 mapping between type ids and sizes for small arrays } @@ -44,21 +44,19 @@ ArrayStore<EntryT, RefT>::initArrayTypes(size_t minClusters, size_t maxClusters) template <typename EntryT, typename RefT> ArrayStore<EntryT, RefT>::ArrayStore(uint32_t maxSmallArraySize) - : ArrayStore<EntryT,RefT>(maxSmallArraySize, MIN_BUFFER_CLUSTERS, RefT::offsetSize()) + : ArrayStore<EntryT,RefT>(maxSmallArraySize, MIN_BUFFER_CLUSTERS, RefT::offsetSize(), 0u) { } template <typename EntryT, typename RefT> -ArrayStore<EntryT, RefT>::ArrayStore(uint32_t maxSmallArraySize, size_t minClusters, size_t maxClusters) +ArrayStore<EntryT, RefT>::ArrayStore(uint32_t maxSmallArraySize, size_t minClusters, size_t maxClusters, size_t numClustersForNewBuffer) : _store(), _maxSmallArraySize(maxSmallArraySize), _smallArrayTypes(), _largeArrayType(), _largeArrayTypeId() { - maxClusters = std::min(maxClusters, RefT::offsetSize()); - minClusters = std::min(minClusters, maxClusters); - initArrayTypes(minClusters, maxClusters); + initArrayTypes(minClusters, maxClusters, numClustersForNewBuffer); _store.initActiveBuffers(); } diff --git a/searchlib/src/vespa/searchlib/datastore/buffer_type.cpp b/searchlib/src/vespa/searchlib/datastore/buffer_type.cpp index 5dbe7c052d6..6af02e31ef1 100644 --- a/searchlib/src/vespa/searchlib/datastore/buffer_type.cpp +++ b/searchlib/src/vespa/searchlib/datastore/buffer_type.cpp @@ -8,10 +8,12 @@ namespace datastore { BufferTypeBase::BufferTypeBase(uint32_t clusterSize, uint32_t minClusters, - uint32_t maxClusters) + uint32_t maxClusters, + uint32_t numClustersForNewBuffer) : _clusterSize(clusterSize), _minClusters(std::min(minClusters, maxClusters)), _maxClusters(maxClusters), + _numClustersForNewBuffer(std::min(numClustersForNewBuffer, maxClusters)), _activeBuffers(0), _holdBuffers(0), _activeUsedElems(0), @@ -21,6 +23,14 @@ BufferTypeBase::BufferTypeBase(uint32_t clusterSize, } +BufferTypeBase::BufferTypeBase(uint32_t clusterSize, + uint32_t minClusters, + uint32_t maxClusters) + : BufferTypeBase(clusterSize, minClusters, maxClusters, 0u) +{ +} + + BufferTypeBase::~BufferTypeBase(void) { assert(_activeBuffers == 0); @@ -82,12 +92,16 @@ BufferTypeBase::onFree(size_t usedElems) _holdUsedElems -= usedElems; } +void +BufferTypeBase::clampMaxClusters(uint32_t maxClusters) +{ + _maxClusters = std::min(_maxClusters, maxClusters); + _minClusters = std::min(_minClusters, _maxClusters); + _numClustersForNewBuffer = std::min(_numClustersForNewBuffer, _maxClusters); +}; size_t -BufferTypeBase::calcClustersToAlloc(uint32_t bufferId, - size_t sizeNeeded, - uint64_t clusterRefSize, - bool resizing) const +BufferTypeBase::calcClustersToAlloc(uint32_t bufferId, size_t sizeNeeded, bool resizing) const { size_t reservedElements = getReservedElements(bufferId); size_t usedElems = _activeUsedElems; @@ -95,26 +109,15 @@ BufferTypeBase::calcClustersToAlloc(uint32_t bufferId, usedElems += *_lastUsedElems; } assert((usedElems % _clusterSize) == 0); - uint64_t maxClusters = std::numeric_limits<size_t>::max() / _clusterSize; - uint64_t maxClusters2 = clusterRefSize; - if (maxClusters > maxClusters2) { - maxClusters = maxClusters2; - } - if (maxClusters > _maxClusters) { - maxClusters = _maxClusters; - } - uint32_t minClusters = _minClusters; - if (minClusters > maxClusters) { - minClusters = maxClusters; - } size_t usedClusters = usedElems / _clusterSize; size_t needClusters = (sizeNeeded + (resizing ? usedElems : reservedElements) + _clusterSize - 1) / _clusterSize; - uint64_t wantClusters = usedClusters + minClusters; + size_t minClusters = _minClusters; + uint64_t wantClusters = usedClusters + std::max(minClusters, (resizing ? usedClusters : 0u)); if (wantClusters < needClusters) { wantClusters = needClusters; } - if (wantClusters > maxClusters) { - wantClusters = maxClusters; + if (wantClusters > _maxClusters) { + wantClusters = _maxClusters; } assert(wantClusters >= needClusters); return wantClusters; diff --git a/searchlib/src/vespa/searchlib/datastore/buffer_type.h b/searchlib/src/vespa/searchlib/datastore/buffer_type.h index 0389e8b8a09..1889b37df11 100644 --- a/searchlib/src/vespa/searchlib/datastore/buffer_type.h +++ b/searchlib/src/vespa/searchlib/datastore/buffer_type.h @@ -15,6 +15,9 @@ protected: uint32_t _clusterSize; // Number of elements in an allocation unit uint32_t _minClusters; // Minimum number of clusters to allocate uint32_t _maxClusters; // Maximum number of clusters to allocate + // Number of clusters needed before allocating a new buffer + // instead of just resizing the first one + uint32_t _numClustersForNewBuffer; uint32_t _activeBuffers; uint32_t _holdBuffers; size_t _activeUsedElems; // used elements in all but last active buffer @@ -36,6 +39,7 @@ public: BufferTypeBase(const BufferTypeBase &rhs) = delete; BufferTypeBase & operator=(const BufferTypeBase &rhs) = delete; BufferTypeBase(uint32_t clusterSize, uint32_t minClusters, uint32_t maxClusters); + BufferTypeBase(uint32_t clusterSize, uint32_t minClusters, uint32_t maxClusters, uint32_t numClustersForNewBuffer); virtual ~BufferTypeBase(); virtual void destroyElements(void *buffer, size_t numElements) = 0; virtual void fallbackCopy(void *newBuffer, const void *oldBuffer, size_t numElements) = 0; @@ -61,9 +65,13 @@ public: * * @return number of clusters to allocate for new buffer */ - virtual size_t calcClustersToAlloc(uint32_t bufferId, size_t sizeNeeded, uint64_t clusterRefSize, bool resizing) const; + virtual size_t calcClustersToAlloc(uint32_t bufferId, size_t sizeNeeded, bool resizing) const; + + void clampMaxClusters(uint32_t maxClusters); uint32_t getActiveBuffers() const { return _activeBuffers; } + uint32_t getMaxClusters() const { return _maxClusters; } + uint32_t getNumClustersForNewBuffer() const { return _numClustersForNewBuffer; } }; @@ -79,7 +87,10 @@ public: : BufferTypeBase(clusterSize, minClusters, maxClusters), _emptyEntry() { } - + BufferType(uint32_t clusterSize, uint32_t minClusters, uint32_t maxClusters, uint32_t numClustersForNewBuffer) + : BufferTypeBase(clusterSize, minClusters, maxClusters, numClustersForNewBuffer), + _emptyEntry() + { } void destroyElements(void *buffer, size_t numElements) override; void fallbackCopy(void *newBuffer, const void *oldBuffer, size_t numElements) override; void initializeReservedElements(void *buffer, size_t reservedElements) override; diff --git a/searchlib/src/vespa/searchlib/datastore/bufferstate.cpp b/searchlib/src/vespa/searchlib/datastore/bufferstate.cpp index 5c85067bff5..9161fed94ee 100644 --- a/searchlib/src/vespa/searchlib/datastore/bufferstate.cpp +++ b/searchlib/src/vespa/searchlib/datastore/bufferstate.cpp @@ -51,7 +51,6 @@ void BufferState::onActive(uint32_t bufferId, uint32_t typeId, BufferTypeBase *typeHandler, size_t sizeNeeded, - size_t maxClusters, void *&buffer) { assert(buffer == NULL); @@ -71,7 +70,7 @@ BufferState::onActive(uint32_t bufferId, uint32_t typeId, size_t reservedElements = typeHandler->getReservedElements(bufferId); (void) reservedElements; - size_t allocClusters = typeHandler->calcClustersToAlloc(bufferId, sizeNeeded, maxClusters, false); + size_t allocClusters = typeHandler->calcClustersToAlloc(bufferId, sizeNeeded, false); size_t allocSize = allocClusters * typeHandler->getClusterSize(); assert(allocSize >= reservedElements + sizeNeeded); _buffer.create(allocSize * typeHandler->elementSize()).swap(_buffer); @@ -230,7 +229,6 @@ BufferState::disableElemHoldList(void) void BufferState::fallbackResize(uint32_t bufferId, uint64_t sizeNeeded, - size_t maxClusters, void *&buffer, Alloc &holdBuffer) { @@ -239,7 +237,6 @@ BufferState::fallbackResize(uint32_t bufferId, assert(holdBuffer.get() == NULL); size_t allocClusters = _typeHandler->calcClustersToAlloc(bufferId, sizeNeeded, - maxClusters, true); size_t allocSize = allocClusters * _typeHandler->getClusterSize(); assert(allocSize >= _usedElems + sizeNeeded); diff --git a/searchlib/src/vespa/searchlib/datastore/bufferstate.h b/searchlib/src/vespa/searchlib/datastore/bufferstate.h index 22f620ba7f6..c2fe3c2827f 100644 --- a/searchlib/src/vespa/searchlib/datastore/bufferstate.h +++ b/searchlib/src/vespa/searchlib/datastore/bufferstate.h @@ -81,13 +81,11 @@ public: * @param typeId registered data type for buffer. * @param typeHandler type handler for registered data type. * @param sizeNeeded Number of elements needed to be free - * @param maxSize number of clusters expressable via reference - * type * @param buffer start of buffer. */ void onActive(uint32_t bufferId, uint32_t typeId, BufferTypeBase *typeHandler, - size_t sizeNeeded, size_t maxSize, void *&buffer); + size_t sizeNeeded, void *&buffer); /** * Transition from ACTIVE to HOLD state. @@ -156,7 +154,7 @@ public: size_t getExtraHoldBytes() const { return _extraHoldBytes; } bool getCompacting() const { return _compacting; } void setCompacting() { _compacting = true; } - void fallbackResize(uint32_t bufferId, uint64_t sizeNeeded, size_t maxClusters, void *&buffer, Alloc &holdBuffer); + void fallbackResize(uint32_t bufferId, uint64_t sizeNeeded, void *&buffer, Alloc &holdBuffer); bool isActive(uint32_t typeId) const { return ((_state == ACTIVE) && (_typeId == typeId)); diff --git a/searchlib/src/vespa/searchlib/datastore/datastorebase.cpp b/searchlib/src/vespa/searchlib/datastore/datastorebase.cpp index 435d9a1423b..4753a997157 100644 --- a/searchlib/src/vespa/searchlib/datastore/datastorebase.cpp +++ b/searchlib/src/vespa/searchlib/datastore/datastorebase.cpp @@ -108,12 +108,41 @@ DataStoreBase::switchActiveBuffer(uint32_t typeId, size_t sizeNeeded) // start using next buffer activeBufferId = nextBufferId(activeBufferId); } while (!_states[activeBufferId].isFree()); - onActive(activeBufferId, typeId, sizeNeeded, _maxClusters); + onActive(activeBufferId, typeId, sizeNeeded); _activeBufferIds[typeId] = activeBufferId; } void +DataStoreBase::switchOrGrowActiveBuffer(uint32_t typeId, size_t sizeNeeded) +{ + auto typeHandler = _typeHandlers[typeId]; + uint32_t clusterSize = typeHandler->getClusterSize(); + size_t numClustersForNewBuffer = typeHandler->getNumClustersForNewBuffer(); + size_t numEntriesForNewBuffer = numClustersForNewBuffer * clusterSize; + uint32_t bufferId = _activeBufferIds[typeId]; + if (sizeNeeded + _states[bufferId].size() >= numEntriesForNewBuffer) { + // Don't try to resize existing buffer, new buffer will be large enough + switchActiveBuffer(typeId, sizeNeeded); + } else { + uint32_t oldBufferId = bufferId; + do { + bufferId = nextBufferId(bufferId); + } while (!_states[bufferId].isFree()); + size_t allocClusters = typeHandler->calcClustersToAlloc(bufferId, sizeNeeded, false); + if (allocClusters < numClustersForNewBuffer) { + // Resize existing buffer + fallbackResize(oldBufferId, sizeNeeded); + } else { + // start using next buffer + onActive(bufferId, typeId, sizeNeeded); + _activeBufferIds[typeId] = bufferId; + } + } +} + + +void DataStoreBase::initActiveBuffers(void) { uint32_t numTypes = _activeBufferIds.size(); @@ -123,7 +152,7 @@ DataStoreBase::initActiveBuffers(void) // start using next buffer activeBufferId = nextBufferId(activeBufferId); } - onActive(activeBufferId, typeId, 0u, _maxClusters); + onActive(activeBufferId, typeId, 0u); _activeBufferIds[typeId] = activeBufferId; } } @@ -134,6 +163,7 @@ DataStoreBase::addType(BufferTypeBase *typeHandler) { uint32_t typeId = _activeBufferIds.size(); assert(typeId == _typeHandlers.size()); + typeHandler->clampMaxClusters(_maxClusters); _activeBufferIds.push_back(0); _typeHandlers.push_back(typeHandler); _freeListLists.push_back(BufferState::FreeListList()); @@ -330,8 +360,7 @@ DataStoreBase::getMemStats(void) const void DataStoreBase::onActive(uint32_t bufferId, uint32_t typeId, - size_t sizeNeeded, - size_t maxClusters) + size_t sizeNeeded) { assert(typeId < _typeHandlers.size()); assert(bufferId < _numBuffers); @@ -339,7 +368,6 @@ DataStoreBase::onActive(uint32_t bufferId, uint32_t typeId, state.onActive(bufferId, typeId, _typeHandlers[typeId], sizeNeeded, - maxClusters, _buffers[bufferId]); enableFreeList(bufferId); } @@ -382,7 +410,6 @@ DataStoreBase::fallbackResize(uint32_t bufferId, uint64_t sizeNeeded) size_t elementSize = state.getTypeHandler()->elementSize(); state.fallbackResize(bufferId, sizeNeeded, - _maxClusters, _buffers[bufferId], toHoldBuffer); GenerationHeldBase::UP diff --git a/searchlib/src/vespa/searchlib/datastore/datastorebase.h b/searchlib/src/vespa/searchlib/datastore/datastorebase.h index f64ff4b3c8a..cefd53132cb 100644 --- a/searchlib/src/vespa/searchlib/datastore/datastorebase.h +++ b/searchlib/src/vespa/searchlib/datastore/datastorebase.h @@ -205,7 +205,7 @@ public: if (__builtin_expect(sizeNeeded > _states[_activeBufferIds[typeId]].remaining(), false)) { - switchActiveBuffer(typeId, sizeNeeded); + switchOrGrowActiveBuffer(typeId, sizeNeeded); } } @@ -227,6 +227,8 @@ public: void switchActiveBuffer(uint32_t typeId, size_t sizeNeeded); + void switchOrGrowActiveBuffer(uint32_t typeId, size_t sizeNeeded); + MemoryUsage getMemoryUsage() const; /** @@ -365,13 +367,9 @@ public: * @param bufferId Id of buffer to be active. * @param typeId registered data type for buffer. * @param sizeNeeded Number of elements needed to be free - * @param maxSize number of clusters expressable via reference - * type */ void - onActive(uint32_t bufferId, uint32_t typeId, - size_t sizeNeeded, - size_t maxSize); + onActive(uint32_t bufferId, uint32_t typeId, size_t sizeNeeded); uint32_t getTypeId(uint32_t bufferId) const |