// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #pragma once #include "singlestringpostattribute.h" #include "single_string_enum_search_context.h" #include "string_direct_posting_store_adapter.hpp" #include #include namespace search { template SingleValueStringPostingAttributeT::SingleValueStringPostingAttributeT(const vespalib::string & name, const AttributeVector::Config & c) : SingleValueStringAttributeT(name, c), PostingParent(*this, this->getEnumStore()), _posting_store_adapter(this->get_posting_store(), this->_enumStore, this->getIsFilter()) { } template SingleValueStringPostingAttributeT::SingleValueStringPostingAttributeT(const vespalib::string & name) : SingleValueStringPostingAttributeT(name, AttributeVector::Config(AttributeVector::BasicType::STRING)) { } template SingleValueStringPostingAttributeT::~SingleValueStringPostingAttributeT() { this->disableFreeLists(); this->disable_entry_hold_list(); clearAllPostings(); } template void SingleValueStringPostingAttributeT::freezeEnumDictionary() { this->getEnumStore().freeze_dictionary(); } template void SingleValueStringPostingAttributeT::mergeMemoryStats(vespalib::MemoryUsage & total) { auto& compaction_strategy = this->getConfig().getCompactionStrategy(); total.merge(this->_posting_store.update_stat(compaction_strategy)); } template void SingleValueStringPostingAttributeT::applyUpdateValueChange(const Change & c, EnumStore & enumStore, std::map &currEnumIndices) { EnumIndex newIdx; if (c.has_entry_ref()) { newIdx = EnumIndex(vespalib::datastore::EntryRef(c.get_entry_ref())); } else { enumStore.find_index(c._data.raw(), newIdx); } currEnumIndices[c._doc] = newIdx; } template void SingleValueStringPostingAttributeT:: makePostingChange(const vespalib::datastore::EntryComparator &cmpa, IEnumStoreDictionary& dictionary, const std::map &currEnumIndices, PostingMap &changePost) { for (const auto& elem : currEnumIndices) { uint32_t docId = elem.first; EnumIndex oldIdx = this->_enumIndices[docId].load_relaxed(); EnumIndex newIdx = elem.second; // add new posting auto remapped_new_idx = dictionary.remap_index(newIdx); changePost[EnumPostingPair(remapped_new_idx, &cmpa)].add(docId, 1); // remove old posting if ( oldIdx.valid()) { auto remapped_old_idx = dictionary.remap_index(oldIdx); changePost[EnumPostingPair(remapped_old_idx, &cmpa)].remove(docId); } } } template void SingleValueStringPostingAttributeT::applyValueChanges(EnumStoreBatchUpdater& updater) { EnumStore & enumStore = this->getEnumStore(); IEnumStoreDictionary& dictionary = enumStore.get_dictionary(); PostingMap changePost; // used to make sure several arithmetic operations on the same document in a single commit works std::map currEnumIndices; for (const auto& change : this->_changes.getInsertOrder()) { auto enumIter = currEnumIndices.find(change._doc); EnumIndex oldIdx; if (enumIter != currEnumIndices.end()) { oldIdx = enumIter->second; } else { oldIdx = this->_enumIndices[change._doc].load_relaxed(); } if (change._type == ChangeBase::UPDATE) { applyUpdateValueChange(change, enumStore, currEnumIndices); } else if (change._type == ChangeBase::CLEARDOC) { currEnumIndices[change._doc] = enumStore.get_default_value_ref().load_relaxed(); } } makePostingChange(enumStore.get_folded_comparator(), dictionary, currEnumIndices, changePost); this->updatePostings(changePost); SingleValueStringAttributeT::applyValueChanges(updater); } template void SingleValueStringPostingAttributeT::reclaim_memory(generation_t oldest_used_gen) { SingleValueStringAttributeT::reclaim_memory(oldest_used_gen); _posting_store.reclaim_memory(oldest_used_gen); } template void SingleValueStringPostingAttributeT::before_inc_generation(generation_t current_gen) { _posting_store.freeze(); SingleValueStringAttributeT::before_inc_generation(current_gen); _posting_store.assign_generation(current_gen); } template std::unique_ptr SingleValueStringPostingAttributeT::getSearch(QueryTermSimpleUP qTerm, const attribute::SearchContextParams & params) const { using BaseSC = attribute::SingleStringEnumSearchContext; using SC = attribute::StringPostingSearchContext; bool cased = this->get_match_is_cased(); auto docid_limit = this->getCommittedDocIdLimit(); BaseSC base_sc(std::move(qTerm), cased, params.fuzzy_matching_algorithm(), *this, this->_enumIndices.make_read_view(docid_limit), this->_enumStore); return std::make_unique(std::move(base_sc), params.useBitVector(), *this); } }