100 Commits
Author SHA1 Message Date
Roman TitovandClaude Opus 5 f8512cbf94 Implement UpdateCollection for consensus state machine (#10403)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 12:45:59 +02:00
Roman TitovandClaude Opus 5 2e71304e6e Implement CreateCollection and DeleteCollection for consensus state machine (#10397)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 12:45:58 +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
Roman TitovandClaude Opus 5 ac21750550 Implement simple consensus operations on ConsensusStateMachine (#10280)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 12:42:26 +02:00
Roman Titov a0d98c7526 Implement ConsensusStateMachine prototype (#10220)
* Add `ConsensusStateMachine` type

* Add `AliasMapping::get` method

* Add `ConsensusStateMachine::apply` method stub

* Add `AliasMapping::iter` and `AliasMapping::insert` methods

* Make `vector_name_schema::add_vector_to_config` function public

* Add generic replay-safety property tests

* Add `Nop` test

* Fix clippy

Clippy is stupid af 🙄
2026-09-03 12:42:25 +02:00
Roman TitovandClaude Opus 4.8 5ba401aacb Fix Transfer::Restart (#9786)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-03 12:36:30 +02:00
Roman TitovandClaude Opus 4.8 14c6b5e0f1 Fix SetRepicaState(Dead)/Transfer::Abort/Resharding::Abort` (#9760)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-03 12:36:30 +02:00
Roman TitovandClaude Opus 5 adc24d8745 Make CreateShardKey idempotent (#10025)
[audit-K] Make create_shard_key crash-safe with a single commit point

create_shard_key persisted shard_key_mapping.json incrementally, one add_shard
per placement entry, so the operation was not atomic across a crash. The
re-apply gate state.shards_key_mapping.contains_key(&shard_key) becomes true
after the first loop iteration, so a crash mid-loop on a multi-shard placement
left the peer permanently holding a subset of the key's shards while every other
peer had all of them.

Write the mapping exactly once instead, after every shard of the key exists on
disk, so there is no partial state to observe. SaveOnDisk writes atomically,
load_shards derives the shard id list from the mapping alone (unreferenced
directories are invisible after restart), create_shard_dir wipes leftovers, and
max_shard_id reads only the mapping - so a replay allocates exactly the ids the
crashed attempt did, which are the ids every other peer allocated too. The
contains_key gate then holds as intended: it fires only for an operation that
already completed in full, or for a genuine duplicate.

ShardHolder::add_shards registers a batch and persists the mapping once, with
add_shard as a one-element wrapper; the mapping write moved ahead of the
in-memory updates, being the only fallible step. No caller changes behavior:
Collection::new and load_shards already hit the write_optional early return, and
start_resharding_unchecked still adds a single id. An empty placement is now
rejected rather than silently returning Ok without creating the key.

Covered by create_shard_key_test.rs: id allocation, replay before and after the
commit, duplicate rejection, and the empty placement guard.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 11:26:23 +02:00
Roman Titov f440446a0b Cleanup 2026-08-04 11:17:02 +02:00
Roman TitovandClaude Opus 4.8 9f5ac6213e [audit-M] Propagate the force-abort error in drop_shard_key
drop_shard_key force-aborted any resharding on the key being dropped, but
swallowed a failed abort_resharding with a log-only error and dropped the
shards anyway. That could leave resharding_state.json referencing the
just-dropped key — a latent inconsistent load-time state.

Propagate the error with `?`. A ServiceError halts consensus and retries after
restart, which is safe because the abort and everything else in drop_shard_key
is replay-tolerant; a user error dismisses the entry before any shard is
dropped, which is equally consistent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-04 11:17:02 +02:00
Roman TitovandClaude Opus 4.8 77f57ec171 [audit-F] Use bad_request instead of service_error in pre-write transfer validations
A ServiceError returned from apply halts consensus on every peer (the entry can
never be applied), deterministically stalling the whole cluster. The transfer
Start validations that report a missing source or destination shard are
reachable — e.g. a committed Start racing a resharding-abort or shard-key-drop
that removed the shard — and all run before any durable write, so dismissing
the entry with a user error is safe and correct.

Convert five such sites to CollectionError::bad_request:
- validate_transfer: source shard missing, and destination shard missing in
  both the resharding and filtered branches (helpers.rs);
- start_shard_transfer: the source and target get_shard lookups
  (shard_transfer.rs).

The genuine "single node deployment" service_errors in collection_meta_ops.rs
are left untouched — those are real misconfiguration guards.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-04 11:17:02 +02:00
Roman TitovandClaude Opus 4.8 109368b983 [audit-D] Make transfer Start validation replay-tolerant
Start's first durable write registers the transfer record; its last write sets
the destination replica state. On re-apply after a crash between the two,
check_transfer_conflicts found the operation's own half-applied transfer and
returned bad_request, which is dismissed and never retried — so the peer
permanently lacked the destination replica entry. Worse, a later Finish on
that peer then silently skips both the destination promotion and the source
removal, pinning a replica-set divergence.

Exclude the transfer's own key from the conflict scan so a replay falls through
and re-runs the (idempotent) start: register_start_shard_transfer is a
set-insert and the destination replica-state write is absolute, so re-running
reconciles the partial state instead of dismissing it. A genuinely conflicting
transfer (different key touching the same shard/peers) is still rejected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-04 11:17:02 +02:00
Roman TitovandClaude Opus 4.8 0474fe308d [audit-J] Stop swallowing config.save errors in resharding
start_resharding, finish_resharding and abort_resharding each saved the
updated collection config with a log-only `if let Err(err) = config.save(..)`
that swallowed the failure. A swallowed save let the operation report success
with a stale shard_number persisted on disk, arming a shard-dir/loader panic
(or a silently unloaded shard) at the next restart.

Propagate the error with `config.save(&self.path)?;` instead. The resulting IO
error is a ServiceError, so consensus halts and retries the entry after
restart. That is safe because in all three functions the config save is
value-idempotent (guarded by `shard_number != new_shard_number`) and every
step is replay-tolerant, so the retry converges.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-04 11:17:02 +02:00
Roman TitovandClaude Opus 4.8 1e5878af6e [audit-H] Persist decremented shard count before dropping shard in abort_resharding
In the up-direction of abort_resharding, ShardHolder::abort_resharding drops
the new shard's directory, but the config.params.shard_number update was
persisted only at the very end of the function — after the transfers abort.
A crash anywhere in that wide window left shard_number pointing at an
already-deleted shard directory, which makes the auto-sharding loader panic
on the missing dir at startup (crash loop), before the consensus replay that
would reconcile the state can run.

Move the shard-count update block to before the shard_holder.abort_resharding
call. The block keeps its value-idempotence guard, so replay converges. The
config write lock is taken while holding the shard_holder write guard, matching
the shard_holder -> config ordering already used in finish_resharding, and is
released before abort_resharding. The reverse crash window (dir still present
but count already decremented) is benign and reconciled by replay.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-04 11:17:02 +02:00
Roman TitovandClaude Opus 4.8 878337c7c2 [audit-H] Persist decremented shard count before dropping shard in finish_resharding
In the down-direction of finish_resharding, the config.params.shard_number
update was persisted *after* drop_and_remove_shard. A crash between the two
left shard_number pointing at an already-deleted shard directory, which makes
the auto-sharding loader panic on the missing dir at startup (crash loop) —
before the consensus replay that would reconcile the state can run.

Move the shard-count update block to before drop_and_remove_shard (still after
remove_shard_from_key_mapping). The block keeps its value-idempotence guard, so
replay converges. The reverse crash window (dir still present but count already
decremented) is benign and reconciled by replay.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-04 11:17:02 +02:00
Roman TitovandClaude Opus 4.8 cdaccae574 [audit-A] Filter from_state in the forward-update failure path
When Medium/Strong write-ordering forwards an update to the leader and it
fails with a transient error, the failure path proposed deactivating the
leader replica while passing its raw peer state as from_state. Unlike the
sibling deactivation site, this did not filter out transient/resharding
states, so a Resharding/ReshardingScaleDown leader could be proposed
Dead with from_state=Some(Resharding*).

On re-apply after a crash inside abort-resharding (which reverts the gated
replica to Active or removes it), the from_state gate no longer matches the
current state -> bad_input -> the entry is dismissed and never retried, so
the peer keeps Active while the rest of the cluster has Dead.

Filter the leader state with `.filter(|state| !state.is_partial_or_recovery())`,
matching the sibling site (PR #7849), so the proposal omits from_state for
transient/resharding states and converges on replay.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-04 11:17:02 +02:00
Roman Titov a7185cc934 Unify Borrowed and Owned read pipeline implementations (#9498) 2026-08-04 11:16:56 +02:00
Roman Titov d4b06b0ece Simplify IoUringRuntime implementation (#9512) 2026-08-04 11:16:55 +02:00
Roman Titov ce3ea64be8 Fix abort resharding live-lock (#7849) 2026-08-04 11:16:52 +02:00
Roman Titov de7bfc9daa Use batched reads in GridstoreView::iter (#9429) 2026-08-04 11:16:52 +02:00
Roman Titov f788c814c9 Add async_payload_storage feature flag (#9409) 2026-08-04 11:16:50 +02:00
Roman Titov 1bf1c47204 Yet another attempt to fix resharding abort logic 🙅‍♀️ (#9395)
* Simplify ownership and locking in `set_shard_replica_state`

Since #8830, replica sets are wrapped in `Arc`, so we don't *need* to
hold `shard_holder` read-lock during `set_shard_replica_state`

* Abort transfers *before* switching replica state to `Dead`

idempotency, am I right boys??
2026-08-04 11:16:50 +02:00
Roman Titov da823efbb9 Explicitly propagate fs into Gridstore (#9381) 2026-08-04 11:16:49 +02:00
Roman Titov e4e088fd1e Add io_uring based payload storage type (#9310) 2026-08-04 11:16:49 +02:00
Roman Titov 61660ef4a1 Use batched reads in vector and payload storage (#9113) 2026-08-04 11:16:47 +02:00
Roman Titov 592e2a948a Fix typo in chunked_vector_storage module name (#9195)
`chuCked_vector_storage -> chuNked_vector_storage`
2026-06-03 14:49:45 +02:00
Roman Titov 12489860e9 Bump mold version used in Dockerfile to 2.41.0 (#9176) 2026-06-03 14:47:41 +02:00
Roman Titov a6bf261bc4 Merge pull request #9034
* Add `iter_batch` method to `EncodedStorage` and `EncodedVectors`

* Remove `EncodedVectors::for_each_in_batch` method

* Add `for_each_in_multi_batch` and `score_vector_max_similarity` metho…

* Refactor `score_stored_batch` for quantized multi-vector scorers...

* Remove `QuantizedMultivectorStorage::score_multi`

* Implement `score_points_batch_mmap` and `score_points_batch_uring`...

* Implement runtime routing between mmap and io_uring batch scoring met…

* review: rename + comments
2026-06-03 14:47:01 +02:00
Roman Titov 9c0248cae3 Upgrade tonic to v0.14.6 (#9139) 2026-06-03 14:47:00 +02:00
Roman Titovandgenerall 1d910011b6 Refactor MultivectorsOffsetsStorageMmap to use UniversalRead (#9071)
* Empty commit to open a PR

* Refactor `MultivectorOffsetsStorageMmap` to use `MmapFile` instead of `MmapSlice`

* simpler result types

---------

Co-authored-by: generall <andrey@vasnetsov.com>
2026-05-22 10:44:09 +02:00
Roman Titov 045b1de45e Refactor quantized multi-vector scorers for io_uring support (#8988)
* Only read each vector once, when scoring quantized multi-vectors

* Simplify `QuantizedMultiQueryScorer`

Replace generic `TEncodedVectors` with concrete `QuantizedMultivectorStorage`

* Simplify `QuantizedMultiCustomQueryScorer`

Replace generic `TEncodedVectors` with concrete `QuantizedMultivectorStorage`

* Further simplify `QuantizedMultiCustomQueryScorer`

Remove `TElement` and `TMetric` type-parameters

* Add `iter_offsets` method to quantized multi-vector storage types

* Add `QuantizedMultivectorStorage::score_multi` method...

...which accepts `MultivectorOffset` instead of `PointOffsetType`

* Implement `QuantizedMultiQueryScorer::score_stored_batch`

* Implement `QuantizedMultiCustomQueryScorer::score_stored_batch`
2026-05-22 10:39:09 +02:00
Roman Titov 79f2b3bbcf Merge pull request #8791
* Add `EncodedStorage::for_each_in_batch` method

* Implement `for_each_in_batch` method for `QuantizedChunkedMmapStorage`

* Add `EncodedVectors::for_each_in_batch` method

* Add `EncodedVectors::score` method

* Implement `score_stored_batch` for `QuantizedQueryScorer` and `Quanti…

* Remove `TElement` and `TMetric` type parameters from `QuantizedMultiQ…

* Use `QuantizedMultiQueryScorer` when building `raw_internal_scorer`...
2026-05-08 13:48:31 +02:00
Roman Titov a4bbcdef1f io_uring pipelinemaxxing (#8897) 2026-05-08 13:48:26 +02:00
Roman Titov 7036240f13 UniversalRead cleanup (#8894)
* Cleanup lifetimes and generic type parameters

- Rename read pipeline lifetime from `'a` into `'file`
- Use explicit `where` clauses everywhere

* Cleanup

* fixup! Cleanup lifetimes and generic type parameters
2026-05-08 13:48:24 +02:00
Roman Titov 54424ce767 Simplify UniversalReadPipeline (#8850) 2026-05-08 13:48:23 +02:00
5c8f57f134 Refactor Sparse*QueryScorer for (future) io_uring support (#8759)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Luis Cossío <luis.cossio@outlook.com>
Co-authored-by: Andrey Vasnetsov <andrey@vasnetsov.com>
2026-05-08 13:47:32 +02:00
Roman Titov 252c46ceea Refactor Multi*QueryScorer for (future) io_uring support (#8702) 2026-05-08 13:47:17 +02:00
Roman Titovandgenerall 3fd242e922 Remove AsyncRawScorer (#8685)
* Merge `scorer_mmap` and `vector_search` benchmarks

* Move micro-batching logic from `RawScorerImpl::score_points` into `QueryScorer::score_stored_batch`

* Propagate micro-batching logic from dense scorers...

...into `ImmutableDenseVectors`/`ChunkedVectors`

* Implement io_uring-specialized `ImmutableDenseVectors::for_each_in_batch_async`

* Implement io_uring-specialized `ChunkedVectors::for_each_in_batch_async`

* Add `UniversalRead::type_id` method for runtime storage-type queries

* fixup! Implement io_uring-specialized `ImmutableDenseVectors::for_each_in_batch_async`

Enable io_uring-specialized scoring on Linux

* fixup! Implement io_uring-specialized `ChunkedVectors::for_each_in_batch_async`

Enable io_uring-specialized scoring on Linux

* Refactor `DenseVectorStorageImpl::read_vectors`...

...to use `ImmutableDenseVectors::for_each_in_batch` instead of `read_vectors_async`

* Remove `AsyncRawScorer`

* fixup! Propagate micro-batching logic from dense scorers...

Fix bugs

* fixup! Propagate micro-batching logic from dense scorers...

* fixup! Merge `scorer_mmap` and `vector_search` benchmarks

Fix clippy 🙄

* fixup! Add `UniversalRead::type_id` method for runtime storage-type queries

Change to `UniversalRead::kind` that returns `UniversalKind` enum

* fixup! Implement io_uring-specialized `ImmutableDenseVectors::for_each_in_batch_async`

Use `UniversalRead::kind` instead of `type_id`

* fixup! Implement io_uring-specialized `ChunkedVectors::for_each_in_batch_async`

Use `UniversalRead::kind` instead of `type_id`

* review: rename point_id -> point_offset to match the type [skip-ci]

---------

Co-authored-by: generall <andrey@vasnetsov.com>
2026-05-08 13:46:48 +02:00
Roman Titov 3f3fec7ad8 Bump cc to 1.2.60 (#8652) 2026-05-08 13:46:40 +02:00
Roman Titov 6ec87feffc 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-05-08 13:46:01 +02:00
Roman Titovandgenerall 6ee9230baa Better IoUringReadIter (#8586)
Co-authored-by: generall <andrey@vasnetsov.com>
2026-05-08 13:46:01 +02:00
Roman Titov 8fa89968ce Small optimization for MmapFile (#8511) 2026-03-26 18:52:06 +01:00
Roman Titov 926e42fd8e Replace MmapUniversal with MmapFile (#8505) 2026-03-26 18:50:12 +01:00
Roman Titov 26e7de22e6 Universal MmapFile that can read any T (#8493) 2026-03-26 18:49:41 +01:00
Roman Titov 6de3af2fcc Dense vector storage based on universal I/O IoUringFile (#8452) 2026-03-26 18:30:12 +01:00
Roman Titov 0c1d10031b Better IoUringFile errors (#8418) 2026-03-26 18:21:18 +01:00
72cf50ab4d 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-26 17:56:06 +01:00
Roman Titov 9781848d0f IoUringFile based on universal I/O interface (#8292) 2026-03-26 17:38:04 +01:00
Roman Titov de9b4d766a Universal I/O (#8183)
* WIP: `UniversalRead`/`UniversalWrite` traits

* fixup! WIP: `UniversalRead`/`UniversalWrite` traits

Relax `Sized` requirement on `UniversalRead`
2026-03-26 16:53:48 +01:00
Roman Titov f4b19411f4 Expose field index operations in qdrant-edge-py (#8187) 2026-03-26 16:53:43 +01:00
Roman Titov 05aded71c8 Use FsType::ExFat on non-Linux, so that Rust won't complain (#8186) 2026-03-26 16:52:29 +01:00
Roman Titov d96709a6db Fix too_many_internal_resets error (#8128)
Patch `tonic` and `hyper` crates to expose `max_local_error_reset_streams`,
and *disable* it when creating internal gRPC connections
2026-02-16 10:17:29 +01:00
Roman Titov bdd4bb5180 Ensure WAL and shard clocks consistency when creating shard snapshot (#8104) 2026-02-13 11:52:23 +01:00
Roman Titov 096f68fb68 Improve SnapshotManifest/SegmentManifest construction (#7961)
* Improve `SnapshotManifest`/`SegmentManifest` construction

* fixup! Improve `SnapshotManifest`/`SegmentManifest` construction

Fix stupidity 😬
2026-02-09 23:22:45 +01:00
Roman Titov 3b2cdd6b9b Always Copy-on-Write when updating payload in immutable segments (#7952) 2026-02-09 23:17:56 +01:00
Roman Titov da70bf13c6 Update qdrant-edge-py version to 0.4.0 (#7926)
* Update `qdrant-edge-py` version to 0.4.0

* fixup! Update `qdrant-edge-py` version to 0.4.0

🙄🙄🙄
2026-02-09 23:08:27 +01:00
Roman Titov 3184b53a32 Rename edge::Shard into edge::EdgeShard (#7925) 2026-02-09 23:08:22 +01:00
Roman Titov 1a15be85ef Flush edge::Shard on Drop (#7911)
And add explicit `flush` and `close` methods
2026-02-09 23:07:20 +01:00
Roman TitovandAndrey Vasnetsov 4c7ed0de44 Implement info request for Qdrant Edge (#7890)
* Implement `edge::Shard::info`

* Add `ReprStr` marker-trait

* Add Python bindings for payload index types

* Implement `PyShard::info`

* fixup! Add Python bindings for payload index types

Add `enable_hnsw` fields

* add __repr__ and exted tests

---------

Co-authored-by: Andrey Vasnetsov <andrey@vasnetsov.com>
2026-02-09 23:02:57 +01:00
Roman Titovandgenerall fd18177766 Implement scroll and count requests for Qdrant Edge (#7880)
* Cleanup `shard` crate module declarations

* Move `ScrollRequestInternal` into `shard` crate

* fixup! Move `ScrollRequestInternal` into `shard` crate

Fix imports

* fixup! Move `ScrollRequestInternal` into `shard` crate

`const fn default_*`

* Implement `edge::Shard::scroll`

* fixup! Implement `edge::Shard::scroll`

Re-export `OrderByInterface`

* Cleanup `edge` module declarations

* Cleanup `qdrant-edge-py` module declarations

* Move `PyWithPayload` and `PyWithVector` into `types::query`

* Add `PyScrollRequest` type

* Implement `PyShard::scroll`

* Move `CountRequestInternal` into `shard` crate

* fixup! Move `CountRequestInternal` into `shard` crate

Fix imports

* fixup! Move `CountRequestInternal` into `shard` crate

Rename `default_exact_count` into `CountRequestInternal::default_exact`

* Implement `edge::Shard::count`

* Implement `PyShard::count`

* review: offset for scroll, default values, examples

* ai review

---------

Co-authored-by: generall <andrey@vasnetsov.com>
2026-02-09 22:55:21 +01:00
Roman Titov 5846411fb3 Add explicit SharedShardHolder type instead of LockedShardHolder type-alias (#7837) 2026-02-09 22:32:50 +01:00
Roman Titov 7715a54f5d Cleanup Dockerfile (#7814) 2026-02-09 22:27:38 +01:00
Roman Titov df20fdbb74 Replace lazy_static with std::sync::LazyLock (#7808) 2026-02-09 22:25:33 +01:00
Roman Titov bc6e25969e Fix CI 😬 (#7796) 2025-12-18 17:29:17 +01:00
Roman Titov 51bed3387b Qdrant Edge Python release CI workflow (#7562) 2025-12-18 17:29:17 +01:00
Roman Titov 962070c686 Implement __repr__ for Qdrant Edge types (Part 3) (#7744) 2025-12-18 17:28:49 +01:00
Roman Titov d0d1c3ded4 Implement __repr__ for Qdrant Edge types (Part 2) (#7742)
* Implement `__repr__` for `PyJsonPath`

* Implement `__repr__` for `PyFilter`

* Implement `__repr__` for `PyQuery`

* Implement `__repr__` for `PyQueryRequest`

* Implement `__repr__` for `PySearchRequest`

* Implement `__repr__` for `PyFilter` using `pyclass_repr` attribute

* Implement `__repr__` for `PyQuery` using `pyclass_repr` attribute

* Implement `__repr__` for `PyQueryRequest` using `pyclass_repr` attribute

* Implement `__repr__` for `PySearchRequest` using `pyclass_repr` attribute
2025-12-18 17:28:22 +01:00
Roman Titovandgenerall 0e7727c2fe Implement __repr__ for Qdrant Edge types (#7695)
* Refactor `PyUpdateOperation` constructors

* Add default parameters to `PyVectorDataConfig::new`

* Add `Repr` trait and `WriteExt` helper

* Implement `__repr__` for config types

* fixup! Implement `__repr__` for config types

Use `Copy` instead of `Clone`

* fixup! Implement `__repr__` for config types

Add basic test

* Implement `__repr__` for `PyPointId`

* Implement `__repr__` for `PyVector`

* Implement `__repr__` for `PyVectorInternal`

* Implement `__repr__` for `PyPayload`

* Implement `__repr__` for `PyValue`

* Implement `__repr__` for `PyPoint`

* Implement `__repr__` for `PyPointVectors`

* Implement `__repr__` for `PyRecord`

* Move `PyScoredPoint` into a separate file

* Implement `__repr__` for `PyScoredPoint`

* Cleanup examples

* fixup! Implement `__repr__` for `PyScoredPoint`

* Move `PyOrderValue` into separate file

* Add `PyScoredPoint::order_value`

* Implement `pyclass_repr` proc-macro attribute

* Implement `__repr__` for config types using `pyclass_repr` attribute

* Implement `__repr__` for `PySparseVector` using `pyclass_repr` attribute

* Implement `__repr__` for `PyPoint` using `pyclass_repr` attribute

* Implement `__repr__` for `PyPointVectors` using `pyclass_repr` attribute

* Implement `__repr__` for `PyRecord` using `pyclass_repr` attribute

* Implement `__repr__` for `PyScoredPoint` using `pyclass_repr` attribute

* Minor fixes and cleanups

* fixup! Minor fixes and cleanups

* rollback copy for quantization config

* rollback copy for quantization config

---------

Co-authored-by: generall <andrey@vasnetsov.com>
2025-12-18 17:28:22 +01:00
Roman Titov e33b4672e5 Fix test_collection_recovery test (#7700) 2025-12-18 17:26:37 +01:00
Roman Titov 38f5ac2bae Qdrant Edge Python bindings improvements (Part 2) (#7639) 2025-12-18 17:26:07 +01:00
Roman Titov d2834de0b5 Mark *new* local replicas as locally-disabled, when recovering Raft snapshot (#7684)
* Remove faulty mark-as-dead condition when recovering Raft snapshot 😅

* Mark new local replicas as locally-disabled when recovering Raft snapshot

* Add test
2025-12-04 08:44:02 +01:00
Roman Titov 106731bdf5 Make snapshot_manifest methods async (#7629)
* Make `snapshot_manifest` methods `async`, so that they don't block async runtime

* Spawn `restore_shard_snapshot` task on `update` runtime instead of "current"
2025-12-03 10:20:12 +01:00
Roman Titov 1de85b956e Qdrant Edge Python bindings improvements (#7561)
* Use anonymous lifetime in `FromPyObject` implementations

* Use `PyResult` in `IntoPyObject` implementations

* Cleanup imports and derives

* Cleanup `filter` conversions

* Add `PointVectors` getters

* Move `config` module into sub-directory

* Split `config` into sub-modules

* Simplify enum bindings

* Add zero-cost conversions for `PyVectorDataConfig` and `PySparseVectorDataConfig`

* Add getters to config structures

* fixup! Add getters to config structures

More zero-cost conversions for `PyVector*DataConfig`

* Implement `PyHnswIndexConfig`

* Implement `PyQuantizationConfig`

* fixup! Simplify enum bindings

* fixup! Implement `PyHnswIndexConfig`

* fixup! Implement `PyHnswIndexConfig`

* fixup! Implement `PyHnswIndexConfig`

* Implement `PySparseVectorDataConfig`

* fixup! Implement `PySparseVectorDataConfig`

* fixup! Implement `PySparseVectorDataConfig`
2025-12-03 10:18:53 +01:00
Roman Titov 8da26c0ded Minor tweaks to WAL compaction logs (#7580) 2025-11-25 11:16:01 +01:00
Roman TitovandTim Visée 7bdab0cf00 Allow payload operations on dummy shard (#7521)
Co-authored-by: Tim Visée <tim+github@visee.me>
2025-11-14 12:31:08 +01:00
Roman Titov 32b7fdfb7f Restrict /logger API (#7527) 2025-11-14 12:31:08 +01:00
Roman Titov 9d2ab514eb Qdrant Edge CI (#7525) 2025-11-14 12:31:07 +01:00
Roman Titov f5fcd9096f Allow partial recovery of dummy shard (#7512) 2025-11-14 12:31:05 +01:00
Roman Titovandgenerall e175c138dc Cleanup edge_py::types::filter module (#7490)
Co-authored-by: generall <andrey@vasnetsov.com>
2025-11-14 12:31:05 +01:00
Roman Titov 5b5b5b8625 Implement PyQuery conversions (#7481)
* Rename `PyVectorType` into `PyNamedVector` 😠

* Move `PyQuery` into `types::query`

* Implement `PyQuery` conversions

* Use `bytemuck` to safely transmute between `edge-py` wrapper types (#7488)
2025-11-14 12:31:04 +01:00
Roman Titovandtimvisee 59b6c5db77 Fix clippy 🙄 (#7486)
Co-authored-by: timvisee <tim@visee.me>
2025-11-14 12:31:03 +01:00
Roman Titov 233c1a0ccd Improvements to Qdrant Edge Python bindings (#7473)
* Cleanup `examples/qdrant-edge.py`

* Cleanup `edge_py::types::vector` module

* Cleanup `edge_py::types::filter::condition` module

* Extend `PyWithPayload` type

* Use `from` instead of `into` for conversions

* Assert variants for enum conversions
2025-11-14 12:31:03 +01:00
Roman Titov f010382630 Implement edge_py::Shard::query (#7465) 2025-11-14 12:30:14 +01:00
Roman Titovandgenerall d977f8e2ce Implement edge::Shard::query (#7440)
Co-authored-by: generall <andrey@vasnetsov.com>
2025-11-14 12:30:12 +01:00
Roman Titov 058222c3d3 Cleanups for shard crate and related stuff (#7445) 2025-11-14 12:30:11 +01:00
Roman Titov 67814b39c5 Move mmr into shard crate (#7429) 2025-11-14 12:30:11 +01:00
Roman Titov 329b223326 Implement edge::Shard::query_scroll (#7426) 2025-11-14 12:29:35 +01:00
Roman Titov 6d5ed0a8f2 Move PlannedQuery and QueryScrollRequestInternal into shard crate (#7417) 2025-11-14 12:29:33 +01:00
Roman Titov c7c8c606bf Move ShardQueryRequest into shard crate (#7410) 2025-11-14 12:29:32 +01:00
Roman Titov af6f8b4826 Move FormulaInternal into shard crate (#7409) 2025-11-14 12:29:32 +01:00
Roman Titov 8ee2d6e61c More type conversion for Qdrant on Edge Python bindings (#7372)
* Cleanup `edge::Shard::retrieve`

* Cleanup Python errors

* Cleanup `PointId` conversions

* Rename `ids` into `point_ids` in `PyShard::retrieve`

* WIP: Prototype native conversions for more types
2025-11-14 12:28:14 +01:00
Roman TitovandAndrey Vasnetsov 144dc3811e Type conversions into native Python types for Qdrant on Edge (#7367)
* Cleanup README.md

* Rename `PyResult` into `Result`

* Rename `interface` module into `types` and simplify imports

`wildcard::goes::brrr::*`

* Add `PointId` conversion

* Add `Payload` conversion

* fixup! Add `Payload` conversion

Avoid cloning `Payload` for output conversion

* fixup! Add `PointId` conversion

Fix example

* review fixes #1: fix uuid parsing, avoid .into, use custom types

* review fixes #2: rewrite point id to avoid chain if

* review fixes #3: allow ot use uuid + remove comment

---------

Co-authored-by: Andrey Vasnetsov <andrey@vasnetsov.com>
2025-11-14 12:28:14 +01:00
Roman Titov 87289eb507 WIP: Extend Qdrant Edge Python bindings (#7343) 2025-11-14 12:27:28 +01:00
Roman Titovandgenerall 7977dbf9e7 Python bindings for Qdrant on Edge (#7312)
* Qdrant Edge Python binding 🐍⛓️‍💥

* fixup! Qdrant Edge Python binding 🐍⛓️‍💥

Fix example + cleanup

* review: move QueryEnum + mark search as deprecated

---------

Co-authored-by: generall <andrey@vasnetsov.com>
2025-11-14 12:27:28 +01:00
Roman Titov eee6719f20 Cleanup fs-err error messages in Edge (#7325) 2025-11-14 12:26:52 +01:00
Roman Titov 81834ec8a0 Qdrant on Edge prototype (#7170) 2025-11-14 12:26:52 +01:00
Roman Titov ad6a1ec220 Fix deadlock during streaming shard snapshot (#7241)
* Add `test_shard_snapshot_deadlock` integration test

* Fix deadlock during streaming shard snapshot
2025-09-29 11:29:22 +02:00
Roman Titov 4dd9d9bf4d Use Path instead of str in ConsensusWal::new (#7205) 2025-09-29 11:26:37 +02:00
Roman Titov e41a480c14 Move CoreSearchRequest and QueryEnum from collection into shard crate (#7169) 2025-09-29 11:25:30 +02:00