xacrimon / dashmap

Blazing fast concurrent HashMap for Rust.
MIT License
2.84k stars 140 forks source link

question when iter to remove key #284

Open vCassius opened 8 months ago

vCassius commented 8 months ago

will fail to remove key when iter,i don't know why.

use dashmap::DashMap;
use serde::{Deserialize, Serialize};
use std::process::exit;
use std::time::Duration;
use tokio::sync::OnceCell;
use tokio::time::sleep;
pub static MESSAGE: OnceCell<DashMap<String, i64>> = OnceCell::const_new();
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Message {
    pub id: u32,
    pub data_len: u32,
    pub data: String,
}

pub enum MessageType {
    Write(Message),
    Close,
}

#[tokio::main]
async fn main() {
    match MESSAGE.set(DashMap::new()) {
        Ok(_) => {}
        Err(e) => {
            println!("fail to set message,err: {e}");
            exit(-1)
        }
    };
    let mut handles = Vec::new();
    let insert = tokio::spawn(async move { insert_hashmap().await });
    handles.push(insert);
    let read = tokio::spawn(async move { read_hashmap().await });
    handles.push(read);
    for h in handles {
        match h.await {
            Ok(_) => {}
            Err(e) => {
                println!("handle err: {e}")
            }
        }
    }
}
async fn insert_hashmap() {
    let Some(message) = MESSAGE.get() else {
        println!("fail to get global static router pool");
        exit(-1)
    };
    let mut count = 0u64;
    loop {
        let value = count + 1;
        message.insert(count.to_string(), value as i64);
        println!("insert key: {value} value: {value} succeed");
        count += 1
    }
}

async fn read_hashmap() {
    let Some(message) = MESSAGE.get() else {
        println!("fail to get global static router pool");
        exit(-1)
    };
    loop {
        // sleep(Duration::from_millis(10)).await;
        for m in message.iter() {
            message.remove(m.key());
            println!("got key: {} value: {}", m.key(), m.value())
        }
    }
}
AshfordN commented 2 months ago

Does the process appear to freeze after the first attempt? If so, then you are likely experiencing a deadlock. The docs for DashMap::remove() says this:

Locking behaviour: May deadlock if called when holding any sort of reference into the map

In your case, you are holding a reference to m while also trying to remove that element. For something like this, consider using DashMap::retain() instead.

// sleep(Duration::from_millis(10)).await;
message.retain(|key, value| {
    println!("got key: {key} value: {value}");

    false
});

As a side note, it is better to isolate your issue as a minimal reproducible example next time. The code above was quite a bit to unpack.