MDEV-39832 mhnsw: skip non-dirty nodes when invalidating the shared cache on commit#5173
MDEV-39832 mhnsw: skip non-dirty nodes when invalidating the shared cache on commit#5173RalXYZ wants to merge 1 commit into
Conversation
…ache on commit
Add a dirty bit to FVectorNode, set it in FVectorNode::save() (which
covers the inserted target node and every neighbor rewritten by
update_second_degree_neighbors) and in mhnsw_invalidate() alongside
the deleted flag. The partial-invalidation loop in do_commit now skips
non-dirty entries. The pre-existing TODO ("consider flushing only
changed nodes (a flag in the node)") is removed.
There was a problem hiding this comment.
Code Review
This pull request introduces a dirty flag to FVectorNode to track modified nodes. During transaction commit (MHNSW_Trx::do_commit), only nodes marked as dirty are invalidated in the shared cache, skipping read-only cache entries and improving performance. The dirty flag is set to true when saving a node or when invalidating/deleting a node. There are no review comments, so I have no additional feedback to provide.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
|
|
gkodinov
left a comment
There was a problem hiding this comment.
Thank you for your contribution! This is a preliminary review.
I believe the diff is clear, understandable and well executed. Approved from my end.
One thing I'd ask you to consider is thinking about a test case for it. Just please think about it: there might be some way. I won't insist on it, but it's a good thing to consider.
Or, maybe, consider at least some observability from the SQL console so that people trying to understand what's wrong can attribute this to cache misses (?). Again: just a thought.
I see that you are already in a dialogue with the final reviewer. This is great! Keep it going. His approval is needed before this can be merged.
Description
While benchmarking MariaDB's vector index against pgvector with VectorDBBench (https://github.com/zilliztech/VectorDBBench), I observed that MariaDB's query latency under read/write concurrency is significantly higher than pgvector's, and grows with the volume of data already inserted.
Benchmark: an HNSW index is created at table-creation time, vectors are then inserted continuously, and read bursts are issued at 20% / 50% / 80% of the total insert progress so that reads and writes run concurrently.
Root cause
In
MHNSW_Trx::do_commit()(sql/vector_mhnsw.cc), the partial-invalidation path walks every entry in the committing transaction's node cache and clears the shared-cache copy'svecpointer:The trx-local cache, however, contains every node the transaction touched, including the many nodes traversed by
search_layerand evaluated byselect_neighborsduring the insert that were never actually modified. The shared-cache copies of those read-only nodes are still consistent with on-disk data, but they get invalidated anyway, forcing concurrent and subsequent readers to reload them throughFVectorNode::load().There is in fact a pre-existing TODO at the same location:
// also, consider flushing only changed nodes (a flag in the node)Proposed fix
Add a
dirtybit toFVectorNodeand set it on the two paths that actually mutate the node:FVectorNode::save()(covers both the newly-inserted target and every neighbor rewritten byupdate_second_degree_neighbors);mhnsw_invalidate()alongsidedeleted = true.The partial-invalidation loop in
do_committhen skips entries whosedirtyis false. The flag fits in the existing trailing byte alongsidestoredanddeleted, soFVectorNode's footprint is unchanged. The flag is set before any storage-engine call insidesave(), so that a write path failing mid-flight still forces the shared cache to reload.Results
On the 1536D-50K VectorDBBench Streaming run (with an HNSW index created at table-creation time):
The fix is local to
sql/vector_mhnsw.ccand small (≈10 lines).Attatchments