feat: preserve indexdata during serialization#7061
Conversation
There was a problem hiding this comment.
Pull request overview
This PR addresses a correctness issue for HNSW indices in “external vector storage” mode (copy_vector=false) by preserving underlying HASH field storage during deferred removals (e.g., while serialization holds read locks), and adds replication coverage for that mode.
Changes:
- Add preservation of StringMap-backed field storage during deferred HNSW removals, plus cleanup hooks to clear preserved data once deferred ops are drained.
- Extend HNSW index APIs to report whether removes executed synchronously and add an explicit “drain pending ops” operation.
- Expand replication test coverage to exercise external-vector mode and assert the HASH encoding matches the expected storage mode.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/dragonfly/replication_test.py | Parameterizes replication test to cover copied vs external vector modes and asserts encoding in external mode. |
| src/server/search/serialization_utils.cc | After global HNSW serialization, drains pending ops and clears preserved field data across shards. |
| src/server/search/doc_index.h | Changes removal APIs, adds preserved-field-data storage and cleanup entrypoints. |
| src/server/search/doc_index.cc | Implements preservation by swapping StringMap entries and tying preservation to deferred vs synchronous removes. |
| src/server/search/doc_index_fallback.cc | Updates fallback signatures and adds no-op preserved-data cleanup. |
| src/server/hset_family.cc | Collects modified HASH fields and passes them to search index removal for targeted preservation. |
| src/server/generic_family.cc | Uses FindMutable to allow preservation logic to mutate PrimeValue during overwrite handling. |
| src/server/family_utils.h | Updates RemoveKeyFromIndexesIfNeeded to accept mutable PrimeValue for preservation. |
| src/server/db_slice.h | Updates deletion callback to pass mutable PrimeValue for preservation. |
| src/core/search/hnsw_index.h | Changes Remove() to return sync/deferred status and adds DrainPendingOps(). |
| src/core/search/hnsw_index.cc | Implements boolean Remove return and DrainPendingOps logic in the adapter. |
🤖 Augment PR SummarySummary: This PR makes HNSW (global) vector indices safe to serialize when vectors are stored as external pointers into HASH StringMap entries (copy_vector=false). Changes:
Technical Notes: The approach relies on swapping StringMap entries to keep old sds allocations alive until deferred HNSW removes execute, then draining deferred ops immediately after serialization to release preserved memory. 🤖 Was this summary useful? React with 👍 or 👎 |
dranikpg
left a comment
There was a problem hiding this comment.
I still think that keeping the shard index as a regular DocIndex inside FieldIndices will remove all the code for custom handling of this index type
| for (auto& hnsw : hnsw_shard_indices_) { | ||
| hnsw.RemoveById(global_id); | ||
| } |
There was a problem hiding this comment.
why not store the shard index inside the field indices? this way you don't need any special hnsw code - and if you need it as it's own type you can cast it back with static_cast or reinterpret_cast
There was a problem hiding this comment.
I will make these changes as a separate PR
| for (auto& [index_name, ptr] : indices_) { | ||
| ptr->InitHnswShardIndices(); |
There was a problem hiding this comment.
and I assume that you then also don't need those parts
Summary: This PR makes HNSW (global) vector indices safe to serialize when vectors are stored as external pointers into HASH StringMap entries (copy_vector=false).
Changes: