Commit Graph
6863 Commits
Author SHA1 Message Date
dependabot[bot] d2c46a34ce build(deps): bump actix-cors from 0.7.1 to 0.7.2 (#10408)
Bumps [actix-cors](https://github.com/actix/actix-extras) from 0.7.1 to 0.7.2.
- [Release notes](https://github.com/actix/actix-extras/releases)
- [Commits](https://github.com/actix/actix-extras/compare/cors-v0.7.1...cors-v0.7.2)

---
updated-dependencies:
- dependency-name: actix-cors
  dependency-version: 0.7.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-03 12:45:55 +02:00
dependabot[bot] a080e1d203 build(deps): bump prost-wkt-types from 0.7.1 to 0.7.2 (#10415)
Bumps [prost-wkt-types](https://github.com/fdeantoni/prost-wkt) from 0.7.1 to 0.7.2.
- [Release notes](https://github.com/fdeantoni/prost-wkt/releases)
- [Changelog](https://github.com/fdeantoni/prost-wkt/blob/master/CHANGELOG.md)
- [Commits](https://github.com/fdeantoni/prost-wkt/compare/v0.7.1...v0.7.2)

---
updated-dependencies:
- dependency-name: prost-wkt-types
  dependency-version: 0.7.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-03 12:45:55 +02:00
dependabot[bot] 88581adc14 build(deps): bump log from 0.4.33 to 0.4.34 (#10409)
Bumps [log](https://github.com/rust-lang/log) from 0.4.33 to 0.4.34.
- [Release notes](https://github.com/rust-lang/log/releases)
- [Changelog](https://github.com/rust-lang/log/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/log/compare/0.4.33...0.4.34)

---
updated-dependencies:
- dependency-name: log
  dependency-version: 0.4.34
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-03 12:45:55 +02:00
dependabot[bot] 185260be3d build(deps): bump uuid from 1.24.1 to 1.26.0 (#10407)
Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.24.1 to 1.26.0.
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/v1.24.1...v1.26.0)

---
updated-dependencies:
- dependency-name: uuid
  dependency-version: 1.26.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-03 12:45:55 +02:00
dependabot[bot] 6c288ecf28 build(deps): bump flate2 from 1.1.9 to 1.1.10 (#10410)
Bumps [flate2](https://github.com/rust-lang/flate2-rs) from 1.1.9 to 1.1.10.
- [Release notes](https://github.com/rust-lang/flate2-rs/releases)
- [Commits](https://github.com/rust-lang/flate2-rs/compare/1.1.9...1.1.10)

---
updated-dependencies:
- dependency-name: flate2
  dependency-version: 1.1.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-03 12:45:54 +02:00
dependabot[bot] 4f0fc9012a build(deps): bump syn from 3.0.3 to 3.0.4 (#10412)
Bumps [syn](https://github.com/dtolnay/syn) from 3.0.3 to 3.0.4.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/3.0.3...3.0.4)

---
updated-dependencies:
- dependency-name: syn
  dependency-version: 3.0.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-03 12:45:54 +02:00
dependabot[bot] a21f535fdb build(deps): bump actix-multipart from 0.8.0 to 0.8.1 (#10411)
Bumps [actix-multipart](https://github.com/actix/actix-web) from 0.8.0 to 0.8.1.
- [Release notes](https://github.com/actix/actix-web/releases)
- [Changelog](https://github.com/actix/actix-web/blob/main/CHANGES.md)
- [Commits](https://github.com/actix/actix-web/compare/multipart-v0.8.0...multipart-v0.8.1)

---
updated-dependencies:
- dependency-name: actix-multipart
  dependency-version: 0.8.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-03 12:45:54 +02:00
dependabot[bot] 7bdfe42aa0 build(deps): bump actix-web from 4.14.1 to 4.15.0 (#10414)
Bumps [actix-web](https://github.com/actix/actix-web) from 4.14.1 to 4.15.0.
- [Release notes](https://github.com/actix/actix-web/releases)
- [Changelog](https://github.com/actix/actix-web/blob/main/CHANGES.md)
- [Commits](https://github.com/actix/actix-web/compare/web-v4.14.1...web-v4.15.0)

---
updated-dependencies:
- dependency-name: actix-web
  dependency-version: 4.15.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-03 12:45:54 +02:00
Luis Cossío 9cfbe82b07 schedule_open returns nothing (#10355) 2026-09-03 12:45:54 +02:00
Luis CossíoandClaude Fable 5 f6e0566f38 [UIO] UniversalReadFs::open_async (#10352)
* `UniversalReadFs::open_async`

* `schedule_open` polls once

Scheduled opens must start eagerly: sync backends complete their
`open_async` on the first poll, preserving the prefetch contract
(handles outlive later file deletions/replacements). Moved down from
the integration branch so this PR stays green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-09-03 12:45:54 +02:00
Luis Cossío 0e68451875 [UIO] renames + enforce LiveReload::live_preload (#10351)
* make LiveReload::live_preload required

* rename `schedule_prefetch`->`schedule_open`

* rename `reschedule_prefetch`->`reschedule_open`
2026-09-03 12:45:53 +02:00
Luis Cossío 52d72d94dc [UIO] impl IoUringFile::read_bytes_async (#10288)
* bridge async with a dedicated `tokio_uring` thread

* impl `IoBufMut` for `AVec`

* [AI] Add tests

* [AI] handle O_DIRECT

odirect test
2026-09-03 12:45:53 +02:00
Tim Viséeandqdrant-cloud-bot 7739fabb7f Add Qdrant Solutions GmbH in LICENSE file (#10401)
* Add Qdrant GmbH in LICENSE file

* Fix copyright holder to Qdrant Solutions GmbH

---------

Co-authored-by: qdrant-cloud-bot <111755117+qdrant-cloud-bot@users.noreply.github.com>
2026-09-03 12:45:53 +02:00
1dad4d9f9f Let multivector runs straddle chunk boundaries (#10283)
* Read vector runs that straddle a chunk boundary

Resolve a run into per-chunk parts instead of a single range, borrowing
when it lands in one chunk and copying when it spans two. The read
pipeline schedules one range per read, so a straddling run is read
outside it.

No writer produces such a run yet, so this changes nothing on its own.
It is what a reader needs before one does — including edge and
live-reload readers, which read files a different version wrote.

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

* Place multivector runs without regard to chunk boundaries

Writers appended a multivector's inner vectors at the end of the row
space unless the run would cross a chunk boundary, in which case they
skipped the chunk tail — the batch writers padding the skipped rows with
explicit zero rows. That made chunk geometry part of the interface every
multivector storage had to reuse.

Runs now go at the end unconditionally and the chunked storage splits
the write across chunks, as it already did for a batch of single
vectors.

What is left of the geometry is a size cap: a multivector may not exceed
one chunk. It is fill-independent, so it constrains nothing about
placement, and it is what the volatile storage needs anyway — that one
returns a plain slice and so cannot serve a straddling run.

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

* Split a run at chunk boundaries in one place

Reading, writing in place and appending each derived the split from
`remaining_chunk_capacity`, so every one of them had to know that a run
does not necessarily fit where it starts.

`split_run` hands out the parts instead: one per chunk the run covers,
each carrying where it goes and how much of the run it takes. Nothing
asks how much room is left any more, and `get_chunk_offset` goes with it.

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

* Keep straddling runs on the read pipeline

Reading a straddling run outside the pipeline blocked the scheduling
loop on one read, which costs a round trip on a backend that fetches
remotely and drops the batch back to sequential.

A run is now scheduled as one read per chunk it covers. Parts complete
in any order, so each run holds what has landed until the last part
does, then hands the callback the stitched vectors. Runs taking a single
read carry the caller's data in the tag and never touch that table.

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

* Stop capping a multivector at one chunk

The cap outlived its reason on disk, but the volatile storage still
needed it: its `get_many` handed out a slice of one chunk, so a run that
crossed a boundary had nowhere to come from. And since a volatile
storage is a target of the batched copy that builds a segment, dropping
the cap only on disk would have turned a rejected write into a failed
merge.

So the volatile storage splits and stitches too. Both are a few lines
each, and placing a run no longer skips a chunk tail, so `extend` is now
`insert_many` at the end of the storage.

Nothing user-facing moves: `MAX_MULTIVECTOR_FLATTENED_LEN` caps a
multivector at 1M elements, far inside a 32 MiB chunk, so the storages
only ever rejected what reached them unvalidated.

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

* Schedule a single-read run without the queue

The scheduling loop resolved every run into the queue and then took it
straight back out, so the overwhelmingly common run — one that fits a
chunk — paid a push and a pop for nothing. It now goes to the pipeline
directly, and the queue holds only what a straddling run leaves behind.

Worth ~10% on the multivector read benchmark, and it collapses the
"top up, then take" pair into one decision. Extracting that bookkeeping
into helpers instead was measured and is much worse: the mmap pipeline
alternates one schedule with one wait, so the loop body is a few dozen
nanoseconds, and a helper carrying the cold map and stitching paths is
too big for the compiler to inline back into it.

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

* Repoint the multivector WAL-replay test at a live rejection

The test upserted a multivector too large for a storage chunk, which no
longer fails: the storages stopped capping one at a chunk. Nothing else
covered a multivector operation that only the apply path rejects.

A raw blob that is not a whole number of quantized records still does,
so the test now uses that, alongside its dense and sparse siblings.

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

* Test reading multivectors with legacy chunk-tail padding

Locks the compatibility contract that pre-straddle files — runs that
skip a chunk's leftover slots — still reopen as single-chunk borrows.

* chore: retrigger CI after flaky test-consensus-compose

* Move ReadTag into for_each_vector, its only user

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AN4Hgbd65gDhesthJk5bUY

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: qdrant-cloud-bot <111755117+qdrant-cloud-bot@users.noreply.github.com>
2026-09-03 12:45:53 +02:00
Arnaud GourlayandClaude Opus 5 374506c2c9 Fix proxied changes dropped when an optimization fails (#10364)
* Add SetFlushInterval op to the model tester

Changes the collection's flush_interval_sec mid-run through the same path
update_collection takes (persist the optimizer-config diff, then recreate
the optimizers in the background). The model is untouched: what it perturbs
is the flush cadence, so how much of the workload is still WAL-only when a
restart hits, plus the worker stop/start race in on_optimizer_config_update.

Kept in FORCE_OFF for now: with the optimizer on it makes stale point state
visible within a few ops of the config change. Narrowed to
recreate_optimizers_background, see the comment on Swarm::BASE.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011AjmS5GFeGztfP3JqutnXj

* Keep SetFlushInterval enabled in the swarm

Drops it from FORCE_OFF so the divergence it surfaces is reachable without
--enable-force-off (which would also enable the broken vector-name ops).
The evidence moves from the FORCE_OFF comment onto the op's own doc.

The two optimizer-on harness gates now fail whenever the swarm draws the op.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011AjmS5GFeGztfP3JqutnXj

* Propagate proxied changes when unwrapping proxies on optimization failure

unwrap_proxy puts the wrapped segments back into the segment holder, so the
changes recorded on the proxy while the optimization ran (deleted points,
index and vector-name changes) have to reach the wrapped segment first. They
did not, so every point deleted or overwritten during the optimization kept
its pre-optimization copy live next to the new copy in the write segment, and
reads saw both: counts too high, scroll and search returning the stale copy.

The snapshot unproxy path already does this; the optimizer failure path was
the only place putting a wrapped segment back without it. It is reachable
whenever the shard outlives the cancellation, in particular an update_collection
that recreates the optimizers while an optimization is in flight.

Lock order is holder-then-updates, matching try_unproxy_segment: updates-then-
holder-write deadlocks against the snapshot path.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011AjmS5GFeGztfP3JqutnXj

* Drop the stale failure note from the SetFlushInterval doc

The divergence it described is fixed in this branch.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011AjmS5GFeGztfP3JqutnXj

* test as well with 0s as flushing interval

* Fail optimization unwrapping when proxy propagation fails

Losing proxied deletes and index changes is data corruption, so return the
error instead of logging it: no proxy is unwrapped and the changes stay
served by the proxies. The cancelled-segment cleanup moves ahead of
unwrap_proxy so the orphan is still removed when that error fires.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CpoaAtGbAQAEuxEi8ScHc5

* Drop the model tester --flush-interval-sec flag

SetFlushInterval covers the interval now, so the run starts at the shipped
5s default (fixture::INITIAL_FLUSH_INTERVAL_SEC, still traced in the header)
and the ops move it from there. Also documents what 0 does now that it is a
generated value.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CpoaAtGbAQAEuxEi8ScHc5

* Fail snapshot unproxying when proxy propagation fails

Both paths logged the error and unwrapped anyway, dropping the deletes and
index changes that never reached the wrapped segment. Same reasoning as
unwrap_proxy in the optimizer.

try_unproxy_segment hands the lock back and leaves the proxy installed, the
failure mode its doc already describes: the caller keeps it in `proxies` and
unproxy_all_segments retries the propagation right after. unproxy_all_segments
returns before touching the holder, so the temp segment the surviving proxies
write into stays in place (remove_segment_if_not_needed only checks whether it
is empty and appendable, not whether a proxy still references it).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CpoaAtGbAQAEuxEi8ScHc5

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 12:45:53 +02:00
Arnaud GourlayandClaude Opus 5 864b39ebcc Fix edge amalgamation path rewriting on ast-grep 0.45 (#10395)
ast-grep 0.45 no longer parses a leading `::` fragment as a pattern, so
`pattern: ::$MOD` stopped matching and every `::common::` / `::wal::` path
survived into the generated qdrant-edge crate, failing `just rs-check`.
Matching the node text instead keeps the rule working on 0.44 and 0.45: the
amalgamation output is byte identical to what 0.44 produced before.


Claude-Session: https://claude.ai/code/session_01CpoaAtGbAQAEuxEi8ScHc5

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 12:45:52 +02:00
Ivan PleshkovandClaude Fable 5 5959e7c421 Fix TurboQuantizer::quantized_size double-padding for Bits1_5 (#10390)
`quantized_size_for` pads its `dim` argument, so passing the already
padded `self.padded_dim` applied the x1.5 expansion of `Bits1_5` a
second time.  Nothing on disk depends on the value for that width: the
quantization path sizes its records with `quantized_size_for` from the
raw dim, and the Turbo datatype storages, which do use
`quantized_size()` as their record size, are fixed at Bits4, where the
padding is idempotent.  The wrong value only over-reserved the
`quantize` output buffer.

Compute the packed size from `padded_dim` directly and cover `Bits1_5`
in the byte-length test.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-09-03 12:45:52 +02:00
Vijay Misalandqdrant-cloud-bot 89830c68c3 fix(strict-mode): enforce max_query_limit on scroll requests when limit is omitted (#10382)
* fix(strict-mode): enforce max_query_limit on scroll requests when limit is omitted (fixes #10373)

* style: rustfmt scroll query_limit for CI lint

---------

Co-authored-by: qdrant-cloud-bot <111755117+qdrant-cloud-bot@users.noreply.github.com>
2026-09-03 12:45:52 +02:00
qdrant-cloud-bot 081ada945f Fix flaky shard snapshot API CI readiness race (#10383)
* Fix flaky shard snapshot API CI readiness race

Run the prebuilt binary and poll /readyz instead of cargo run + fixed sleep, which can miss startup when cargo recompiles.

* Move shard snapshot API CI runner into a dedicated script

Keep workflow YAML thin by starting Qdrant, waiting for /readyz, and invoking shard-snapshot-api.sh from tests/shard-snapshot-api-tests.sh.
2026-09-03 12:45:52 +02:00
Roman Titov ce62c3d4a8 Implement more operations on ConsensusStateMachine [2/2] (#10339)
* fixup! Implement `ChangeAliases` operation

* fixup! Add `ChangeAliases` to replay-safety tests

* fixup! Add `ChangeAliases` tests

* De-slop ⛷️

* De-slop 🏂

* Add `TestSlowDown` and `TestTransientError` actions

These would have to be implemented on `TableOfContent` when switching
to `ConsensusStateMachine` as main consensus impl

* Handle more stupid corner-cases for `ChangeAliases` prop tests
2026-09-03 12:45:52 +02:00
Roman TitovandClaude Opus 5 470694ae96 Implement more operations on ConsensusStateMachine [1/2] (#10309)
* Add `AliasMapping::remove` and `AliasMapping::rename` methods

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

* Implement `ChangeAliases` operation

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

* Add `ChangeAliases` to replay-safety tests

Multi-action operations that rename an alias are skipped in the convergence
property: the current implementation does not replay them convergently, and
the machine reproduces that.

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

* Add `ChangeAliases` tests

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

* Add test-only `PeerMetadata::new` constructor

Test state needs peers at a version other than this build. The `version` field
is crate-private and `current()` is the only constructor, so gate the new one
on the `testing` feature and enable it for the `storage` test build.

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

* Implement `UpdatePeerMetadata` operation

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

* Add `UpdatePeerMetadata` to replay-safety tests

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

* Add `UpdatePeerMetadata` tests

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

* Implement `UpdateClusterMetadata` operation

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

* Add `UpdateClusterMetadata` to replay-safety tests

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

* Add `UpdateClusterMetadata` tests

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

* Implement `SetQuotaConfig` operation

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

* Add `SetQuotaConfig` to replay-safety tests

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

* Add `SetQuotaConfig` tests

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

* Implement `TestSlowDown` and `TestTransientError` operations

Both are node-local: one sleeps, the other fails at random. They plan no
actions, like `Nop`, so the replay-safety properties have nothing to add.

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

* Add `TestSlowDown` and `TestTransientError` tests

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

* fixup! Add `UpdatePeerMetadata` to replay-safety tests

* fixup! Add `UpdateClusterMetadata` tests

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 12:45:52 +02:00
Luis Cossío 7a1e1f7684 [UIO] impl DiskCache::read_bytes_async (#10259)
* [AI] TDD: new tests

* impl `read_bytes_async` for simplediskcache
2026-09-03 12:45:51 +02:00
Luis Cossío 4e6ca7d05a [UIO] UniversalRead::read_bytes_async stubs (#10258)
* impl `read_bytes_async` stubs

* clippy

* map err to `TaskPanicked` when appropriate
2026-09-03 12:45:51 +02:00
Atirna 70b1b6aa5f fix: token-aware Text and Phrase matching on unindexed payload fields (#10341)
Unindexed Match::Text and Match::Phrase previously shared a String::contains
arm, so phrase order was ignored and queries matched across token boundaries.
Use the default Word tokenizer for best-effort parity with indexed fields.

Fixes #10182
2026-09-03 12:45:51 +02:00
Jojii fc23bdab73 Hide DRAM latency in quantized scoring with software prefetch (#10342)
* Add prefetch to quantization storage

* Gated prefetch

* Add support for ARM

* Update doc strings

* T1 Prefetching

* Update stale doc strings + Tests
2026-09-03 12:45:51 +02:00
f6ef1965b2 Keep consensus operation awaiters alive for concurrent waiters (#10338)
* Keep consensus operation awaiters alive for concurrent waiters

Callers proposing an identical consensus operation deduplicate onto one
broadcast channel, and the map holds its only sender. Removing the entry on
timeout therefore closed the channel for every other waiter, failing their
still in-flight operation with "Channel sender dropped".

Only remove the entry once no receiver is left, dropping our own receiver
first so the last caller out cleans up. Apply the same to
await_for_multiple_operations, which registered awaiters but never
deregistered them when it timed out.

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

* Add debug assert to ensure we clean up consensus operation waiters

* Deregister consensus operation awaiters when the waiter is dropped

Dispatcher::submit_collection_meta_op registers the expected operations before
proposing, then drops that future unpolled whenever the proposal itself fails.
The awaiters stayed in the map with no receiver left, so the next identical
request deduplicated onto a dead entry and never heard back. This is what
tripped the new debug assert in CI: a rejected create-collection left a
SetShardReplicaState awaiter behind, and the next run of the same test hit it.

Move registration into an OperationAwaiters guard that deregisters on drop, so
timeout, drop-before-poll and request cancellation are all covered by one path.

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

* Close the race the awaiter debug assert trips on

The assert is sound only if no one can observe an entry whose receivers are all
gone. Both cleanup sites dropped their receiver before taking the map lock, so a
concurrent register could see exactly that and panic. Drop the receiver while
holding the lock instead, and take that lock once per batch rather than once per
operation: creating a collection registers an awaiter per replica, on the mutex
the consensus thread needs for every entry it applies.

Collect the awaiters into the guard as we go, so giving up part way still
deregisters the ones already registered, and only build the broadcast channel
when the operation is not already in-flight.

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: timvisee <tim@visee.me>
2026-09-03 12:45:51 +02:00
qdrant-cloud-bot 1d98640411 fix: stabilize segment builder cancellation test on Windows CI (#10346)
Add stop checks during the pre-HNSW build setup phase so cancellation
is observed promptly, and widen timing tolerance for noisy Windows debug
builds where post-stop delays can exceed 1s.
2026-09-03 12:45:50 +02:00
Seth Ockerman 90abcda5f1 avoid building full SegmentInfo just to read segment_type in shard status (#10345) 2026-09-03 12:45:50 +02:00
Mohamed Salah 93f3aafe31 docs(schema): declare enforced 1..=65536 bound on VectorParams.size (#10324)
* docs(schema): declare enforced 1..=65536 bound on VectorParams.size

The REST layer enforces an upper bound of 65536 on VectorParams.size
via a custom validator (validate_nonzerou64_range_min_1_max_65536),
but custom validators contribute no bounds to the generated JSON
schema - so the published OpenAPI document only declared minimum: 1,
while DenseVectorConfig.size already documented both bounds.

Add an explicit #[schemars(range(min = 1, max = 65536))] attribute so
clients validating requests against the schema see the same contract
the server enforces, update docs/redoc/master/openapi.json
accordingly, and pin the bound with a unit test asserting the
generated schema.

Fixes #9942

* test(openapi): accept documented size bound as a rejection path

test_vector_dimension_limit asserted that an oversized VectorParams.size
reaches the server and returns the exact runtime 422 message. Now that the
enforced 1..=65536 bound is documented in the served OpenAPI schema (#9942),
request_with_validation rejects such payloads client-side before sending.
Accept either layer: a client-side jsonschema.ValidationError or the
server-side validation error.

* test(openapi): handle both rejection layers in dimension limit

pytest.raises only covered the client-side jsonschema rejection; if the
request reached the server instead, the test would fail on an unhandled
response. Use try/except around request_with_validation and assert the
server-side status and exact error message in the else branch.

* test(openapi): assert exact HTTP 422 on server-side rejection

A broad not-ok check would pass on any error status carrying the same
error text; pin the documented contract to 422.

* refactor(tests): address review feedback

Remove the unit test asserting the generated VectorParams schema shape -
it only restates the schemars attribute and adds maintenance cost.

Reduce test_vector_dimension_limit to its actual contract: an oversized
dimension is rejected by the documented OpenAPI schema before the
request is sent.
2026-09-03 12:45:50 +02:00
Arnaud GourlayandClaude Opus 5 8065b9efa3 Remove stale clippy allows and the obsolete large-error-threshold override (#10337)
* Drop obsolete clippy large-error-threshold override

The 256 threshold was pinned for clippy 1.87 while tonic's `Status` was a
large error type. Upstream boxed its contents in `5de7bad` (hyperium/tonic#2253),
which is in the pinned 0.14.6 fork, so `Status` is now a single `Box` and the
default threshold of 128 passes.

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

* Remove stale clippy allows

These 11 allows no longer suppress anything under any of the three CI clippy
configurations (default, --all-targets, --all-targets --all-features).

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 12:45:50 +02:00
Arnaud GourlayandClaude Opus 5 334d180202 build(deps): disable unused default features (#10331)
Drops 6 crates from the release build and 7 from the workspace test
build, with no source changes.

- geo: no triangulation, only Contains/Intersects/Haversine (spade, earcut)
- jsonwebtoken: HS256 from_secret only, no PEM keys (pem, simple_asn1)
- tar: nothing sets unpack_xattrs, which defaults to false (xattr)
- duplicate: every duplicate_item names its module (proc-macro2-diagnostics)
- pprof: no C++ frames to demangle (cpp_demangle)

Also promotes duplicate to a workspace dependency.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 12:45:50 +02:00
Tarun Jain b6b1ec1f9b [qdrant-edge] multi-vector ColBERT-style search example (#10325) 2026-09-03 12:45:50 +02:00
Ivan DaschinskiyandIvan Dashchinskiy 8887b24e86 perf: skip external-id resolution in search post-processing (#10312)
* perf: skip external-id resolution in search post-processing

process_search_result hands its scored points to retrieve(), which resolves
every external id back into an internal offset — although the offsets are
already known there: they come straight from the vector index as
ScoredPointOffset. Every request therefore performs top_k x segments
redundant external->internal lookups.

Whether that costs anything depends on the id tracker being mutable: a
freshly optimized segment looks ids up through a BTree, while a restarted
node maps an immutable tracker and resolves in constant time. So the effect
shows up right after ingestion or optimization and disappears after a
restart, which is what makes it easy to miss — a benchmark that starts from
a freshly booted node never sees it.

Split retrieve() into resolution + retrieve_resolved() and pass the offsets
from process_search_result directly, applying the deferred cutoff by offset
instead of resolving ids just to filter them. retrieve() behaviour is
unchanged for all other callers; retrieve_resolved() is private and states
that deferred filtering is the caller's responsibility.

Measured on glove-100-angular (1.18M points, 21 segments, top_k=10) at a
fixed request rate, on a node that had just finished ingesting: median
latency ~15-24% lower, ~8% less CPU per request. Both figures come from the
same node before and after the change.

* review fix

* review fix

---------

Co-authored-by: Ivan Dashchinskiy <iadashchinskiy@sbertech.ru>
2026-09-03 12:45:49 +02:00
Jojii 9074435d93 Optimization: Skipping items before pushing into PriorityQueue. (#10099)
* Optimization: Skipping items before pushing into PriorityQueue.

* Apply suggestion from top-k-update branch

* Stabilize order of equal scored items in tests
2026-09-03 12:45:49 +02:00
dependabot[bot]andqdrant-cloud-bot 75fe4cb2bc build(deps): bump tango-bench from 0.7.2 to 0.8.0 (#10317)
* build(deps): bump tango-bench from 0.7.2 to 0.8.0

Bumps [tango-bench](https://github.com/bazhenov/tango) from 0.7.2 to 0.8.0.
- [Release notes](https://github.com/bazhenov/tango/releases)
- [Commits](https://github.com/bazhenov/tango/compare/v0.7.2...v0.8.0)

---
updated-dependencies:
- dependency-name: tango-bench
  dependency-version: 0.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

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

* fix: drop deprecated tango_main for tango-bench 0.8.0

tango_benchmarks! now generates main(); tango_main! is a deprecated no-op.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: qdrant-cloud-bot <111755117+qdrant-cloud-bot@users.noreply.github.com>
2026-09-03 12:45:49 +02:00
qdrant-cloud-bot 23ca62115c test: wait for receiver Active after snapshot transfer (#10330)
Finish can apply on peer 0 before the destination peer, so asserting
Active on peer 2 right after peer 0 reports all-Active was flaky.
2026-09-03 12:45:49 +02:00
qdrant-cloud-botanddependabot[bot] 2e8d618123 build(deps): bump serde_with to 3.22.0 without default features (#10329)
* build(deps): bump serde_with from 3.21.0 to 3.22.0

Bumps [serde_with](https://github.com/jonasbb/serde_with) from 3.21.0 to 3.22.0.
- [Release notes](https://github.com/jonasbb/serde_with/releases)
- [Commits](https://github.com/jonasbb/serde_with/compare/v3.21.0...v3.22.0)

---
updated-dependencies:
- dependency-name: serde_with
  dependency-version: 3.22.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

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

* build(deps): disable serde_with default features

Avoid pulling jiff timezone DB features via serde_with's std weak
dependencies; we only need macros and alloc.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-03 12:42:28 +02:00
dependabot[bot] 42a1e3122c build(deps): bump lukemathwalker/cargo-chef (#10314)
Bumps lukemathwalker/cargo-chef from latest-rust-1.97.1-bookworm to latest-rust-1.98.0-bookworm.

---
updated-dependencies:
- dependency-name: lukemathwalker/cargo-chef
  dependency-version: latest-rust-1.98.0-bookworm
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-03 12:42:28 +02:00
dependabot[bot] ab2035514d build(deps): bump ordered-float from 5.3.0 to 5.5.0 (#10316)
Bumps [ordered-float](https://github.com/reem/rust-ordered-float) from 5.3.0 to 5.5.0.
- [Release notes](https://github.com/reem/rust-ordered-float/releases)
- [Commits](https://github.com/reem/rust-ordered-float/compare/v5.3.0...v5.5.0)

---
updated-dependencies:
- dependency-name: ordered-float
  dependency-version: 5.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-03 12:42:28 +02:00
dependabot[bot] e79e50e8fc build(deps): bump io-uring from 0.7.13 to 0.7.14 (#10319)
Bumps [io-uring](https://github.com/tokio-rs/io-uring) from 0.7.13 to 0.7.14.
- [Commits](https://github.com/tokio-rs/io-uring/compare/v0.7.13...v0.7.14)

---
updated-dependencies:
- dependency-name: io-uring
  dependency-version: 0.7.14
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-03 12:42:28 +02:00
dependabot[bot] c98203f940 build(deps): bump uuid from 1.24.0 to 1.24.1 (#10318)
Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.24.0 to 1.24.1.
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/v1.24.0...v1.24.1)

---
updated-dependencies:
- dependency-name: uuid
  dependency-version: 1.24.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-03 12:42:28 +02:00
qdrant-cloud-bot da78e8f5c4 test: de-flake test_recover_from_snapshot shard placement assertion (#10310)
Mirror the fix from #9938 for test_upload_snapshot: assert every shard
has n_replicas active replicas across local+remote shards instead of
assuming peer 0 always sees exactly 2*n_replicas remote shards.
2026-09-03 12:42:27 +02:00
dependabot[bot] 9688d09d80 build(deps): bump rui314/setup-mold (#10315)
Bumps [rui314/setup-mold](https://github.com/rui314/setup-mold) from 9c9c13bf4c3f1adef0cc596abc155580bcb04444 to 7e4f20ad28a2e8ca6fd0892ccf72e2abb706b9c3.
- [Commits](https://github.com/rui314/setup-mold/compare/9c9c13bf4c3f1adef0cc596abc155580bcb04444...7e4f20ad28a2e8ca6fd0892ccf72e2abb706b9c3)

---
updated-dependencies:
- dependency-name: rui314/setup-mold
  dependency-version: 7e4f20ad28a2e8ca6fd0892ccf72e2abb706b9c3
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-03 12:42:27 +02:00
dependabot[bot] 6d13c124f9 build(deps): bump cc from 1.4.3 to 1.4.4 (#10321)
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.4.3 to 1.4.4.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.4.3...cc-v1.4.4)

---
updated-dependencies:
- dependency-name: cc
  dependency-version: 1.4.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-03 12:42:27 +02:00
dependabot[bot] 4b8071428d build(deps): bump actix-files from 0.6.10 to 0.7.0 (#10322)
Bumps [actix-files](https://github.com/actix/actix-web) from 0.6.10 to 0.7.0.
- [Release notes](https://github.com/actix/actix-web/releases)
- [Changelog](https://github.com/actix/actix-web/blob/v0.7.0/CHANGES.md)
- [Commits](https://github.com/actix/actix-web/compare/v0.6.10...v0.7.0)

---
updated-dependencies:
- dependency-name: actix-files
  dependency-version: 0.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-03 12:42:27 +02:00
dependabot[bot] 72b8e2884b build(deps): bump docker/setup-buildx-action from 4.2.0 to 4.3.0 (#10323)
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 4.2.0 to 4.3.0.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/bb05f3f5519dd87d3ba754cc423b652a5edd6d2c...37fe631027851001ddb9b187196cc803df7f5f0e)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-version: 4.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-03 12:42:27 +02:00
Ivan Pleshkov 96cdcdc8fe remove slow L1 turbo hnsw test (#10326) 2026-09-03 12:42:27 +02:00
Arnaud GourlayandClaude Opus 5 016328a3cc Stop growing appendable segments past max_segment_size (#10027)
* Steer writes away from appendable segments at max_segment_size

* pick a write target that stays under the configured size cap, instead of
  growing an appendable segment past it
* clamp the deferred points threshold to max_segment_size, treating a zero cap
  as uncapped
* apply the same cap when replaying the WAL, so recovery matches live updates
* plumb the cap through the update worker and cover the silent-failure gaps

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

* Extract the per-segment capacity check into a helper

Lets has_appendable_segment_with_capacity short-circuit on the first segment
below the cap instead of collecting every eligible ID.

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 12:42:26 +02:00
mikemikimike 750d999dfc fix(segment): handle null values in arrays (#10101) 2026-09-03 12:42:26 +02:00
qdrant-cloud-bot 0479d359c2 fix(grpc): raise http2 max pending accept reset streams on public API (#10306)
Mirror the internal gRPC server setting to avoid GOAWAY/ENHANCE_YOUR_CALM
errors when clients multiplex many short-lived streams (e.g. coach
high_concurrency drill). See #1907.
2026-09-03 12:42:26 +02:00