mirror of
https://github.com/loro-dev/loro.git
synced 2025-01-22 21:07:43 +00:00
fix: state lock when emit events (#272)
* fix: state lock when emit events * test: add deadlock test
This commit is contained in:
parent
7dd0d96be3
commit
1f4a59e85c
2 changed files with 46 additions and 5 deletions
|
@ -438,8 +438,7 @@ impl LoroDoc {
|
|||
}
|
||||
};
|
||||
|
||||
let mut state = self.state.lock().unwrap();
|
||||
self.emit_events(&mut state);
|
||||
self.emit_events();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -520,8 +519,12 @@ impl LoroDoc {
|
|||
ans
|
||||
}
|
||||
|
||||
fn emit_events(&self, state: &mut DocState) {
|
||||
let events = state.take_events();
|
||||
fn emit_events(&self) {
|
||||
// we should not hold the lock when emitting events
|
||||
let events = {
|
||||
let mut state = self.state.lock().unwrap();
|
||||
state.take_events()
|
||||
};
|
||||
for event in events {
|
||||
self.observer.emit(event);
|
||||
}
|
||||
|
@ -737,7 +740,8 @@ impl LoroDoc {
|
|||
from_checkout: true,
|
||||
new_version: Cow::Owned(frontiers.clone()),
|
||||
});
|
||||
self.emit_events(&mut state);
|
||||
drop(state);
|
||||
self.emit_events();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -792,3 +792,40 @@ fn issue_batch_import_snapshot() {
|
|||
let doc3 = LoroDoc::new();
|
||||
doc3.import_batch(&[data1, data2]).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn state_may_deadlock_when_import() {
|
||||
// helper function ref: https://github.com/rust-lang/rfcs/issues/2798#issuecomment-552949300
|
||||
use std::time::Duration;
|
||||
use std::{sync::mpsc, thread};
|
||||
fn panic_after<T, F>(d: Duration, f: F) -> T
|
||||
where
|
||||
T: Send + 'static,
|
||||
F: FnOnce() -> T,
|
||||
F: Send + 'static,
|
||||
{
|
||||
let (done_tx, done_rx) = mpsc::channel();
|
||||
let handle = thread::spawn(move || {
|
||||
let val = f();
|
||||
done_tx.send(()).expect("Unable to send completion signal");
|
||||
val
|
||||
});
|
||||
|
||||
match done_rx.recv_timeout(d) {
|
||||
Ok(_) => handle.join().expect("Thread panicked"),
|
||||
Err(_) => panic!("Thread took too long"),
|
||||
}
|
||||
}
|
||||
|
||||
panic_after(Duration::from_millis(100), || {
|
||||
let doc = LoroDoc::new_auto_commit();
|
||||
let map = doc.get_map("map");
|
||||
doc.subscribe_root(Arc::new(move |_e| {
|
||||
map.id();
|
||||
}));
|
||||
|
||||
let doc2 = LoroDoc::new_auto_commit();
|
||||
doc2.get_map("map").insert("foo", 123).unwrap();
|
||||
doc.import(&doc.export_snapshot()).unwrap();
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue