aboutsummaryrefslogtreecommitdiffstats
path: root/searchlib
diff options
context:
space:
mode:
Diffstat (limited to 'searchlib')
-rw-r--r--searchlib/src/tests/attribute/attribute_test.cpp12
-rw-r--r--searchlib/src/tests/attribute/changevector/changevector_test.cpp19
-rw-r--r--searchlib/src/vespa/searchlib/attribute/attributevector.hpp54
-rw-r--r--searchlib/src/vespa/searchlib/attribute/changevector.h83
-rw-r--r--searchlib/src/vespa/searchlib/attribute/changevector.hpp54
-rw-r--r--searchlib/src/vespa/searchlib/attribute/enumattribute.hpp2
-rw-r--r--searchlib/src/vespa/searchlib/attribute/enumstore.hpp2
-rw-r--r--searchlib/src/vespa/searchlib/attribute/multienumattribute.hpp2
-rw-r--r--searchlib/src/vespa/searchlib/attribute/multivalueattribute.h1
-rw-r--r--searchlib/src/vespa/searchlib/attribute/multivalueattribute.hpp14
-rw-r--r--searchlib/src/vespa/searchlib/attribute/singleboolattribute.cpp2
-rw-r--r--searchlib/src/vespa/searchlib/attribute/singleenumattribute.hpp2
-rw-r--r--searchlib/src/vespa/searchlib/attribute/singlenumericattribute.hpp2
-rw-r--r--searchlib/src/vespa/searchlib/attribute/singlenumericpostattribute.hpp2
-rw-r--r--searchlib/src/vespa/searchlib/attribute/singlesmallnumericattribute.cpp2
-rw-r--r--searchlib/src/vespa/searchlib/attribute/singlestringpostattribute.hpp2
16 files changed, 120 insertions, 135 deletions
diff --git a/searchlib/src/tests/attribute/attribute_test.cpp b/searchlib/src/tests/attribute/attribute_test.cpp
index af1fcea2e21..79e120d0683 100644
--- a/searchlib/src/tests/attribute/attribute_test.cpp
+++ b/searchlib/src/tests/attribute/attribute_test.cpp
@@ -1670,8 +1670,8 @@ AttributeTest::testStatus()
AttributePtr ptr = createAttribute("as", cfg);
addDocs(ptr, numDocs);
auto & sa = *(static_cast<StringAttribute *>(ptr.get()));
- const size_t numUniq(16);
- const size_t numValuesPerDoc(16);
+ const size_t numValuesPerDoc(values.size());
+ const size_t numUniq(numValuesPerDoc);
for (uint32_t i = 0; i < numDocs; ++i) {
EXPECT_TRUE(appendToVector(sa, i, numValuesPerDoc, values));
}
@@ -1680,11 +1680,11 @@ AttributeTest::testStatus()
EXPECT_EQUAL(ptr->getStatus().getNumValues(), numDocs*numValuesPerDoc);
EXPECT_EQUAL(ptr->getStatus().getNumUniqueValues(), numUniq);
size_t expUsed = 0;
- expUsed += 1 * InternalNodeSize + 1 * LeafNodeSize; // enum store tree
- expUsed += numUniq * 32; // enum store (16 unique values, 32 bytes per entry)
+ expUsed += 1 * InternalNodeSize + 1 * LeafNodeSize; // Approximate enum store tree
+ expUsed += 272; // TODO Approximate... enum store (16 unique values, 17 bytes per entry)
// multi value mapping (numdocs * sizeof(MappingIndex) + numvalues * sizeof(EnumIndex) +
- // numdocs * sizeof(Array<EnumIndex>) (due to vector vector))
- expUsed += numDocs * sizeof(vespalib::datastore::EntryRef) + numDocs * numValuesPerDoc * sizeof(IEnumStore::Index) + ((numValuesPerDoc > 1024) ? numDocs * NestedVectorSize : 0);
+ // 32 + numdocs * sizeof(Array<EnumIndex>) (due to vector vector))
+ expUsed += 32 + numDocs * sizeof(vespalib::datastore::EntryRef) + numDocs * numValuesPerDoc * sizeof(IEnumStore::Index) + ((numValuesPerDoc > 1024) ? numDocs * NestedVectorSize : 0);
EXPECT_GREATER_EQUAL(ptr->getStatus().getUsed(), expUsed);
EXPECT_GREATER_EQUAL(ptr->getStatus().getAllocated(), expUsed);
}
diff --git a/searchlib/src/tests/attribute/changevector/changevector_test.cpp b/searchlib/src/tests/attribute/changevector/changevector_test.cpp
index ad33774e904..7bcf519bb18 100644
--- a/searchlib/src/tests/attribute/changevector/changevector_test.cpp
+++ b/searchlib/src/tests/attribute/changevector/changevector_test.cpp
@@ -2,17 +2,24 @@
#include <vespa/vespalib/testkit/testapp.h>
#include <vespa/searchlib/attribute/changevector.hpp>
-
+#include <vespa/vespalib/stllike/hash_set.h>
using namespace search;
template <typename T>
void verifyStrictOrdering(const T & v) {
- long count(0);
- for (const auto & c : v) {
- count++;
- EXPECT_EQUAL(count, c._data.get());
+ vespalib::hash_set<uint32_t> complete;
+ uint32_t prev_doc(0);
+ uint32_t prev_value;
+ for (const auto & c : v.getDocIdInsertOrder()) {
+ if (prev_doc != c._doc) {
+ complete.insert(prev_doc);
+ EXPECT_FALSE(complete.contains(c._doc));
+ prev_doc = c._doc;
+ } else {
+ EXPECT_GREATER(c._data, prev_value);
+ }
+ prev_value = c._data;
}
- EXPECT_EQUAL(v.size(), size_t(count));
}
class Accessor {
diff --git a/searchlib/src/vespa/searchlib/attribute/attributevector.hpp b/searchlib/src/vespa/searchlib/attribute/attributevector.hpp
index efc96bc57c2..616096e9091 100644
--- a/searchlib/src/vespa/searchlib/attribute/attributevector.hpp
+++ b/searchlib/src/vespa/searchlib/attribute/attributevector.hpp
@@ -89,40 +89,36 @@ AttributeVector::adjustWeight(ChangeVectorT< ChangeTemplate<T> >& changes, DocId
template<typename T>
bool
-AttributeVector::applyArithmetic(ChangeVectorT< ChangeTemplate<T> > & changes, DocId doc, const T & v,
+AttributeVector::applyArithmetic(ChangeVectorT< ChangeTemplate<T> > & changes, DocId doc, const T &,
const ArithmeticValueUpdate & arithm)
{
- (void) v;
- bool retval(!hasMultiValue() && (doc < getNumDocs()));
- if (retval) {
- size_t oldSz(changes.size());
- ArithmeticValueUpdate::Operator op(arithm.getOperator());
- double aop = arithm.getOperand();
- if (op == ArithmeticValueUpdate::Add) {
- changes.push_back(ChangeTemplate<T>(ChangeBase::ADD, doc, 0, 0));
- } else if (op == ArithmeticValueUpdate::Sub) {
- changes.push_back(ChangeTemplate<T>(ChangeBase::SUB, doc, 0, 0));
- } else if (op == ArithmeticValueUpdate::Mul) {
- changes.push_back(ChangeTemplate<T>(ChangeBase::MUL, doc, 0, 0));
- } else if (op == ArithmeticValueUpdate::Div) {
- if (this->getClass().inherits(IntegerAttribute::classId) && aop == 0) {
- divideByZeroWarning();
- } else {
- changes.push_back(ChangeTemplate<T>(ChangeBase::DIV, doc, 0, 0));
- }
+ if (hasMultiValue() || (doc >= getNumDocs())) return false;
+
+ size_t oldSz(changes.size());
+ ArithmeticValueUpdate::Operator op(arithm.getOperator());
+ double aop = arithm.getOperand();
+ if (op == ArithmeticValueUpdate::Add) {
+ changes.push_back(ChangeTemplate<T>(ChangeBase::ADD, doc, 0, 0));
+ } else if (op == ArithmeticValueUpdate::Sub) {
+ changes.push_back(ChangeTemplate<T>(ChangeBase::SUB, doc, 0, 0));
+ } else if (op == ArithmeticValueUpdate::Mul) {
+ changes.push_back(ChangeTemplate<T>(ChangeBase::MUL, doc, 0, 0));
+ } else if (op == ArithmeticValueUpdate::Div) {
+ if (this->getClass().inherits(IntegerAttribute::classId) && aop == 0) {
+ divideByZeroWarning();
} else {
- retval = false;
- }
- if (retval) {
- const size_t diff = changes.size() - oldSz;
- _status.incNonIdempotentUpdates(diff);
- _status.incUpdates(diff);
- if (diff > 0) {
- changes.back()._arithOperand = aop;
- }
+ changes.push_back(ChangeTemplate<T>(ChangeBase::DIV, doc, 0, 0));
}
+ } else {
+ return false;
}
- return retval;
+ const size_t diff = changes.size() - oldSz;
+ _status.incNonIdempotentUpdates(diff);
+ _status.incUpdates(diff);
+ if (diff > 0) {
+ changes.back()._arithOperand = aop;
+ }
+ return true;
}
template<typename T>
diff --git a/searchlib/src/vespa/searchlib/attribute/changevector.h b/searchlib/src/vespa/searchlib/attribute/changevector.h
index c3b4d0ce3b0..df0c4d839d2 100644
--- a/searchlib/src/vespa/searchlib/attribute/changevector.h
+++ b/searchlib/src/vespa/searchlib/attribute/changevector.h
@@ -2,7 +2,6 @@
#pragma once
-#include <vespa/vespalib/stllike/hash_map.h>
#include <vespa/searchcommon/common/undefinedvalues.h>
#include <vector>
@@ -26,11 +25,10 @@ struct ChangeBase {
DIV,
CLEARDOC
};
- enum {TAIL=0, UNSET_ENUM = 0xffffffffu};
+ enum {UNSET_ENUM = 0xffffffffu};
ChangeBase() :
_type(NOOP),
- _next(TAIL),
_doc(0),
_weight(1),
_enumScratchPad(UNSET_ENUM),
@@ -39,7 +37,6 @@ struct ChangeBase {
ChangeBase(Type type, uint32_t d, int32_t w = 1) :
_type(type),
- _next(TAIL),
_doc(d),
_weight(w),
_enumScratchPad(UNSET_ENUM),
@@ -48,18 +45,11 @@ struct ChangeBase {
int cmp(const ChangeBase &b) const { int diff(_doc - b._doc); return diff; }
bool operator <(const ChangeBase & b) const { return cmp(b) < 0; }
- bool isAtEnd() const { return _next == TAIL; }
- uint32_t getNext() const { return _next; }
- void setNext(uint32_t next) { _next = next; }
uint32_t getEnum() const { return _enumScratchPad; }
void setEnum(uint32_t value) const { _enumScratchPad = value; }
bool isEnumValid() const { return _enumScratchPad != UNSET_ENUM; }
- void invalidateEnum() const { _enumScratchPad = UNSET_ENUM; }
Type _type;
-private:
- uint32_t _next;
-public:
uint32_t _doc;
int32_t _weight;
mutable uint32_t _enumScratchPad;
@@ -131,54 +121,65 @@ NumericChangeData<double>::operator<(const NumericChangeData<double> &rhs) const
return _v < rhs._v;
}
-class ChangeVectorBase {
-protected:
-};
-
/**
- * Maintains a list of changes where changes to the same docid are adjacent, but ordered by insertion order.
- * Apart from that no ordering by docid.
+ * Maintains a list of changes.
+ * You can select to view the in insert order,
+ * or unordered, but changes to the same docid are adjacent and ordered by insertion order.
*/
template <typename T>
-class ChangeVectorT : public ChangeVectorBase {
+class ChangeVectorT {
private:
- using Map = vespalib::hash_map<uint32_t, uint32_t>;
using Vector = std::vector<T>;
public:
+ using const_iterator = typename Vector::const_iterator;
ChangeVectorT();
~ChangeVectorT();
- class const_iterator {
- public:
- const_iterator(const Vector & vector, uint32_t next) : _v(&vector), _next(next) { }
- bool operator == (const const_iterator & rhs) const { return _v == rhs._v && _next == rhs._next; }
- bool operator != (const const_iterator & rhs) const { return _v != rhs._v || _next != rhs._next; }
- const_iterator& operator++() { advance(); return *this; }
- const_iterator operator++(int) { const_iterator other(*this); advance(); return other; }
- const T & operator * () const { return v()[_next]; }
- const T * operator -> () const { return &v()[_next]; }
- private:
- void advance() { _next = v()[_next].getNext(); }
- const Vector & v() const { return *_v; }
- const Vector * _v;
- uint32_t _next;
- };
-
void push_back(const T & c);
template <typename Accessor>
void push_back(uint32_t doc, Accessor & ac);
- const T & back() const { return _v.back(); }
T & back() { return _v.back(); }
size_t size() const { return _v.size(); }
bool empty() const { return _v.empty(); }
void clear();
- const_iterator begin() const { return const_iterator(_v, 0); }
- const_iterator end() const { return const_iterator(_v, size()); }
+ class InsertOrder {
+ public:
+ InsertOrder(const Vector & v) : _v(v) { }
+ const_iterator begin() const { return _v.begin(); }
+ const_iterator end() const { return _v.end(); }
+ private:
+ const Vector &_v;
+ };
+ class DocIdInsertOrder {
+ using AdjacentDocIds = std::vector<uint64_t>;
+ public:
+ class const_iterator {
+ public:
+ const_iterator(const Vector & vector, const AdjacentDocIds & order, uint32_t cur)
+ : _v(&vector), _o(&order), _cur(cur) { }
+ bool operator == (const const_iterator & rhs) const { return _v == rhs._v && _cur == rhs._cur; }
+ bool operator != (const const_iterator & rhs) const { return _v != rhs._v || _cur != rhs._cur; }
+ const_iterator& operator++() { _cur++; return *this; }
+ const_iterator operator++(int) { const_iterator other(*this); _cur++; return other; }
+ const T & operator * () const { return v(); }
+ const T * operator -> () const { return &v(); }
+ private:
+ const T & v() const { return (*_v)[(*_o)[_cur] & 0xffffffff]; }
+ const Vector * _v;
+ const AdjacentDocIds * _o;
+ uint32_t _cur;
+ };
+ DocIdInsertOrder(const Vector & v);
+ const_iterator begin() const { return const_iterator(_v, _adjacent, 0); }
+ const_iterator end() const { return const_iterator(_v, _adjacent, _v.size()); }
+ private:
+ const Vector &_v;
+ AdjacentDocIds _adjacent;
+ };
+ InsertOrder getInsertOrder() const { return InsertOrder(_v); }
+ DocIdInsertOrder getDocIdInsertOrder() const { return DocIdInsertOrder(_v); }
vespalib::MemoryUsage getMemoryUsage() const;
private:
- void linkIn(uint32_t doc, size_t index, size_t last);
Vector _v;
- Map _docs;
- uint32_t _tail;
};
} // namespace search
diff --git a/searchlib/src/vespa/searchlib/attribute/changevector.hpp b/searchlib/src/vespa/searchlib/attribute/changevector.hpp
index dcb31ebae73..24cb05adf91 100644
--- a/searchlib/src/vespa/searchlib/attribute/changevector.hpp
+++ b/searchlib/src/vespa/searchlib/attribute/changevector.hpp
@@ -4,6 +4,7 @@
#include "changevector.h"
#include <vespa/vespalib/util/memoryusage.h>
+#include <vespa/vespalib/util/alloc.h>
namespace search {
@@ -16,9 +17,7 @@ constexpr size_t NUM_ELEMS_TO_RESERVE = 200;
template <typename T>
ChangeVectorT<T>::ChangeVectorT()
- : _v(),
- _docs(NUM_ELEMS_TO_RESERVE*2),
- _tail(0)
+ : _v()
{
_v.reserve(vespalib::roundUp2inN(NUM_ELEMS_TO_RESERVE, sizeof(T)));
}
@@ -30,16 +29,13 @@ template <typename T>
void
ChangeVectorT<T>::clear() {
_v.clear();
- _docs.clear();
}
template <typename T>
void
ChangeVectorT<T>::push_back(const T & c)
{
- size_t index(size());
_v.push_back(c);
- linkIn(c._doc, index, index);
}
template <typename T>
@@ -49,48 +45,32 @@ ChangeVectorT<T>::push_back(uint32_t doc, Accessor & ac)
{
if (ac.size() <= 0) { return; }
- size_t index(size());
- _v.reserve(vespalib::roundUp2inN(index + ac.size(), sizeof(T)));
+ _v.reserve(vespalib::roundUp2inN(size() + ac.size(), sizeof(T)));
for (size_t i(0), m(ac.size()); i < m; i++, ac.next()) {
_v.push_back(T(ChangeBase::APPEND, doc, typename T::DataType(ac.value()), ac.weight()));
- _v.back().setNext(index + i + 1);
}
- linkIn(doc, index, size() - 1);
}
template <typename T>
-void
-ChangeVectorT<T>::linkIn(uint32_t doc, size_t first, size_t last)
+vespalib::MemoryUsage
+ChangeVectorT<T>::getMemoryUsage() const
{
- if (first != 0 && (_v[_tail]._doc == doc)) {
- _v[_tail].setNext(first);
- _tail = last;
- } else {
- Map::iterator found(_docs.find(doc));
- if (found == _docs.end()) {
- _docs[doc] = last;
- if (_tail != first) {
- _v[_tail].setNext(first);
- }
- _tail = last;
- } else {
- uint32_t prev(found->second);
- for (; _v[_v[prev].getNext()]._doc == doc; prev = _v[prev].getNext());
- _v[last].setNext(_v[prev].getNext());
- _v[prev].setNext(first);
- found->second = last;
- }
- }
- _v[_tail].setNext(size());
+ size_t usedBytes = _v.size() * sizeof(T);
+ size_t allocBytes = _v.capacity() * sizeof(T);
+ return vespalib::MemoryUsage(allocBytes, usedBytes, 0, 0);
}
template <typename T>
-vespalib::MemoryUsage
-ChangeVectorT<T>::getMemoryUsage() const
+ChangeVectorT<T>::DocIdInsertOrder::DocIdInsertOrder(const Vector & v)
+ : _v(v),
+ _adjacent()
{
- size_t usedBytes = _v.size() * sizeof(T) + _docs.getMemoryUsed();
- size_t allocBytes = _v.capacity() * sizeof(T) + _docs.getMemoryConsumption();
- return vespalib::MemoryUsage(allocBytes, usedBytes, 0, 0);
+ _adjacent.reserve(v.size());
+ uint32_t index(0);
+ for (const auto & c : _v) {
+ _adjacent.push_back((uint64_t(c._doc) << 32) | index++);
+ }
+ std::sort(_adjacent.begin(), _adjacent.end());
}
} // namespace search
diff --git a/searchlib/src/vespa/searchlib/attribute/enumattribute.hpp b/searchlib/src/vespa/searchlib/attribute/enumattribute.hpp
index fd576b3a9ba..164bb411061 100644
--- a/searchlib/src/vespa/searchlib/attribute/enumattribute.hpp
+++ b/searchlib/src/vespa/searchlib/attribute/enumattribute.hpp
@@ -63,7 +63,7 @@ void
EnumAttribute<B>::insertNewUniqueValues(EnumStoreBatchUpdater& updater)
{
// find and insert new unique strings
- for (const auto & data : this->_changes) {
+ for (const auto & data : this->_changes.getInsertOrder()) {
considerAttributeChange(data, updater);
}
}
diff --git a/searchlib/src/vespa/searchlib/attribute/enumstore.hpp b/searchlib/src/vespa/searchlib/attribute/enumstore.hpp
index 90bcf92a103..9885613f4e3 100644
--- a/searchlib/src/vespa/searchlib/attribute/enumstore.hpp
+++ b/searchlib/src/vespa/searchlib/attribute/enumstore.hpp
@@ -207,7 +207,7 @@ template <typename EntryT>
vespalib::MemoryUsage
EnumStoreT<EntryT>::update_stat()
{
- auto &store = _store.get_allocator().get_data_store();
+ auto &store = _store.get_data_store();
_cached_values_memory_usage = store.getMemoryUsage();
_cached_values_address_space_usage = store.getAddressSpaceUsage();
_cached_dictionary_btree_usage = _dict->get_btree_memory_usage();
diff --git a/searchlib/src/vespa/searchlib/attribute/multienumattribute.hpp b/searchlib/src/vespa/searchlib/attribute/multienumattribute.hpp
index 8475451ba60..072398abcf9 100644
--- a/searchlib/src/vespa/searchlib/attribute/multienumattribute.hpp
+++ b/searchlib/src/vespa/searchlib/attribute/multienumattribute.hpp
@@ -25,7 +25,7 @@ template <typename B, typename M>
bool
MultiValueEnumAttribute<B, M>::extractChangeData(const Change & c, EnumIndex & idx)
{
- if (c._enumScratchPad == Change::UNSET_ENUM) {
+ if ( ! c.isEnumValid() ) {
return this->_enumStore.find_index(c._data.raw(), idx);
}
idx = EnumIndex(vespalib::datastore::EntryRef(c._enumScratchPad));
diff --git a/searchlib/src/vespa/searchlib/attribute/multivalueattribute.h b/searchlib/src/vespa/searchlib/attribute/multivalueattribute.h
index 66ca6bd2eac..d36777a25a9 100644
--- a/searchlib/src/vespa/searchlib/attribute/multivalueattribute.h
+++ b/searchlib/src/vespa/searchlib/attribute/multivalueattribute.h
@@ -20,7 +20,6 @@ protected:
typedef typename B::DocId DocId;
typedef typename B::Change Change;
typedef typename B::ChangeVector ChangeVector;
- typedef typename B::ChangeVector::const_iterator ChangeVectorIterator;
using MultiValueType = M;
using MultiValueMapping = attribute::MultiValueMapping<MultiValueType>;
diff --git a/searchlib/src/vespa/searchlib/attribute/multivalueattribute.hpp b/searchlib/src/vespa/searchlib/attribute/multivalueattribute.hpp
index 0cd2e0bbc27..2e73909ea1e 100644
--- a/searchlib/src/vespa/searchlib/attribute/multivalueattribute.hpp
+++ b/searchlib/src/vespa/searchlib/attribute/multivalueattribute.hpp
@@ -78,11 +78,12 @@ void
MultiValueAttribute<B, M>::apply_attribute_changes_to_array(DocumentValues& docValues)
{
// compute new values for each document with changes
- for (ChangeVectorIterator current(this->_changes.begin()), end(this->_changes.end()); (current != end); ) {
+ auto iterable = this->_changes.getDocIdInsertOrder();
+ for (auto current(iterable.begin()), end(iterable.end()); (current != end); ) {
DocId doc = current->_doc;
// find last clear doc
- ChangeVectorIterator last_clear_doc = end;
- for (ChangeVectorIterator iter = current; (iter != end) && (iter->_doc == doc); ++iter) {
+ auto last_clear_doc = end;
+ for (auto iter = current; (iter != end) && (iter->_doc == doc); ++iter) {
if (iter->_type == ChangeBase::CLEARDOC) {
last_clear_doc = iter;
}
@@ -137,12 +138,13 @@ void
MultiValueAttribute<B, M>::apply_attribute_changes_to_wset(DocumentValues& docValues)
{
// compute new values for each document with changes
- for (ChangeVectorIterator current(this->_changes.begin()), end(this->_changes.end()); (current != end); ) {
+ auto iterable = this->_changes.getDocIdInsertOrder();
+ for (auto current(iterable.begin()), end(iterable.end()); (current != end); ) {
const DocId doc = current->_doc;
// find last clear doc
- ChangeVectorIterator last_clear_doc = end;
+ auto last_clear_doc = end;
size_t max_elems_inserted = 0;
- for (ChangeVectorIterator iter = current; (iter != end) && (iter->_doc == doc); ++iter) {
+ for (auto iter = current; (iter != end) && (iter->_doc == doc); ++iter) {
if (iter->_type == ChangeBase::CLEARDOC) {
last_clear_doc = iter;
}
diff --git a/searchlib/src/vespa/searchlib/attribute/singleboolattribute.cpp b/searchlib/src/vespa/searchlib/attribute/singleboolattribute.cpp
index 2b40150f87b..6c8edea13cf 100644
--- a/searchlib/src/vespa/searchlib/attribute/singleboolattribute.cpp
+++ b/searchlib/src/vespa/searchlib/attribute/singleboolattribute.cpp
@@ -59,7 +59,7 @@ SingleBoolAttribute::onCommit() {
if ( ! _changes.empty()) {
// apply updates
ValueModifier valueGuard(getValueModifier());
- for (const auto & change : _changes) {
+ for (const auto & change : _changes.getInsertOrder()) {
if (change._type == ChangeBase::UPDATE) {
std::atomic_thread_fence(std::memory_order_release);
setBit(change._doc, change._data != 0);
diff --git a/searchlib/src/vespa/searchlib/attribute/singleenumattribute.hpp b/searchlib/src/vespa/searchlib/attribute/singleenumattribute.hpp
index b39bdeb3b00..bf75400b157 100644
--- a/searchlib/src/vespa/searchlib/attribute/singleenumattribute.hpp
+++ b/searchlib/src/vespa/searchlib/attribute/singleenumattribute.hpp
@@ -175,7 +175,7 @@ void
SingleValueEnumAttribute<B>::applyValueChanges(EnumStoreBatchUpdater& updater)
{
ValueModifier valueGuard(this->getValueModifier());
- for (const auto& change : this->_changes) {
+ for (const auto& change : this->_changes.getInsertOrder()) {
if (change._type == ChangeBase::UPDATE) {
applyUpdateValueChange(change, updater);
} else if (change._type >= ChangeBase::ADD && change._type <= ChangeBase::DIV) {
diff --git a/searchlib/src/vespa/searchlib/attribute/singlenumericattribute.hpp b/searchlib/src/vespa/searchlib/attribute/singlenumericattribute.hpp
index fd913f34c3a..671bdc44e22 100644
--- a/searchlib/src/vespa/searchlib/attribute/singlenumericattribute.hpp
+++ b/searchlib/src/vespa/searchlib/attribute/singlenumericattribute.hpp
@@ -37,7 +37,7 @@ SingleValueNumericAttribute<B>::onCommit()
{
// apply updates
typename B::ValueModifier valueGuard(this->getValueModifier());
- for (const auto & change : this->_changes) {
+ for (const auto & change : this->_changes.getInsertOrder()) {
if (change._type == ChangeBase::UPDATE) {
std::atomic_thread_fence(std::memory_order_release);
_data[change._doc] = change._data;
diff --git a/searchlib/src/vespa/searchlib/attribute/singlenumericpostattribute.hpp b/searchlib/src/vespa/searchlib/attribute/singlenumericpostattribute.hpp
index f5ab855565c..e1c2a817af7 100644
--- a/searchlib/src/vespa/searchlib/attribute/singlenumericpostattribute.hpp
+++ b/searchlib/src/vespa/searchlib/attribute/singlenumericpostattribute.hpp
@@ -84,7 +84,7 @@ SingleValueNumericPostingAttribute<B>::applyValueChanges(EnumStoreBatchUpdater&
// used to make sure several arithmetic operations on the same document in a single commit works
std::map<DocId, EnumIndex> currEnumIndices;
- for (const auto& change : this->_changes) {
+ for (const auto& change : this->_changes.getInsertOrder()) {
auto enumIter = currEnumIndices.find(change._doc);
EnumIndex oldIdx;
if (enumIter != currEnumIndices.end()) {
diff --git a/searchlib/src/vespa/searchlib/attribute/singlesmallnumericattribute.cpp b/searchlib/src/vespa/searchlib/attribute/singlesmallnumericattribute.cpp
index f1d0da42165..8d460b5c661 100644
--- a/searchlib/src/vespa/searchlib/attribute/singlesmallnumericattribute.cpp
+++ b/searchlib/src/vespa/searchlib/attribute/singlesmallnumericattribute.cpp
@@ -53,7 +53,7 @@ SingleValueSmallNumericAttribute::onCommit()
{
// apply updates
B::ValueModifier valueGuard(getValueModifier());
- for (const auto & change : _changes) {
+ for (const auto & change : _changes.getInsertOrder()) {
if (change._type == ChangeBase::UPDATE) {
std::atomic_thread_fence(std::memory_order_release);
set(change._doc, change._data);
diff --git a/searchlib/src/vespa/searchlib/attribute/singlestringpostattribute.hpp b/searchlib/src/vespa/searchlib/attribute/singlestringpostattribute.hpp
index 39ad8d71021..4432acf2c55 100644
--- a/searchlib/src/vespa/searchlib/attribute/singlestringpostattribute.hpp
+++ b/searchlib/src/vespa/searchlib/attribute/singlestringpostattribute.hpp
@@ -85,7 +85,7 @@ SingleValueStringPostingAttributeT<B>::applyValueChanges(EnumStoreBatchUpdater&
// used to make sure several arithmetic operations on the same document in a single commit works
std::map<DocId, EnumIndex> currEnumIndices;
- for (const auto& change : this->_changes) {
+ for (const auto& change : this->_changes.getInsertOrder()) {
auto enumIter = currEnumIndices.find(change._doc);
EnumIndex oldIdx;
if (enumIter != currEnumIndices.end()) {