863 Commits

Author SHA1 Message Date
Andrey Vasnetsov
634d6c5bee Log slow operations during local shard WAL recovery (#9282)
* feat: log slow operations during local shard WAL recovery

Warn when applying a single WAL operation during recovery of a local
shard takes longer than 30s, including the operation type (e.g.
PointOperation::UpsertPoints) so slow recoveries can be diagnosed.

Adds CollectionUpdateOperations::label() returning a human-readable
label including the inner variant.

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

* refactor: reuse audit operation names for slow WAL recovery logging

Move the canonical operation-name mapping next to the
CollectionUpdateOperations definition in the shard crate as an inherent
operation_name() method, and have the audit AuditableOperation impl
delegate to it. The slow WAL recovery warning now reuses these same
names (e.g. upsert_points) instead of a duplicated label mapping.

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

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 14:58:25 +02:00
Arnaud Gourlay
0e2ed93172 Remove unecesssary Clippy allows (#9267) 2026-06-03 14:57:10 +02:00
qdrant-cloud-bot
d75d805533 Strict mode: add max_disk_usage_percent (#9212)
* Strict mode: add `max_disk_usage_percent`

Mirrors `max_resident_memory_percent`: rejects disk-consuming update ops
(upsert, set/overwrite payload, update vectors) when the filesystem hosting
Qdrant storage is filled above the configured percentage. Delete-style ops
remain allowed so callers can free disk.

Disk usage is sampled via `statvfs` and TTL-cached for 5s (same cadence as
the resident-memory reader) so high-RPS request paths don't hammer the
syscall. Reader is keyed by path in `common::disk_usage` and returns `None`
on stat failure — callers (the strict-mode check) treat `None` as "skip",
matching the memory-check behaviour.

Plumbing follows the existing pattern: field on `StrictModeConfig` (+
output/diff/Hash), gRPC proto field `22`, validation 1..=100, REST/proto
conversions, and the hook into `check_strict_mode_toc_batch` alongside the
memory check (both guarded by `any_consumes_memory`).

Co-authored-by: Cursor <cursoragent@cursor.com>

* Fix CI: Windows disk_usage test + e2e WAL config

- `missing_path_returns_none` panicked on Windows because
  `GetDiskFreeSpaceEx` succeeds for non-existent paths (it resolves up to
  the containing drive). Relax the assertion to "must not panic; if a
  value is returned it must be well-formed". The contract we care about
  (None on failure) is platform-defined, not something we can portably
  force.

- e2e test failed at batch 0 with "WAL buffer size exceeds available disk
  space": Qdrant's existing per-shard `DiskUsageWatcher` enforces
  `free >= 2 * wal_capacity_mb` and the default WAL didn't fit in the
  50 MB tmpfs. Bump tmpfs to 200 MB and shrink `wal_capacity_mb` to 1 MB
  (same pattern as `test_low_disk.py`) so our strict-mode gate is the
  one that fires, not the WAL pre-check. Raise the gate threshold to
  50% to match the larger headroom.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-03 14:54:03 +02:00
Luis Cossío
d808afb086 [#9159 alternative] Oversample with approx facet (#9208)
* Oversample with approx facet

* return early for limit=0

* Document distributed limit flow on Collection::facet

Add an ASCII diagram showing how the facet limit is oversampled once on
the entry node and how peer nodes enter via facet_internal without
re-oversampling.

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

---------

Co-authored-by: generall <andrey@vasnetsov.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 14:53:11 +02:00
Roman Titov
9c0248cae3 Upgrade tonic to v0.14.6 (#9139) 2026-06-03 14:47:00 +02:00
Tim Visée
6833924fe7 Recreate workers/optimizers async to not block consensus (#9121)
* Recreate optimizers in non-blocking fashion from consensus calls

* Update comments

* On optimizer config update failure, report error status to local shard

* Add a test to confirm we don't block consensus

* Rerun recreation if called multiple times

* Use atomics instead

* Move to the bottom

* Reformat
2026-05-22 10:51:10 +02:00
xzfc
2b5cf80f66 Warn on clippy::wildcard_enum_match_arm (#9096) 2026-05-22 10:46:36 +02:00
Andrey Vasnetsov
144fb01a09 fix: notify pending consensus ops on snapshot apply (#8990)
When an `AddPeer` / `RemovePeer` / `UpdatePeerMetadata` /
`UpdateClusterMetadata` operation is proposed locally and then committed
remotely, the resulting log entry can be delivered back to us as part of
a raft snapshot rather than as a regular log entry. In that case the
operation never flows through `apply_conf_change_entry` /
`apply_normal_entry`, so the awaiter registered by
`propose_consensus_op_with_await` was never woken and timed out after
10s — manifesting as flaky failures of `test_peer_snapshot_bootstrap`
("Failed to add peer: ... Waiting for consensus operation commit failed").

Resolve awaiters in `apply_snapshot` whenever their effect is directly
observable in the new persistent state.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 10:32:48 +02:00
Tim Visée
ca1971ad4f Fix inconsistent resharding state, SetShardState/AbortTransfer idempotency (#8917)
* [ai] Add integration test for triggering inconsistent resharding state

* [ai] Also add test for resharding down

* Update test

* Resolve resharding idempotency through setting replica states

* Remove resharding down test

* Reformat

* [ai] Remove resharding abort order, abort before setting replica state

* [ai] Resolve test flakiness

* Collapse matches into helper function

* Check preconditions before aborting resharding

* Fix test flakiness by not waiting for a dead node

* Abort resharding before aborting transfer for idempotency

* Update comment

* Release shard holder lock on transfer/reshard abort to prevent deadlock

* Remove now unused shard holder parameter

* Split handle_replica_changes to eliminate need for juggling locking

* In resharding tests, import all utils to enable every_test cleanup

Resolves flakiness I've been seeing in
test_set_replica_dead_clears_resharding_state test
2026-05-08 16:30:08 +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
Andrey Vasnetsov
4a9aefd191 [AI] Do not hold shards_holder.read on search (#8830) 2026-05-08 13:47:47 +02:00
Andrey Vasnetsov
7c60c1ec75 Dynamic cpu pool (#8790)
* [AI] inptoduce CPU process measurement

* use parking_lot + 4 seconds refresh rate

* [AI] AdaptiveSearchHandle

* fmt

* openapi schema

* keep Runtime field

* fix test

* [AI] instead of async semaphore, use 2 runtimes

* Adjust usage window to 2 seconds

* Address CodeRabbit review comments for dynamic CPU pool

- OpenAPI / telemetry: user-facing cpu_cores_used description (2s window, when null).
- process_cpu_usage: backoff after procfs errors; serialize Linux unit tests on CACHE.
- Docs: decouple runtime thread comments from hardcoded 4× multiplier; name search_runtime in test.
- consensus test: replace stale runtime comment.

Made-with: Cursor

* chore(openapi): regenerate master spec via generate_openapi_models.sh

Replace hand-edited cpu_cores_used description with output from
schema_generator + merge pipeline so openapi_consistency_check passes.

Made-with: Cursor

---------

Co-authored-by: Cursor Agent <agent@cursor.com>
2026-05-08 13:47:31 +02:00
Arnaud Gourlay
71ad3ea524 Delete unused code (#8771)
* Delete unused code

* restore initialize_global

* drop BadShardSelection

* Remove now obsolete allow(dead_code) attributes

* Remove more dead code

---------

Co-authored-by: timvisee <tim@visee.me>
2026-05-08 13:47:29 +02:00
Andrey Vasnetsov
5f452e500d Sync peers after CreateNamedVector/DeleteNamedVector (#8761)
submit_collection_meta_op was returning after the local apply on the
leader for these two ops, so a follow-up GET on a different peer could
still see the old vectors config until that peer applied the consensus
entry. Add them to the do_sync_nodes branch so the API only returns once
all reachable peers have caught up, matching CreateCollection /
CreateShardKey.

Drop the sleep(1) workarounds in test_vector_crud_with_consensus_snapshot
and tighten the client timeout on calls made while a peer is killed so the
server-side sync bounds quickly on the unreachable node.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 13:47:18 +02:00
Andrey Vasnetsov
231075410e low ram strict mode (#8715)
* [AI] strict mode parameter for limiting update requests if ram usage is over threshold

* opanAPI update

* [AI] end-to-end test

* fmt

* Fix e2e test: memory rejection check broken by string truncation

UnexpectedResponse.__str__() truncates the raw response body, cutting
off the `max_resident_memory_percent` hint at the end of the error
message. Use `resident memory usage` instead, which appears early
enough to survive the truncation.

Made-with: Cursor

* add grpc validation

* test check_resident_memory

---------

Co-authored-by: Cursor Agent <agent@cursor.com>
Co-authored-by: Arnaud Gourlay <arnaud.gourlay@gmail.com>
2026-05-08 13:46:58 +02:00
Andrey Vasnetsov
0d7ec28879 Low Memory mode (#8714)
* [AI] implement parameter + cover populate + cover quantized vectors

* telemetry OpenAPI schema

* [AI] hook immutable payload indexes

* fmt

* do not populate payload index if we fallback to mmap

* Reformat

* Also suppress universal IO disk cache population

---------

Co-authored-by: timvisee <tim@visee.me>
2026-05-08 13:46:49 +02:00
Arnaud Gourlay
7bac30caa6 Toc has deterministic collections iteration (#8712) 2026-05-08 13:46:47 +02:00
Arnaud Gourlay
70b30ccf29 Sort HashMap keys for deterministic iteration (#8706) 2026-05-08 13:46:46 +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
b0d525805d Clean up temporary directories before loading collections (#8689)
Previously `clear_all_tmp_directories()` was called in `main.rs` after
`TableOfContent::new()` had already loaded all collections and applied
WAL. Stale temp files from a previous crash (e.g. interrupted snapshot
transfers) could interfere with the recovery process.

Move the cleanup into `TableOfContent::new()` so it runs before the
collection loading loop. Extract a standalone `clear_tmp_directories()`
function that only needs `StorageConfig`, and delegate the existing
method to it.

Made-with: Cursor

Co-authored-by: Cursor Agent <agent@cursor.com>
2026-05-08 13:46:44 +02:00
Andrey Vasnetsov
607f016bbf crud named vectors (#8605)
* Add empty placeholder vector storage types for named vector CRUD

Introduce EmptyDenseVectorStorage and EmptySparseVectorStorage as
placeholder storages for newly created named vectors on immutable
segments. These report all vectors as deleted, consume no disk space,
and are reconstructed from segment config on load via the new
VectorStorageType::Empty and SparseVectorStorageType::Empty variants.

Key design decisions:
- is_on_disk is derived from original user config, not hardcoded
- MultiVectorConfig is preserved for multi-vector support
- Config mismatch optimizer skips Empty storage to avoid false rebuilds
- Quantization delegates normally (handles 0 vectors gracefully)
- get_vector includes debug_assert to catch unexpected access

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

* [AI] segment-level operations for creating and deleting anmed vectors

* [AI] implement named vector creation and deleting in proxy segment

* [AI] Step 3: Proxy Segment Handling for Named Vector Operations

* [AI] implement for Edge

* [AI] implement consensus operations for named vector operations

* [AI] refactor VectorNameConfig, remove VectorNameConfigInternal

* [AI] handle vector schema inconsistency in raft snapshot recovery

* [AI] rest + grpc API

* [AI] clippy

* [AI] generate openAPI schema

* fmt

* ci fixes

* [AI] fix jwt access test

* [AI] nop operation for awaiting of consensus-commited update ops

* [AI] move vector name operations into points service

* [AI] implement internal api for vector name operations

* [AI] change collection-level config along with segment level operation

* [AI] vector schema reconceliation instead of error

* fmt

* missing compile-time option

* [AI] integration test

* [AI] fix missing JWT tests

* [AI] remove NOP

* [AI] openapi test

* [AI] fix initialization of mutable segment

* [AI] more simple integration tests

* fmt

* [AI] make cluster test a bit harder

* [AI] make test less flacky

* [AI] rabbit comments

* [AI] check params compatibility before writing vector config

* [AI] make sure to register vector storages in structure payload index

* [AI] vector name validation

* lower vector length validation to 200 chars to account for prefix in filename

* [AI] proxy segment: prevent stale data leak through optimization

* fmt

* [AI] filter out removed vectors from proxy response

* [AI] handle vector name in proxy

* fmt

* adjust proxy info based on dropped vectors

* [AI] proxy segment: update filters to correct has_vector condition

* fmt

* clippy

* Fix consensus snapshot applicaiton for vector schema

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-08 13:46:38 +02:00
Leo Henon
d1cc51bcd8 Fix empty sparse vector name validation (#8194)
* Fix empty sparse vector name validation

* Reorder validation to check empty sparse name before duplicate name

---------

Co-authored-by: leohenon <77656081+lhenon999@users.noreply.github.com>
2026-05-08 13:46:38 +02:00
Leo Henon
7b147954cc Return error instead of panicking for corrupted aliases file on startup (#8293)
* Return error instead of panicking for corrupted aliases file on startup

* common::fs::ops: provide file name in error messages

And drop FileStorageError in favor of std::io::Error, since we always
convert all kinds of errors into ServiceError anyway.

* TableOfContent:🆕 return errors instead of panics

Also, drop context strings. We use fs_err anyway, that should be enough.

---------

Co-authored-by: leohenon <77656081+lhenon999@users.noreply.github.com>
Co-authored-by: xzfc <xzfcpw@gmail.com>
2026-05-08 13:46:38 +02:00
qdrant-cloud-bot
f4c15cdad7 Change audit log_api default from false to true (#8635)
When audit logging is enabled, log the API method path (REST path or
gRPC method name) by default. Users who don't want the extra field can
still set `audit.log_api: false` explicitly.

Made-with: Cursor

Co-authored-by: Cursor Agent <agent@cursor.com>
2026-05-08 13:46:37 +02:00
Tim Visée
7e02bd0970 Claude: simplify codebase (#8627)
* [ai] Replace manual into mappings with Into::into

* Reformat

* [ai] Use implicit .iter

* Don't iterate over keys too

* [ai] Replace unwrap_or

* Reformat

* [ai] Use as_deref and then_some

* [ai] Use more to_string

* [ai] Use explicitly typed into conversions

* Reformat

* [ai] More explicit into conversions

* Reformat
2026-05-08 13:46:37 +02:00
Andrey Vasnetsov
36fee82038 Add optional api field to audit log events (#8626)
* Add optional `api` field to audit log events

Add a new `api` field to audit log entries that records the API method
path (REST path or gRPC method name). Controlled by the `log_api` audit
config option. For denied auth requests, `api` is always logged and
`method` is omitted since there is no internal operation name available.

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

* Fix formatting

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

* deconstruct

* fix: test edge case

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Daniel Boros <dancixx@gmail.com>
2026-05-08 13:46:37 +02:00
Arnaud Gourlay
111dc76095 Remove unused dependency crates (#8589) 2026-05-08 13:46:00 +02:00
Arnaud Gourlay
d23daab2f5 Upgrade raft-rs to latest revision (#8588) 2026-05-08 13:46:00 +02:00
dependabot[bot]
5c17606fa6 build(deps): bump sha2 from 0.10.9 to 0.11.0 (#8558)
* build(deps): bump sha2 from 0.10.9 to 0.11.0

Bumps [sha2](https://github.com/RustCrypto/hashes) from 0.10.9 to 0.11.0.
- [Commits](https://github.com/RustCrypto/hashes/compare/sha2-v0.10.9...sha2-v0.11.0)

---
updated-dependencies:
- dependency-name: sha2
  dependency-version: 0.11.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

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

* fix: adapt to sha2 0.11.0 API changes

sha2 0.11.0 switched from GenericArray to hybrid_array::Array for hash
output, which no longer implements LowerHex. Replace `format!("{:x}")`
with explicit per-byte hex formatting.

Made-with: Cursor

* fix: replace write_all with update for sha2 0.11.0 compatibility

sha2 0.11.0 removed the std::io::Write impl on hashers.
Use Digest::update() instead of Write::write_all().

Made-with: Cursor

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Cursor Agent <agent@cursor.com>
2026-05-08 13:46:00 +02:00
Kyamran Shakhaev
c30cfa6d5d Use StorageError funcs (#8565) 2026-05-08 13:45:44 +02:00
Bhagirath Kapdi
732d34027f Feature/strict mode search max batchsize (#8469)
* feat: add search_max_batchsize to strict mode config

* added test case for search_max_batchsize

* Changes for fixing CI issue dure openapi

* Modify check_strict_mode_batch

---------

Co-authored-by: Arnaud Gourlay <arnaud.gourlay@gmail.com>
2026-03-26 18:54:05 +01:00
qdrant-cloud-bot
685466df60 Add #[must_use] to RAII guard and task handle types (#8499)
* Add `#[must_use]` to RAII guard and task handle types

These types rely on being held for a scope — dropping them immediately is
almost always a bug:

- `StoppingGuard`: sets `is_stopped` flag on drop
- `UpdateGuard`: decrements update counter on drop
- `UpdatesGuard`: releases mutex preventing concurrent updates on drop
- `ClockGuard`: marks clock as inactive on drop
- `IsAliveGuard`: releases liveness lock on drop
- `ScopeTrackerGuard`: decrements scope counter on drop
- `CancellableAsyncTaskHandle`: detaches task on drop
- `StoppableTaskHandle`: may abort task on drop (AbortOnDropHandle)

Made-with: Cursor

* Remove redundant function-level #[must_use] now covered by type

With ScopeTrackerGuard marked #[must_use] at the type level, the
function-level attributes on measure_scope(), measure(),
track_create_snapshot_request(), and count_snapshot_creation() are
redundant and trigger clippy::double_must_use.

Made-with: Cursor

---------

Co-authored-by: Cursor Agent <agent@cursor.com>
2026-03-26 18:48:41 +01:00
qdrant-cloud-bot
9d9aa4bdf4 Add REST API for reading audit logs across the cluster (#8498)
* Add REST API for reading audit logs across the cluster

Introduces a new `GET /audit/logs` endpoint that retrieves audit log
entries from all peers in the cluster. The API supports filtering by
time range (time_from/time_to), dynamic key=value field filters, and
a built-in limit parameter to prevent reading too many logs at once.

- Add `audit_reader` module in storage crate for efficient file-based
  log retrieval, selecting only files whose date range overlaps the
  query window
- Add `GetAuditLog` internal gRPC RPC for cross-peer log retrieval
- Add `GET /audit/logs` REST endpoint restricted to management access
- Aggregate and sort results from all peers by timestamp (newest first)

Made-with: Cursor

* [AI] Update filter_files_by_time_range make it aware of the log rotation granulatity (either hourly or daily)

* [AI] For AuditLogParams, try to use DateTime types natively into serde, instead of manual parsing

* [AI] Refactor API into separate file, propagate timeout, use spawn-blocking

* [AI] introduce cancellation token

* [AI] move timestamp to constant

* small manual fixes

* review fixes part 1

* review: switch to POST instead of GET

* [AI] review: sorting update

* [AI] use strict typing

---------

Co-authored-by: Cursor Agent <agent@cursor.com>
Co-authored-by: Andrey Vasnetsov <andrey@vasnetsov.com>
2026-03-26 18:44:12 +01:00
qdrant-cloud-bot
1e6cf720ff Add struct destructuring to catch missing fields at compile time (#8497)
Destructure structs in conversions, key/match functions, and config
builders so the compiler will error when new fields are added but not
handled. This prevents a common class of bugs where a newly added
struct field is silently ignored.

Covered spots:
- RecommendPointGroups → RecommendGroupsRequestInternal (15 fields)
- ShardTransferTelemetry ↔ ShardTransferInfo (7 fields, both directions)
- ReshardingTelemetry ↔ ReshardingInfo (6 fields, both directions)
- HwMeasurementAcc → HardwareUsage (7 fields, 3 call sites)
- VectorParams destructuring in optimizers_builder and config (7 fields)
- SparseVectorParams destructuring in optimizers_builder (2 fields)
- ShardTransfer → ShardTransferRestart (5 fields)
- ReshardState::matches and ReshardState::key (5 fields each)
- ShardTransfer::key and ShardTransferRestart::key (4 fields each)
- SnapshotDescription → grpc (4 fields)
- WithLookup REST → internal (3 fields)
- SegmentConfigV5 → SegmentConfig (5 fields)

Made-with: Cursor

Co-authored-by: Cursor Agent <agent@cursor.com>
2026-03-26 18:44:00 +01:00
Andrey Vasnetsov
aa5a158e30 [AI] implement wait override (#8476) 2026-03-26 18:36:02 +01:00
Tim Visée
9f8602d854 Allow peer to bootstrap with used URI if empty (#8301)
* [ai] Allow peer to bootstrap with existing URI if peer has no shards

Prompt:

I have a Qdrant cluster in distributed mode with some nodes registered
in consensus. If I bootstrap a new node with an URL that is already used
it is rejected and an error is returned. I would like to change this
behavior and allow this to happen. This would effectively replace a peer
because internally we'd drop the existing peer first, and then we'd add
the new peer so we can reuse the same peer URL. We must still reject
bootstrapping with the same URL if the peer that used the URL before us
still has any shards on it.

* [ai] Add test to assert new behavior, can rejoin if empty

Prompt:

Add two tests to assert the new behavior.

The first test should:
- create a cluster
- create a collection
- bootstrap a new peer
- kill and delete the local data for this peer without removing it from consensus
- bootstrap a new peer but reuse the URI of the peer we just killed to rejoin
- bootstrapping is expected to succeed

The second test should:
- create a cluster
- create a collection
- bootstrap a new peer but reuse the URI of the last node
- bootstrapping is expected to fail because the node being replaced has data on it

* [ai] Attempt to fix new tests

* Reformat

* [ai] Fix deadlock when rejoining with same peer URI

* [ai] Add test to ensure existing peer stops consensus on replace
2026-03-26 18:34:39 +01:00
dependabot[bot]
80f397ecb9 build(deps): bump tempfile from 3.26.0 to 3.27.0 (#8427)
* build(deps): bump tempfile from 3.26.0 to 3.27.0

Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.26.0 to 3.27.0.
- [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stebalien/tempfile/compare/v3.26.0...v3.27.0)

---
updated-dependencies:
- dependency-name: tempfile
  dependency-version: 3.27.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

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

* Replace deprecated TempPath::from_path with TempPath::try_from_path

tempfile 3.27.0 deprecates `TempPath::from_path` in favor of
`TempPath::try_from_path` which properly handles relative path
resolution failures by returning a Result.

Made-with: Cursor

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Cursor Agent <agent@cursor.com>
2026-03-26 18:21:44 +01:00
Andrey Vasnetsov
c9ebed8569 add tracing ID into audit logging (#8402)
* add tracing ID into audit logging

* format and refactor

* clippy

* review fixes

* fmt
2026-03-26 18:18:10 +01:00
Arnaud Gourlay
d58a6975d0 Default shard transfer with snapshot when prevent_unoptimized (#8358)
* Default shard transfer with snapshot when prevent_unoptimized

* extract heuristic

* adjust all possible call sites

* keep previous style

* rework default shard transfer method

* Ensure we don't combine non-streaming transfers with filters

* Clippy

* add http ok assertion before json()

* Use exhaustive match

* keep stream records as fallback

* use effective_optimizers_config

* fix fallback success signal

---------

Co-authored-by: jojii <jojii@gmx.net>
Co-authored-by: timvisee <tim@visee.me>
2026-03-26 17:55:51 +01:00
Andrey Vasnetsov
c6f7550fdc Restrict snaphsot recovery to snapshots directory, hide file contents (#8341)
* restrict recovery from snapshot folder

* fmt

* clippy

* Extend test, path must be inside snapshots directory

* In release builds, hide detailed tar error message to not leak contents

* Change from bad request to forbidden

* fix(auth_tests): place snapshot in peer snapshots dir for recover_collection_snapshot

The recover from snapshot API now requires file:// paths to be inside the
configured snapshots directory. Write the test snapshot into the peer's
snapshots directory instead of a temp file so the request is allowed.

Made-with: Cursor

---------

Co-authored-by: timvisee <tim@visee.me>
Co-authored-by: Tim Visée <tim+github@visee.me>
Co-authored-by: Cursor Agent <agent@cursor.com>
2026-03-26 17:48:45 +01:00
qdrant-cloud-bot
4d23f32681 Introduce EdgeShardConfig for edge shard (#8322)
* Introduce EdgeShardConfig for edge shard

- Add EdgeShardConfig and EdgeOptimizersConfig in lib/edge/src/config.rs
  - Segment config (vector_data, sparse_vector_data, payload_storage_type)
  - Global hnsw_config and per-vector HNSW in segment config
  - Optimizer params: deleted_threshold, vacuum_min_vector_number,
    default_segment_number, max_segment_size, indexing_threshold,
    prevent_unoptimized (excludes memmap_threshold, flush_interval_sec,
    max_optimization_threads)
- Persist/load as edge_config.json in shard path
- EdgeShard uses RwLock<EdgeShardConfig>; load() accepts Option<EdgeShardConfig>,
  falls back to file or infer from segments; compatibility checked on load
- load_with_segment_config() for backward compatibility (SegmentConfig -> EdgeShardConfig)
- optimize() uses EdgeShardConfig for hnsw and optimizer thresholds
- Public methods: set_hnsw_config(), set_vector_hnsw_config(), set_optimizers_config()
  (update and persist)
- Python and examples use load_with_segment_config with existing config API

Made-with: Cursor

* Refactor EdgeShardConfig: user-facing params only, config module

- Replace SegmentConfig inside EdgeShardConfig with user-facing fields:
  - on_disk_payload (bool) instead of payload_storage_type
  - vectors: HashMap<VectorNameBuf, EdgeVectorParams> with on_disk per vector,
    no per-vector quantization; global quantization_config only
  - sparse_vectors: HashMap<VectorNameBuf, EdgeSparseVectorParams> with on_disk
- EdgeVectorParams / EdgeSparseVectorParams use on_disk (bool) instead of
  storage_type; conversion to VectorDataConfig/SparseVectorDataConfig in
  to_segment_config()
- Add config module: mod.rs, optimizers.rs, vectors.rs, shard.rs
- from_segment_config(&SegmentConfig) fills all inferrable params
- to_segment_config() builds SegmentConfig for segments and optimize()
- load_with_segment_config takes Option<SegmentConfig>, uses from_segment_config

Made-with: Cursor

* Move optimizer threshold helpers to shard crate

- Add get_number_segments, get_indexing_threshold_kb, get_max_segment_size_kb,
  get_deferred_points_threshold_bytes in shard::optimizers::config
- Collection OptimizersConfig and edge EdgeOptimizersConfig delegate to these
- Single place for threshold logic; collection and edge use shard helpers

Made-with: Cursor

* Use destructuring in config conversions to avoid missing new fields

- EdgeVectorParams: destructure VectorDataConfig in from_*, destructure self in to_vector_data_config
- EdgeSparseVectorParams: destructure SparseVectorDataConfig and SparseIndexConfig in from_*, destructure self in to_sparse_vector_data_config
- EdgeShardConfig: destructure SegmentConfig in from_segment_config, destructure self in to_segment_config
Adding new fields to source structs will now cause compile errors until conversions are updated.

Made-with: Cursor

* refactor: centralize on_disk_payload→payload_storage_type, on_disk→storage_type, and appendable quantization logic

- PayloadStorageType::from_on_disk_payload(bool) in segment (Mmap/InRamMmap)
- VectorStorageType::from_on_disk(bool) in segment (ChunkedMmap/InRamChunkedMmap)
- QuantizationConfig::for_appendable_segment(Option<&Self>) in segment (feature flag + supports_appendable)
- collection: use from_on_disk_payload in non-rocksdb branch
- edge shard/vectors: use new helpers; remove duplicated conditionals
- shard optimizers: use from_on_disk and for_appendable_segment

Made-with: Cursor

* refactor(edge): use EdgeShardConfig directly, drop segment_config

- Add plain_segment_config() for create_appendable_segment (no HNSW)
- Add segment_optimizer_config() built from EdgeShardConfig for blocking optimizers
- Add vector_data_config(name) for query/MMR
- build_blocking_optimizers: use segment_optimizer_config() instead of SegmentConfig
- create_appendable_segment: use plain_segment_config()
- search/query: use config().vectors and vector_data_config() instead of segment_config()
- Remove segment_config() from EdgeShardConfig and EdgeShard
- Add to_plain_vector_data_config on EdgeVectorParams

Made-with: Cursor

* [manual] review changes

* refactor(edge-py): wrap EdgeShardConfig, add EdgeVectorParams/EdgeSparseVectorParams

- PyEdgeConfig now wraps EdgeShardConfig (vectors, sparse_vectors, on_disk_payload, etc.)
- PyEdgeVectorParams / PyEdgeSparseVectorParams wrap edge config types
- PyEdgeOptimizersConfig for optional optimizer settings
- EdgeShard.load() uses EdgeShardConfig; edge::config made pub for Python crate
- cargo fmt + clippy (remove map_identity)

Made-with: Cursor

* refactor(edge-py): simplify config API, remove unused Py* types, add EdgeConfig

- Remove unused PyPayloadStorageType, PyVectorDataConfig, PyVectorStorageType,
  PySparseVectorDataConfig, PySparseVectorStorageType from Python bindings
- Move PyEdgeOptimizersConfig to lib/edge/python/src/config/optimizers.rs
- Update qdrant_edge.pyi: EdgeConfig with vectors/sparse_vectors,
  EdgeVectorParams, EdgeSparseVectorParams, EdgeOptimizersConfig
- Update examples (common.py, repr.py) to use new config API
- Run cargo fmt

Made-with: Cursor

* [manual] review changes

* [manual] review changes

* [manual] fix test

* Address CodeRabbit review comments for PR 8322 (#8324)

* Address CodeRabbit review comments for PR 8322

- Python examples: explicit imports (repr.py, common.py) and new EdgeConfig API
- HnswIndexConfig: add max_indexing_threads param and property in .pyi and Rust bindings
- EdgeConfig: make vectors optional for sparse-only configs; validate at least one of vectors/sparse_vectors
- EdgeShardConfig::load: use try_exists(), propagate I/O errors
- from_segment_config: infer hnsw_config from per-vector HNSW when all agree
- EdgeShard setters: atomic clone-mutate-save-then-replace; persist config save errors
- Segment compat: prefix vector name in error messages; resolve None datatype to Float32
- max_indexing_threads: preserve 0 (auto) sentinel in trait default; remove per-optimizer overrides
- SegmentOptimizerConfig:🆕 build plain and optimizer maps in single pass
- config_mismatch_optimizer tests: use VectorNameBuf::from() instead of .into()
- vectors.rs: doc updates for per-vector quantization

Made-with: Cursor

* Address @generall review: SaveOnDisk for config, resolve num_rayon_threads in optimizer

- Use SaveOnDisk<EdgeShardConfig> for EdgeShard config (generall: 'We have SaveOnDisk struct for this')
  - Create via SaveOnDisk::new() after resolving config; setters use .write() for atomic persist
  - set_vector_hnsw_config: clone then mutate then write (fallible setter)
- max_indexing_threads: resolve 0 (auto) via num_rayon_threads inside impl (generall: 'proper solution would be to resolve num_rayon_threads inside the optimizer impl')
  - max_indexing_threads_sentinel_aware() now returns Some(num_rayon_threads(raw)) so callers get actual thread count

Made-with: Cursor

* [manual] reorganize num_rayon_threads -> get_num_indexing_threads to better account per-vector configuration

---------

Co-authored-by: Cursor Agent <agent@cursor.com>
Co-authored-by: generall <andrey@vasnetsov.com>

* update docstring and pyi

* fmt

* fmt

* clipy

---------

Co-authored-by: Cursor Agent <agent@cursor.com>
Co-authored-by: generall <andrey@vasnetsov.com>
2026-03-26 17:40:51 +01:00
xzfc
e23cc13d0a Remove shard dependency on api (#8284)
* Move `DenseVector`/`MultiDenseVector` from `api` to `segment`

* Move `OrderByInterface` from `api` to `segment`

Reason: it's used in `edge` which shouldn't depend on `api`.

* Make `shard` -> `api` dependency optional

* Remove `api` from the amalgamation

* Don't install protoc in edge Actions
2026-03-26 17:37:48 +01:00
krapcys1-maker
1e1da031b7 [snapshot] Avoid leaving replicas in recovery state when shard data is absent (#8179)
* snapshot

* snapshot recovery: remove stale state read in revert guard
2026-03-26 17:11:38 +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
Andrey Vasnetsov
d713ab7be1 Timeout for snapshot stream (#8166)
* [AI] Imeplement timeout for reading snapshot stream

* remove debug code

* [no-AI] fix error type and cancellation test(not the one which actually found the problem)
2026-02-18 11:22:58 +01:00
xzfc
66d0c36009 Merge io and memory into common (#8155)
* Unify parking_lot/arc_lock feature

* Move lib/common/{io,memory}/* -> lib/common/common/*

- Mmap-related items are grouped into `common::mmap` sub-module:
  - `memory/src/chunked_utils.rs`      -> `common/src/mmap/chunked.rs`
  - `memory/src/madvise.rs`            -> `common/src/mmap/advice.rs`
  - `memory/src/mmap_ops.rs`           -> `common/src/mmap/ops.rs`
  - `memory/src/mmap_type_readonly.rs` -> `common/src/mmap/mmap_readonly.rs`
  - `memory/src/mmap_type.rs`          -> `common/src/mmap/mmap_rw.rs`
- Filesystem-related items are grouped into `common::fs` sub-module:
  - `common/src/fs.rs`          -> `common/src/fs/sync.rs`
  - `io/src/file_operations.rs` -> `common/src/fs/ops.rs`
  - `io/src/move_files.rs`      -> `common/src/fs/move.rs`
  - `io/src/safe_delete.rs`     -> `common/src/fs/safe_delete.rs`
  - `memory/src/checkfs.rs`     -> `common/src/fs/check.rs`
  - `memory/src/fadvise.rs`     -> `common/src/fs/fadvise.rs`
- Rest is moved straight into `common`:
  - `io/src/storage_version.rs` -> `common/src/storage_version.rs`

The old `io` and `memory` are now hollow crates that re-export items
from `common`. These hollow crates will be removed in next commits.

* Replace uses of `io` and `memory` with new paths in `common`

Since `io` and `memory` are just re-exports of `common`, these
replacements are no-op.

* Remove `io` and `memory` crates
2026-02-17 11:01:14 +01:00
Andrey Vasnetsov
341d4294ee HTTPS snapshot links (#8095)
* [manual] generate snapshot download link with respect of enabled tls

* Simplify http(s) selection

---------

Co-authored-by: Tim Visée <tim+github@visee.me>
2026-02-13 09:55:15 +01:00
Andrey Vasnetsov
015e1b2656 audit logging (#8071)
* initial implementation

* internal logging type

* wrap more places into auth function

* [manual refactor] use &Auth in .toc fucntion - minimise direct .access()

* [manual refactor] fmt

* [manual refactor] remove unannotated .access in creation of snapshots

* [manual refactor] remove unannotated .access in cluster telemetry

* [manual refactor] remove unannotated .access

* [manual refactor] do not log /metrics api access

* [manual refactor] do not run the service if audit logging failed to init

* [manual refactor] make auditable operation names for point and cluster updates

* [manual refactor] remove excess cloning of auth object

* [manual refactor] fmt

* [AI] instead of manual writing into the file, use tracing_appender crate

* [AI] simplify configuration to match internal crate

* fmt

* [manual refactor] cover staging options

* [AI] refactor x-forwarded-for handelling

* [manual refactor] use consts for x-forwarded-for + recover handelling for RFC case in tonic

* Update src/tonic/forwarded.rs

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* [manual] review fix: use FORWARDED in actix

* [manual] review fix: do not log strict mode checks

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-02-10 00:07:27 +01:00
xzfc
b1e3e421b0 Chore: promote dependencies to workspace level (#8061)
* Promote `env_logger` to workspace dependency

* Promote `anyhow` to workspace dependency

* Promote `rmp-serde` to workspace dependency

* Promote `tinyvec` to workspace dependency

* Promote `async-trait` to workspace dependency

* Promote `url` to workspace dependency

* Promote `self_cell` to workspace dependency

* Promote `cc` to workspace dependency

* Promote `bitpacking` to workspace dependency
2026-02-10 00:02:45 +01:00
Tim Visée
ac4cfed143 For snapshots directly restored, use default temp path in storage volume (#8059) 2026-02-10 00:00:00 +01:00