* IoUringState: generic `RequestId`
* UniversalRead: generic `RequestId`
* Simplify `gridstore::Pages::get_page_value_ranges`
Now we don't need two separate `SmallVec`s as we can put `buffer_offset`
into `RequestId`.
* Better doc comment
* Rename `RequestId` -> `Meta`
* Propagate HardwareCounterCell through MmapMapIndex::get_values
Previously, `MmapMapIndex::get_values` used `ConditionedCounter::never()`,
which silently skipped all hardware IO counter tracking for mmap map index
value reads. This propagates a real `HardwareCounterCell` through the full
call chain so that disk IO from `values_iter` is properly measured.
Changes:
- `MmapMapIndex::get_values` now accepts `&HardwareCounterCell`, creates a
`ConditionedCounter` via `make_conditioned_counter`, and measures the
`deleted` bitvec access (matching `check_values_any` behavior).
- `MapIndex::get_values` forwards the counter to the `Mmap` variant.
- `FacetIndex::get_point_values` trait method now accepts `&HardwareCounterCell`,
propagated through `FacetIndexEnum` and both impls (MapIndex, BoolIndex).
- `indexed_variable_retriever` accepts and forwards the counter to
`IntMapIndex`, `KeywordIndex`, and `UuidMapIndex` calls.
- `SegmentBuilder::update` and `_get_ordering_value` accept and propagate
the counter instead of creating disposable instances.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add test
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Daniel Boros <dancixx@gmail.com>
* Skip broken tests
* Add rocksdb dropper
This is a temporary tool. It will be removed later in this PR.
* [automated] Drop rocksdb
This commit is made by running tools/rocksdb/drop.sh
* Touch-up after ast-grep
The previous automated commit removed items, but not their comments.
Also, some blocks are left with only one item.
Also, ast-grep can't handle macros like `vec![]`.
This commit completes the job.
* Remove RocksDB dropper
* Remove mentions of rocksdb feature in CI
* Fix clippy warnings
These `FIXME` comments added previously in this PR by ast-grep by
"peeling" cfg_attr like this:
-#[cfg_attr(not(feature = "rocksdb"), expect(...))]
+#[expect(...)] // FIXME(rocksdb): ...
This commit removes these allow/expect attributes and fixes clippy
lints.
* Remove leftover rocksdb-related code
Removed:
- Cargo.toml: rocksdb cargo feature flag and dependencies.
- code: rocksdb-related items that was not under feature flag.
- flags.rs: rocksdb-related qdrant feature flags.
Disabled:
- Some benchmarks because these do not compile now.
* Print warning if rocksdb leftovers found in snapshots
* Remove Clone from tokenizer
* Regenerate openapi.json
* [AI] Implement low-level iterator for universal-io implementation of io_uring
* [AI] io_uring pool
* fmt
* [AI] refactor io_uring into multiple files
* [AI] implement IoUringReadMultiIter
* [AI] replace file_indices Vec -> AHashMap to prevent memory growth
* fmt
* Guard populate() when file uses O_DIRECT
O_DIRECT bypasses the page cache, so reading the whole file to warm
it is pointless — return early as a no-op.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Update comment about O_DIRECT in concurrent read iter test
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: apply submit_and_wait retry loop to read iterators
On older kernels, submit_and_wait may return before completions are
available. Apply the same retry loop to the iterator step() methods
to prevent premature iterator termination.
Made-with: Cursor
* do not step every time
* [AI] unify iterators
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Cursor Agent <agent@cursor.com>
Loop `submit_and_wait(1)` until the completion queue is non-empty in
`UniversalRead::read` and `UniversalWrite::write`. On some earlier
kernel versions, `submit_and_wait` may return before the requested
number of events have completed, which would cause the subsequent
`.expect()` to panic.
Made-with: Cursor
Co-authored-by: Cursor Agent <agent@cursor.com>
* Fix edge sparse vector search panic on score postprocessing
The distance lookup for score postprocessing only checked dense vector
configs, causing a panic when searching sparse vectors. Fall back to
Distance::Dot for sparse vectors, matching the full server behavior.
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>
* Address PR review: return error instead of panic, fix example
- Replace panic! with OperationError::service_error for unknown vector
names in edge search, avoiding process crash on bad client input
- Update stale "panics" comments and add assertions in sparse-search example
Made-with: Cursor
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Cursor Agent <agent@cursor.com>
* 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>
* Remove UniversalRead::is_empty
Reason: Less methods to override in wrappers. And I don't think this
method makes much sense.
* Move common::universal_io::{ => wrappers}::read_only
* Update ReadOnly wrapper
Implement missing methods, and follow the code style of the upcoming
TypedStrorage wrapper.
* Add TypedStorage
* Use TypedStorage
* Add reminder comments
* Clarify TypedStorage use-case
Two bugs introduced in 9a14ed7:
1. `HashSet::insert` returns `true` when the value is *new*, but the
code assigned it to `already_seen` and skipped on `true` — inverting
the deduplication so every unique geohash was skipped during removal.
2. `filter()` returns `OperationResult<Option<Box<dyn Iterator>>>`;
the new tests called `.unwrap()` once (unwrapping the Result) but
missed the second `.unwrap()` for the Option, causing a compile error.
Made-with: Cursor
Co-authored-by: Cursor Agent <agent@cursor.com>
* Add reproducing test for spurious geo index warning on duplicate geo values
When a point has multiple geo values that produce the same max-precision
geohash (e.g. duplicate coordinates in a multi-value geo field),
`InMemoryGeoMapIndex::remove_point` logs a spurious warning:
"Geo index error: no points for hash X was found".
The root cause is an asymmetry between `point_to_values` (stores all
values including duplicates) and `points_map` (uses a HashSet, so
duplicates are collapsed). During removal the loop processes each value
individually — the first iteration removes the `points_map` entry, and
subsequent iterations for the same hash can't find it.
This commit adds:
- A `debug_assert!` in `remove_point` (matching the existing pattern in
`decrement_hash_value_counts`) to make the issue detectable in tests.
- `test_remove_point_with_duplicate_geo_values` — reproduces the bug by
adding a point with `[BERLIN, BERLIN]` then removing it.
- `test_frequent_add_remove_geo_points` — exercises repeated add/remove
cycles to cover the user-reported scenario.
Made-with: Cursor
* fix: redulplicate hash IDs, replace warn with debug assertion
* fmt
---------
Co-authored-by: Cursor Agent <agent@cursor.com>
Co-authored-by: generall <andrey@vasnetsov.com>
* Don't insert deferred points into sparse index
# Conflicts:
# lib/segment/src/segment/tests.rs
# lib/segment/src/segment_constructor/segment_constructor_base.rs
# Conflicts:
# lib/segment/src/segment_constructor/segment_constructor_base.rs
* Clippy
* Assert consistency of deferred_internal_id var
* Return before SparseVector conversion in case of deferred point
* Use debug_assert instead
* 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>
* 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>