Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
af0f8e2
initial
Apr 20, 2026
339d156
use shared_mutex for translator protection
Apr 22, 2026
0683f0c
Merge branch 'main' into seqlock
razdoburdin Apr 28, 2026
0c76ef3
fix translator size calculation
Apr 28, 2026
d336a1f
fix silent edge drop during concurent addition
Apr 28, 2026
7c510e4
fix insertion into deleted translarot entry
Apr 29, 2026
1f3f1b2
bump clang version to clang19 for macos ci
Apr 29, 2026
ac6113c
bump clang version to clang20 for macos ci
Apr 29, 2026
ffebf9c
fix macos build
Apr 29, 2026
46800ff
fix silent vector loosing in concurent additions
Apr 30, 2026
7bf994f
fix consolidate
May 4, 2026
5d8ecdf
Merge branch 'main' into seqlock
razdoburdin May 5, 2026
25b5b53
reduce critical section in add_points()
May 19, 2026
826421b
Merge branch 'main' into seqlock
razdoburdin May 19, 2026
7caf032
fix race for compact()
May 29, 2026
1cfe979
Merge branch 'main' into seqlock
razdoburdin May 29, 2026
fe4c380
fix race for concurent resize vs search
Jun 2, 2026
44a8ec0
fix race for iterator
Jun 5, 2026
bce928c
initial
Jun 10, 2026
c56958b
set segmentsize 512
Jun 10, 2026
886ce9a
simplify and improve
Jun 11, 2026
6244510
Merge branch 'intel:main' into seqlock
razdoburdin Jun 11, 2026
f9ce259
fixes for multi and reported num_deleted
Jul 9, 2026
b2a4ae7
linting
Jul 9, 2026
9d57724
add_points keeps date unmodified if throw
Jul 13, 2026
6d746f9
fix delete-consolidate-compact race
Jul 15, 2026
1e0f547
gc fixes
Jul 27, 2026
c32569d
revert redundant changes
Jul 27, 2026
5a0b92d
Merge branch 'main' into seqlock
razdoburdin Jul 28, 2026
0abe7f3
fix MutableVamana Index Memory Usage test
Jul 28, 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
7 changes: 5 additions & 2 deletions bindings/python/include/svs/python/manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ pybind11::tuple py_search(
matrix_view(result_idx), matrix_view(result_dists)
);

svs::index::search_batch_into(self, q_result, query_data.cview());
{
pybind11::gil_scoped_release release;
svs::index::search_batch_into(self, q_result, query_data.cview());
}
return pybind11::make_tuple(result_idx, result_dists);
}

Expand Down Expand Up @@ -86,7 +89,7 @@ void add_threading_interface(pybind11::class_<Manager>& manager) {
"num_threads",
&Manager::get_num_threads,
[](Manager& self, int num_threads) {
self.set_threadpool(svs::threads::DefaultThreadPool(num_threads));
self.set_threadpool(svs::threads::SwitchNativeThreadPool(num_threads));
},
"Read/Write (int): Get and set the number of threads used to process queries."
);
Expand Down
27 changes: 23 additions & 4 deletions bindings/python/src/dynamic_vamana.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,12 @@ void add_points(
"Expected IDs to be the same length as the number of rows in points!"
);
}
index.add_points(data_view(py_data), std::span(ids.data(), ids.size()), reuse_empty);
auto data = data_view(py_data);
auto id_span = std::span(ids.data(), ids.size());
{
py::gil_scoped_release release;
index.add_points(data, id_span, reuse_empty);
}
}

