// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #pragma once #include "multinumericattribute.h" #include "attributevector.hpp" #include "multinumericattributesaver.h" #include "multi_numeric_search_context.h" #include "numeric_sort_blob_writer.h" #include "load_utils.h" #include "primitivereader.h" #include "valuemodifier.h" #include #include #include namespace search { using fileutil::LoadedBuffer; template typename MultiValueNumericAttribute::T MultiValueNumericAttribute::getFromEnum(EnumHandle e) const { (void) e; return 0; } template bool MultiValueNumericAttribute::findEnum(T value, EnumHandle & e) const { (void) value; (void) e; return false; } template MultiValueNumericAttribute:: MultiValueNumericAttribute(const vespalib::string & baseFileName, const AttributeVector::Config & c) : MultiValueAttribute(baseFileName, c) { } template uint32_t MultiValueNumericAttribute::getValueCount(DocId doc) const { if (doc >= B::getNumDocs()) { return 0; } MultiValueArrayRef values(this->_mvMapping.get(doc)); return values.size(); } template void MultiValueNumericAttribute::onCommit() { DocumentValues docValues; this->applyAttributeChanges(docValues); { typename B::ValueModifier valueGuard(this->getValueModifier()); for (const auto & value : docValues) { clearOldValues(value.first); setNewValues(value.first, value.second); } } std::atomic_thread_fence(std::memory_order_release); this->reclaim_unused_memory(); this->_changes.clear(); if (this->_mvMapping.consider_compact(this->getConfig().getCompactionStrategy())) { this->incGeneration(); this->updateStat(true); } } template void MultiValueNumericAttribute::onUpdateStat() { auto& compaction_strategy = this->getConfig().getCompactionStrategy(); vespalib::MemoryUsage usage = this->_mvMapping.update_stat(compaction_strategy); usage.merge(this->getChangeVectorMemoryUsage()); this->updateStatistics(this->_mvMapping.getTotalValueCnt(), this->_mvMapping.getTotalValueCnt(), usage.allocatedBytes(), usage.usedBytes(), usage.deadBytes(), usage.allocatedBytesOnHold()); } template void MultiValueNumericAttribute::clearOldValues(DocId doc) { (void) doc; } template void MultiValueNumericAttribute::setNewValues(DocId doc, const std::vector & values) { this->_mvMapping.set(doc, values); } template void MultiValueNumericAttribute::reclaim_memory(generation_t oldest_used_gen) { this->_mvMapping.reclaim_memory(oldest_used_gen); } template void MultiValueNumericAttribute::before_inc_generation(generation_t current_gen) { this->_mvMapping.assign_generation(current_gen); } template bool MultiValueNumericAttribute::onLoadEnumerated(ReaderBase & attrReader) { uint32_t numDocs = attrReader.getNumIdx() - 1; this->setNumDocs(numDocs); this->setCommittedDocIdLimit(numDocs); this->_mvMapping.reserve(numDocs+1); auto udatBuffer = attribute::LoadUtils::loadUDAT(*this); assert((udatBuffer->size() % sizeof(T)) == 0); vespalib::ConstArrayRef map(reinterpret_cast(udatBuffer->buffer()), udatBuffer->size() / sizeof(T)); uint32_t maxvc = attribute::loadFromEnumeratedMultiValue(this->_mvMapping, attrReader, map, vespalib::ConstArrayRef(), attribute::NoSaveLoadedEnum()); this->checkSetMaxValueCount(maxvc); return true; } template bool MultiValueNumericAttribute::onLoad(vespalib::Executor *) { PrimitiveReader attrReader(*this); bool ok(attrReader.getHasLoadData()); if (!ok) return false; this->setCreateSerialNum(attrReader.getCreateSerialNum()); if (attrReader.getEnumerated()) return onLoadEnumerated(attrReader); bool hasWeight(attrReader.hasWeight()); size_t numDocs = attrReader.getNumIdx() - 1; this->_mvMapping.prepareLoadFromMultiValue(); // set values std::vector values; B::setNumDocs(numDocs); B::setCommittedDocIdLimit(numDocs); this->_mvMapping.reserve(numDocs+1); for (DocId doc = 0; doc < numDocs; ++doc) { const uint32_t valueCount(attrReader.getNextValueCount()); for (uint32_t i(0); i < valueCount; i++) { MValueType currData = attrReader.getNextData(); values.emplace_back(multivalue::ValueBuilder::build(currData, hasWeight ? attrReader.getNextWeight() : 1)); } this->checkSetMaxValueCount(valueCount); setNewValues(doc, values); values.clear(); } this->_mvMapping.doneLoadFromMultiValue(); return true; } template std::unique_ptr MultiValueNumericAttribute::getSearch(QueryTermSimple::UP qTerm, const attribute::SearchContextParams & params) const { (void) params; return std::make_unique>(std::move(qTerm), *this, this->_mvMapping.make_read_view(this->getCommittedDocIdLimit())); } template std::unique_ptr MultiValueNumericAttribute::onInitSave(vespalib::stringref fileName) { vespalib::GenerationHandler::Guard guard(this->getGenerationHandler().takeGuard()); return std::make_unique> (std::move(guard), this->createAttributeHeader(fileName), this->_mvMapping); } template template long MultiValueNumericAttribute::on_serialize_for_sort(DocId doc, void* serTo, long available) const { attribute::NumericSortBlobWriter writer; auto indices = this->_mvMapping.get(doc); for (auto& v : indices) { writer.candidate(multivalue::get_value(v)); } return writer.write(serTo, available); } template long MultiValueNumericAttribute::onSerializeForAscendingSort(DocId doc, void* serTo, long available, const common::BlobConverter*) const { return on_serialize_for_sort(doc, serTo, available); } template long MultiValueNumericAttribute::onSerializeForDescendingSort(DocId doc, void* serTo, long available, const common::BlobConverter*) const { return on_serialize_for_sort(doc, serTo, available); } } // namespace search