Skip to content

Commit 8db1174

Browse files
committed
Updated to handle CasError in wasm mapping, ensure new cas is returned to client
Signed-off-by: Darwin Boersma <[email protected]>
1 parent 1cc913c commit 8db1174

File tree

5 files changed

+34
-29
lines changed

5 files changed

+34
-29
lines changed

crates/factor-key-value/src/host.rs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,13 @@ impl wasi_keyvalue::atomics::HostCas for KeyValueDispatch {
358358

359359
#[async_trait]
360360
impl wasi_keyvalue::atomics::Host for KeyValueDispatch {
361+
fn convert_cas_error(
362+
&mut self,
363+
error: spin_world::wasi::keyvalue::atomics::CasError,
364+
) -> std::result::Result<spin_world::wasi::keyvalue::atomics::CasError, anyhow::Error> {
365+
Ok(error)
366+
}
367+
361368
#[instrument(name = "spin_key_value.increment", skip(self, bucket, key, delta), err(level = Level::INFO), fields(otel.kind = "client"))]
362369
async fn increment(
363370
&mut self,
@@ -374,27 +381,29 @@ impl wasi_keyvalue::atomics::Host for KeyValueDispatch {
374381
&mut self,
375382
cas_res: Resource<atomics::Cas>,
376383
value: Vec<u8>,
377-
) -> Result<std::result::Result<(), CasError>> {
384+
) -> Result<(), CasError> {
378385
let cas_rep = cas_res.rep();
379386
let cas = self
380387
.get_cas(Resource::<Bucket>::new_own(cas_rep))
381388
.map_err(|e| CasError::StoreError(atomics::Error::Other(e.to_string())))?;
382389

383390
match cas.swap(value).await {
384-
Ok(_) => Ok(Ok(())),
391+
Ok(_) => Ok(()),
385392
Err(err) => match err {
386393
SwapError::CasFailed(_) => {
387394
let bucket = Resource::new_own(cas.bucket_rep().await);
388-
let new_cas = self.new(bucket, cas.key().await).await?;
395+
let new_cas = self
396+
.new(bucket, cas.key().await)
397+
.await
398+
.map_err(CasError::StoreError)?;
389399
let new_cas_rep = new_cas.rep();
390-
self.current(Resource::new_own(new_cas_rep)).await?;
391-
Err(anyhow::Error::new(CasError::CasFailed(Resource::new_own(
392-
new_cas_rep,
393-
))))
400+
self.current(Resource::new_own(new_cas_rep))
401+
.await
402+
.map_err(CasError::StoreError)?;
403+
let res = Resource::new_own(new_cas_rep);
404+
Err(CasError::CasFailed(res))
394405
}
395-
SwapError::Other(msg) => Err(anyhow::Error::new(CasError::StoreError(
396-
atomics::Error::Other(msg),
397-
))),
406+
SwapError::Other(msg) => Err(CasError::StoreError(atomics::Error::Other(msg))),
398407
},
399408
}
400409
}

crates/key-value-spin/src/store.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -522,15 +522,10 @@ mod test {
522522
let res = kv.swap(Resource::new_own(cas.rep()), cas_final_value).await;
523523
match res {
524524
Ok(_) => panic!("expected a CAS failure"),
525-
Err(err) => {
526-
for cause in err.chain() {
527-
if let Some(cas_err) = cause.downcast_ref::<CasError>() {
528-
assert!(matches!(cas_err, CasError::CasFailed(_)));
529-
return Ok(());
530-
}
531-
}
532-
panic!("expected a CAS failure")
533-
}
525+
Err(err) => match err {
526+
CasError::CasFailed(_) => Ok(()),
527+
CasError::StoreError(_) => panic!("expected a CasFailed error"),
528+
},
534529
}
535530
}
536531

crates/world/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ wasmtime::component::bindgen!({
3333
"spin:postgres/postgres/error" => spin::postgres::postgres::Error,
3434
"wasi:config/[email protected]/error" => wasi::config::store::Error,
3535
"wasi:keyvalue/store/error" => wasi::keyvalue::store::Error,
36+
"wasi:keyvalue/atomics/cas-error" => wasi::keyvalue::atomics::CasError,
3637
},
3738
trappable_imports: true,
3839
});

wit/deps/keyvalue-2024-10-17/atomic.wit

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,22 @@ interface atomics {
1313

1414
/// The error returned by a CAS operation
1515
variant cas-error {
16-
/// A store error occurred when performing the operation
17-
store-error(error),
16+
/// A store error occurred when performing the operation
17+
store-error(error),
1818
/// The CAS operation failed because the value was too old. This returns a new CAS handle
1919
/// for easy retries. Implementors MUST return a CAS handle that has been updated to the
2020
/// latest version or transaction.
21-
cas-failed(cas),
21+
cas-failed(cas),
2222
}
2323

2424
/// A handle to a CAS (compare-and-swap) operation.
2525
resource cas {
26-
/// Construct a new CAS operation. Implementors can map the underlying functionality
27-
/// (transactions, versions, etc) as desired.
28-
new: static func(bucket: borrow<bucket>, key: string) -> result<cas, error>;
29-
/// Get the current value of the key (if it exists). This allows for avoiding reads if all
30-
/// that is needed to ensure the atomicity of the operation
31-
current: func() -> result<option<list<u8>>, error>;
26+
/// Construct a new CAS operation. Implementors can map the underlying functionality
27+
/// (transactions, versions, etc) as desired.
28+
new: static func(bucket: borrow<bucket>, key: string) -> result<cas, error>;
29+
/// Get the current value of the key (if it exists). This allows for avoiding reads if all
30+
/// that is needed to ensure the atomicity of the operation
31+
current: func() -> result<option<list<u8>>, error>;
3232
}
3333

3434
/// Atomically increment the value associated with the key in the store by the given delta. It

wit/deps/keyvalue-2024-10-17/world.wit

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package wasi: [email protected];
1+
package wasi:keyvalue@0.2.0-draft2;
22

33
/// The `wasi:keyvalue/imports` world provides common APIs for interacting with key-value stores.
44
/// Components targeting this world will be able to do:

0 commit comments

Comments
 (0)