MCPcopy Create free account
hub / github.com/NodeDB-Lab/nodedb / execute_vector_delete

Method execute_vector_delete

nodedb/src/data/executor/handlers/vector.rs:236–303  ·  view source on GitHub ↗
(
        &mut self,
        task: &ExecutionTask,
        tid: u64,
        collection: &str,
        vector_id: u32,
    )

Source from the content-addressed store, hash-verified

234 }
235
236 pub(in crate::data::executor) fn execute_vector_delete(
237 &mut self,
238 task: &ExecutionTask,
239 tid: u64,
240 collection: &str,
241 vector_id: u32,
242 ) -> Response {
243 debug!(core = self.core_id, %collection, vector_id, "vector delete");
244 // Resolve the actual index key. Legacy `CREATE VECTOR INDEX` uses
245 // an empty field segment; vector-primary collections use
246 // `"{collection}:{field}"`. Try the legacy key first, then scan
247 // for any field-suffixed key under the same (tenant, collection).
248 let tenant = TenantId::new(tid);
249 let plain_key = (tenant, collection.to_string());
250 let prefix = format!("{collection}:");
251 let resolved_key = if self.vector_collections.contains_key(&plain_key) {
252 Some(plain_key)
253 } else {
254 self.vector_collections
255 .keys()
256 .find(|(t, c)| *t == tenant && c.starts_with(&prefix))
257 .cloned()
258 };
259 let Some(index_key) = resolved_key else {
260 return self.response_error(task, ErrorCode::NotFound);
261 };
262
263 // Capture the surrogate before deletion so we can fetch the
264 // payload row from the sparse store and update the bitmap. The
265 // bitmap stores node-id -> field-value membership; without the
266 // original field values we cannot remove the entries cleanly.
267 //
268 // Asymmetric with the insert path (`vector_upsert`): insert
269 // atomically rolls back the HNSW node if the sparse write fails,
270 // because a phantom node would be returned by future searches.
271 // Delete is best-effort cleanup — if the sparse read or decode
272 // fails we still drop the HNSW node and skip bitmap cleanup.
273 // Phantom bitmap entries are safe (the bitmap is filtered against
274 // live node ids on read), so leaving them is preferable to
275 // aborting the delete and leaking the vector.
276 let surrogate_opt = self
277 .vector_collections
278 .get(&index_key)
279 .and_then(|c| c.get_surrogate(vector_id));
280
281 if let Some(surrogate) = surrogate_opt {
282 let row_key = format!("{:08x}", surrogate.as_u32());
283 let fields = match self.sparse.get(tid, collection, &row_key) {
284 Ok(Some(bytes)) => decode_payload_lowercased(&bytes).ok(),
285 _ => None,
286 };
287 if let Some(fields) = fields
288 && let Some(coll) = self.vector_collections.get_mut(&index_key)
289 {
290 coll.payload.delete_row(vector_id, &fields);
291 }
292 }
293

Callers 2

dispatch_vectorMethod · 0.80

Calls 12

to_stringMethod · 0.80
response_errorMethod · 0.80
delete_rowMethod · 0.80
mark_dirtyMethod · 0.80
response_okMethod · 0.80
findMethod · 0.45
getMethod · 0.45
get_surrogateMethod · 0.45
okMethod · 0.45
get_mutMethod · 0.45
deleteMethod · 0.45

Tested by

no test coverage detected