48 Commits

Author SHA1 Message Date
Arnaud Gourlay
0346ea66cd fix: unblock optimizer after deleting a named vector (#9641)
* fix: unblock optimizer after deleting a named vector

Deleting a named vector could permanently block the config-mismatch
optimizer. The source-superset check in SegmentBuilder::update cancelled
every rebuild that found the deleted vector still in old segment files,
and each retry cancelled again, so optimizations got stuck forever.

Removing the check (as in #9609) would fix delete but reintroduce data
loss for the CreateVectorName race. Instead, tell the two cases apart
with the live collection schema: prune a source vector that is gone from
the schema (a real deletion), but cancel when it is still present (a
freshly created vector this optimizer has not yet seen). This is safe
because the schema is persisted before the op reaches segments, and the
live schema is read after the source segments are frozen.

The live set covers dense and sparse vectors, since a segment stores both
together. When no live source is wired in, the conservative always-cancel
behavior is kept.

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

* fix: wire live vector names into edge optimizers

Deleting a named vector left the edge path with the pre-fix behavior:
segment_optimizer_config hardcoded live_vector_names to None, so a merge
touching a segment that still carried the deleted vector cancelled, and
EdgeShard::optimize() propagated the cancellation as a hard error forever.

Share the shard config behind an Arc and hand the blocking optimizers a
provider that reads the current vector names on every call. Same safety
argument as the server wiring: update() holds the segments read guard
across both the segment application and the config update, so any name a
frozen source segment carries is visible to the live read.

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

* refactor: share vector-name enumeration via CollectionParams::vector_names

The optimizer's live-schema set and the WAL-recovery valid-name set are
the same dense+sparse enumeration and must stay in lockstep; a drift
between them would reintroduce a wrong prune/cancel decision. Replace
the private helper in optimizers_builder and the inline block in WAL
recovery with a single CollectionParams method.

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

* refactor: drop SegmentOptimizer::live_vector_names forwarding hop

The default trait method only forwarded to the config getter and had a
single caller; ShardOptimizationStrategy now reads the config directly,
removing one layer of indirection.

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

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 12:41:26 +02:00
Andrey Vasnetsov
852ca200b5 feat: feature-flagged segment manifest for LocalShard (#9530)
* feat: feature-flagged segment manifest for LocalShard

Add an on-disk segment manifest (`segments/manifest.json`) that lists a
shard's segments and their state, so out-of-process readers (e.g. a
read-only follower, possibly over object storage) can discover segments
without scanning the filesystem. Gated by the new `write_segment_manifest`
feature flag (off by default).

shard: define the structure + helpers (`SegmentsManifest`,
`SegmentManifestState`, `from_segment_holder`) in a new `segment_manifest`
module, plus the `SEGMENT_MANIFEST_FILE` constant and path helper. The
manifest is a flat `{ "<uuid>": "<state>" }` map; only `active` is written
today, with `under_construction`/`retiring` defined so the format can be
extended without breaking compatibility.

collection: LocalShard owns the writing logic. The manifest is persisted
via `SaveOnDisk<SegmentsManifest>`, initialized from the live segment set
on load/build and refreshed by the optimization worker whenever the
segment set changes (the helper re-derives from the holder and no-ops when
unchanged). No changes to `lib/shard/src/optimize.rs` internals.

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

* feat: make append_only_mutations a proper feature flag

Replace the debug-only `QDRANT_APPEND_ONLY_MUTATIONS=1` env-var escape
hatch in segment construction with a `FeatureFlags::append_only_mutations`
flag, so it works in release builds and is configurable like the other
flags (config / `QDRANT__FEATURE_FLAGS__APPEND_ONLY_MUTATIONS`).

Deliberately left out of `FeatureFlags::all()`: it changes mutation
semantics and `all` is enabled in dev and e2e configs, so it stays
explicit opt-in.

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

* upd openapi schema

* feat: register segments in manifest via must-use token, holder builder

Wire segment-manifest maintenance through the segment lifecycle so a
newly created segment is registered as soon as it exists on disk, and
construction can't silently skip it:

- build_segment now returns a #[must_use] NewSegmentToken carrying the
  new segment UUID; the lint forces callers to register or drop it.
- SegmentHolder owns the manifest and reconciles it on sync; new
  segments are registered ASAP (even before being added to the holder)
  via the token, before they can receive writes.
- SegmentHolderBuilder is the only way to obtain a shard's holder; its
  build() wires up the manifest, so it can't be forgotten. init/set
  manifest helpers are now private / test-only.
- Optimization registers the optimized segment before dropping the
  superseded segments' data; deletion is intentionally lenient.
- Document the consistency assumptions on SegmentsManifest: it is a
  superset-biased view that may list not-yet-finalized or already-deleted
  segments, which readers must tolerate.

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-22 12:51:57 +02:00
Arnaud Gourlay
386e222b42 fix: reject source-superset schema mismatch at SegmentBuilder (#9110)
* fix: serialize optimization proxy install against shard updates

execute_optimization captures `target_config` from the optimizer's frozen
config and then wraps source segments in proxies. Between those two points,
`CollectionUpdater::update` can apply a `CreateVectorName(V)` to the source
segments via `apply_segments`, leaving the optimizer with sources that have
V but a target_config that does not. The optimization then produces a
merged segment without V, and a follow-up optimization (running with the
refreshed config that includes V) fails to use that segment as a source:
"Cannot update from other segment because it is missing vector name X".

Close the race by extending the scope of the existing
`LockedSegmentHolder::acquire_updates_lock` to cover the proxy install
window. `CollectionUpdater::update` already takes this lock before
processing any shard update, so concurrent writers wait until proxies are
in place — at which point further mutations hit the proxies (recorded as
intent and propagated to the merged segment in `finish_optimization`)
instead of the originals. The guard is dropped right after proxy install so
the slow build phase does not extend it.

Tests:
- Three `SegmentBuilder::update` tests document the precondition the lock
  now guarantees: with a target schema that adds a named vector the source
  lacks, update errors with "missing vector name X". Quantized and
  mixed-source variants exercise the same error path.
- `test_optimize_blocks_proxy_install_on_updates_lock` asserts the
  invariant directly: while the updates lock is held, proxies are not yet
  installed. Verified to fail when the new guard is removed (otherwise it
  passes because `finish_optimization` also takes the same lock, so a
  naive "did optimize finish?" check would not catch a missing proxy-install
  guard).

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

* fix(optimize): finish_optimization lock order; drop redundant tests

Address review of #9110:

1. `finish_optimization` was acquiring `upgradable_read` before
   `acquire_updates_lock`, while the new guard at the start of
   `execute_optimization` acquires them in the reverse order. With two
   optimizer threads in flight, thread A in `finish_optimization` could
   hold `upgradable_read` and wait on `updates_lock` while thread B at the
   top of `execute_optimization` held `updates_lock` and waited on
   `upgradable_read` (parking_lot allows only one upgradable reader),
   deadlocking. Swap `finish_optimization` to take `updates_lock` first so
   both halves agree.

2. Drop the quantized and mixed-source variants of the inverted
   `SegmentBuilder` unit test — all three asserted the same error path
   (the mismatch check fires before quantization training or per-source
   branching), so only one is useful as documentation of the precondition.

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

* fix: reject source-superset schema mismatch at SegmentBuilder

Drop the lock approach (deadlocked test_continuous_snapshot) and fix the bug
at the merge layer instead.

Snapshot's proxy_all_segments_and_apply acquires the segment_holder
upgradable_read first and then takes acquire_updates_lock tactically inside
the snapshot operation. The previous commits' lock-extension acquired
updates_lock before upgradable_read, so a snapshot in flight and an
optimization just entering execute_optimization could deadlock holding each
other's required next lock. Snapshot cannot easily reverse its order — that
would hold updates_lock for the entire snapshot duration, blocking all
writes.

Move the fix to where the actual harm happens: SegmentBuilder::update
iterates the target's vector_data and silently drops source vectors that
aren't in target. That silent drop is what produces the broken merged
segment in the CreateVectorName-vs-optimizer race. Add a check that every
source vector name is in the target schema; the optimization aborts cleanly
on mismatch and the next round (with refreshed config) merges correctly.

This is strictly stronger than the lock: the lock only closed the window
where V arrived *during* the proxy-install region. The schema check catches
both that window and the window where V's apply_segments completed before
the optimizer's lock acquisition.

Diff is contained to lib/segment; no locking changes, no cross-crate
plumbing. test_continuous_snapshot passes again.

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

* fix(segment_builder): use Cancelled instead of ServiceError for schema mismatch

ServiceError flips the shard to RED status (via `report_optimizer_error` →
`segments.optimizer_errors`) and stays sticky until the next
`recreate_optimizers_blocking` clears it. That's the right shape for
hardware/IO failures but wrong for the schema-mismatch case here, which is
an expected, recoverable race outcome — the next optimizer round with a
refreshed target_config merges the same originals cleanly.

`Cancelled` is the variant the optimization worker treats as a recoverable
cancellation: logged at debug, tracker marked Cancelled, no
`report_optimizer_error` call, no RED status.

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

* fix(segment_builder): also use Cancelled for the existing target-superset error

The existing "missing vector name" check at the start of the merge loop
also fires during a race — specifically the optimizer-vs-DeleteVectorName
shape, where V is removed from originals before J wraps proxies but J's
frozen target_config still has V. Like the new source-superset check, this
is an expected, recoverable race outcome, so use Cancelled instead of
ServiceError to avoid flipping the shard to RED.

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 17:25:15 +02:00
Andrey Vasnetsov
c1597ac57e Split IdTracker trait into IdTrackerRead and IdTracker (#8826)
Read-only methods now live on a separate IdTrackerRead trait, with the
mutating IdTracker trait extending it. This lets read-only call sites
depend only on the read API.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 09:20:45 +02:00
Andrey Vasnetsov
f5474ef248 Propagate HardwareCounterCell through MmapMapIndex::get_values (#8574)
* 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>
2026-04-01 10:26:20 +02:00
Ivan Boldyrev
2a0b95b08d Further split segment traits (#8434)
* Refactor: `SearchSegmentEntry` for search ops

* Move `has_deferrend_points_method`

to `SearchSegmentEntry`

* Reorg imports

* Renamings per review

* fixup! Renamings per review

* `StorageSegmentEntry` trait

It contains methods dealing with storage and syncronization

* Move index methods from `ReadSegmentEntry`

to `SegmentEntry`

* Add `_concurrent` suffix to some methods

* move field index methods into NonAppendableSegmentEntry

---------

Co-authored-by: generall <andrey@vasnetsov.com>
2026-03-24 10:02:53 +01:00
Ivan Boldyrev
9146dc4bfe Explicit point_mappings guard (#8261)
Instead of `IdTracker` to have `iter_*` methods, it now has a `point_mappings()` method, returning a guard to `PointMapping` value.  It prepares for moving the point_mappings under a lock to allow parallel searches and deletions.

Also, an incorrect unsafe in `Segment::iter_points` is replaced by a safe version with `self_cell`.
2026-03-20 03:07:21 +07:00
qdrant-cloud-bot
7e15d343c2 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-10 00:10:04 +01:00
Ivan Pleshkov
30cf43382b Deferred threshold integration (#8246)
* Deferred threshold integration

* update deferred id

* apply update_deferred_internal_id

* fix segment inspector

* use avaliable bytes count

* renamings

* review remarks

* review remarks

* move has_deferred_points

* remove todo

* update comments
2026-03-02 09:57:19 +01:00
krapcys1-maker
3ddf6234e1 test(segment): stabilize building cancellation timing assertions (#8243)
Co-authored-by: local-user <local-user@local>
2026-02-27 13:08:35 +01:00
Ivan Boldyrev
9bf8369a6a Use IdTrackerEnum type instead of dyn IdTracker (#8168)
* Use `IdTrackerEnum` type instead of `dyn IdTracker`

It would allow to be more flexible on the IdTracker trait, making it
dyn-incompatible eventually.

Coauthored with Claude Code.

* Review fixes
2026-02-24 10:53:23 +01:00
Ivan Boldyrev
56799122b0 Split SegmentEntry into appendable and non-appendable part (#8047)
* Split `SegmentEntry`

Add `ImmutableSegmentEntry` for operations that can be applied to
immutable segments, and make the `SegmentEntry` as it subtrait.

* Rename to `NonAppendableSegmentEntry`

It differs semantically from `ImmutableSegmentEntry` by allowing point
deletion.  Move point deletion to the trait too.

* Fix docstring

* use NonAppendableSegmentEntry where possible

---------

Co-authored-by: Andrey Vasnetsov <andrey@vasnetsov.com>
2026-02-05 15:46:58 +01:00
xzfc
92b8913084 Enforce segment UUIDs (#7958)
* Swap docstrings for segment_ids/segment_uuids

Terse internal docs, detailed user-facing docs, not vice versa.

* Enforce segment UUIDs

* Export upcoming segment UUID to telemetry

* Add `optimize_for_test` wrapper

* Tune log message

Reason: the UUID is now guaranteed.

* Improve argument naming/docs
2026-01-21 15:43:32 +00:00
xzfc
77c71712db Indexing progress (#7625)
* Add progress_tracker.rs

* Pass progress tracker around

* Populate progress tracker with actual data

* Expose progress on `/collections/{name}/optimizations` endpoint
2025-12-09 00:15:36 +00:00
xzfc
a0d62330c7 Use fs-err (#7319) 2025-09-29 12:47:10 +00:00
Arnaud Gourlay
a7ee4ceb51 Fix hardware counter vector_io for segment vector retrieval (#6863) 2025-07-15 11:30:22 +02:00
xzfc
706571d8b4 Configurable HNSW healing threshold (#6756) 2025-06-25 10:22:18 +00:00
Tim Visée
f90b9d6d65 Fix tests after removing RocksDB feature flag (#6649)
* Use sparse vector storage fixture without RocksDB

* Fix some tests

* Replace RocksDB sparse storage with Gristore in mutable text index tests

* Use in-memory vector storage in multivector HNSW test

* Flag many more RocksDB specifics in tests

* Use database placeholder type without RocksDB flag

* Flag more tests

* Flag even more tests

* Fix imports, fix typo, and repair base test build

* Initialize dummy database if RocksDB flag is disabled

* Assert correct storage types

* Don't use old vector storage type when RocksDB is disabled

* Expos default for vector storage type only in tests

* Only expose simple segment constructor in tests

* Don't derive Default

* Fix inverted appendable flag
2025-06-11 15:04:27 +02:00
Luis Cossío
93dea164e8 Deterministic HNSW builder (#6477)
* pass a RNG to hnsw index building

* use single-threaded build for accuracy-measuring tests

* clippy
2025-05-07 11:20:19 -04:00
Andrey Vasnetsov
2a7c931aee careful index creation (#6403)
* make sure to delete existing index, if it is not compatible with a new one

* fmt

* fix tests

* review fixes
2025-04-23 15:36:31 +02:00
Jojii
ae64690c7a Measure Payload Index IO Writes (#6137)
* Prepare measurement of index creation + Remove vector deletion
measurement

* add hw_counter to add_point functions

* Adjust add_point(..) function signatures

* Add new measurement type: payload index IO write

* Measure payload index IO writes

* Some Hw measurement performance improvements

* Review remarks

* Fix measurements in distributed setups

* review fixes

---------

Co-authored-by: generall <andrey@vasnetsov.com>
2025-03-24 19:39:17 +01:00
Tim Visée
3e536347e1 Bump Rust edition to 2024 (#6042)
* Bump Rust edition to 2024

* gen is a reserved keyword now

* Remove ref mut on references

* Mark extern C as unsafe

* Wrap unsafe function bodies in unsafe block

* Geo hash implements Copy, don't reference but pass by value instead

* Replace secluded self import with parent

* Update execute_cluster_read_operation with new match semantics

* Fix lifetime issue

* Replace map_or with is_none_or

* set_var is unsafe now

* Reformat
2025-02-25 11:21:25 +01:00
Andrey Vasnetsov
f7d0814ab6 IO resource usage permit (#6015)
* rename cpu_budget -> resource_budget

* clippy

* add io budget to resources

* fmt

* move budget structures into a separate file

* add extend permit function

* dont extend existing permit

* switch from IO to CPU permit

* do not release resource before aquiring an extension

* fmt

* Review remarks

* Improve resource permit number assertion

* Make resource permit replace_with only acquire extra needed permits

* Remove obsolete drop implementation

* allocate IO budget same as CPU

* review fixes

---------

Co-authored-by: timvisee <tim@visee.me>
2025-02-20 09:05:00 +01:00
xzfc
d90a68137b Add VectorName type alias (#5763)
* Add VectorName/VectorNameBuf type aliases [1/2]

* Add VectorName/VectorNameBuf type aliases [2/2]
2025-01-24 01:29:01 +00:00
Jojii
fd4705c29d Measure payload read IO (#5773)
* Measure read io for payload storage

* Add Hardware Counter to update functions

* Fix tests and benches

* Rename (some) *_measured functions back to original
2025-01-16 14:25:55 +01:00
Tim Visée
8d2b3c6ba2 Add unit test for segment builder bug mixing internal point IDs (#5614)
* Add unit test for segment builder bug mixing internal point IDs

* Link to PR
2024-12-10 09:33:36 +01:00
Arnaud Gourlay
9dcd3dd406 Fix path to new payload storage for optimized segments (#5530)
* Fix path to storage for optimized segment

* add minimal test

* clippy
2024-11-27 16:59:46 +01:00
xzfc
7bbb7eed36 Integration tests for on-disk payload indices (#4819)
* refactor: let SegmentBuilder::update take unlocked segments

* style: split long lines

* refactor: introduce TestSegments

* test: add tests for mmap indices
2024-08-03 22:00:03 +02:00
Jojii
7432ece2f9 remove testing non-defragmented segments for non-defragmentation (#4734) 2024-07-23 10:47:13 +02:00
xzfc
a0ea3caccf Enable some of the pedantic clippy lints (#4715)
* Use workspace lints

* Enable lint: manual_let_else

* Enable lint: enum_glob_use

* Enable lint: filter_map_next

* Enable lint: ref_as_ptr

* Enable lint: ref_option_ref

* Enable lint: manual_is_variant_and

* Enable lint: flat_map_option

* Enable lint: inefficient_to_string

* Enable lint: implicit_clone

* Enable lint: inconsistent_struct_constructor

* Enable lint: unnecessary_wraps

* Enable lint: needless_continue

* Enable lint: unused_self

* Enable lint: from_iter_instead_of_collect

* Enable lint: uninlined_format_args

* Enable lint: doc_link_with_quotes

* Enable lint: needless_raw_string_hashes

* Enable lint: used_underscore_binding

* Enable lint: ptr_as_ptr

* Enable lint: explicit_into_iter_loop

* Enable lint: cast_lossless
2024-07-22 08:19:19 +00:00
Jojii
68373fb600 Basic defragmentation (#4610)
* sorting

* migrate tests and move logic into SegmentBuilder

* add test and improve implementation

* improve code

* review

* code review improvements

* add index building to test

* Do not clone ranges

* Resolve clippy warnings due to recent PR on dev

* review suggestions

* Defragmentation in api (#4684)

* add tenant config to api

* deduplicate used defragmentation keys

* rename is_tenant to is_primary

* use all values to defrag key

* rename is_primary -> is_tenant

* update schema

---------

Co-authored-by: generall <andrey@vasnetsov.com>
Co-authored-by: timvisee <tim@visee.me>
2024-07-18 11:43:56 +02:00
Andrey Vasnetsov
d4807dcc8b Api consistency update (#4533)
* rename search_params -> params

* rename multivector_config + generate schema

* upd tests
2024-06-23 23:56:42 +02:00
Ivan Pleshkov
3ed43b50e8 fix building cancellation flaky test (#4477) 2024-06-18 10:14:36 +02:00
Ivan Pleshkov
61cfb8bcb5 Test fix segment builder for sparse (#4397)
* test fix segment builder for sparse

* are you happy fmt
2024-06-05 13:52:08 +02:00
Arnaud Gourlay
571143ae87 Simplify MaxSim configuration (#4171)
* Simplify MaxSim configuration

* enable extension of multivectorconfig

* rename multi_vec_config to multivec_config
2024-05-06 14:19:42 +02:00
Ivan Pleshkov
224e4f600a Byte storage integration into segment (#4049)
* byte storage with quantization

raw scorer integration

config and test

are you happy fmt

fn renamings

cow refactor

use quantization branch

quantization update

* are you happy clippy

* don't use distance in quantized scorers

* fix build

* add fn quantization_preprocess

* apply preprocessing for only cosine float metric

* fix sparse vectors tests

* update openapi

* more complicated integration test

* update openapi comment

* mmap byte storages support

* fix async test

* move .unwrap closer to the actual check of the vector presence

* fmt

* remove distance similarity function

* avoid copying data while working with cow

---------

Co-authored-by: generall <andrey@vasnetsov.com>
2024-04-18 00:42:17 +02:00
Arnaud Gourlay
b49000858a Multivec knob for SegmentConfig (#3963)
* Multivec knob for SegmentConfig

* regen openapi

* add TODO for next step

* introduce multivecconfig to support more similarity aggregation

* update openapi
2024-04-04 16:38:09 +02:00
Tim Visée
0301e39943 Dynamic CPU saturation internals (#3364)
* Move CPU count function to common, fix wrong CPU count in visited list

* Change default number of rayon threads to 8

* Use CPU budget and CPU permits for optimizer tasks to limit utilization

* Respect configured thread limits, use new sane defaults in config

* Fix spelling issues

* Fix test compilation error

* Improve breaking if there is no CPU budget

* Block optimizations until CPU budget, fix potentially getting stuck

Our optimization worker now blocks until CPU budget is available to
perform the task.

Fix potential issue where optimization worker could get stuck. This
would happen if no optimization task is started because there's no
available CPU budget. This ensures the worker is woken up again to
retry.

* Utilize n-1 CPUs with optimization tasks

* Better handle situations where CPU budget is drained

* Dynamically scale rayon CPU count based on CPU size

* Fix incorrect default for max_indexing_threads conversion

* Respect max_indexing_threads for collection

* Make max_indexing_threads optional, use none to set no limit

* Update property documentation and comments

* Property max_optimization_threads is per shard, not per collection

* If we reached shard optimization limit, skip further checks

* Add remaining TODOs

* Fix spelling mistake

* Align gRPC comment blocks

* Fix compilation errors since last rebase

* Make tests aware of CPU budget

* Use new CPU budget calculation function everywhere

* Make CPU budget configurable in settings, move static budget to common

* Do not use static CPU budget, instance it and pass it through

* Update CPU budget description

* Move heuristic into defaults

* Fix spelling issues

* Move cpu_budget property to a better place

* Move some things around

* Minor review improvements

* Use range match statement for CPU count heuristics

* Systems with 1 or 2 CPUs do not keep cores unallocated by default

* Fix compilation errors since last rebase

* Update lib/segment/src/types.rs

Co-authored-by: Luis Cossío <luis.cossio@qdrant.com>

* Update lib/storage/src/content_manager/toc/transfer.rs

Co-authored-by: Luis Cossío <luis.cossio@qdrant.com>

* Rename cpu_budget to optimizer_cpu_budget

* Update OpenAPI specification

* Require at least half of the desired CPUs for optimizers

This prevents running optimizations with just one CPU, which could be
very slow.

* Don't use wildcard in CPU heuristic match statements

* Rename cpu_budget setting to optimizer_cpu_budget

* Update CPU budget comments

* Spell acquire correctly

* Change if-else into match

Co-authored-by: Luis Cossío <luis.cossio@qdrant.com>

* Rename max_rayon_threads to num_rayon_threads, add explanation

* Explain limit in update handler

* Remove numbers for automatic selection of indexing threads

* Inline max_workers variable

* Remove CPU budget from ShardTransferConsensus trait, it is in collection

* small allow(dead_code) => cfg(test)

* Remove now obsolete lazy_static

* Fix incorrect CPU calculation in CPU saturation test

* Make waiting for CPU budget async, don't block current thread

* Prevent deadlock on optimizer signal channel

Do not block the optimization worker task anymore to wait for CPU budget
to be available. That prevents our optimizer signal channel from being
drained, blocking incoming updates because the cannot send another
optimizer signal. Now, prevent blocking this task all together and
retrigger the optimizers separately when CPU budget is available again.

* Fix incorrect CPU calculation in optimization cancel test

* Rename CPU budget wait function to notify

* Detach API changes from CPU saturation internals

This allows us to merge into a patch version of Qdrant. We can
reintroduce the API changes in the upcoming minor release to make all of
it fully functional.

---------

Co-authored-by: Luis Cossío <luis.cossio@qdrant.com>
Co-authored-by: Luis Cossío <luis.cossio@outlook.com>
2024-01-31 11:56:34 +01:00
Ivan Pleshkov
336efea59e Sparse index segment and collection config (#2802)
* quantization storage as separate entity

sparse index try to extend segment types

fix build

fix async scorer

codespell

update openapi

update vector index

remove code duplications

more fixes

more fixes

fix build

fix deserialization test

remove transform_into

are you happy clippy

update openapi

update openapi

are you happy clippy

fix build

optional serialize

more defaults

update openapi

fix comments

generic transpose_map_into_named_vector

rename fields in tests

remove obsolete parts

only named sparse config

VectorStruct without unnamed sparse

NamedVectorStruct without unnamed sparse

remove obsolete test

update openapi

mmap index

revert preprocess function

are you happy fmt

update openapi

fix build

fix tests

are you happy fmt

fix for client generation

fix sparse segment creation

fix basic sparse test

fix conflicts

remove obsolete convertion

fix build

config diffs

update openapi

review remarks

update openapi

fix batch upsert

add failing test showing bad ids matching

fix sparse vector insertion

remove on_disk flag

update openapi

revert debug assert

simplify conversions

update openapi

remove on disk storage flag

update openapi

default for vector config

update openapi comment

remove diffs

update openapi

* enable consensus test

* add comment

* update openapi
2023-12-01 13:10:58 +01:00
Arnaud Gourlay
2e4729a1f3 Promote operation error to dedicated file (#2736) 2023-09-29 16:23:24 +02:00
Luis Cossío
4e24ce2219 Increase acceptable stopping delay, better debug info in test_building_cancellation (#2713) 2023-09-22 09:42:28 -03:00
Tim Visée
b62ab26f1f Fix test_building_cancellation flakiness with different delays (#2697)
* Reduce flakiness of `test_building_cancellation` with 5k base segment

* use fixed acceptable stopping delay, and relative cancelling delay

* Remove debug statement

---------

Co-authored-by: Luis Cossío <luis.cossio@outlook.com>
2023-09-20 10:56:33 +02:00
Tim Visée
9b848e5929 Reduce flakiness of test_building_cancellation with larger base seg… (#2682)
* Reduce flakiness of `test_building_cancellation` with larger base segment

* Change number of points to 2k, increase timeouts a bit
2023-09-18 14:31:57 -03:00
Luis Cossío
562b3aa070 fix clippy errors on segment_builder_test.rs (#2606) 2023-09-06 12:32:10 -03:00
Luis Cossío
3558c71285 fix test_building_cancellation (#2094) 2023-09-06 11:34:01 -03:00
Ivan Pleshkov
12423f910d Add missed vector preprocess (#2203)
* test missed preprocess after segment update

* missed preprocess

* remove preprocess_named_vectors fn

* are you happy clippy

* fix integration tests

---------

Co-authored-by: generall <andrey@vasnetsov.com>
2023-07-05 00:30:15 +02:00
Arnaud Gourlay
5bb721e1fb Add debug info for flaky test Windows (#2039) 2023-06-09 13:45:50 +02:00
Arnaud Gourlay
fcf55b8943 merge integration binaries (segment) (#2033) 2023-06-07 08:46:49 +02:00