Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
345b9d1
MOD-14916 Devirtualize HNSW / brute-force search hot path (#937)
ofiryanai Apr 19, 2026
4f9d216
initial
Jun 23, 2026
b5c1c08
optimization
Jun 26, 2026
417b970
fix threadpool
Jun 26, 2026
2d5d699
minor fix
Jun 26, 2026
3c3f842
minor cleaning
Jun 29, 2026
952efbf
clean up
Jul 1, 2026
8265a7a
remove dead code
Jul 1, 2026
71c92bd
fixes; tests pass
Jul 8, 2026
b130e31
refactoring
Jul 8, 2026
78b4ef0
fixes for GC
Jul 15, 2026
fedd22e
copy blob before flat unlock
Jul 20, 2026
fcf83dd
Remove null characters from end of file
mihaic Jul 24, 2026
7b71aac
Merge pull request #1 from mihaic/lockfree-fix-end
razdoburdin Jul 25, 2026
4035699
fixes for gc
Jul 28, 2026
5f182bb
Merge branch 'lockfree' of https://github.com/razdoburdin/VectorSimil…
Jul 28, 2026
649460a
fix writer starvation for compaction
Jul 30, 2026
07f2c8f
adopt sigle label consolidation
Aug 11, 2026
db1d106
vecsim separate fin-grain index enabling
ethanglaser Aug 22, 2026
a540c0a
Rename SVSIndexBase thread API to match upstream
ethanglaser Aug 27, 2026
29c6af6
Merge upstream/main into dev/eglaser-lockfree
ethanglaser Aug 27, 2026
ac97868
CI fixes
ethanglaser Sep 2, 2026
a32aa9d
clean-up commented and unused dead code
Sep 3, 2026
978a49e
harmonize test
Sep 3, 2026
30abed6
Merge branch 'main' into dev/eglaser-lockfree
razdoburdin Sep 4, 2026
2a06ff7
minor revisions for CI
ethanglaser Sep 4, 2026
095ae3b
fix build and tests
Sep 7, 2026
6379bfd
Merge branch 'dev/eglaser-lockfree' of https://github.com/ethanglaser…
Sep 7, 2026
cce885c
fix ub
Sep 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
362 changes: 237 additions & 125 deletions src/VecSim/algorithms/svs/svs.h

Large diffs are not rendered by default.

22 changes: 16 additions & 6 deletions src/VecSim/algorithms/svs/svs_extensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,28 @@
#pragma once
#include "VecSim/algorithms/svs/svs_utils.h"
#include "svs/extensions/vamana/scalar.h"
// Tells SQDataset that the concurrent SegmentedBlocked tag is a blocked allocator, so
// that resize()/compact() are not constrained away. Without it a scalar-quantized
// concurrent index fails to compile the moment the index grows.
#include "svs/concurrent/extensions/scalar.h"

#if HAVE_SVS_LVQ
#include SVS_LVQ_HEADER
#include SVS_LEANVEC_HEADER
// The same treatment for the LVQ and LeanVec datasets, each of which keeps its own private
// copy of the blocked-allocator trait. LeanVec additionally picks the allocator for its inner
// datasets through that trait, and its blocked branch hardcodes svs::data::Blocked -- so
// without this the inner storage would quietly lose the grow-stable guarantee.
#include "svs/concurrent/extensions/lvq.h"
#include "svs/concurrent/extensions/leanvec.h"
#endif // HAVE_SVS_LVQ

// Scalar Quantization traits for SVS
template <typename DataType>
struct SVSStorageTraits<DataType, 1, 0, false> {
using element_type = std::int8_t;
using allocator_type = svs_details::SVSAllocator<element_type>;
using blocked_type = svs::data::Blocked<svs::AllocatorHandle<element_type>>;
using blocked_type = svs::concurrent::SegmentedBlocked<svs::AllocatorHandle<element_type>>;
using index_storage_type =
svs::quantization::scalar::SQDataset<element_type, svs::Dynamic, blocked_type>;

Expand All @@ -32,7 +42,7 @@ struct SVSStorageTraits<DataType, 1, 0, false> {
// SVS block size is a power of two, so we can use it directly
auto svs_bs = svs_details::SVSBlockSize(block_size, element_size(dim));
allocator_type data_allocator{std::move(allocator)};
return svs::make_blocked_allocator_handle({svs_bs}, data_allocator);
return svs_details::make_segmented_blocked_allocator_handle({svs_bs}, data_allocator);
}

static constexpr VecSimSvsQuantBits get_compression_mode() { return VecSimSvsQuant_Scalar; }
Expand Down Expand Up @@ -89,7 +99,7 @@ template <typename DataType, size_t QuantBits, size_t ResidualBits>
struct SVSStorageTraits<DataType, QuantBits, ResidualBits, false,
std::enable_if_t<(QuantBits > 1)>> {
using allocator_type = svs_details::SVSAllocator<std::byte>;
using blocked_type = svs::data::Blocked<svs::AllocatorHandle<std::byte>>;
using blocked_type = svs::concurrent::SegmentedBlocked<svs::AllocatorHandle<std::byte>>;
using strategy_type = typename svs_details::LVQSelector<QuantBits>::strategy;
using index_storage_type =
svs::quantization::lvq::LVQDataset<QuantBits, ResidualBits, svs::Dynamic, strategy_type,
Expand Down Expand Up @@ -118,7 +128,7 @@ struct SVSStorageTraits<DataType, QuantBits, ResidualBits, false,
auto elem_size = std::max(primary_element_size(dim), residual_element_size(dim));
auto svs_bs = svs_details::SVSBlockSize(block_size, elem_size);
allocator_type data_allocator{std::move(allocator)};
return svs::make_blocked_allocator_handle({svs_bs}, data_allocator);
return svs_details::make_segmented_blocked_allocator_handle({svs_bs}, data_allocator);
}

template <svs::data::ImmutableMemoryDataset Dataset, svs::threads::ThreadPool Pool>
Expand Down Expand Up @@ -181,7 +191,7 @@ struct SVSStorageTraits<DataType, QuantBits, ResidualBits, false,
template <typename DataType, size_t QuantBits, size_t ResidualBits>
struct SVSStorageTraits<DataType, QuantBits, ResidualBits, true> {
using allocator_type = svs_details::SVSAllocator<std::byte>;
using blocked_type = svs::data::Blocked<svs::AllocatorHandle<std::byte>>;
using blocked_type = svs::concurrent::SegmentedBlocked<svs::AllocatorHandle<std::byte>>;
using index_storage_type = svs::leanvec::LeanDataset<svs::leanvec::UsingLVQ<QuantBits>,
svs::leanvec::UsingLVQ<ResidualBits>,
svs::Dynamic, svs::Dynamic, blocked_type>;
Expand Down Expand Up @@ -212,7 +222,7 @@ struct SVSStorageTraits<DataType, QuantBits, ResidualBits, true> {
auto elem_size = std::max(primary_element_size(dim), secondary_element_size(dim));
auto svs_bs = svs_details::SVSBlockSize(block_size, elem_size);
allocator_type data_allocator{std::move(allocator)};
return svs::make_blocked_allocator_handle({svs_bs}, data_allocator);
return svs_details::make_segmented_blocked_allocator_handle({svs_bs}, data_allocator);
}

template <svs::data::ImmutableMemoryDataset Dataset, svs::threads::ThreadPool Pool>
Expand Down
7 changes: 4 additions & 3 deletions src/VecSim/algorithms/svs/svs_serializer_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,17 +93,17 @@ void SVSIndex<MetricType, DataType, isMulti, QuantBits, ResidualBits, IsLeanVec>
compareMetadataFile(folder_path + "/metadata");

if constexpr (isMulti) {
auto loaded = svs::index::vamana::auto_multi_dynamic_assemble(
auto loaded = svs::concurrent::auto_multi_dynamic_assemble(
folder_path + "/config",
SVS_LAZY(graph_builder_t::load(folder_path + "/graph", this->blockSize,
this->buildParams, this->getAllocator())),
SVS_LAZY(storage_traits_t::load(folder_path + "/data", this->blockSize, this->dim,
this->getAllocator())),
distance_f(), std::move(threadpool_handle),
svs::index::vamana::MultiMutableVamanaLoad::FROM_MULTI, logger_);
svs::concurrent::MultiMutableVamanaLoad::FROM_MULTI, logger_);
impl_ = std::make_unique<impl_type>(std::move(loaded));
} else {
auto loaded = svs::index::vamana::auto_dynamic_assemble(
auto loaded = svs::concurrent::auto_dynamic_assemble(
folder_path + "/config",
SVS_LAZY(graph_builder_t::load(folder_path + "/graph", this->blockSize,
this->buildParams, this->getAllocator())),
Expand All @@ -112,6 +112,7 @@ void SVSIndex<MetricType, DataType, isMulti, QuantBits, ResidualBits, IsLeanVec>
distance_f(), std::move(threadpool_handle), false, logger_);
impl_ = std::make_unique<impl_type>(std::move(loaded));
}
setReady();
}

template <typename MetricType, typename DataType, bool isMulti, size_t QuantBits,
Expand Down
Loading