Skip to content

Commit 77bf0c5

Browse files
committed
replacing ndoes mutex in one byte mutex
1 parent dd48820 commit 77bf0c5

File tree

2 files changed

+41
-19
lines changed

2 files changed

+41
-19
lines changed

src/VecSim/algorithms/hnsw/hnsw.h

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ class HNSWIndex : public VecSimIndexAbstract<DistType>,
9797
mutable VisitedNodesHandlerPool visited_nodes_handler_pool;
9898
mutable std::mutex entry_point_guard_;
9999
mutable std::mutex index_data_guard_;
100-
mutable vecsim_stl::vector<std::mutex> element_neighbors_locks_;
100+
mutable vecsim_stl::vector<vecsim_stl::one_byte_mutex> element_neighbors_locks_;
101101

102102
#ifdef BUILD_TESTS
103103
#include "VecSim/algorithms/hnsw/hnsw_base_tests_friends.h"
@@ -148,8 +148,8 @@ class HNSWIndex : public VecSimIndexAbstract<DistType>,
148148
void revisitNeighborConnections(size_t level, idType new_node_id, idType selected_neighbor,
149149
idType *new_node_neighbors_list,
150150
idType *neighbor_neighbors_list,
151-
std::unique_lock<std::mutex> &node_lock,
152-
std::unique_lock<std::mutex> &neighbor_lock);
151+
std::unique_lock<vecsim_stl::one_byte_mutex> &node_lock,
152+
std::unique_lock<vecsim_stl::one_byte_mutex> &neighbor_lock);
153153
idType mutuallyConnectNewElement(idType new_node_id,
154154
candidatesMaxHeap<DistType> &top_candidates, size_t level);
155155
template <bool with_timeout>
@@ -484,7 +484,7 @@ DistType HNSWIndex<DataType, DistType>::processCandidate(
484484
tag_t *elements_tags, vecsim_stl::abstract_priority_queue<DistType, Identifier> &top_candidates,
485485
candidatesMaxHeap<DistType> &candidate_set, DistType lowerBound) const {
486486

487-
std::unique_lock<std::mutex> lock(element_neighbors_locks_[curNodeId]);
487+
std::unique_lock<vecsim_stl::one_byte_mutex> lock(element_neighbors_locks_[curNodeId]);
488488
idType *node_links = get_linklist_at_level(curNodeId, layer);
489489
linkListSize links_num = getListCount(node_links);
490490

@@ -536,7 +536,7 @@ void HNSWIndex<DataType, DistType>::processCandidate_RangeSearch(
536536
tag_t *elements_tags, std::unique_ptr<vecsim_stl::abstract_results_container> &results,
537537
candidatesMaxHeap<DistType> &candidate_set, DistType dyn_range, double radius) const {
538538

539-
std::unique_lock<std::mutex> lock(element_neighbors_locks_[curNodeId]);
539+
std::unique_lock<vecsim_stl::one_byte_mutex> lock(element_neighbors_locks_[curNodeId]);
540540
idType *node_links = get_linklist_at_level(curNodeId, layer);
541541
linkListSize links_num = getListCount(node_links);
542542

@@ -665,8 +665,8 @@ void HNSWIndex<DataType, DistType>::getNeighborsByHeuristic2(
665665
template <typename DataType, typename DistType>
666666
void HNSWIndex<DataType, DistType>::revisitNeighborConnections(
667667
size_t level, idType new_node_id, idType selected_neighbor, idType *new_node_neighbors_list,
668-
idType *neighbor_neighbors_list, std::unique_lock<std::mutex> &node_lock,
669-
std::unique_lock<std::mutex> &neighbor_lock) {
668+
idType *neighbor_neighbors_list, std::unique_lock<vecsim_stl::one_byte_mutex> &node_lock,
669+
std::unique_lock<vecsim_stl::one_byte_mutex> &neighbor_lock) {
670670

671671
// Collect the existing neighbors and the new node as the neighbor's neighbors candidates.
672672
candidatesMaxHeap<DistType> candidates(this->allocator);
@@ -717,9 +717,10 @@ void HNSWIndex<DataType, DistType>::revisitNeighborConnections(
717717

718718
std::sort(nodes_to_update.begin(), nodes_to_update.end());
719719
size_t nodes_to_update_count = nodes_to_update.size();
720-
std::unique_lock<std::mutex> locks[nodes_to_update_count];
720+
std::unique_lock<vecsim_stl::one_byte_mutex> locks[nodes_to_update_count];
721721
for (size_t i = 0; i < nodes_to_update_count; i++) {
722-
locks[i] = std::unique_lock<std::mutex>(element_neighbors_locks_[nodes_to_update[i]]);
722+
locks[i] = std::unique_lock<vecsim_stl::one_byte_mutex>(
723+
element_neighbors_locks_[nodes_to_update[i]]);
723724
}
724725

725726
auto *neighbour_incoming_edges = getIncomingEdgesPtr(selected_neighbor, level);
@@ -809,17 +810,19 @@ idType HNSWIndex<DataType, DistType>::mutuallyConnectNewElement(
809810
setIncomingEdgesPtr(new_node_id, level, (void *)incoming_edges);
810811

811812
for (idType selected_neighbor : selected_neighbors) {
812-
std::unique_lock<std::mutex> node_lock;
813-
std::unique_lock<std::mutex> neighbor_lock;
813+
std::unique_lock<vecsim_stl::one_byte_mutex> node_lock;
814+
std::unique_lock<vecsim_stl::one_byte_mutex> neighbor_lock;
814815
idType lower_id = (new_node_id < selected_neighbor) ? new_node_id : selected_neighbor;
815816
if (lower_id == new_node_id) {
816-
node_lock = std::unique_lock<std::mutex>(element_neighbors_locks_[new_node_id]);
817-
neighbor_lock =
818-
std::unique_lock<std::mutex>(element_neighbors_locks_[selected_neighbor]);
817+
node_lock =
818+
std::unique_lock<vecsim_stl::one_byte_mutex>(element_neighbors_locks_[new_node_id]);
819+
neighbor_lock = std::unique_lock<vecsim_stl::one_byte_mutex>(
820+
element_neighbors_locks_[selected_neighbor]);
819821
} else {
820-
neighbor_lock =
821-
std::unique_lock<std::mutex>(element_neighbors_locks_[selected_neighbor]);
822-
node_lock = std::unique_lock<std::mutex>(element_neighbors_locks_[new_node_id]);
822+
neighbor_lock = std::unique_lock<vecsim_stl::one_byte_mutex>(
823+
element_neighbors_locks_[selected_neighbor]);
824+
node_lock =
825+
std::unique_lock<vecsim_stl::one_byte_mutex>(element_neighbors_locks_[new_node_id]);
823826
}
824827

825828
// get the updated count - this may change between iterations due to releasing the lock.
@@ -1077,7 +1080,7 @@ void HNSWIndex<DataType, DistType>::greedySearchLevel(const void *vector_data, s
10771080
return;
10781081
}
10791082
changed = false;
1080-
std::unique_lock<std::mutex> lock(element_neighbors_locks_[curObj]);
1083+
std::unique_lock<vecsim_stl::one_byte_mutex> lock(element_neighbors_locks_[curObj]);
10811084
idType *node_links = get_linklist(curObj, level);
10821085
linkListSize links_count = getListCount(node_links);
10831086

@@ -1103,7 +1106,7 @@ void HNSWIndex<DataType, DistType>::resizeIndexInternal(size_t new_max_elements)
11031106
element_levels_.shrink_to_fit();
11041107
resizeLabelLookup(new_max_elements);
11051108
visited_nodes_handler_pool.resize(new_max_elements);
1106-
vecsim_stl::vector<std::mutex>(new_max_elements, this->allocator)
1109+
vecsim_stl::vector<vecsim_stl::one_byte_mutex>(new_max_elements, this->allocator)
11071110
.swap(element_neighbors_locks_);
11081111
// Reallocate base layer
11091112
char *data_level0_memory_new = (char *)this->allocator->reallocate(

src/VecSim/utils/vecsim_stl.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,23 @@ class unordered_set
9191
alloc) {}
9292
};
9393

94+
struct one_byte_mutex {
95+
void lock() {
96+
if (state.exchange(locked, std::memory_order_acquire) == unlocked)
97+
return;
98+
while (state.exchange(sleeper, std::memory_order_acquire) != unlocked)
99+
state.wait(sleeper, std::memory_order_relaxed);
100+
}
101+
void unlock() {
102+
if (state.exchange(unlocked, std::memory_order_release) == sleeper)
103+
state.notify_one();
104+
}
105+
106+
private:
107+
std::atomic<uint8_t> state{unlocked};
108+
109+
static constexpr uint8_t unlocked = 0;
110+
static constexpr uint8_t locked = 0b01;
111+
static constexpr uint8_t sleeper = 0b10;
112+
};
94113
} // namespace vecsim_stl

0 commit comments

Comments
 (0)