Skip to content

Commit

Permalink
skiplist: Fix #1023 (#1101)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tianion authored Apr 19, 2024
1 parent 2128578 commit e7b5922
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 28 deletions.
40 changes: 12 additions & 28 deletions crossbeam-skiplist/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -871,33 +871,17 @@ where
// the lifetime of the guard.
let guard = &*(guard as *const _);

let mut search;
loop {
// First try searching for the key.
// Note that the `Ord` implementation for `K` may panic during the search.
search = self.search_position(&key, guard);

let r = match search.found {
Some(r) => r,
None => break,
};
// First try searching for the key.
// Note that the `Ord` implementation for `K` may panic during the search.
let mut search = self.search_position(&key, guard);
if let Some(r) = search.found {
let replace = replace(&r.value);
if replace {
// If a node with the key was found and we should replace it, mark its tower
// and then repeat the search.
if r.mark_tower() {
self.hot_data.len.fetch_sub(1, Ordering::Relaxed);
}
} else {
if !replace {
// If a node with the key was found and we're not going to replace it, let's
// try returning it as an entry.
if let Some(e) = RefEntry::try_acquire(self, r) {
return e;
}

// If we couldn't increment the reference count, that means someone has just
// now removed the node.
break;
}
}

Expand Down Expand Up @@ -937,6 +921,12 @@ where
)
.is_ok()
{
// This node has been abandoned
if let Some(r) = search.found {
if r.mark_tower() {
self.hot_data.len.fetch_sub(1, Ordering::Relaxed);
}
}
break;
}

Expand All @@ -956,13 +946,7 @@ where

if let Some(r) = search.found {
let replace = replace(&r.value);
if replace {
// If a node with the key was found and we should replace it, mark its
// tower and then repeat the search.
if r.mark_tower() {
self.hot_data.len.fetch_sub(1, Ordering::Relaxed);
}
} else {
if !replace {
// If a node with the key was found and we're not going to replace it,
// let's try returning it as an entry.
if let Some(e) = RefEntry::try_acquire(self, r) {
Expand Down
21 changes: 21 additions & 0 deletions crossbeam-skiplist/tests/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -920,3 +920,24 @@ fn clear() {
assert!(s.is_empty());
assert_eq!(s.len(), 0);
}

// https://github.com/crossbeam-rs/crossbeam/issues/1023
#[test]
fn concurrent_insert_get_same_key() {
use std::sync::Arc;
let map: Arc<SkipMap<u32, ()>> = Arc::new(SkipMap::new());
let len = 10_0000;
let key = 0;
map.insert(0, ());

let getter = map.clone();
let handle = std::thread::spawn(move || {
for _ in 0..len {
map.insert(0, ());
}
});
for _ in 0..len {
assert!(getter.get(&key).is_some());
}
handle.join().unwrap()
}
21 changes: 21 additions & 0 deletions crossbeam-skiplist/tests/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -692,3 +692,24 @@ fn clear() {
assert!(s.is_empty());
assert_eq!(s.len(), 0);
}

// https://github.com/crossbeam-rs/crossbeam/issues/1023
#[test]
fn concurrent_insert_get_same_key() {
use std::sync::Arc;
let set: Arc<SkipSet<u32>> = Arc::new(SkipSet::new());
let len = 10_0000;
let key = 0;
set.insert(0);

let getter = set.clone();
let handle = std::thread::spawn(move || {
for _ in 0..len {
set.insert(0);
}
});
for _ in 0..len {
assert!(getter.get(&key).is_some());
}
handle.join().unwrap()
}

0 comments on commit e7b5922

Please sign in to comment.