Skip to content

Commit e7b5922

Browse files
authored
skiplist: Fix #1023 (#1101)
1 parent 2128578 commit e7b5922

File tree

3 files changed

+54
-28
lines changed

3 files changed

+54
-28
lines changed

crossbeam-skiplist/src/base.rs

+12-28
Original file line numberDiff line numberDiff line change
@@ -871,33 +871,17 @@ where
871871
// the lifetime of the guard.
872872
let guard = &*(guard as *const _);
873873

874-
let mut search;
875-
loop {
876-
// First try searching for the key.
877-
// Note that the `Ord` implementation for `K` may panic during the search.
878-
search = self.search_position(&key, guard);
879-
880-
let r = match search.found {
881-
Some(r) => r,
882-
None => break,
883-
};
874+
// First try searching for the key.
875+
// Note that the `Ord` implementation for `K` may panic during the search.
876+
let mut search = self.search_position(&key, guard);
877+
if let Some(r) = search.found {
884878
let replace = replace(&r.value);
885-
if replace {
886-
// If a node with the key was found and we should replace it, mark its tower
887-
// and then repeat the search.
888-
if r.mark_tower() {
889-
self.hot_data.len.fetch_sub(1, Ordering::Relaxed);
890-
}
891-
} else {
879+
if !replace {
892880
// If a node with the key was found and we're not going to replace it, let's
893881
// try returning it as an entry.
894882
if let Some(e) = RefEntry::try_acquire(self, r) {
895883
return e;
896884
}
897-
898-
// If we couldn't increment the reference count, that means someone has just
899-
// now removed the node.
900-
break;
901885
}
902886
}
903887

@@ -937,6 +921,12 @@ where
937921
)
938922
.is_ok()
939923
{
924+
// This node has been abandoned
925+
if let Some(r) = search.found {
926+
if r.mark_tower() {
927+
self.hot_data.len.fetch_sub(1, Ordering::Relaxed);
928+
}
929+
}
940930
break;
941931
}
942932

@@ -956,13 +946,7 @@ where
956946

957947
if let Some(r) = search.found {
958948
let replace = replace(&r.value);
959-
if replace {
960-
// If a node with the key was found and we should replace it, mark its
961-
// tower and then repeat the search.
962-
if r.mark_tower() {
963-
self.hot_data.len.fetch_sub(1, Ordering::Relaxed);
964-
}
965-
} else {
949+
if !replace {
966950
// If a node with the key was found and we're not going to replace it,
967951
// let's try returning it as an entry.
968952
if let Some(e) = RefEntry::try_acquire(self, r) {

crossbeam-skiplist/tests/map.rs

+21
Original file line numberDiff line numberDiff line change
@@ -920,3 +920,24 @@ fn clear() {
920920
assert!(s.is_empty());
921921
assert_eq!(s.len(), 0);
922922
}
923+
924+
// https://github.com/crossbeam-rs/crossbeam/issues/1023
925+
#[test]
926+
fn concurrent_insert_get_same_key() {
927+
use std::sync::Arc;
928+
let map: Arc<SkipMap<u32, ()>> = Arc::new(SkipMap::new());
929+
let len = 10_0000;
930+
let key = 0;
931+
map.insert(0, ());
932+
933+
let getter = map.clone();
934+
let handle = std::thread::spawn(move || {
935+
for _ in 0..len {
936+
map.insert(0, ());
937+
}
938+
});
939+
for _ in 0..len {
940+
assert!(getter.get(&key).is_some());
941+
}
942+
handle.join().unwrap()
943+
}

crossbeam-skiplist/tests/set.rs

+21
Original file line numberDiff line numberDiff line change
@@ -692,3 +692,24 @@ fn clear() {
692692
assert!(s.is_empty());
693693
assert_eq!(s.len(), 0);
694694
}
695+
696+
// https://github.com/crossbeam-rs/crossbeam/issues/1023
697+
#[test]
698+
fn concurrent_insert_get_same_key() {
699+
use std::sync::Arc;
700+
let set: Arc<SkipSet<u32>> = Arc::new(SkipSet::new());
701+
let len = 10_0000;
702+
let key = 0;
703+
set.insert(0);
704+
705+
let getter = set.clone();
706+
let handle = std::thread::spawn(move || {
707+
for _ in 0..len {
708+
set.insert(0);
709+
}
710+
});
711+
for _ in 0..len {
712+
assert!(getter.get(&key).is_some());
713+
}
714+
handle.join().unwrap()
715+
}

0 commit comments

Comments
 (0)