Commit Graph

11 Commits

Author SHA1 Message Date
Andrey Vasnetsov
2c257314a2 wal: fix WAL lock on Android by using fs4 flock instead of std try_lock (#9226)
`dir.try_lock()` resolves to the inherent `fs_err`/`std` `File::try_lock`,
which Rust's stdlib gates to a fixed target list that excludes
`target_os = "android"` (1.89+). On Android it returns
`ErrorKind::Unsupported` ("try_lock() not supported"), so opening a WAL —
and thus creating/loading a shard via qdrant-edge — fails.

Dispatch explicitly to `fs4::FileExt::try_lock` on the underlying
`std::fs::File`, which issues a direct `flock(LOCK_EX | LOCK_NB)` syscall
that Android supports. This restores the pre-#8770 behavior. UFCS is needed
because fs4's trait method collides by name with the inherent one (which
otherwise wins method resolution).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 14:51:13 +02:00
Arnaud Gourlay
c044074eb8 Fix Clippy 1.96 (#9198) 2026-06-03 14:49:46 +02:00
Sasha Denisov
c1e89fb3e9 feat(edge): expose WAL options via EdgeShard::load_with_wal_options (#9067)
* feat(edge): expose WAL options via EdgeShard::load_with_wal_options

Adds a sibling method to EdgeShard::load that accepts custom
WalOptions, alongside the existing load() which keeps using
default_wal_options().

Motivation: embedded/mobile deployments (e.g. Flutter plugins on
iOS/Android) need much smaller WAL segments than the 32 MiB default —
typically 4 MiB. On filesystems with sparse files (APFS/ext4/F2FS)
the physical footprint is small, but the visible/reported size is
the full segment capacity, which is surfaced by iCloud backup, OS
size pickers, etc.

Changes:

* New EdgeShard::load_with_wal_options(path, config, wal_options).
* EdgeShard::load delegates to it with default_wal_options() — no
  behavior change for existing callers.
* ensure_dirs_and_open_wal now takes WalOptions explicitly; called
  from both EdgeShard::new (with default) and load_with_wal_options.
* WalOptions re-exported from edge crate root.
* Two regression tests in lib/edge/tests/wal_options.rs.

WAL options are intentionally a runtime parameter, not part of
EdgeConfig (which is persisted to edge_config.json) — different
processes may legitimately open the same shard with different WAL
options.

* test(edge): verify mismatching WAL options on reload preserve data

Addresses upstream review feedback (qdrant/qdrant#9067): demonstrate
that reloading an existing shard with WAL options different from the
ones it was created with is safe and preserves all previously written
points.

Two new tests in lib/edge/tests/wal_options.rs:

* reload_with_smaller_wal_capacity_after_upsert:
  create shard with default 32 MiB WAL -> upsert point 42 ->
  drop -> reload with 4 MiB WAL options -> point 42 still readable ->
  upsert point 43 under smaller WAL -> count == 2.

* reload_with_larger_wal_capacity_after_upsert (symmetric):
  create -> reload with 4 MiB -> upsert point 100 -> drop ->
  reload with default 32 MiB -> point 100 readable -> upsert
  point 101 -> count == 2.

Both pass. The WAL crate does not validate segment_capacity on
reload — existing segments on disk keep their original size,
subsequent appends honor the runtime options. This confirms the
PR description's claim that WalOptions is a runtime hint, not
persisted shard state.

* style(edge): cargo fmt for wal_options.rs mismatch tests

* refactor(edge): replace load_with_wal_options with builder-based options

Addresses upstream feedback (timvisee, generall): the sibling
constructor pattern doesn't scale as runtime configurability grows.

Replaces `EdgeShard::load_with_wal_options(path, config, wal_options)`
with `EdgeShard::load_with_options(path, config, EdgeShardOptions)`,
where `EdgeShardOptions` is a builder-style runtime-options struct.

* `EdgeShardOptions::new().with_wal_options(opts)` is the equivalent
  of the old call.
* Adding new runtime options later (e.g. wal flush interval, initial
  indexing threshold) is now an additive change — new builder method
  on `EdgeShardOptions`, no new constructor variant on `EdgeShard`.
* `EdgeShardOptions` is intentionally not persisted (no
  Serialize/Deserialize). The reload-mismatch tests above confirm
  that WAL options are a runtime hint, not shard identity, so they
  don't belong in `EdgeConfig` (which is persisted to
  `edge_config.json`).
* `EdgeShard::load(path, config)` unchanged for existing callers —
  delegates to `load_with_options(..., EdgeShardOptions::default())`.

Tests in `lib/edge/tests/wal_options.rs` migrated to the new shape;
all four still pass:

  test load_with_options_accepts_custom_wal_capacity ... ok
  test load_still_works_with_default_wal_options ... ok
  test reload_with_smaller_wal_capacity_after_upsert ... ok
  test reload_with_larger_wal_capacity_after_upsert ... ok

* refactor(edge): add fluent builders; move wal_options into EdgeConfig

Replaces the EdgeShardOptions side-channel with a single EdgeConfig that
carries wal_options inline, and introduces fluent builders for the three
user-facing config types.

* WalOptions now derives Clone/PartialEq/Eq/Serialize/Deserialize so it
  can live inside EdgeConfig and round-trip through edge_config.json.
* EdgeConfig.wal_options (Option<WalOptions>) replaces EdgeShardOptions.
  EdgeShard::load_with_options is folded into EdgeShard::load; both new
  and load drive the WAL from config.wal_options.unwrap_or_default().
* New builders/ module hosts EdgeConfigBuilder, EdgeVectorParamsBuilder,
  and EdgeSparseVectorParamsBuilder. Each builder has explicit per-field
  storage and constructs its target via an exhaustive struct literal in
  build(), so adding a field to the target forces a compile error in the
  builder.
* publish example switched to the new builder API.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* style(edge): cargo fmt after builder refactor

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Andrey Vasnetsov <andrey@vasnetsov.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-03 14:47:41 +02:00
qdrant-cloud-bot
7f372880ed perf(tests): reduce test volume on Windows for IO-heavy tests (#8864)
Windows CI takes ~28min vs ~18min on Linux, with some individual tests
running 10-50x slower due to Windows filesystem IO overhead. Since we
only need functional compatibility on Windows (not performance testing),
reduce iteration counts for the worst offenders:

- WAL quickcheck: 10 → 3 iterations (saves ~350s)
- Consensus manager proptests: 256 → 10 cases (saves ~100s)
- Deferred point tests: reduce loop combinations (saves ~250s)
- Gridstore test_behave_like_hashmap: 50k → 10k operations (saves ~200s)

Co-authored-by: Cursor Agent <agent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-08 13:47:47 +02:00
qdrant-cloud-bot
d4ac8caa80 Update fs4 from 0.13.1 to 1.0.0 (#8770)
Adapt to breaking changes in fs4 1.0.0:

- `fs4::fs_std::FileExt` flattened to `fs4::FileExt` (segment.rs)
- Removed `fs4::FileExt` import from lib.rs — with Rust 1.89+
  `File::try_lock()` is stabilized in std, so the fs4 trait is no
  longer needed for exclusive locking
- `try_lock_exclusive()` → `try_lock()` via `fs_err::File` wrapper
  with return type `Result<(), TryLockError>` (WouldBlock on contention)
- Removed `lock_contended_error()` — use `ErrorKind::WouldBlock`

On Windows, fs4 1.0.0 skips set_len inside allocate() when the
cluster-aligned allocation already covers the requested size. Add
explicit set_len calls after allocate() so the mmap has the correct
file extent.

The `fs4::available_space()` function used in shard/optimize.rs and
collection/disk_usage_watcher.rs is unchanged in 1.0.0.

Made-with: Cursor

Co-authored-by: Cursor Agent <agent@cursor.com>
2026-05-08 13:47:20 +02:00
Tim Visée
1e8a7a98ec Fix clippy warnings for Rust 1.95 (#8695)
* Remove redundant into_iter

* Remove redundant type casting

* Use if-branches in match

* Use sort_by_key

* Only iterate over values

* Dismiss bench loop counter warning

* done done

---------

Co-authored-by: Arnaud Gourlay <arnaud.gourlay@gmail.com>
2026-05-08 13:46:45 +02:00
qdrant-cloud-bot
db0c4b320f Speed up slow unit tests (#8385)
Reduce test parameters across 5 areas to cut test runtime without
sacrificing coverage:

1. HNSW PQ tests: lower vector dimensionality from 131 to 64 for product
   quantization variants, cutting PQ codebook training time (~31s -> ~8s)

2. HNSW index build: use 2 threads instead of 1 for index construction;
   the tests only check accuracy above a threshold so determinism is not
   required

3. Search attempts: reduce from 10 to 5 query vectors per test

4. Rescoring: skip the expensive re-upsert-all-as-zeros rescoring check
   for PQ tests (already covered by scalar quantization variants)

5. Near-miss speedups:
   - WAL: reduce QuickCheck iterations from 100 to 50
   - Gridstore: halve operation counts, drop 64-byte block size case,
     reduce proptest cases for gap search
   - Continuous snapshot: reduce timeout from 20s to 10s

Made-with: Cursor

Co-authored-by: Cursor Agent <agent@cursor.com>
2026-03-26 18:16:27 +01:00
Arnaud Gourlay
ba4a12045a Decrease Quickcheck test count for WAL on Windows (#8229) 2026-03-26 17:17:20 +01:00
dependabot[bot]
a7739dbf2d build(deps): bump rand_distr from 0.5.1 to 0.6.0 (#8148)
* build(deps): bump rand_distr from 0.5.1 to 0.6.0

Bumps [rand_distr](https://github.com/rust-random/rand_distr) from 0.5.1 to 0.6.0.
- [Release notes](https://github.com/rust-random/rand_distr/releases)
- [Changelog](https://github.com/rust-random/rand_distr/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-random/rand_distr/compare/0.5.1...0.6.0)

---
updated-dependencies:
- dependency-name: rand_distr
  dependency-version: 0.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Migrate main code base to rand 0.10

* Migrate tests

* Migrate benches

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: timvisee <tim@visee.me>
2026-03-26 17:09:49 +01:00
Luis Cossío
26f174c2ab Fix unused self lint in macos (#8215)
* expect unused self

* Update lib/wal/src/mmap_view_sync.rs

Co-authored-by: Tim Visée <tim+github@visee.me>

---------

Co-authored-by: Tim Visée <tim+github@visee.me>
2026-03-26 17:03:27 +01:00
xzfc
8fb7adea98 Move github.com/qdrant/wal into lib/wal (#8185)
* Copy github.com/qdrant/wal into lib/wal

Commit: c07fb56ebc8120ebe4e3c602d31ce98f356f4676 2026-02-18

* Clean cruft

* Integrate lib/wal into workspace

* Cargo fmt

* Fix clippy warnings

* Adhere to our conventions

* Fix codespell warnings
2026-03-26 16:53:55 +01:00