bug(rvf-runtime): delete() bitmap is permanent — re-ingest does not undelete; compact drops re-ingested data
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 4.5k
- Forks
- 603
- Avg merge
- 23h 32m
- Merged PRs (30d)
- 59
Description
Summary
RvfStore::delete(ids) sets bits in deletion_bitmap. Those bits:
- Survive re-ingest of the same id —
ingest_batchinserts vector data but never clears the deletion bit. - Cause
query()(and index paths) to skip the id while the bit remains set. - Cause
compact()to treat the id as dead: it physically removes the vector — including a freshly re-ingested payload — then clears the bitmap.
So “delete then re-insert under the same id” is broken, and “delete → re-insert → compact” destroys the re-inserted data.
DeletionBitmap::clear_ids already exists in deletion.rs but is not called from the re-ingest path.
Affected versions
- Confirmed: 0.2.0 (
store.rsdelete / ingest_batch / query / compact) - Same interaction present in 0.3.0 (delete sets bitmap; query filters deleted; compact removes deleted_ids)
Repro
use rvf_runtime::{DistanceMetric, QueryOptions, RvfOptions, RvfStore};
fn main() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("del.rvf");
let opts = RvfOptions {
dimension: 2,
metric: DistanceMetric::L2,
..Default::default()
};
let mut s = RvfStore::create(&path, opts).unwrap();
let v = [1.0f32, 0.0];
s.ingest_batch(&[&v], &[42], None).unwrap();
s.delete(&[42]).unwrap();
let v2 = [0.0f32, 1.0];
s.ingest_batch(&[&v2], &[42], None).unwrap();
let hits = s.query(&[0.0, 1.0], 1, &QueryOptions::default()).unwrap();
// Actual: 42 not returned (still soft-deleted) — BUG
// Expected: 42 present with v2
s.compact().unwrap();
let hits2 = s.query(&[0.0, 1.0], 1, &QueryOptions::default()).unwrap();
// Actual: still absent — re-ingested payload reclaimed as dead — BUG
let _ = (hits, hits2);
}
Expected
On successful ingest_batch / upsert of an id, clear that id from deletion_bitmap (e.g. clear_ids). Document soft-delete vs re-ingest-as-undelete. compact should only drop ids still soft-deleted at compact time.
Downstream impact
WeftOS BranchableMemory::delete never calls RvfStore::delete on working tips; it uses a crate-level tombstone set so delete→re-ingest works and chain-walk query masking is correct. Promote-to-base still hits this sticky-bitmap path — a real correctness hazard.
Reported from WeftOS WEFT-662.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in store.rs with RvfStore::ingest_batch, delete, query, and compact, then inspect DeletionBitmap::clear_ids in deletion.rs. Run the provided delete→re-ingest→query→compact reproduction. Done means re-ingested ids are queryable with the new vector and remain present after compact, while ids still soft-deleted are removed.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- databases
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100