const char* ADD_POINTS_DOCSTRING = R"(
Expand Down Expand Up @@ -381,8 +386,18 @@ void wrap(py::module& m) {

add_dynamic_vamana_properties(vamana);

vamana.def("consolidate", &svs::DynamicVamana::consolidate, CONSOLIDATE_DOCSTRING);
vamana.def("compact", &svs::DynamicVamana::compact, COMPACT_DOCSTRING);
vamana.def(
"consolidate",
&svs::DynamicVamana::consolidate,
py::call_guard<py::gil_scoped_release>(),
CONSOLIDATE_DOCSTRING
);
vamana.def(
"compact",
&svs::DynamicVamana::compact,
py::call_guard<py::gil_scoped_release>(),
COMPACT_DOCSTRING
);

// Reloading
vamana.def(
Expand Down Expand Up @@ -435,7 +450,11 @@ void wrap(py::module& m) {
vamana.def(
"delete",
[](svs::DynamicVamana& index, const py_contiguous_array_t<size_t>& ids) {
index.delete_points(as_span(ids));
auto id_span = as_span(ids);
{
py::gil_scoped_release release;
index.delete_points(id_span);
}
},
py::arg("ids"),
DELETE_DOCSTRING
Expand Down
2 changes: 1 addition & 1 deletion bindings/python/src/python_bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ class ScopedModuleNameOverride {

} // namespace

PYBIND11_MODULE(_svs, m) {
PYBIND11_MODULE(_svs, m, py::mod_gil_not_used()) {
// Internally, the top level `__init__.py` imports everything from the C++ module named
// `_svs`.
//
Expand Down
22 changes: 16 additions & 6 deletions include/svs/concepts/graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@

namespace svs::graphs {

/// Outcome of `MemoryGraph::add_edge(src, dst)`. Distinguishes three cases so callers
/// can route dropped edges (e.g. to a backedge buffer) without a TOCTOU race between a
/// pre-check and the insert.
enum class AddEdgeResult : uint8_t {
Added, // Edge was inserted.
AlreadyExists, // Edge was already present (or self-loop). Not inserted.
Full, // Node's adjacency list is at max_degree. Edge NOT inserted.
};

// clang-format off

///
Expand Down Expand Up @@ -135,12 +144,13 @@ template <ImmutableMemoryGraph G> using index_type_t = typename G::index_type;
/// @code{.cpp}
/// template <typename T>
/// concept MemoryGraph = requires(T& g, const T& const_g) {
/// // Add an edge to the graph.
/// // Must return the out degree of `src` after adding the edge `src -> dst`.
/// // If adding the edge would result in the graph exceeding its maximum degree,
/// // implementations are free to not add this edge.
/// // Add an edge to the graph atomically. Returns an AddEdgeResult indicating:
/// // Added - edge was inserted
/// // AlreadyExists - edge was already present (or self-loop); no insert
/// // Full - node is at max_degree; edge NOT inserted (caller should
/// // route to an overflow buffer if needed)
/// requires requires(index_type_t<T> src, index_type_t<T> dst) {
/// { g.add_edge(src, dst) } -> std::convertible_to<size_t>;
/// { g.add_edge(src, dst) } -> std::convertible_to<AddEdgeResult>;
/// };
///
/// // Completely clear the adjacency list for vertex ``i``.
Expand All @@ -164,7 +174,7 @@ template <typename T>
concept MemoryGraph = requires(T& g, const T& const_g) {
// Adding an edge.
requires requires(index_type_t<T> src, index_type_t<T> dst) {
{ g.add_edge(src, dst) } -> std::convertible_to<size_t>;
{ g.add_edge(src, dst) } -> std::convertible_to<AddEdgeResult>;
};

// Clear adjacency list.
Expand Down
13 changes: 9 additions & 4 deletions include/svs/core/data/simple.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "svs/lib/misc.h"
#include "svs/lib/prefetch.h"
#include "svs/lib/saveload.h"
#include "svs/lib/segmented_vector.h"
#include "svs/lib/threads.h"
#include "svs/lib/uuid.h"

Expand Down Expand Up @@ -729,7 +730,6 @@ class SimpleData<T, Extent, Blocked<Alloc>> {
, allocator_{alloc} {
size_t elements_per_block = blocksize_.value();
size_t num_blocks = lib::div_round_up(n_elements, elements_per_block);
blocks_.reserve(num_blocks);
for (size_t i = 0; i < num_blocks; ++i) {
add_block();
}
Expand Down Expand Up @@ -782,10 +782,10 @@ class SimpleData<T, Extent, Blocked<Alloc>> {
/// Add a new data block to the end of the current collection of blocks.
///
void add_block() {
blocks_.emplace_back(
blocks_.push_back(array_type(
make_dims(blocksize().value(), lib::forward_extent<Extent>(dimensions())),
allocator_.get_allocator()
);
));
}

///
Expand Down Expand Up @@ -967,7 +967,12 @@ class SimpleData<T, Extent, Blocked<Alloc>> {
private:
// The blocksize in terms of number of vectors.
lib::PowerOfTwo blocksize_;
std::vector<array_type> blocks_;
// Grow-stable directory of fixed-size blocks: appending a block never relocates the
// existing block wrappers (or the heap buffers they point to), so a concurrent
// lock-free reader subscripting blocks_[block_id] is safe against a writer growing the
// dataset. Element addressing (block_id, data_id) is unchanged; only the outer block
// directory is grow-stable (2-level lock-free array). See svs/lib/segmented_vector.h.
lib::SegmentedVector<array_type> blocks_;
size_t dimensions_;
size_t size_;
Blocked<Alloc> allocator_;
Expand Down
Loading
Loading