What is an atomic operation?
An atomic operation is a memory read, write, or read-modify-write that the hardware carries out as one indivisible step from the perspective of other threads — so no other thread can observe a torn half-update or interleave its own access in the middle of that step.
What problem do atomic operations solve that ordinary loads and stores do not?
A plain increment of a shared counter in software is usually several CPU instructions: load the value into a register, add one, store it back. Between those instructions another thread can load the old value, do its own add, and store — so both threads think they incremented once, yet the counter only moved by one. Larger structures are worse: updating two fields of a node, or writing a pointer and a length, can leave a reader in another thread seeing the new pointer with the old length, or only part of a multi-byte value on some architectures. Atomic operations close that window for a single memory location (or a small, hardware-supported unit) by guaranteeing the load-modify-store, or the write, appears instantaneous to others. They are the building blocks underneath lock-free counters, flags, and many “compare and swap” loops that retry until an update sticks.
Concurrent HNSW needs exactly this kind of guarantee for a handful of hot shared fields even when most of a search touches only private heaps.
Where do atomic operations typically appear in concurrent HNSW?
Global metadata is the classic case: the current entry point, the maximum level seen so far, the next free node ID, or a generation counter used to reset visited sets without clearing a huge array. Two inserting threads might both try to claim a new node index or publish a higher entry point; atomic fetch-add or compare-and-swap makes one winner without corrupting the counter. Some designs mark a node as deleted or “being updated” with an atomic flag so searchers can skip or retry instead of following a half-rewired neighbor list. Read-mostly query paths may still use atomic loads with acquire semantics when they must observe a writer’s published graph update in the right order. Systems that serve concurrent queries and inserts against one in-memory graph — including deployments like Weaviate’s HNSW index — rely on these primitives (often wrapped in a language’s atomic or synchronization library) so shared counters and publication flags stay coherent across threads.
Atomicity for one word is not the same as coordinating a whole neighbor-list rewrite, which is why atomics and locks usually coexist in a real implementation.
How do atomics relate to mutexes and to memory ordering?
A mutex makes an entire critical section appear atomic — many loads and stores to many locations — by ensuring only one thread runs that section at a time. An atomic operation makes one hardware-sized access indivisible without excluding other threads from the rest of the graph. Updating a node’s full neighbor array is usually too large for a single atomic; implementations either lock that node, rebuild under a private buffer and swing a pointer with one atomic publish, or accept a protocol where readers notice a version bump and retry. Memory ordering is the subtle twin: even an atomic write can be reordered with surrounding accesses unless the programmer picks the right barrier semantics (relaxed, acquire, release, sequential consistency). Publishing a new neighbor-list pointer with release, then reading it with acquire on the search side, is the usual pattern so a query never follows a pointer to uninitialized edge storage. Getting the atomicity right but the ordering wrong still produces rare, timing-dependent graph corruption that is notoriously hard to reproduce.
Atomics are also not free: under contention they bounce cache lines between cores and can dominate profiles just like a hot lock.
When do atomic operations become a performance problem in HNSW?
Every atomic read-modify-write needs exclusive ownership of the cache line that holds the variable. If all insertion threads hammer the same next-ID counter or the same global statistics word, that line ping-pongs across the machine — a form of contention closely related to false sharing when unrelated fields share a line. The fix is the same spirit as for locks: keep per-thread counters and merge occasionally, shard free-list allocation, and avoid putting a global atomic on the search hot path when a thread-local visited generation would do. For queries, prefer read-only traversal of an immutable snapshot over atomic bumps on every hop. Used sparingly on true shared publication points, atomics are cheap compared with the distance work HNSW already does; used as a substitute for thoughtful ownership on every edge update, they become a scalability ceiling.
An atomic operation is the hardware’s indivisible memory step that keeps shared HNSW metadata coherent across threads without locking the whole graph. From here, the pages on mutexes and reader/writer locks cover broader critical sections, false sharing and contention explain the cache-line cost of hot atomics, the thread glossary entry sets the concurrent actors in place, and the chapter on concurrent HNSW construction and querying shows how these primitives combine into a full protocol.