MCPcopy Create free account
hub / github.com/NVIDIA/OpenShell / update_message_cas

Method update_message_cas

crates/openshell-server/src/persistence/mod.rs:440–509  ·  view source on GitHub ↗

Update a protobuf message using CAS (compare-and-swap). Fetches the current object, validates the expected version, applies the mutation function, and attempts a single CAS write. Returns Conflict on version mismatch for caller-driven retry. # Arguments `id` - Object ID to update `expected_version` - Required resource version for the update to proceed. Pass 0 to use the current version (internal

(
        &self,
        id: &str,
        expected_version: u64,
        mut mutate: F,
    )

Source from the content-addressed store, hash-verified

438 /// * `Err(Conflict)` - Version mismatch; caller should retry
439 /// * `Err(Database)` - Object not found or other DB error
440 pub async fn update_message_cas<T, F>(
441 &self,
442 id: &str,
443 expected_version: u64,
444 mut mutate: F,
445 ) -> PersistenceResult<T>
446 where
447 T: Message
448 + Default
449 + ObjectType
450 + ObjectId
451 + ObjectName
452 + ObjectLabels
453 + SetResourceVersion
454 + GetResourceVersion
455 + Clone,
456 F: FnMut(&mut T),
457 {
458 // Fetch current object with authoritative resource_version
459 let current = self
460 .get_message::<T>(id)
461 .await?
462 .ok_or_else(|| PersistenceError::Database(format!("object {id} not found")))?;
463
464 let current_version = current.get_resource_version();
465
466 // Determine the version to use for CAS:
467 // - If expected_version is 0, use current version (internal operations)
468 // - Otherwise, validate that expected matches current (client-facing operations)
469 let cas_version = if expected_version == 0 {
470 current_version
471 } else {
472 if expected_version != current_version {
473 return Err(PersistenceError::Conflict {
474 current_resource_version: Some(current_version),
475 });
476 }
477 expected_version
478 };
479
480 // Apply mutation
481 let mut updated = current.clone();
482 mutate(&mut updated);
483
484 // Serialize labels
485 let labels_map = updated.object_labels();
486 let labels_json = if labels_map.as_ref().is_none_or(HashMap::is_empty) {
487 None
488 } else {
489 Some(serde_json::to_string(&labels_map).map_err(|e| {
490 PersistenceError::Encode(format!("failed to serialize labels: {e}"))
491 })?)
492 };
493
494 // Single-attempt CAS write - fails with Conflict on version mismatch
495 let result = self
496 .put_if(
497 T::object_type(),

Callers

nothing calls this directly

Calls 6

get_resource_versionMethod · 0.80
object_labelsMethod · 0.80
object_idMethod · 0.80
object_nameMethod · 0.80
set_resource_versionMethod · 0.80
put_ifMethod · 0.45

Tested by

no test coverage detected