You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
qdrant-edge: EdgeShard never acknowledges its WAL, so wal/ grows with every update #11068
EdgeShard writes every operation to its WAL, but nothing ever acknowledges or truncates it:
EdgeShard::update appends each operation with wal.write(...) (update.rs#L32).
EdgeShard::flush flushes the WAL and then all segments, but never calls ack, although flush_all returns the persisted version (mod.rs#L268-L277).
EdgeShard::load never reads the WAL back, so nothing else truncates it either.
As a result, wal/ only ever grows, and every closed segment stays forever. On Windows, each segment is allocated in full up front (segment.rs#L166), so every segment costs 32 MiB of disk space by default. Loading a shard also gets slower over time, because Wal::open reads and checks every segment.
We embed qdrant-edge in a desktop app for local RAG, with one EdgeShard per data source. Numbers from real installations:
Windows 11: one shard held the WAL entries [0, 15451) in four segments plus a preallocated empty one, so 160 MiB of WAL. Opening these segments took 175 ms.
macOS: in every shard, the WAL was larger than the segments, e.g., 76 MB of WAL next to 50 MB of segment data.
#10189 noted this for edge-tool ("never acked … grows with every upsert") and skips wal/ on upload. The library itself is still affected, in the published 0.8.0 and on master as of 016542a.
Steps to Reproduce
Create a shard with small WAL segments, so the effect shows quickly. The default 32 MiB segments behave the same.
Upsert a few hundred points one at a time, calling shard.flush() after each update.
Call shard.optimize(), drop the shard, and load it again with EdgeShard::load(&path, None).
List path/wal.
The directory holds one closed-* file for every filled segment. The count only goes up with further updates, flushes, optimizations, and reloads.
Expected Behavior
Once flush() has persisted the segments, the WAL acknowledges the entries up to the persisted version and truncates its closed segments, keeping retain_closed of them, like the WAL of a collection shard.
Possible Solution
Acknowledge the persisted version in EdgeShard::flush, as the collection's flush worker does after flushing its segments (flush_workers.rs#L99-L124):
ack truncates through prefix_truncate, which keeps the newest closed segment. That matters, see below.
Related: the WAL also carries the operation numbering
While working around this, we found that the WAL must not be deleted completely. Wal::open takes the next operation number from the first closed-* segment and starts at 0 without one (lib.rs#L179). EdgeShard::load does not restore it from the segment versions. The segments then skip every operation whose number is below the stored point version (segment_ops.rs#L641), so later upserts and deletes of existing points are silently ignored.
We confirmed this with a test: after removing all closed-* segments of a shard and loading it again, an upsert of an existing point with a new payload succeeds, but the point keeps its old payload. Keeping the newest closed segment avoids this.
This might also affect shards uploaded without wal/ since #10189 if they get updated after the download. We have not tested that flow. Perhaps load should start an empty WAL after the highest segment version, e.g., with Wal::generate_empty_wal_starting_at_index (lib.rs#L105).
Context (Environment)
qdrant-edge 0.8.0 from crates.io, Rust 1.99.0. The code above is unchanged on master as of 016542a.
Windows 11 x64 and macOS.
MindWork AI Studio uses one EdgeShard per local data source and calls flush() after every update().
Our workaround until this is fixed: while a shard is not loaded, we delete all closed-* segments except the newest one, oldest first. We do this before EdgeShard::load and after optimize(), dropping the shard first. We would be glad to remove it again.
Activity
[AI] fix(edge): acknowledge the persisted version in EdgeShard::flush (…
fix(edge): prevent LSN divergence on cold start and complete WAL trun…
fix(edge): prevent LSN divergence on cold start and complete WAL trun…
fix(edge): prevent LSN divergence on cold start and complete WAL trun…
[AI] fix(edge): acknowledge the persisted version in EdgeShard::flush (…