Skip to content

Commit 6300fe7

Browse files
author
APl
committed
Update to version v5.11.1
1 parent e7fb0cd commit 6300fe7

19 files changed

Lines changed: 438 additions & 107 deletions

File tree

bindings/consts.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package bindings
22

33
const CInt32Max = int(^uint32(0) >> 1)
44

5-
const ReindexerVersion = "v5.11.0"
5+
const ReindexerVersion = "v5.11.1"
66

77
// public go consts from type_consts.h and reindexer_ctypes.h
88
const (

changelog.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
# Version 5.11.1 (05.03.2026)
2+
## Fulltext
3+
- [fix] Fixed possible heap-use-after in composite fulltext indexes, created over non-indexed fields
4+
- [fix] Fixed composite fulltext index cache invalidation after `UPDATE`-queries
5+
- [fix] Fixed deleted docs handling, when selection results exceeding `merge_limit` and there are multiple build steps in incremental index
6+
7+
## Vector indexes
8+
- [fix] Fixed possible buffer overflow in transactions logic in case of multithreading insertion into `HNSW`
9+
110
# Version 5.11.0 (06.02.2026)
211
## Core
312
- [fea] Optimized indexes memory layout for namespaces with large amount of items. Index `IdSet`-structures now produce noticeably less overhead

cpp_src/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ else()
6767
option(LINK_RESOURCES "Link web resources as binary data" ON)
6868
endif()
6969

70-
set (REINDEXER_VERSION_DEFAULT "5.11.0")
70+
set (REINDEXER_VERSION_DEFAULT "5.11.1")
7171

7272
if(NOT CMAKE_BUILD_TYPE)
7373
set(CMAKE_BUILD_TYPE "RelWithDebInfo")

cpp_src/cmd/reindexer_server/contrib/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ RUN mkdir build && \
3131

3232
FROM alpine:3.22
3333

34-
ARG RX_VERSION=v5.11.0
34+
ARG RX_VERSION=v5.11.1
3535

3636
COPY --from=build /usr/local /usr/local
3737
COPY --from=build /entrypoint.sh /entrypoint.sh

cpp_src/core/ft/ft_fast/mergerimpl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,9 @@ void Merger<IdCont, MergeDataType, MergeOffsetT>::collectRestrictingMask(std::ve
504504

505505
size_t minScoreDocsTaken = 0;
506506
for (size_t i = 0; i < docsScores.size(); i++) {
507+
if (vdocs[i].IsRemoved() || mergeStatuses_[i] == FtMergeStatuses::kExcluded) {
508+
continue;
509+
}
507510
if (docsScores[i] > minScore) {
508511
restrictingMask_.set(i);
509512
} else if (docsScores[i] == minScore && minScoreDocsTaken < minScoreDocs) {

cpp_src/core/index/indextext/fastindextext.cc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ Variant FastIndexText<T>::Upsert(const Variant& key, IdType id, bool& clearCache
6161
this->tracker_.markUpdated(this->idx_map, keyIt, false);
6262
} else {
6363
this->delMemStat(keyIt);
64+
Base::refreshCompositeKeyImpl(key, keyIt);
6465
}
6566
if (keyIt->second.Unsorted().Add(id, this->opts_.IsPK() ? IdSetEditMode::Ordered : IdSetEditMode::Auto, 0)) {
6667
this->isBuilt_ = false;
@@ -108,7 +109,7 @@ void FastIndexText<T>::Delete(const Variant& key, IdType id, MustExist mustExist
108109
{strHolder, this->KeyType().template Is<KeyValueType::String>()});
109110
} else {
110111
static_assert(is_payload_map_v<T>);
111-
this->idx_map.template erase<no_deep_clean>(keyIt);
112+
this->idx_map.template erase<no_deep_clean>(keyIt, strHolder);
112113
}
113114
} else {
114115
this->addMemStat(keyIt);
@@ -200,6 +201,7 @@ IdSet::Ptr FastIndexText<T>::afterSelect(FtCtx& ftCtx, MergeType&& mergeData, Ra
200201
case RankSortType::RankOnly:
201202
for (auto& vid : mergeData) {
202203
auto& vdoc = holder.vdocs_[vid.id.ToNumber()];
204+
assertrx_dbg(!vdoc.IsRemoved());
203205
assertrx_throw(!vdoc.keyEntry->Unsorted().empty());
204206
cnt += vdoc.keyEntry->Sorted(0).size();
205207
++relevantDocs;
@@ -562,8 +564,8 @@ std::unique_ptr<Index> FastIndexText_New(const IndexDef& idef, PayloadType&& pay
562564
return std::make_unique<FastIndexText<unordered_str_map<FtKeyEntry>>>(idef, std::move(payloadType), std::move(fields),
563565
cacheCfg);
564566
case IndexCompositeFastFT:
565-
return std::make_unique<FastIndexText<unordered_payload_map<FtKeyEntry>>>(idef, std::move(payloadType), std::move(fields),
566-
cacheCfg);
567+
return std::make_unique<FastIndexText<unordered_payload_map_ft<FtKeyEntry>>>(idef, std::move(payloadType), std::move(fields),
568+
cacheCfg);
567569
case IndexStrHash:
568570
case IndexStrBTree:
569571
case IndexIntBTree:

cpp_src/core/index/indextext/fuzzyindextext.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ std::unique_ptr<Index> FuzzyIndexText_New(const IndexDef& idef, PayloadType&& pa
7979
return std::make_unique<FuzzyIndexText<unordered_str_map<FtKeyEntry>>>(idef, std::move(payloadType), std::move(fields),
8080
cacheCfg);
8181
case IndexCompositeFuzzyFT:
82-
return std::make_unique<FuzzyIndexText<unordered_payload_map<FtKeyEntry>>>(idef, std::move(payloadType), std::move(fields),
83-
cacheCfg);
82+
return std::make_unique<FuzzyIndexText<unordered_payload_map_ft<FtKeyEntry>>>(idef, std::move(payloadType), std::move(fields),
83+
cacheCfg);
8484
case IndexStrHash:
8585
case IndexStrBTree:
8686
case IndexIntBTree:

cpp_src/core/index/indextext/indextext.cc

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ IndexText<T>::IndexText(const IndexDef& idef, PayloadType&& payloadType, FieldsS
3535
this->selectKeyType_ = KeyValueType::String{};
3636
initSearchers();
3737
}
38+
39+
template <typename T>
40+
bool IndexText<T>::RefreshCompositeKey(const Variant& key) noexcept {
41+
if (Base::RefreshCompositeKey(key)) {
42+
cache_ft_.Clear();
43+
return true;
44+
}
45+
return false;
46+
}
47+
3848
// Generic implementation for string index
3949
template <typename T>
4050
void IndexText<T>::initSearchers() {
@@ -78,6 +88,15 @@ void IndexText<T>::SetOpts(const IndexOpts& opts) {
7888
}
7989
}
8090

91+
template <typename T>
92+
bool IndexText<T>::HoldsStrings() const noexcept {
93+
if constexpr (is_payload_map_v<T>) {
94+
return this->idx_map.have_str_fields() || Base::HoldsStrings();
95+
} else {
96+
return Base::HoldsStrings();
97+
}
98+
}
99+
81100
template <typename T>
82101
void IndexText<T>::ReconfigureCache(const NamespaceCacheConfigData& cacheCfg) {
83102
if (cacheMaxSize_ != cacheCfg.ftIdxCacheSize || hitsToCache_ != cacheCfg.ftIdxHitsToCache) {
@@ -243,7 +262,19 @@ FieldsGetter IndexText<T>::Getter() {
243262
return FieldsGetter(this->Fields(), this->payloadType_, this->KeyType());
244263
}
245264

265+
template <typename T>
266+
void IndexText<T>::refreshCompositeKeyImpl(const Variant& key, typename T::iterator& keyIt) noexcept {
267+
if constexpr (is_payload_map_v<T>) {
268+
auto& newKey = static_cast<const PayloadValue&>(key);
269+
this->tracker_.refreshKey(keyIt->first, newKey);
270+
keyIt.refresh_key(PayloadValueWithHash(PayloadValue(newKey), this->payloadType_, this->Fields()));
271+
} else {
272+
(void)key;
273+
(void)keyIt;
274+
}
275+
}
276+
246277
template class IndexText<unordered_str_map<FtKeyEntry>>;
247-
template class IndexText<unordered_payload_map<FtKeyEntry>>;
278+
template class IndexText<unordered_payload_map_ft<FtKeyEntry>>;
248279

249280
} // namespace reindexer

cpp_src/core/index/indextext/indextext.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class [[nodiscard]] IndexText : public IndexUnordered<Map> {
2121
public:
2222
IndexText(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields, const NamespaceCacheConfigData& cacheCfg);
2323

24+
bool RefreshCompositeKey(const Variant& key) noexcept override;
2425
SelectKeyResults SelectKey(const VariantArray& keys, CondType, SortType, const Index::SelectContext&, const RdxContext&) override final;
2526
SelectKeyResults SelectKey(const VariantArray& keys, CondType, const Index::SelectContext&, FtPreselectT&&, const RdxContext&) override;
2627

@@ -39,6 +40,7 @@ class [[nodiscard]] IndexText : public IndexUnordered<Map> {
3940
commitFulltextImpl();
4041
this->isBuilt_ = true;
4142
}
43+
bool HoldsStrings() const noexcept override;
4244
void SetSortedIdxCount(int) override final {}
4345
void DestroyCache() override {
4446
Base::DestroyCache();
@@ -68,7 +70,7 @@ class [[nodiscard]] IndexText : public IndexUnordered<Map> {
6870

6971
void initSearchers();
7072
FieldsGetter Getter();
71-
73+
void refreshCompositeKeyImpl(const Variant& key, typename Map::iterator& keyIt) noexcept override;
7274
FtIdSetCache cache_ft_;
7375
size_t cacheMaxSize_;
7476
uint32_t hitsToCache_;

cpp_src/core/index/indexunordered.cc

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#include "indexunordered.h"
22
#include "core/dbconfig.h"
33
#include "core/index/indextext/ftkeyentry.h"
4-
#include "core/index/payload_map.h"
54
#include "core/index/string_map.h"
65
#include "core/indexdef.h"
76
#include "core/rdxcontext.h"
@@ -82,8 +81,8 @@ IndexUnordered<unordered_str_map<FtKeyEntry>>::IndexUnordered(const IndexDef& id
8281
hitsToCache_(cacheCfg.idxIdsetHitsToCache) {}
8382

8483
template <>
85-
IndexUnordered<unordered_payload_map<FtKeyEntry>>::IndexUnordered(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields,
86-
const NamespaceCacheConfigData& cacheCfg)
84+
IndexUnordered<unordered_payload_map_ft<FtKeyEntry>>::IndexUnordered(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields,
85+
const NamespaceCacheConfigData& cacheCfg)
8786
: Base(idef, std::move(payloadType), std::move(fields)),
8887
idx_map(PayloadType{Base::GetPayloadType()}, FieldsSet{Base::Fields()}),
8988
cacheMaxSize_(cacheCfg.idxIdsetCacheSize),
@@ -219,6 +218,7 @@ Variant IndexUnordered<T>::Upsert(const Variant& key, IdType id, bool& clearCach
219218
if (keyIt == this->idx_map.end()) {
220219
keyIt = this->idx_map.insert({static_cast<key_type>(key), typename T::mapped_type()}).first;
221220
} else {
221+
refreshCompositeKeyImpl(key, keyIt);
222222
delMemStat(keyIt);
223223
if (this->opts_.IsPK()) {
224224
WrSerializer wrser;
@@ -278,9 +278,12 @@ void IndexUnordered<T>::Delete(const Variant& key, IdType id, MustExist mustExis
278278
if constexpr (is_str_map_v<T>) {
279279
idx_map.template erase<StringMapEntryCleaner<true>>(
280280
keyIt, {strHolder, this->KeyType().template Is<KeyValueType::String>() && this->opts_.GetCollateMode() == CollateNone});
281+
} else if constexpr (is_ft_payload_map_v<T>) {
282+
idx_map.template erase<DeepClean>(keyIt, strHolder);
281283
} else {
282284
idx_map.template erase<DeepClean>(keyIt);
283285
}
286+
284287
} else {
285288
addMemStat(keyIt);
286289
this->tracker_.markUpdated(this->idx_map, keyIt);
@@ -299,27 +302,10 @@ bool IndexUnordered<T>::RefreshCompositeKey(const Variant& key) noexcept {
299302
assertrx_dbg(false);
300303
return false;
301304
}
302-
delMemStat(keyIt);
303305

304-
#ifdef RX_WITH_STDLIB_DEBUG
305-
const hash_composite hashF(this->GetPayloadType(), this->Fields());
306-
assertrx_dbg(hashF(keyIt->first) == hashF(static_cast<const PayloadValue&>(key)));
307-
const equal_composite equalF(this->GetPayloadType(), this->Fields());
308-
assertrx_dbg(equalF(keyIt->first, static_cast<const PayloadValue&>(key)));
309-
const less_composite lessF(PayloadType(this->GetPayloadType()), FieldsSet(this->Fields()));
310-
assertrx_dbg(!lessF(keyIt->first, static_cast<const PayloadValue&>(key)));
311-
assertrx_dbg(!lessF(static_cast<const PayloadValue&>(key), keyIt->first));
312-
#endif // RX_WITH_STDLIB_DEBUG
313-
314-
auto& newKey = static_cast<const PayloadValue&>(key);
315-
this->tracker_.refreshKey(keyIt->first, static_cast<const PayloadValue&>(key));
316-
if constexpr (std::is_same_v<typename T::key_type, PayloadValueWithHash>) {
317-
const_cast<PayloadValueWithHash&>(keyIt->first) =
318-
PayloadValueWithHash(PayloadValue(newKey), this->payloadType_, this->Fields());
306+
delMemStat(keyIt);
319307

320-
} else {
321-
const_cast<PayloadValue&>(keyIt->first) = newKey;
322-
}
308+
refreshCompositeKeyImpl(key, keyIt);
323309

324310
addMemStat(keyIt);
325311
cache_.ResetImpl();
@@ -602,6 +588,34 @@ IndexMemStat IndexUnordered<T>::GetMemStat(const RdxContext& ctx) {
602588
return ret;
603589
}
604590

591+
template <typename T>
592+
void IndexUnordered<T>::refreshCompositeKeyImpl(const Variant& key, typename T::iterator& keyIt) noexcept {
593+
if constexpr (is_payload_map_v<T>) {
594+
#ifdef RX_WITH_STDLIB_DEBUG
595+
const hash_composite hashF(this->GetPayloadType(), this->Fields());
596+
assertrx_dbg(hashF(keyIt->first) == hashF(static_cast<const PayloadValue&>(key)));
597+
const equal_composite equalF(this->GetPayloadType(), this->Fields());
598+
assertrx_dbg(equalF(keyIt->first, static_cast<const PayloadValue&>(key)));
599+
const less_composite lessF(PayloadType(this->GetPayloadType()), FieldsSet(this->Fields()));
600+
assertrx_dbg(!lessF(keyIt->first, static_cast<const PayloadValue&>(key)));
601+
assertrx_dbg(!lessF(static_cast<const PayloadValue&>(key), keyIt->first));
602+
#endif // RX_WITH_STDLIB_DEBUG
603+
604+
auto& newKey = static_cast<const PayloadValue&>(key);
605+
this->tracker_.refreshKey(keyIt->first, static_cast<const PayloadValue&>(key));
606+
if constexpr (std::is_same_v<typename T::key_type, PayloadValueWithHash>) {
607+
const_cast<PayloadValueWithHash&>(keyIt->first) =
608+
PayloadValueWithHash(PayloadValue(newKey), this->payloadType_, this->Fields());
609+
610+
} else {
611+
const_cast<PayloadValue&>(keyIt->first) = newKey;
612+
}
613+
} else {
614+
(void)key;
615+
(void)keyIt;
616+
}
617+
}
618+
605619
template <typename T>
606620
template <typename S>
607621
void IndexUnordered<T>::dump(S& os, std::string_view step, std::string_view offset) const {
@@ -724,7 +738,7 @@ template class IndexUnordered<payload_map<Index::KeyEntry>>;
724738

725739
template class IndexUnordered<unordered_str_map<FtKeyEntry>>;
726740

727-
template class IndexUnordered<unordered_payload_map<FtKeyEntry>>;
741+
template class IndexUnordered<unordered_payload_map_ft<FtKeyEntry>>;
728742

729743
template class IndexUnordered<unordered_uuid_map<Index::KeyEntryPK>>;
730744
template class IndexUnordered<unordered_uuid_map<Index::KeyEntryPlain>>;

0 commit comments

Comments
 (0)