qdrant_edge/edge/edge_shard/
update.rs1use std::fmt;
2
3use crate::common::counter::hardware_counter::HardwareCounterCell;
4use crate::segment::common::operation_error::{OperationError, OperationResult};
5use crate::shard::operations::vector_name_ops::VectorNameConfig;
6use crate::shard::operations::{CollectionUpdateOperations, VectorNameOperations};
7use crate::shard::update::*;
8use crate::shard::wal::WalRawRecord;
9
10use crate::edge::EdgeShard;
11use crate::edge::config::vectors::{EdgeSparseVectorParams, EdgeVectorParams};
12
13impl EdgeShard {
14 pub fn update(&self, operation: CollectionUpdateOperations) -> OperationResult<()> {
15 if let CollectionUpdateOperations::VectorNameOperation(
21 VectorNameOperations::CreateVectorName(create),
22 ) = &operation
23 {
24 self.check_vector_name_create_compatible(&create.vector_name, &create.config)?;
25 }
26
27 let record = WalRawRecord::new(&operation).map_err(service_error)?;
28
29 let mut wal = self.wal.lock();
30
31 let operation_id = wal.write(&record).map_err(service_error)?;
32 let hw_counter = HardwareCounterCell::disposable();
33 let _update_guard = self.segments.acquire_updates_lock();
34
35 let segments_guard = self.segments.read();
36
37 let result = match operation {
38 CollectionUpdateOperations::PointOperation(point_operation) => {
39 process_point_operation(&segments_guard, operation_id, point_operation, &hw_counter)
40 }
41 CollectionUpdateOperations::VectorOperation(vector_operation) => {
42 process_vector_operation(
43 &segments_guard,
44 operation_id,
45 vector_operation,
46 &hw_counter,
47 )
48 }
49 CollectionUpdateOperations::PayloadOperation(payload_operation) => {
50 process_payload_operation(
51 &segments_guard,
52 operation_id,
53 payload_operation,
54 &hw_counter,
55 )
56 }
57 CollectionUpdateOperations::FieldIndexOperation(index_operation) => {
58 process_field_index_operation(
59 &segments_guard,
60 operation_id,
61 &index_operation,
62 &hw_counter,
63 )
64 }
65 CollectionUpdateOperations::VectorNameOperation(ref vector_name_operation) => {
66 let result = process_vector_name_operation(
67 &segments_guard,
68 operation_id,
69 vector_name_operation,
70 );
71 if let Ok(changed) = result {
77 self.apply_vector_name_to_config(vector_name_operation, changed)?;
78 }
79 result
80 }
81 #[cfg(feature = "staging")]
82 CollectionUpdateOperations::StagingOperation(staging_operation) => {
83 crate::shard::update::process_staging_operation(
84 &segments_guard,
85 operation_id,
86 staging_operation,
87 )
88 }
89 };
90
91 result.map(|_| ())
92 }
93
94 fn check_vector_name_create_compatible(
97 &self,
98 name: &str,
99 config: &VectorNameConfig,
100 ) -> OperationResult<()> {
101 let conflict = match requested_vector_params(config) {
109 RequestedVectorParams::Dense(params) => self
110 .config
111 .read()
112 .vectors
113 .get(name)
114 .is_some_and(|existing| !dense_identity_matches(existing, ¶ms)),
115 RequestedVectorParams::Sparse(params) => self
116 .config
117 .read()
118 .sparse_vectors
119 .get(name)
120 .is_some_and(|existing| !sparse_identity_matches(existing, ¶ms)),
121 };
122 if conflict {
123 return Err(OperationError::validation_error(format!(
124 "vector '{name}' already exists with different parameters; delete \
125 it before recreating with a different configuration"
126 )));
127 }
128 Ok(())
129 }
130
131 fn apply_vector_name_to_config(
133 &self,
134 operation: &VectorNameOperations,
135 changed: usize,
136 ) -> OperationResult<()> {
137 match operation {
138 VectorNameOperations::CreateVectorName(create) => {
139 if changed == 0 {
145 return Ok(());
146 }
147 self.config
148 .write(|config| match requested_vector_params(&create.config) {
149 RequestedVectorParams::Dense(params) => {
150 config.vectors.insert(create.vector_name.clone(), params);
151 }
152 RequestedVectorParams::Sparse(params) => {
153 config
154 .sparse_vectors
155 .insert(create.vector_name.clone(), params);
156 }
157 })
158 .map_err(service_error)?;
159 }
160 VectorNameOperations::DeleteVectorName(delete) => {
161 self.config
162 .write(|config| {
163 config.vectors.remove(&delete.vector_name);
164 config.sparse_vectors.remove(&delete.vector_name);
165 })
166 .map_err(service_error)?;
167 }
168 }
169 Ok(())
170 }
171}
172
173enum RequestedVectorParams {
176 Dense(EdgeVectorParams),
177 Sparse(EdgeSparseVectorParams),
178}
179
180fn requested_vector_params(config: &VectorNameConfig) -> RequestedVectorParams {
181 match config {
182 VectorNameConfig::Dense(wrapper) => RequestedVectorParams::Dense(EdgeVectorParams {
183 size: wrapper.dense.size,
184 distance: wrapper.dense.distance,
185 on_disk: None,
186 multivector_config: wrapper.dense.multivector_config,
187 datatype: wrapper.dense.datatype,
188 quantization_config: None,
189 hnsw_config: None,
190 }),
191 VectorNameConfig::Sparse(wrapper) => {
192 RequestedVectorParams::Sparse(EdgeSparseVectorParams {
193 full_scan_threshold: None,
194 on_disk: None,
195 modifier: wrapper.sparse.modifier,
196 datatype: wrapper.sparse.datatype,
197 })
198 }
199 }
200}
201
202fn dense_identity_matches(existing: &EdgeVectorParams, requested: &EdgeVectorParams) -> bool {
206 existing.size == requested.size
207 && existing.distance == requested.distance
208 && existing.multivector_config == requested.multivector_config
209 && existing.datatype == requested.datatype
210}
211
212fn sparse_identity_matches(
216 existing: &EdgeSparseVectorParams,
217 requested: &EdgeSparseVectorParams,
218) -> bool {
219 existing.modifier == requested.modifier && existing.datatype == requested.datatype
220}
221
222fn service_error(err: impl fmt::Display) -> OperationError {
223 OperationError::service_error(err.to_string())
224}