-
Notifications
You must be signed in to change notification settings - Fork 48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add reservation-based methods #12
Comments
I started working on this in #32. For now, only compute_if_present is implemented. |
I would like to propose the following for the entry API: impl<K, V, S> HashMap<K, V, S> {
pub fn entry<'g>(&'g self, key: K, guard: &'g Guard) -> Entry<'g, K, V, S> {
todo!()
}
}
pub enum Entry<'g, K, V, S> {
Vacant(VacantEntry<'g, K, V, S>),
Occupied(OccupiedEntry<'g, K, V, S>),
}
pub struct VacantEntry<'g, K, V, S> {
_todo: PhantomData<('g, K, V, S)>,
}
pub struct OccupiedEntry<'g, K, V, S> {
_todo: PhantomData<('g, K, V, S)>,
}
impl<'g, K, V, S> Entry<'g, K, V, S> {
pub fn or_insert(self, default: V) -> &'g V {
todo!()
}
pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'g V {
todo!()
}
pub fn key(&'g self) -> &'g K {
todo!()
}
pub fn and_modify<F: FnOnce(&'g V) -> V>(self, f: F) -> Self {
todo!()
}
}
impl<'g, K, V: Default, S> Entry<'g, K, V, S> {
pub fn or_default(self) -> &'g V {
todo!()
}
}
impl<'g, K, V, S> VacantEntry<'g, K, V, S> {
pub fn key(&self) -> &K {
todo!()
}
pub fn into_key(self) -> K {
todo!()
}
pub fn insert(self, value: V) -> &'g V {
todo!()
}
}
impl<'g, K, V, S> OccupiedEntry<'g, K, V, S> {
pub fn key(&self) -> &K {
todo!()
}
pub fn remove_entry(self) -> (&'g K, &'g V) {
todo!()
}
pub fn get(&self) -> &'g V {
todo!()
}
pub fn insert(&mut self, value: V) -> &'g V {
todo!()
}
pub fn remove(self) -> &'g V {
todo!()
}
} Notable changes from
The API shape would imply that the lock is held for both the vacant and occupied cases for the entirety of the Entry being in scope. This does mean that a poorly written could possibly deadlock itself:
I don't have a good suggestion on how to prevent this with the API above. An alternative is to make the entry API 'lazy' and only actually interact with the map when the methods of the I thought I would post the API contract in here first instead of getting too far into an implementation as I think the API is important to get right. |
I like the suggestion and the thinking behind it. It's very similar to what I imagined. The point about deadlock is a good one though, and I worry that it might become an unexpectedly large problem since we have to lock the entire bin, not just the one key... That said, that is what the Java code does, so it sounds like it's still (possibly) a reasonable use-case. We just need to make sure we document that behavior well. We could also perhaps find a way to name the top-level method such that it becomes clear that it might deadlock. Something like As for the suggestion to make As an aside, I took a look into the Java code, and it turns out that |
I've been thinking about the entry API considerably over the last few days, thinking through the outstanding problems with the API proposed. To reiterate the issues outstanding as I see them, they are:
IMO more sophisticated deadlocks scenarios which could be contrived which span coordination across multiple threads should not be considered in any solution and simply documented that they can occur. Due to the I have not been able to think of a solution to the first problem. I think if there was a straight forward way to only allow the single BinEntry to be locked and still allow for inserts and removals, the Java ConcurrentHashMap would already be using it. In terms of the misuse of the entry API, I don't think its possible to prevent via the type system but it could detect the misuse at runtime and panic using a reentrantlock. Given these outstanding problems, I'm thinking it may be better to avoid the entry API, at least for now, and build APIs similar to those on the Java API:
At least the |
@jhinch Sorry it took me so long to get back to this -- yes, I agree with you, we should probably stick with the Java API for now. I think deadlocks are just as likely (people will end up doing something blocking in the One alternative is to implement an internal entry-based API, and then for the time being just expose the Java-like versions. I think that should be about the same complexity. |
No worries. Thanks for your response! Sounds like a plan then. I might take a look over the next few days. If no one hears from me over the next week, I likely haven't had the time and people should feel free to go ahead and pick this up. |
Add
computeIfAbsent
,computeIfPresent
,compute
I have a suspicion that
ReservationNode
could also be used to implement anEntry
-API like the one onstd::collections::HashMap
, so that may be worth looking into.The text was updated successfully, but these errors were encountered: