From abd3e382538f577aba49f32d487cc5c3d5d63d0b Mon Sep 17 00:00:00 2001 From: Zixuan Chen Date: Sun, 2 Jul 2023 23:24:17 +0800 Subject: [PATCH] chore: bk --- .vscode/settings.json | 1 + Cargo.lock | 13 ++++ crates/loro-internal/Cargo.toml | 1 + crates/loro-internal/src/change.rs | 2 + .../src/container/text/text_container.rs | 8 +- crates/loro-internal/src/log_store.rs | 2 +- crates/loro-internal/src/op.rs | 5 -- crates/loro-internal/src/refactor/oplog.rs | 45 ++++++++++- .../loro-internal/src/refactor/oplog/dag.rs | 75 +++++++++++++++++++ crates/loro-internal/src/refactor/state.rs | 28 +++++++ 10 files changed, 167 insertions(+), 13 deletions(-) create mode 100644 crates/loro-internal/src/refactor/oplog/dag.rs diff --git a/.vscode/settings.json b/.vscode/settings.json index 2d28f9e7..92b9e7f5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -25,6 +25,7 @@ }, "rust-analyzer.cargo.features": ["test_utils"], "editor.defaultFormatter": "rust-lang.rust-analyzer", + "rust-analyzer.server.extraEnv": { "RUSTUP_TOOLCHAIN": "stable" }, "editor.formatOnSave": true, "todo-tree.general.tags": [ "BUG", diff --git a/Cargo.lock b/Cargo.lock index be128fcd..08cb49a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -528,6 +528,18 @@ dependencies = [ "syn 1.0.107", ] +[[package]] +name = "enum_dispatch" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11f36e95862220b211a6e2aa5eca09b4fa391b13cd52ceb8035a24bf65a79de2" +dependencies = [ + "once_cell", + "proc-macro2 1.0.49", + "quote 1.0.23", + "syn 1.0.107", +] + [[package]] name = "fastrand" version = "1.8.0" @@ -786,6 +798,7 @@ dependencies = [ "debug-log", "dhat", "enum-as-inner", + "enum_dispatch", "flate2", "fxhash", "itertools", diff --git a/crates/loro-internal/Cargo.toml b/crates/loro-internal/Cargo.toml index 6014bbed..9f766ec3 100644 --- a/crates/loro-internal/Cargo.toml +++ b/crates/loro-internal/Cargo.toml @@ -31,6 +31,7 @@ serde_columnar = { version = "0.2.5" } tracing = { version = "0.1.37" } append-only-bytes = { version = "0.1.4", features = ["u32_range"] } itertools = "0.10.5" +enum_dispatch = "0.3.11" [dev-dependencies] serde_json = "1.0.87" diff --git a/crates/loro-internal/src/change.rs b/crates/loro-internal/src/change.rs index e507c2e3..93a893d6 100644 --- a/crates/loro-internal/src/change.rs +++ b/crates/loro-internal/src/change.rs @@ -19,6 +19,8 @@ pub type Timestamp = i64; pub type Lamport = u32; /// A `Change` contains a list of [Op]s. +/// +/// When undo/redo we should always undo/redo a whole [Change]. #[derive(Debug, Clone)] pub struct Change { pub(crate) ops: RleVec<[O; 2]>, diff --git a/crates/loro-internal/src/container/text/text_container.rs b/crates/loro-internal/src/container/text/text_container.rs index 9076387a..04fb8175 100644 --- a/crates/loro-internal/src/container/text/text_container.rs +++ b/crates/loro-internal/src/container/text/text_container.rs @@ -1,7 +1,6 @@ -use std::sync::{Arc, Mutex, Weak}; +use std::sync::{Mutex, Weak}; use append_only_bytes::AppendOnlyBytes; -use debug_log::debug_dbg; use rle::HasLength; use smallvec::{smallvec, SmallVec}; use tracing::instrument; @@ -21,7 +20,6 @@ use crate::{ op::{InnerContent, Op, RemoteContent, RichOp}, transaction::Transaction, value::LoroValue, - version::PatchedVersionVector, LoroError, Transact, VersionVector, }; @@ -29,7 +27,7 @@ use super::{ rope::Rope, string_pool::{Alive, PoolString, StringPool}, text_content::{ListSlice, SliceRange}, - tracker::{Effect, Tracker}, + tracker::Tracker, utf16::count_utf16_chars, }; @@ -87,6 +85,8 @@ impl TextContainer { Ok(()) } + pub fn diff(&mut self) {} + fn _record_insert_op( &mut self, txn: &mut Transaction, diff --git a/crates/loro-internal/src/log_store.rs b/crates/loro-internal/src/log_store.rs index 50060830..920de50b 100644 --- a/crates/loro-internal/src/log_store.rs +++ b/crates/loro-internal/src/log_store.rs @@ -59,7 +59,7 @@ impl GcConfig { } } -type ClientChanges = FxHashMap>; +pub(crate) type ClientChanges = FxHashMap>; pub(crate) type RemoteClientChanges = FxHashMap>>; #[derive(Debug)] diff --git a/crates/loro-internal/src/op.rs b/crates/loro-internal/src/op.rs index 6628d128..2fca5f2b 100644 --- a/crates/loro-internal/src/op.rs +++ b/crates/loro-internal/src/op.rs @@ -15,11 +15,6 @@ use smallvec::SmallVec; /// Operation is a unit of change. /// -/// It has 3 types: -/// - Insert -/// - Delete -/// - Restore -/// /// A Op may have multiple atomic operations, since Op can be merged. #[derive(Debug, Clone)] pub struct Op { diff --git a/crates/loro-internal/src/refactor/oplog.rs b/crates/loro-internal/src/refactor/oplog.rs index 2b09a28d..8760a41b 100644 --- a/crates/loro-internal/src/refactor/oplog.rs +++ b/crates/loro-internal/src/refactor/oplog.rs @@ -1,4 +1,43 @@ -/// This store the -pub struct OpLog {} +mod dag; -pub struct Dag {} +use fxhash::FxHashMap; +use rle::{HasIndex, HasLength, Mergable, RleVec, Sliceable}; +use smallvec::SmallVec; + +use crate::change::{Change, Lamport, Timestamp}; +use crate::dag::{Dag, DagNode}; +use crate::id::{ClientID, Counter, ID}; +use crate::log_store::ClientChanges; +use crate::span::{HasId, HasLamport}; +use crate::version::{Frontiers, VersionVector}; + +/// [OpLog] store all the ops i.e. the history. +/// It allows multiple [AppState] to attach to it. +/// So you can derive different versions of the state from the [OpLog]. +/// It allows us to build a version control system. +/// +#[derive(Debug, Clone)] +pub struct OpLog { + pub(crate) dag: AppDag, + pub(crate) changes: ClientChanges, + pub(crate) latest_lamport: Lamport, + pub(crate) latest_timestamp: Timestamp, +} + +/// [AppDag] maintains the causal graph of the app. +/// It's faster to answer the question like what's the LCA version +#[derive(Debug, Clone)] +pub struct AppDag { + map: FxHashMap>, + frontiers: Frontiers, + vv: VersionVector, +} + +#[derive(Debug, Clone)] +pub struct AppDagNode { + client: ClientID, + cnt: Counter, + lamport: Lamport, + parents: SmallVec<[ID; 2]>, + len: usize, +} diff --git a/crates/loro-internal/src/refactor/oplog/dag.rs b/crates/loro-internal/src/refactor/oplog/dag.rs new file mode 100644 index 00000000..d9960f14 --- /dev/null +++ b/crates/loro-internal/src/refactor/oplog/dag.rs @@ -0,0 +1,75 @@ +use super::*; +impl HasIndex for AppDagNode { + type Int = Counter; + fn get_start_index(&self) -> Self::Int { + self.cnt + } + + fn get_end_index(&self) -> Self::Int { + self.cnt + self.len as Counter + } +} + +impl Sliceable for AppDagNode { + fn slice(&self, from: usize, to: usize) -> Self { + AppDagNode { + client: self.client, + cnt: self.cnt + from as Counter, + lamport: self.lamport + from as Lamport, + parents: Default::default(), + len: to - from, + } + } +} + +impl HasId for AppDagNode { + fn id_start(&self) -> ID { + ID { + client_id: self.client, + counter: self.cnt, + } + } +} + +impl HasLength for AppDagNode { + fn atom_len(&self) -> usize { + self.len + } + + fn content_len(&self) -> usize { + self.len + } +} + +impl Mergable for AppDagNode {} + +impl HasLamport for AppDagNode { + fn lamport(&self) -> Lamport { + self.lamport + } +} + +impl DagNode for AppDagNode { + fn deps(&self) -> &[ID] { + &self.parents + } +} + +impl Dag for AppDag { + type Node = AppDagNode; + + fn frontier(&self) -> &[ID] { + &self.frontiers + } + + fn get(&self, id: ID) -> Option<&Self::Node> { + let ID { client_id, counter } = id; + self.map + .get(&client_id) + .and_then(|rle| rle.get(counter).map(|x| x.element)) + } + + fn vv(&self) -> VersionVector { + self.vv.clone() + } +} diff --git a/crates/loro-internal/src/refactor/state.rs b/crates/loro-internal/src/refactor/state.rs index c8adbd74..288c3628 100644 --- a/crates/loro-internal/src/refactor/state.rs +++ b/crates/loro-internal/src/refactor/state.rs @@ -1,7 +1,35 @@ +use enum_dispatch::enum_dispatch; +use fxhash::FxHashMap; + +use crate::{container::ContainerID, InternalString, VersionVector}; + mod list; mod map; mod text; +#[enum_dispatch] pub trait ContainerState: Clone { fn apply_diff(&mut self); } + +pub struct AppState { + vv: VersionVector, + state: FxHashMap, +} + +#[enum_dispatch(ContainerState)] +#[derive(Clone)] +pub enum State { + ListState, + MapState, + TextState, +} + +#[derive(Clone)] +pub struct ListState {} + +#[derive(Clone)] +pub struct MapState {} + +#[derive(Clone)] +pub struct TextState {}