-
Notifications
You must be signed in to change notification settings - Fork 21
[MOD-10559] Decouple the shrinking and growing logic of large containers in Flat and HNSW #753
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #753 +/- ##
==========================================
+ Coverage 96.82% 96.86% +0.04%
==========================================
Files 122 122
Lines 7496 7533 +37
==========================================
+ Hits 7258 7297 +39
+ Misses 238 236 -2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR decouples the shrinking and growing logic in vector index algorithms (HNSW and BruteForce) to prevent oscillating allocation/deallocation cycles at block boundaries. The changes implement a conservative resize strategy with a 2-block buffer zone to avoid frequent reallocations of large containers.
- Implements separate growing and shrinking conditions to prevent oscillation between allocation/deallocation
- Distinguishes between data containers (block-based) and metadata containers (index-sized) with different resize strategies
- Adds comprehensive test coverage to verify the new resize behavior and prevent oscillation
Reviewed Changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.
Show a summary per file
File | Description |
---|---|
tests/unit/test_hnsw_tiered.cpp | Adds comprehensive test for HNSW tiered index resize behavior and lock management verification |
tests/unit/test_common.cpp | Updates log message expectations to reflect new resize patterns with additional FLAT and HNSW resize messages |
tests/unit/test_bruteforce_multi.cpp | Enhances multi-index resize testing with detailed container size verification and 2-block buffer strategy validation |
tests/unit/test_bruteforce.cpp | Adds comprehensive resize behavior verification and new oscillation prevention test |
tests/unit/test_allocator.cpp | Updates memory allocation tests with detailed container size verification and new resize behavior expectations |
src/VecSim/vec_sim_tiered_index.h | Adds helper methods for lock management and test instrumentation for resize operations |
src/VecSim/vec_sim_index.h | Fixes spelling error in comment (Stroage -> Storage) |
src/VecSim/vec_sim_common.h | Removes deprecated comment for initialCapacity field |
src/VecSim/containers/data_blocks_container.h | Exposes numBlocks() method from test-only to public API for better introspection |
src/VecSim/containers/data_blocks_container.cpp | Moves numBlocks() implementation outside BUILD_TESTS guard |
src/VecSim/algorithms/hnsw/hnsw_tiered_tests_friends.h | Adds friend class declaration for new resize test |
src/VecSim/algorithms/hnsw/hnsw_tiered.h | Updates to use new lock management helper methods and capacity checking |
src/VecSim/algorithms/hnsw/hnsw.h | Implements decoupled resize logic with isCapacityFull() method and 2-block buffer strategy |
src/VecSim/algorithms/brute_force/brute_force.h | Centralizes resize logic with new resizeIndexCommon() method and implements 2-block buffer strategy |
Comments suppressed due to low confidence (1)
tests/unit/test_bruteforce_multi.cpp:1
- There's a typo in the test comment 'Index size = 1Verifying allocation delta...'. It should be 'Index size = 1. Verifying allocation delta...' with proper spacing.
/*
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
Few small questions
Also - let'd add a short micro benchmark for the oscillation use case (and validate the improvement)
Backport failed for Please cherry-pick the changes locally and resolve any conflicts. git fetch origin 0.6
git worktree add -d .worktree/backport-753-to-0.6 origin/0.6
cd .worktree/backport-753-to-0.6
git switch --create backport-753-to-0.6
git cherry-pick -x df0664cb1d45a46dc81c81d9eb235f08cffe1de3 |
Backport failed for Please cherry-pick the changes locally and resolve any conflicts. git fetch origin 0.7
git worktree add -d .worktree/backport-753-to-0.7 origin/0.7
cd .worktree/backport-753-to-0.7
git switch --create backport-753-to-0.7
git cherry-pick -x df0664cb1d45a46dc81c81d9eb235f08cffe1de3 |
Backport failed for Please cherry-pick the changes locally and resolve any conflicts. git fetch origin 0.8
git worktree add -d .worktree/backport-753-to-0.8 origin/0.8
cd .worktree/backport-753-to-0.8
git switch --create backport-753-to-0.8
git cherry-pick -x df0664cb1d45a46dc81c81d9eb235f08cffe1de3 |
…ers in Flat and HNSW (#753) * brute force 75% capacity imp * same solution brute force and hnsw * align flat growby block with hnsw * resisng tests for BF * allocator tests that accounts for one block buffer * tests * remove comment * remove * fix resize test for macos * change to estimation * generelize test (cherry picked from commit df0664c)
Successfully created backport PR for |
…ontainers in Flat and HNSW (#775) [MOD-10559] Decouple the shrinking and growing logic of large containers in Flat and HNSW (#753) * brute force 75% capacity imp * same solution brute force and hnsw * align flat growby block with hnsw * resisng tests for BF * allocator tests that accounts for one block buffer * tests * remove comment * remove * fix resize test for macos * change to estimation * generelize test (cherry picked from commit df0664c) Co-authored-by: meiravgri <109056284+meiravgri@users.noreply.github.com>
Purpose
This PR decouples the shrinking and growing logic in vector index algorithms to avoid scenarios where updates can result in oscillating allocation and deallocation of large containers such as label to id hash tables, or id to metadata vectors.
Problem Statement
The previous implementation performed both growing and shrinking operations when
index_size % blockSize == 0
, causing frequent allocation/deallocation cycles during index updates at block boundaries. This was particularly problematic for large containers like:Solution Overview
The changes implement a more conservative resize strategy that decouples shrinking and growing logic to prevent oscillating allocation/deallocation cycles. The key improvements include:
Resize Strategy (Both Algorithms)
indexSize() == indexCapacity()
(capacity is full)indexCapacity() >= (indexSize() + 2 * blockSize)
(2+ free blocks), shrinking by one blockHNSW-Specific Container Architecture Changes
Updated
maxElements
Definition:maxElements
represented capacity for both data containers and metadata containersmaxElements
only tracks capacity for data containers (graphDataBlocks
,vectors
)idToMetaData
,visitedNodesHandlerPool
,labelLookup
) now resize independently based on the 2-block buffer strategyHNSW Container Type Distinction:
Data Containers: Block-based containers that resize by adding/removing single blocks
graphDataBlocks
- stores graph connectivity data in blocksvectors
(DataBlocksContainer) - stores vector data in blocksemplace_back()
orpop_back()
single blocksMetadata Containers: Index-sized containers that require full reallocation
idToMetaData
- maps internal IDs to metadata (labels, flags)visitedNodesHandlerPool
- tracks visited nodes during searchlabelLookup
- hash table mapping labels to internal IDsresize()
+shrink_to_fit()
entire containerBruteForce-Specific Container Changes
BruteForce Container Architecture:
vectors
(DataBlocksContainer
) - block-based vector storageidToLabelMapping
- maps internal IDs to labelslabelLookup
- hash table mapping labels to internal IDs (single/multi variants)resize()
+shrink_to_fit()
entire containerMemory Management
Key Changes
BruteForce Algorithm (
src/VecSim/algorithms/brute_force/brute_force.h
)resizeIndexCommon()
method: Centralizes resize logic with proper assertions and loggingshrinkByBlock()
: Only shrinks when there are 2+ free blocks (indexCapacity() >= (indexSize() + 2 * blockSize)
)growByBlock()
: Simplified growing logic with better assertionsindexCapacity()
: Now returnsidToLabelMapping.capacity()
instead ofsize()
HNSW Algorithm (
src/VecSim/algorithms/hnsw/hnsw.h
)isCapacityFull()
method: Encapsulates capacity check logic (indexSize() == maxElements
)storeNewElement()
: Proactive capacity checking before element insertionshrinkByBlock()
: Implements the same 2-block buffer strategy as BruteForceTiered Index (
src/VecSim/algorithms/hnsw/hnsw_tiered.h
)insertVectorToHNSW()
to use the newisCapacityFull()
method for cleaner capacity checkinglockMainIndexGuard()
andunlockMainIndexGuard()
to centralize lock acquisition/releasemainIndexGuard_write_lock_count
(guarded byBUILD_TESTS
macro) counter for testing resize operations in tiered indexesContainer Improvements (
src/VecSim/containers/data_blocks_container.h
)numBlocks()
method: Moved from test-only to public API for better introspectionTest Updates
IndexAllocatorTest.test_bf_index_block_size_1
: Enhanced with detailed container size verification and memory delta calculationsIndexAllocatorTest.test_hnsw_reclaim_memory
: Updated memory allocation expectations for new resize behaviorHNSWTieredIndexTestBasic.HNSWResize_Test
: New test for tiered index resize behavior and lock management verificationBruteForceTest.resize_and_align_index
: Enhanced with detailed container size verification functionsBruteForceTest.brute_force_no_oscillation_test
: New test to verify the 2-block buffer strategy prevents allocation/deallocation cyclesBruteForceMultiTest.resize_and_align_index
: Enhanced multi-index resize testing with comprehensive verificationCommonAPITest.testlogTieredIndex
: Updated to expect additional resize log messages from both FLAT and HNSW indexes