``HashMap::retain()`` and async/await

While converting a project to async/await I noticed an issue with
HashMap::retain():

use std::collections::HashMap;
use tokio::sync::Mutex;

#[tokio::main]
async fn main() {
    let mut m = HashMap::new();

    m.insert("foo", Mutex::new(42));
    m.insert("bar", Mutex::new(1337));

    m.retain(|key, _| *key == "bar"); /* ok, non-async */
    m.retain(|_, &mut val| {
        let rwdata = val.lock().await; /* bad */
        *rwdata == 42
    });
}

Where of course tokio’s version Mutex::lock() is an async fn
so it can’t be passed to retain even though the outer function
is async.

After browsing the hashbrown sources I concluded that it is not
feasible to implement retain as efficiently without access to
non-exported functionality. The hashmap is a central component
that is being accessed from a swarm of tasks so it is essential
that the critical section be as short as possible and I would
prefer to avoid traversing elements twice.

I’d be grateful for any pointers or suggestions.

Are you holding the locks across await points or for large amounts of computation? If not, you can just use normal non-async locks instead.

To add to @sfackler, there are also atomics.

I had a shot at a most likely unrecommended way for understanding.
Your example becomes too simplistic; to call retain you have mutable access to the map. There is no point in stand alone Mutex's /(other way)/ there has to be shared access to make using Mutex necessary.

-<| Quoting Steven Fackler via The Rust Programming Language Forum rust_lang+38fe2c86065e2d17e20066b5fbeb3f4b@discoursemail.com, on Friday, 2020-01-10 02:04:25 PM |>-

Are you holding the locks across await points or for large
amounts of computation? If not, you can just use normal non-async
locks instead.

Yeah, you’re right. I reviewed the mutexes (actually mostly
RwLocks) guarding values inside the map and none of them cross
await points. (As opposed to the one that guards the map itself.)
Reverting them to the sync version did the trick.

Thank you!