vorner / arc-swap

Support atomic operations on Arc itself

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Rcu that is allowed to fail

sophie-h opened this issue · comments

pub fn rcu<R, F>(&self, f: F) -> T
where
    F: FnMut(&T) -> R,
    R: Into<T>,
    S: CaS<T>, 

I found out that some of my updates could actually fail, for example if a key is not present in &T. Wouldn't it make sense to have a version where F returns a Result?

pub fn rcu_result<R, F, E>(&self, f: F) -> Result<T, E>
where
    F: FnMut(&T) -> Result<R, E>,
    R: Into<T>,
    S: CaS<T>, 

Actually, I'm not even sure the basic rcu pulls its weight. It is already a bit niche and on the side of what arc-swap is for. This use case is likely to be rarer.

Furthermore, I'd say that it would be better to push any kind of fallibility before the rcu even starts. So adding such method would actually promote using something that is a bit of an antipattern.

And then, if the rcu_result is added, then it's reasonable to ask for rcu_option and rcu_future and few more. That would pollute the API even more, considering that rcu is niche already.

But it should be reasonably easy to emulate, either by borrowing the code of rcu (and simplifying it, you probably don't need all that generic flexibility):

let mut val = a.load();
loop {
    let new_val = try_update(&val)?;
    let attempt = a.compare_and_swap(&*val, new_val);
    if ptr_eq(&*val, &*attempt) {
      break;
    }
    val = attempt;
}

Or by „updating“ to the same value and exporting the error:

let mut error = None;
a.rcu(|val| {
    match try_update(val) {
       Ok(n) => n,
       Err(e) => {
          error = Some(e);
          val
    }
})

I hope one of these works for your use case, but I don't want to pollute the API too much.