From 3adcb89e324757709789eae145b2087b349db703 Mon Sep 17 00:00:00 2001 From: DarkSky <25152247+darkskygit@users.noreply.github.com> Date: Tue, 22 Aug 2023 19:26:46 +0800 Subject: [PATCH] fix: dead lock in map (#518) --- y-octo/src/doc/types/map.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/y-octo/src/doc/types/map.rs b/y-octo/src/doc/types/map.rs index 5044a48..1116563 100644 --- a/y-octo/src/doc/types/map.rs +++ b/y-octo/src/doc/types/map.rs @@ -12,13 +12,18 @@ impl_type!(Map); pub(crate) trait MapType: AsInner { fn insert(&mut self, key: impl AsRef, value: impl Into) -> JwstCodecResult { - let mut inner = self.as_inner().get().unwrap().write().unwrap(); + // when we apply update, we may get write store then get ytype, so we ensure + // that everywhere, the write store is fetched before the write ytype to + // avoid deadlocks + let inner = self.as_inner().get().unwrap().read().unwrap(); let left = inner.map.as_ref().and_then(|map| { map.get(key.as_ref()) .and_then(|struct_info| struct_info.left()) .map(|l| l.as_item()) }); if let Some(store) = inner.store.upgrade() { + drop(inner); + let mut store = store.write().unwrap(); let item = store.create_item( value.into(), @@ -27,6 +32,7 @@ pub(crate) trait MapType: AsInner { Some(Parent::Type(self.as_inner().clone())), Some(key.as_ref().into()), ); + let mut inner = self.as_inner().get().unwrap().write().unwrap(); store.integrate(Node::Item(item), 0, Some(&mut inner))?; } @@ -74,12 +80,19 @@ pub(crate) trait MapType: AsInner { } fn remove(&mut self, key: impl AsRef) -> bool { - let mut inner = self.as_inner().get().unwrap().write().unwrap(); + // when we apply update, we may get write store then get ytype, so we ensure + // that everywhere, the write store is fetched before the write ytype to + // avoid deadlocks + let inner = self.as_inner().get().unwrap().read().unwrap(); let node = inner.map.as_ref().and_then(|map| map.get(key.as_ref())); if let Some(store) = inner.store.upgrade() { - let mut store = store.write().unwrap(); if let Some(item) = ItemRef::from(node).get() { + drop(inner); + + let mut store = store.write().unwrap(); store.delete_set.add(item.id.client, item.id.clock, item.len()); + + let mut inner = self.as_inner().get().unwrap().write().unwrap(); DocStore::delete_item(item, Some(&mut inner)); return true; }