431 Commits

Author SHA1 Message Date
xzfc
a1a005c7d5 rustdoc: syntax/path fixes 2026-04-07 21:13:58 +00:00
xzfc
3be620d2b7 rustdoc: add doc for generic_consts
(Copied from closed PR #8458)
2026-04-07 20:54:40 +00:00
xzfc
2d9d953a45 UniversalIO: generic RequestId (#8601)
* 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`
2026-04-07 17:10:40 +00:00
xzfc
8e07ccb7c3 IoUringState: replace HashMap with flat slice (#8599) 2026-04-07 12:31:55 +00:00
xzfc
38d5439078 UIO read benchmark (#8575) 2026-04-03 12:31:36 +00:00
Roman Titov
5739daa53a Improvements to io_uring (#8592)
* Cleanup `IoUringGuard`

* Cleanup `IoUringRuntime`

* Simplify imports

* Extract `io_error_context` into `error` sub-module

* Rename `IoUringFile::uses_o_direct` into `direct_io`

* Rename `IoUringRequest::Read` fields

* Minor cleanups

* Cleanup `IoUringPool` 😵‍💫

* Track file index during multi-file operations as part of `IoUringState`
2026-04-03 05:09:30 +00:00
Roman Titov
e43acaf9ab Better IoUringReadIter (#8586)
Co-authored-by: generall <andrey@vasnetsov.com>
2026-04-01 19:55:50 +02:00
Arnaud Gourlay
a4059c15af Remove unused dependency crates (#8589) 2026-04-01 18:15:18 +02:00
xzfc
5e7a3b0593 IoUringFile: don't use io_uring for single operations (#8576) 2026-04-01 00:27:51 +00:00
xzfc
0b0df145b3 Drop RocksDB (#8529)
* 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
2026-03-31 18:08:39 +00:00
Andrey Vasnetsov
f473e83ed0 universal io iterator (#8535)
* [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>
2026-03-31 15:54:52 +02:00
qdrant-cloud-bot
f7dd3ae896 Fix io_uring submit_and_wait returning before completions on older kernels (#8547)
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>
2026-03-30 21:45:24 +02:00
Luis Cossío
fa8b441454 Allow shorter reads in IoUring (#8466)
* use assume_init_vec

* allow shorter reads at EOF

* add prevent_caching openoption, allow short read dynamically

* codespell

* fix rebase
2026-03-26 11:56:22 -03:00
xzfc
50e4796597 Add TypedStorage wrapper (#8508)
* 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
2026-03-26 14:10:19 +00:00
Roman Titov
69b70ee401 Small optimization for MmapFile (#8511) 2026-03-26 12:19:35 +01:00
Roman Titov
bcdf2d2577 Replace MmapUniversal with MmapFile (#8505) 2026-03-25 19:37:45 +01:00
Luis Cossío
3af9349e83 impl populate for CachedSlice (#8462)
* impl populate

* nits
2026-03-25 13:59:02 -03:00
Roman Titov
a7550f893f Universal MmapFile that can read any T (#8493) 2026-03-25 16:57:53 +01:00
Luis Cossío
7f106ce397 impl UniversalRead for local disk cache (#8368)
* checkout from `ssd-cache-wip`

* impl UniversalRead for CachedFile

* use `CachedSlice` for `UniversalRead` implementation

* block exhaustion test

* fix block exhaustion error

* fix alignment on owned path

* merge CachedFile into CachedSlice

* propagate io errors

* self-review

- log warning if long wait
- Option for RequestState
- clippy

* handle coderabbit's comments

* fix num read bytes check

* don't allocate twice for cache misses

* not for windows, sorry

* no more dead code

* use atomic for file id

* update cache controller description

* rebase fixes

* Self: Sized

* Use imports

* Remove with_global (unused)

* Add TODO

* move common::disk_cache -> universal_io::disk_cache

---------

Co-authored-by: xzfc <xzfcpw@gmail.com>
2026-03-25 11:39:26 -03:00
qdrant-cloud-bot
401cb7f12c 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-25 14:51:38 +01:00
Excellencedev
3230f1d952 Implement Per collection metrics for Promethus (#8214)
* Implement Per-Collection Prometheus Metrics

* Update config/config.yaml

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

* Update tests/per_collection_metrics_test.sh

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

* Update tests/per_collection_metrics_test.sh

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

* fix ci

* comment

* Update tests/per_collection_metrics_test.sh

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

* adress revew

* fix: linter

* refactor: cardinality limit, anonymize fix, cleanup

- Add max_per_collection_metrics config (default 256) to bound
  per-collection label cardinality
- Fix anonymize: strip per_collection_responses entirely instead of
  leaking hashed collection names
- Move CollectionName into requests_telemetry, remove
  telemetry_context.rs
- Add unit tests for cardinality limits
- Add integration test assertions for default mode
- Regenerate OpenAPI spec
- Document why internal gRPC doesn't attach CollectionName

* avoid cloning

* fix: address pr reviews

* fix: linter

* fix: linter

* feat: enforce {name} in actix api

* chore: remove empty line

* feat: add actix pre-commit hook

* feat: potential enforce tonic collection name

* feat: use proc_macro instead

* feat: use collection_name instead of name

* feat: add tonic telemetry tests

* fix: linter

* fix: linter

* chore: remove unneccessary clone

* fix: use collection_name everywhere

* fix: python tests and openapi

* chore: simplify collection_name tests

* actix collection_name enforcign: use relative path in test + avoid grep

* fix: remove macro

* chore: add some comment to telemetry_wrapper

* fix: clippy

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Daniel Boros <dancixx@gmail.com>
Co-authored-by: generall <andrey@vasnetsov.com>
2026-03-23 15:19:02 +01:00
Andrey Vasnetsov
454f11b515 Fix io_uring reads: use byte offset (#8470)
* [AI] use byte offset instead of element range

* [AI] change ElementOffset -> ByteOffset
2026-03-20 21:03:23 +01:00
Roman Titov
04e9bbc4b2 Dense vector storage based on universal I/O IoUringFile (#8452) 2026-03-20 11:16:12 +01:00
xzfc
7bd5759105 Touch-up UIO traits (#8457)
* UIO traits: require Sized

I don't think we ever going to add unsized implementation. So, lets,
require it on the whole trait rather than on individual methods.

* Move `AccessPattern` to the `common` package

Was: segment::vector_storage::vector_storage_base::AccessPattern
Now: common::generic_consts::AccessPattern

* UIO traits: replace `bool` with `AccessPattern`
2026-03-19 20:28:21 +00:00
Luis Cossío
ad8334928d Use UniversalIo for MmapBitSlice (#8339)
* feat(universal_io): add storage-agnostic BitSliceStorage with read/write support`

Add BitSliceStorage<S> generic over
UniversalRead<u64>/UniversalWrite<u64>,
providing bit-level read and write operations over u64-element storage.

Read operations (S: UniversalRead<u64>):
- read_all: returns Cow<BitSlice> (zero-copy for mmap, owned for others)
- get_bit: single bit read via u64 element fetch
- read_bit_range: arbitrary bit range read

Write operations (S: UniversalWrite<u64>):
- set_bit / replace_bit: single bit write (skips write if unchanged)
- write_bit_range: arbitrary bit range write from BitSlice source
- fill_bit_range: fill range with a value
- set_bits_batch: batch individual bit updates coalesced by element
- flusher: flush underlying storage

* refactor: replace MmapBitSlice with BitSliceStorage in MmapBitSliceBufferedUpdateWrapper

Migrate all deleted-flag bitslice storage from the legacy MmapBitSlice
(Deref-based mmap wrapper) to BitSliceStorage<MmapUniversal<u64>>
(storage-agnostic universal IO backend).

Updated consumers:
- MmapMapIndex
- MmapNumericIndex
- MmapGeoMapIndex
- MmapInvertedIndex (fulltext)
- ImmutableIdTracker
- Benchmark

Additionally:
- Add BitSliceStorage::create(path, num_bits) to encapsulate
  file creation + sizing + open (eliminates duplicated size math
  across 5 call sites)
- Add MmapBitSliceStorage type alias for
BitSliceStorage<MmapUniversal<u64>>
- Add count_ones() convenience method
- Use set_bits_batch() in wrapper flusher and all build paths
  instead of per-bit set_bit() loops (coalesces u64 read-modify-writes)
- Fix silent error swallowing in wrapper get(): log + debug_assert
  on I/O errors instead of .ok().flatten()
- Remove dead bitmap_mmap_size function from immutable_id_tracker

* use bitvec's approach for offset

* less api

* misc improvements

* refactor write method

* move to segment crate

* handle creation of file outside of StoredBitSlice logic

* fix codespell

* document bitwise calculations

* coalesce more updates into a single write, batch all writes

* use native `extend_from_bitslice` instead of iterating.

* clarity refactor

* clippyyy

* use `u64` as BitStore everywhere

* assume iterator is sorted

* only use chunk_by for generating runs

* fix update wrapper flusher

* review fixes

* larger set bits batch test

* remove reintroduced file

* oops, fix new test

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: generall <andrey@vasnetsov.com>
2026-03-19 12:26:47 -03:00
qdrant-cloud-bot
09b3ff00cb refactor(edge): split EdgeShard load into new() and load() (#8326)
* refactor(edge): split EdgeShard load into new() and load()

- new(path, config): create edge shard only when path has no existing segments
- load(path, config?): load from existing files; config optional (load from
  edge_config.json or infer from segments)
- Helpers: has_existing_segments, ensure_dirs_and_open_wal, resolve_initial_config,
  load_segments, ensure_appendable_segment
- Python: EdgeShard.create_new(path, config); __init__ still calls load()
- Examples use new() for creation and load(path, None) for reopen
- Error instead of panic on config mismatch; explicit load/create in Python
- fix: use OptimizerThresholds.deferred_internal_id for dev compatibility

Made-with: Cursor

* rollback threshold changes

* fix(edge): address dancixx review comments

- Persist inferred config in load() when edge_config.json does not exist
  (SaveOnDisk::new only saves when file exists)
- Python: add #[new] delegating to load() for backward compatibility
- qdrant_edge.pyi: Optional return types for deleted_threshold,
  vacuum_min_vector_number, default_segment_number; add __init__ doc

Made-with: Cursor

* Revert "fix(edge): address dancixx review comments"

This reverts commit 370e21a6c74c41210e1658f89814395cb86ed81c.

* fix: optional returns

* fix: save config it is not exist

* fix: save data on disk always

* fix: python examples

* chore: remove edge.close()

* fix: wal lock

* fix: rename of EdgeShardConfig -> EdgeConfig

---------

Co-authored-by: Cursor Agent <agent@cursor.com>
Co-authored-by: Andrey Vasnetsov <andrey@vasnetsov.com>
Co-authored-by: Daniel Boros <dancixx@gmail.com>
2026-03-18 15:25:01 +01:00
Roman Titov
a3d4570a12 Better IoUringFile errors (#8418) 2026-03-17 10:13:42 +01:00
qdrant-cloud-bot
6ddb60e5b5 Log individual payload index load time per field (#8390)
* Log individual payload index load time per field

Add per-field timing to `load_all_fields()` in `StructPayloadIndex`,
using the existing `LOAD_TIMING_LOG_TARGET` infrastructure. Each
payload field index that takes >= 5ms to load now gets its own log
line, making it easy to identify slow-loading fields.

Made-with: Cursor

* Move `log_load_timing` to common module and use everywhere

Move the `log_load_timing` helper from `segment_constructor_base` into
`common::defaults` so it can be reused across crates. Convert all raw
`log::debug!(target: LOAD_TIMING_LOG_TARGET, ...)` call sites to use
the shared function, giving consistent formatting and min-duration
suppression everywhere.

Made-with: Cursor

---------

Co-authored-by: Cursor Agent <agent@cursor.com>
2026-03-13 18:38:04 +01:00
qdrant-cloud-bot
2406dd9562 Suppress noisy zero-duration load timing logs (#8388)
Add a `log_load_timing` helper that checks elapsed time against a 5ms
threshold before logging. Sub-component loads faster than this round to
"0.00s" in the {:.2} format and are pure noise. The per-segment "total
loaded" line remains unconditional.

Made-with: Cursor

Co-authored-by: Cursor Agent <agent@cursor.com>
2026-03-13 12:47:19 +01:00
Andrey Vasnetsov
07cff7387f log cpu utilization (#8342)
* [AI] init implementaions of CPU usage reatio logging

* [AI] better function to access ratio

* fmt

* Update slow_requests_log.rs

* more logging
2026-03-13 08:44:13 +01:00
Roman Titov
a3786cfacc Improvements for IoUringFile (#8300)
* Improvements for `IoUringFile`

- handle read and write requests more explicitly
- assert against partial reads/writes

* Implement `read_multi`/`write_multi`

* Implement `populate` and `clear_ram_cache`

* Rename internal structures as `IoUringSomething`

* [ai] Make `UniversalRead`/`UniversalWrite` impl generic over `T`

* Handle `io_uring` initialization error

* Check that `io_uring` is initialized and supported, when opening `IoUringFile`

* fixup! Check that `io_uring` is initialized and supported, when opening `IoUringFile`

Fix typo

* test for reading u64 from file with uring

* fmt

* clippy

* fix(io_uring): allocate Vec<MaybeUninit<T>> for reads to fix alignment for T (#8353)

* fix(io_uring): allocate Vec<MaybeUninit<T>> for reads to fix alignment for T

Refactor IoUringState::read to take generic T and item_offset/items_length
instead of byte_offset/byte_length. Allocate Vec<MaybeUninit<T>> so the
kernel writes into correctly aligned memory, then convert to Vec<T> in
finalize. Fixes bytemuck::cast_vec alignment panic for types like u64.

Made-with: Cursor

* refactor(io_uring): only make read/write methods generic, not state or runtime

- IoUringState and IoUringRuntime no longer generic over T
- read<T>() allocates Vec<MaybeUninit<T>>, transmutes to Vec<MaybeUninit<u8>> for storage
- finalize returns ReadBuffer; callers use .into_vec::<T>() to get Vec<T>
- Write path unchanged (callers pass bytes via bytemuck::cast_slice)

Made-with: Cursor

* Cleanup

* review n1

* review n2

* fmt

---------

Co-authored-by: Cursor Agent <agent@cursor.com>
Co-authored-by: Roman Titov <ffuugoo@users.noreply.github.com>
Co-authored-by: Andrey Vasnetsov <andrey@vasnetsov.com>

* use AHash instead of just hash

* add ahash to deps

---------

Co-authored-by: Andrey Vasnetsov <andrey@vasnetsov.com>
Co-authored-by: qdrant-cloud-bot <111755117+qdrant-cloud-bot@users.noreply.github.com>
Co-authored-by: Cursor Agent <agent@cursor.com>
2026-03-12 22:40:59 +01:00
qdrant-cloud-bot
f90be3fc10 Add optional extended load timing logging for storage components (#8363)
* Add debug-level load timing logs for storage components

Add log::debug! calls with target "qdrant::load_timing" that report
how long each storage component takes to load during startup:

- Total shard load time (including WAL replay)
- Total segment load time + load_state
- Per-segment: payload_storage, id_tracker, payload_index
- Per-vector: vector_storage (dense/sparse), quantized_vectors,
  vector_index (dense/sparse)

These logs are at DEBUG level so they are silent by default. Enable
selectively via log_level config or env, for example:

  log_level: "INFO,qdrant::load_timing=debug"

No config fields, no global flags, no function signature changes.

Made-with: Cursor

* Use seconds with 10ms resolution for load timing logs, extract log target constant

Switch from `{:.2}ms` with `as_secs_f64() * 1000.0` to `{:.2}s` with
`as_secs_f64()` for cleaner output. Move the "qdrant::load_timing"
log target string to a LOAD_TIMING_LOG_TARGET constant in each file.

Made-with: Cursor

* Move LOAD_TIMING_LOG_TARGET to common::defaults

Single definition shared by segment and collection crates, avoiding
duplication of the log target string.

Made-with: Cursor

---------

Co-authored-by: Cursor Agent <agent@cursor.com>
2026-03-12 14:42:18 +01:00
Andrey Vasnetsov
64cc539f9b strictly read only mmap (#8350)
* [AI] Implement generic to make pure read-only universal io mmap version

* fmt

* [AI + manual nits] /simplify (#8351)

---------

Co-authored-by: Luis Cossío <luis.cossio@outlook.com>
2026-03-12 13:18:15 +01:00
Andrey Vasnetsov
317a8d3929 openning read-only mmap should not require creation and append mode (#8372) 2026-03-12 12:21:59 +01:00
Jojii
e7e5f4cc4f Filter deferred points: facets (#8313)
* Filter deferred: facets

* Add test (facet)

* Review remark

* Review remarks

* Fix unique_values returning values even if occurring only in deferred
points

* Clippy

* Rename Filter=>Exclude
2026-03-11 17:31:53 +01:00
Jojii
f91e2179d5 Disable deferred point filtering in resharding (#8310)
* Add ignore_deferred flag for internal scroll API

* Ignore deferred points in ProxyShard::update

* Use enum instead of bool as type in function parameters

* Use consistent parameter name

* fmt

* Apply suggestions from code review

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

* More explicit naming

* Add DeferredBehavior to `count()` and disable filtering in stream_records

* Don't filter `retrieve()` everywhere

* Use consistent filter behavior in read operations

* Add TODO for ignored parameter in remote_shard

* Rebase fixes

---------

Co-authored-by: timvisee <tim@visee.me>
Co-authored-by: Tim Visée <tim+github@visee.me>
2026-03-11 16:13:26 +01:00
Andrey Vasnetsov
b14e0be4ed 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-10 17:13:32 +01:00
qdrant-cloud-bot
d9702ef30f chore: remove unused dependencies reported by cargo-machete (#8347)
- gridstore: remove memmap2
- common: remove ahash
- edge: remove serde_json from dependencies
- examples (lib/edge/publish/examples): remove anyhow

Made-with: Cursor

Co-authored-by: Cursor Agent <agent@cursor.com>
2026-03-10 11:05:30 +01:00
Luis Cossío
c7eadf49de Refactor PointToValues to use UniversalRead (#8298)
* refactor PointToValues to use UniversalRead

It includes a significant change to `MmapValue` trait to be able to
handle Cow reads, instead of just references.

* fix str parsing

* fix incorrect path

* use fallible casting

* clippy

* No eager allocation

this also makes it so that borrowed strs can keep happening :heart-eyes:

* Lifetime cleanup

---------

Co-authored-by: Roman Titov <ffuugoo@users.noreply.github.com>
2026-03-06 16:11:13 -03:00
Roman Titov
d53c712c50 IoUringFile based on universal I/O interface (#8292) 2026-03-05 18:19:37 +01:00
Andrey Vasnetsov
7083e7f2b6 gridstore live reload (#8287)
* [manual] live reload functions for gridstore-read

* [AI] tests for life reload

* fmt

* Address CodeRabbit review (PR 8287)

- gridstore/mod: acquire pages read lock once in files() loop
- universal_io/mmap: use fs_err::exists() to propagate IO errors
- pages: fix live_reload last_page_id underflow when pages is empty

Made-with: Cursor

* review changes

* thx coderabbit

---------

Co-authored-by: Cursor Agent <agent@cursor.com>
Co-authored-by: Luis Cossío <luis.cossio@outlook.com>
2026-03-04 18:30:21 +01:00
Andrey Vasnetsov
77b296d579 storage-backend dependent file listing (#8286) 2026-03-04 14:18:58 +01:00
dependabot[bot]
dda856a4ec build(deps): bump tango-bench from 0.6.0 to 0.7.2 (#8272)
* build(deps): bump tango-bench from 0.6.0 to 0.7.2

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

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

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

* Fix benchmark compilation error

---------

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-03 14:50:50 +01:00
Andrey Vasnetsov
b6c1987038 MultiFile Universal UI in gridstore pages (#8256)
* [manual] implement Pages for read-only

* Simpler `ReadMulti`/`WriteMulti` interface (#8263)

* [manual] Dumbify `ReadMulti`/`WriteMulti` interface

* fixup! [manual] Dumbify `ReadMulti`/`WriteMulti` interface

🤷‍♀️

* fixup! [manual] Dumbify `ReadMulti`/`WriteMulti` interface

Remove `VecMultiUniversalIo`

* [manual] review fix + silplify json load option

* [AI] split read and write + revome *Multi traits

* [AI] implement write for pages

* [AI] integrate pages into gridstore

---------

Co-authored-by: Roman Titov <ffuugoo@users.noreply.github.com>
2026-03-03 14:50:44 +01:00
Andrey Vasnetsov
9b344197a5 feat(universal_io): MultiUniversalRead trait and VecMultiUniversalRead implementation (#8255)
* feat(universal_io): add MultiUniversalRead trait and VecMultiUniversalRead impl

- Add SourceId, MultiUniversalRead<T> trait with read_batch_multi, source_len,
  populate, clear_ram_cache (latter two with default no-op).
- Add UniversalIoError::InvalidSourceId for invalid source id in batch reads.
- Add VecMultiUniversalRead<T, S>: minimal implementation over Vec<S: UniversalRead<T>>
  with attach(source) -> SourceId for adding sources at runtime.
- Add test vec_multi_universal_read_batch_and_attach using MmapUniversal.
- Handle InvalidSourceId in segment OperationError From<UniversalIoError>.

Implements the interface and minimal mmap-based implementation from
docs/design/multi-file-universal-io-plan.md (multi-source universal I/O).

Made-with: Cursor

* refactor(universal_io): move multi-source interface to separate file, drop plan from PR

- Add universal_io/multi_universal_read.rs with SourceId, MultiUniversalRead,
  VecMultiUniversalRead and test; re-export from mod.rs.
- Remove docs/design/multi-file-universal-io-plan.md from the branch.

Made-with: Cursor

* refactor(universal_io): require populate/clear_ram_cache; add new, attach, len, is_empty to trait

- MultiUniversalRead: remove default impls for populate() and clear_ram_cache();
  they are now required.
- Add to trait: new(), len(), is_empty() (default), attach() (default Err).
- Introduce associated type Source for attach; add AttachUnsupported<T>
  placeholder for impls that do not support dynamic attach.
- VecMultiUniversalRead: type Source = S; implement all trait methods.
- Re-export AttachUnsupported from universal_io.

Made-with: Cursor

* refactor(universal_io): remove AttachUnsupported; require attach for all impls

- Drop AttachUnsupported placeholder type and its UniversalRead/Send impls.
- Make attach() a required method on MultiUniversalRead (no default).
- Doc: all implementations must support attaching sources dynamically.
- Remove AttachUnsupported from re-exports.

Made-with: Cursor

* refactor(universal_io): attach by path, new(options), split vec impls, add MultiUniversalWrite

MultiUniversalRead:
- Remove type Source; attach(path, options) opens by path and returns SourceId.
- new(options: OpenOptions) for creating an empty multi-source view.
- Move VecMultiUniversalRead to vec_multi_universal_read.rs.

MultiUniversalWrite (new):
- Trait: new(options), len(), is_empty(), attach(path, options),
  write_batch_multi((SourceId, offset, data)...), source_len, flusher(),
  populate(), clear_ram_cache().
- VecMultiUniversalWrite in vec_multi_universal_write.rs; flusher()
  runs all source flushers.

Re-export MultiUniversalWrite, VecMultiUniversalWrite from universal_io.

Made-with: Cursor

* universal_io: MultiUniversalWrite extends MultiUniversalRead

Make MultiUniversalWrite<T>: MultiUniversalRead<T> like UniversalWrite
extends UniversalRead. Remove duplicated methods (new, len, is_empty,
attach, source_len, populate, clear_ram_cache) from the write trait;
keep only write_batch_multi and flusher. VecMultiUniversalWrite now
impl MultiUniversalRead and MultiUniversalWrite separately.

Made-with: Cursor

* [manual] final fixes

---------

Co-authored-by: Cursor Agent <agent@cursor.com>
2026-03-02 18:19:56 +01:00
Andrey Vasnetsov
82c49df611 feat(universal_io): add read_whole and read_json_via for config files (#8251)
* feat(universal_io): add read_whole and read_json_via for config files

- Extend UniversalRead with read_whole() for single-access whole-file read
- Default impl uses len() + read(0..len()); MmapUniversal overrides with one slice
- Add UniversalIoError::SerdeJson for JSON deserialization errors
- Add read_json_via<S,T>(path, options) in common::universal_io
- Gridstore: use read_json_via for config in read_config_and_tracker
- Segment: use read_json_via in ChunkedVectors::load_config, handle NotFound
- Segment: extend From<UniversalIoError> for OperationError with SerdeJson variant

Made-with: Cursor

* feat(universal_io): add UniversalIoError::NotFound for file-not-found

- Add NotFound { path } variant so callers can match without io::ErrorKind
- MmapUniversal::open maps io::ErrorKind::NotFound to NotFound { path }
- ChunkedVectors::load_config matches NotFound => Ok(None)
- OperationError From<UniversalIoError> handles NotFound

Made-with: Cursor

* style: apply cargo fmt

Made-with: Cursor

* fix(common): satisfy clippy explicit_auto_deref in read_json_via

Use &bytes instead of &*bytes; auto-deref handles Cow

Made-with: Cursor

---------

Co-authored-by: Cursor Agent <agent@cursor.com>
2026-03-02 16:38:17 +01:00
Luis Cossío
5403ea68ab Chunked vectors with UniversalWrite storage (#8233)
* use CowMultiVector as return type from storages

* add advice to OpenOptions

* Implement ChunkedVectors with generic storage

* rename ChunkedVectors->VolatileChunkedVectors and ChunkedMmapVectors-> ChunkedVectors

* propagate everywhere

fix tests

* [auto] rename BytesRange -> ElementsRange

* [auto] rename BytesOffset -> ElementOffset

* coderabbit nits

---------

Co-authored-by: generall <andrey@vasnetsov.com>
2026-02-27 12:47:15 -03:00
Luis Cossío
21890d2738 use Cow<'_, [T]> as return type in dense vector storages (#8221)
* use `Cow<'_, [T]>` as return type in vector storages

* extract complex type

* clippy

* improve maybe_uninit_fill_from

* don't commit to graphlinks yet
2026-02-26 13:30:21 -03:00
Andrey Vasnetsov
03c0fa2cf7 Universal IO: gridstore pages (#8223)
* [manunal] Gridstore page use universal IO

* fmt

* Apply review feedback for universal IO gridstore pages (#8230)

* Apply review feedback from PR #8223

- Use `super::Result` import in mmap.rs instead of fully-qualified `crate::universal_io::Result`
- Restructure ValuePointer destructuring in get_value and delete_value to
  first match Some(pointer), then destructure separately

* Replace Either<E, GridstoreError> with E: From<GridstoreError> in Gridstore::iter

Use a trait bound instead of Either to combine callback and gridstore
errors, allowing `?` to work directly on GridstoreError. This simplifies
callers by removing Either matching and io::Error conversion workarounds.

---------

Co-authored-by: qdrant-claw <qdrant-claw@users.noreply.github.com>

---------

Co-authored-by: qdrant-claw <qdrant-claw@users.noreply.github.com>
2026-02-25 19:46:00 +01:00
dependabot[bot]
18a7587d4b 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-02-25 14:15:04 +01:00