refactor: use Weak in container

This commit is contained in:
leeeon233 2022-12-27 15:15:07 +08:00 committed by Leonzhao
parent 9748779f08
commit 065e646a7e
13 changed files with 74 additions and 49 deletions

View file

@ -1,5 +1,5 @@
// TODO: refactor, extract common code with text
use std::sync::{Arc, Mutex};
use std::sync::{Mutex, Weak};
use rle::{
rle_tree::{tree_trait::CumulateTreeTrait, HeapMode},
@ -88,9 +88,9 @@ impl ListContainer {
let (event, container_id) = self.insert_obj(ctx, pos, value.into_container().unwrap());
let m = ctx.log_store();
let store = m.read().unwrap();
let container = Arc::clone(store.get_container(&container_id).unwrap());
let container = store.get_container(&container_id).unwrap();
drop(store);
prelim.integrate(ctx, &container);
prelim.integrate(ctx, container);
(event, Some(container_id))
} else {
let value = value.into_value().unwrap();
@ -554,21 +554,21 @@ impl Container for ListContainer {
}
pub struct List {
instance: Arc<Mutex<ContainerInstance>>,
instance: Weak<Mutex<ContainerInstance>>,
client_id: ClientID,
}
impl Clone for List {
fn clone(&self) -> Self {
Self {
instance: Arc::clone(&self.instance),
instance: Weak::clone(&self.instance),
client_id: self.client_id,
}
}
}
impl List {
pub fn from_instance(instance: Arc<Mutex<ContainerInstance>>, client_id: ClientID) -> Self {
pub fn from_instance(instance: Weak<Mutex<ContainerInstance>>, client_id: ClientID) -> Self {
Self {
instance,
client_id,
@ -618,7 +618,8 @@ impl ContainerWrapper for List {
where
F: FnOnce(&mut Self::Container) -> R,
{
let mut container_instance = self.instance.try_lock().unwrap();
let w = self.instance.upgrade().unwrap();
let mut container_instance = w.try_lock().unwrap();
let list = container_instance.as_list_mut().unwrap();
let ans = f(list);
drop(container_instance);

View file

@ -1,4 +1,4 @@
use std::sync::{Arc, Mutex};
use std::sync::{Mutex, Weak};
use super::{super::pool::Pool, InnerMapSet};
use crate::{
@ -73,9 +73,9 @@ impl MapContainer {
let (event, container_id) = self.insert_obj(ctx, key, value.into_container().unwrap());
let m = ctx.log_store();
let store = m.read().unwrap();
let container = Arc::clone(store.get_container(&container_id).unwrap());
let container = store.get_container(&container_id).unwrap();
drop(store);
prelim.integrate(ctx, &container);
prelim.integrate(ctx, container);
(event, Some(container_id))
} else {
let value = value.into_value().unwrap();
@ -481,21 +481,21 @@ impl Container for MapContainer {
}
pub struct Map {
instance: Arc<Mutex<ContainerInstance>>,
instance: Weak<Mutex<ContainerInstance>>,
client_id: ClientID,
}
impl Clone for Map {
fn clone(&self) -> Self {
Self {
instance: Arc::clone(&self.instance),
instance: Weak::clone(&self.instance),
client_id: self.client_id,
}
}
}
impl Map {
pub fn from_instance(instance: Arc<Mutex<ContainerInstance>>, client_id: ClientID) -> Self {
pub fn from_instance(instance: Weak<Mutex<ContainerInstance>>, client_id: ClientID) -> Self {
Self {
instance,
client_id,
@ -521,6 +521,8 @@ impl Map {
pub fn id(&self) -> ContainerID {
self.instance
.upgrade()
.unwrap()
.try_lock()
.unwrap()
.as_map()
@ -531,6 +533,8 @@ impl Map {
pub fn get_value(&self) -> LoroValue {
self.instance
.upgrade()
.unwrap()
.try_lock()
.unwrap()
.as_map()
@ -556,7 +560,8 @@ impl ContainerWrapper for Map {
where
F: FnOnce(&mut Self::Container) -> R,
{
let mut container_instance = self.instance.try_lock().unwrap();
let w = self.instance.upgrade().unwrap();
let mut container_instance = w.try_lock().unwrap();
let map = container_instance.as_map_mut().unwrap();
let ans = f(map);
drop(container_instance);

View file

@ -1,6 +1,6 @@
use std::{
ops::{Deref, DerefMut},
sync::{Arc, Mutex, RwLockWriteGuard},
sync::{Arc, Mutex, RwLockWriteGuard, Weak},
};
use enum_as_inner::EnumAsInner;
@ -248,10 +248,10 @@ impl ContainerRegistry {
}
#[inline(always)]
pub fn get(&self, id: &ContainerID) -> Option<&Arc<Mutex<ContainerInstance>>> {
pub fn get(&self, id: &ContainerID) -> Option<Weak<Mutex<ContainerInstance>>> {
self.container_to_idx
.get(id)
.map(|x| &self.containers[x.0 as usize].container)
.map(|x| Arc::downgrade(&self.containers[x.0 as usize].container))
}
#[inline(always)]
@ -290,7 +290,7 @@ impl ContainerRegistry {
self.insert(id.clone(), container)
}
pub(crate) fn get_or_create(&mut self, id: &ContainerID) -> &Arc<Mutex<ContainerInstance>> {
pub(crate) fn get_or_create(&mut self, id: &ContainerID) -> Weak<Mutex<ContainerInstance>> {
if !self.container_to_idx.contains_key(id) {
let container = self.create(id.clone());
self.insert(id.clone(), container);

View file

@ -1,4 +1,4 @@
use std::sync::{Arc, Mutex};
use std::sync::{Mutex, Weak};
use append_only_bytes::AppendOnlyBytes;
use rle::HasLength;
@ -476,21 +476,21 @@ impl Container for TextContainer {
}
pub struct Text {
instance: Arc<Mutex<ContainerInstance>>,
instance: Weak<Mutex<ContainerInstance>>,
client_id: ClientID,
}
impl Clone for Text {
fn clone(&self) -> Self {
Self {
instance: Arc::clone(&self.instance),
instance: Weak::clone(&self.instance),
client_id: self.client_id,
}
}
}
impl Text {
pub fn from_instance(instance: Arc<Mutex<ContainerInstance>>, client_id: ClientID) -> Self {
pub fn from_instance(instance: Weak<Mutex<ContainerInstance>>, client_id: ClientID) -> Self {
Self {
instance,
client_id,
@ -499,6 +499,8 @@ impl Text {
pub fn id(&self) -> ContainerID {
self.instance
.upgrade()
.unwrap()
.try_lock()
.unwrap()
.as_text()
@ -527,6 +529,8 @@ impl Text {
pub fn get_value(&self) -> LoroValue {
self.instance
.upgrade()
.unwrap()
.try_lock()
.unwrap()
.as_text()
@ -551,7 +555,8 @@ impl ContainerWrapper for Text {
where
F: FnOnce(&mut Self::Container) -> R,
{
let mut container_instance = self.instance.try_lock().unwrap();
let w = self.instance.upgrade().unwrap();
let mut container_instance = w.try_lock().unwrap();
let text = container_instance.as_text_mut().unwrap();
let ans = f(text);
drop(container_instance);

View file

@ -1,4 +1,4 @@
use std::sync::{Arc, Mutex, RwLock};
use std::sync::{Arc, Mutex, RwLock, Weak};
use crate::{
container::{registry::ContainerInstance, ContainerID},
@ -7,7 +7,7 @@ use crate::{
pub trait Context {
fn log_store(&self) -> Arc<RwLock<LogStore>>;
fn get_container(&self, id: &ContainerID) -> Option<Arc<Mutex<ContainerInstance>>>;
fn get_container(&self, id: &ContainerID) -> Option<Weak<Mutex<ContainerInstance>>>;
}
impl Context for LoroCore {
@ -15,11 +15,7 @@ impl Context for LoroCore {
self.log_store.clone()
}
fn get_container(&self, id: &ContainerID) -> Option<Arc<Mutex<ContainerInstance>>> {
self.log_store
.try_read()
.unwrap()
.get_container(id)
.cloned()
fn get_container(&self, id: &ContainerID) -> Option<Weak<Mutex<ContainerInstance>>> {
self.log_store.try_read().unwrap().get_container(id)
}
}

View file

@ -160,6 +160,8 @@ impl Hierarchy {
if let Some(parent) = parent {
let parent_node = reg.get(parent).unwrap();
let index = parent_node
.upgrade()
.unwrap()
.try_lock()
.unwrap()
.index_of_child(node_id)

View file

@ -10,7 +10,7 @@ pub use encoding::{EncodeConfig, EncodeMode, LoroEncoder};
pub(crate) use import::ImportContext;
use std::{
marker::PhantomPinned,
sync::{Arc, Mutex, MutexGuard, RwLock},
sync::{Arc, Mutex, MutexGuard, RwLock, Weak},
};
use fxhash::FxHashMap;
@ -341,12 +341,12 @@ impl LogStore {
pub fn get_or_create_container(
&mut self,
container: &ContainerID,
) -> &Arc<Mutex<ContainerInstance>> {
) -> Weak<Mutex<ContainerInstance>> {
self.reg.get_or_create(container)
}
#[inline(always)]
pub fn get_container(&self, container: &ContainerID) -> Option<&Arc<Mutex<ContainerInstance>>> {
pub fn get_container(&self, container: &ContainerID) -> Option<Weak<Mutex<ContainerInstance>>> {
self.reg.get(container)
}

View file

@ -198,7 +198,12 @@ pub(super) fn encode_snapshot(store: &LogStore, gc: bool) -> Result<Vec<u8>, Lor
let (_, containers) = store.reg.export();
for container_id in containers.iter() {
let container = store.reg.get(container_id).unwrap();
container.try_lock().unwrap().initialize_pool_mapping();
container
.upgrade()
.unwrap()
.try_lock()
.unwrap()
.initialize_pool_mapping();
}
let mut changes = Vec::with_capacity(change_num);
@ -220,6 +225,8 @@ pub(super) fn encode_snapshot(store: &LogStore, gc: bool) -> Result<Vec<u8>, Lor
let container_id = store.reg.get_id(container_idx).unwrap();
let container = store.reg.get(container_id).unwrap();
let new_ops = container
.upgrade()
.unwrap()
.try_lock()
.unwrap()
.to_export_snapshot(&op.content, gc);
@ -251,6 +258,8 @@ pub(super) fn encode_snapshot(store: &LogStore, gc: bool) -> Result<Vec<u8>, Lor
.map(|container_id| {
let container = store.reg.get(container_id).unwrap();
container
.upgrade()
.unwrap()
.try_lock()
.unwrap()
.encode_and_release_pool_mapping()

View file

@ -338,7 +338,8 @@ impl LogStore {
for change in changes.iter() {
for op in change.ops.iter() {
if !container_map.contains_key(&op.container) {
let guard = self.reg.get_or_create(&op.container).try_lock().unwrap();
let guard = self.reg.get_or_create(&op.container).upgrade().unwrap();
let guard = guard.try_lock().unwrap();
container_map
// SAFETY: ignore lifetime issues here, because it's safe for us to store the mutex guard here
.insert(op.container.clone(), unsafe { std::mem::transmute(guard) });

View file

@ -1,4 +1,4 @@
use std::sync::{Arc, Mutex};
use std::sync::{Mutex, Weak};
use enum_as_inner::EnumAsInner;
@ -14,7 +14,7 @@ pub trait Prelim: Sized {
fn convert_value(self) -> (PrelimValue, Option<Self>);
/// How to integrate the value into the Loro.
fn integrate<C: Context>(self, ctx: &C, container: &Arc<Mutex<ContainerInstance>>);
fn integrate<C: Context>(self, ctx: &C, container: Weak<Mutex<ContainerInstance>>);
}
#[derive(Debug, EnumAsInner)]
@ -33,7 +33,7 @@ where
(PrelimValue::Value(value), None)
}
fn integrate<C: Context>(self, _ctx: &C, _container: &Arc<Mutex<ContainerInstance>>) {}
fn integrate<C: Context>(self, _ctx: &C, _container: Weak<Mutex<ContainerInstance>>) {}
}
impl Prelim for ContainerType {
@ -41,7 +41,7 @@ impl Prelim for ContainerType {
(PrelimValue::Container(self), Some(self))
}
fn integrate<C: Context>(self, _ctx: &C, _container: &Arc<Mutex<ContainerInstance>>) {}
fn integrate<C: Context>(self, _ctx: &C, _container: Weak<Mutex<ContainerInstance>>) {}
}
impl From<LoroValue> for PrelimValue {

View file

@ -52,7 +52,8 @@ impl LoroValue {
self = reg
.get(id)
.map(|container| {
let mut value = container.try_lock().unwrap().get_value();
let mut value =
container.upgrade().unwrap().try_lock().unwrap().get_value();
match &mut value {
LoroValue::List(list) => {

View file

@ -263,12 +263,14 @@ fn encode_hierarchy() {
let (_, text_id) = {
let list_id = map.insert(&c1, "a", ContainerType::List).unwrap();
let list = c1.get_container(&list_id.unwrap()).unwrap();
let list = list.upgrade().unwrap();
let mut list = list.try_lock().unwrap();
let list = list.as_list_mut().unwrap();
list.insert(&c1, 0, ContainerType::Text)
};
{
let text = c1.get_container(&text_id.unwrap()).unwrap();
let text = text.upgrade().unwrap();
let mut text = text.try_lock().unwrap();
let text = text.as_text_mut().unwrap();
text.insert(&c1, 0, "text_text");

View file

@ -1,6 +1,6 @@
use std::{
collections::HashMap,
sync::{Arc, Mutex},
sync::{Arc, Mutex, Weak},
};
use loro_core::{
@ -35,7 +35,7 @@ impl Prelim for PrelimType {
}
}
fn integrate<C: Context>(self, ctx: &C, container: &Arc<Mutex<ContainerInstance>>) {
fn integrate<C: Context>(self, ctx: &C, container: Weak<Mutex<ContainerInstance>>) {
match self {
PrelimType::Text(t) => t.integrate(ctx, container),
PrelimType::Map(m) => m.integrate(ctx, container),
@ -148,8 +148,9 @@ impl Prelim for PrelimText {
(PrelimValue::Container(ContainerType::Text), Some(self))
}
fn integrate<C: Context>(self, ctx: &C, container: &Arc<Mutex<ContainerInstance>>) {
let mut text = container.try_lock().unwrap();
fn integrate<C: Context>(self, ctx: &C, container: Weak<Mutex<ContainerInstance>>) {
let text = container.upgrade().unwrap();
let mut text = text.try_lock().unwrap();
let text = text.as_text_mut().unwrap();
text.insert(ctx, 0, &self.0);
}
@ -160,8 +161,9 @@ impl Prelim for PrelimList {
(PrelimValue::Container(ContainerType::List), Some(self))
}
fn integrate<C: Context>(self, ctx: &C, container: &Arc<Mutex<ContainerInstance>>) {
let mut list = container.try_lock().unwrap();
fn integrate<C: Context>(self, ctx: &C, container: Weak<Mutex<ContainerInstance>>) {
let list = container.upgrade().unwrap();
let mut list = list.try_lock().unwrap();
let list = list.as_list_mut().unwrap();
let values: Vec<LoroValue> = self.0.into_iter().map(|v| v.into()).collect();
list.insert_batch(ctx, 0, values);
@ -173,8 +175,9 @@ impl Prelim for PrelimMap {
(PrelimValue::Container(ContainerType::Map), Some(self))
}
fn integrate<C: Context>(self, ctx: &C, container: &Arc<Mutex<ContainerInstance>>) {
let mut map = container.try_lock().unwrap();
fn integrate<C: Context>(self, ctx: &C, container: Weak<Mutex<ContainerInstance>>) {
let map = container.upgrade().unwrap();
let mut map = map.try_lock().unwrap();
let map = map.as_map_mut().unwrap();
for (key, value) in self.0.into_iter() {
let value: LoroValue = value.into();