Skip to content

fix: strict upsert accounting and opt-in end-of-index flush - #638

Open
j-sperling wants to merge 3 commits into
zilliztech:mainfrom
j-sperling:fix/strict-upsert-optin-flush
Open

fix: strict upsert accounting and opt-in end-of-index flush#638
j-sperling wants to merge 3 commits into
zilliztech:mainfrom
j-sperling:fix/strict-upsert-optin-flush

Conversation

@j-sperling

Copy link
Copy Markdown
Contributor

Summary

  • MilvusStore.upsert() returns len(chunks) as the success count even when the server explicitly reports upsert_count: 0, so memsearch index can report success while nothing became durable (MilvusStore.upsert() reports success but writes are not durable on remote Milvus 2.5+ (missing flush) #534). It now trusts the server-reported count and raises on an explicit zero-write response; responses without a count keep the historical fallback.
  • Adds milvus.flush_on_index (bool, default false — current behavior is unchanged): one flush() at the end of an indexing run, for pipelines where a reader in another process searches immediately after memsearch index returns. Deliberately not per-upsert flushing, which would create many small sealed segments.
  • Documents the read-after-write visibility semantics in docs/troubleshooting.md and the config key table.

This is the fix shape proposed by the maintainer in #534 (strict count + opt-in end-of-index flush + documented consistency behavior). Datapoint from a different environment than that issue's repro: we run memsearch index from an agent Stop/SessionEnd hook on macOS with Milvus Lite, and a separate short-lived process that searches immediately afterwards intermittently missed the fresh chunks until we added an external flush after each run — so the cross-process visibility gap is not exclusive to remote Milvus, even though Lite auto-flushes on close.

Test plan

  • tests/test_store.py: server-reported count trusted over len(chunks); explicit zero-write raises RuntimeError; missing count falls back; flush() targets the configured collection
  • tests/test_flush_on_index.py: end-of-index flush fires exactly once when enabled, never by default, and not on runs that index nothing
  • _cfg_to_memsearch_kwargs translation test covers the new key; config set milvus.flush_on_index true coerces via _BOOL_FIELDS
  • Full suite: 271 passed, 7 skipped; ruff check / ruff format --check clean

Milvus can acknowledge an upsert while reporting upsert_count 0, and no
flush happens anywhere in the indexing path, so a reader in another
process can see an empty or stale collection right after `memsearch
index` reports success (zilliztech#534).

- MilvusStore.upsert() trusts the server-reported upsert_count and
  raises on an explicit zero-write response instead of silently
  falling back to len(chunks).
- New milvus.flush_on_index config key (default false, preserving
  current behavior) seals pending writes once at the end of an
  indexing run; per-upsert flushing is deliberately avoided because it
  creates many small sealed segments.
- Document read-after-write visibility in the troubleshooting guide
  and the config key table.
…ptin-flush

# Conflicts:
#	src/memsearch/config.py
#	src/memsearch/core.py
The end-of-index flush was gated on the upserted-chunk count, so a run
whose only writes were deletions (a removed section's stale chunks or
deleted-file cleanup) never flushed — leaving other readers with stale
results in exactly the cross-process scenario flush_on_index exists
for. _index_file now reports stale-chunk deletions and the gate treats
any write as flush-worthy. Partial server counts (0 < n < batch) are
logged instead of passing silently.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant