refactor: reset snapshot

This commit is contained in:
Zixuan Chen 2022-07-25 13:00:22 +08:00
parent 50c7a827c9
commit 590a6e8ee6
14 changed files with 125 additions and 45 deletions

5
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,5 @@
{
"cSpell.words": [
"smstring"
]
}

View file

@ -14,6 +14,8 @@ fxhash = "0.2.1"
ring = "0.16.20"
moveit = "0.5.0"
pin-project = "1.0.10"
serde = {version = "1.0.140", features = ["derive"]}
thiserror = "1.0.31"
[dev-dependencies]
proptest = "1.0.0"

View file

@ -5,10 +5,11 @@
//! Every [Container] can take a [Snapshot], which contains [crate::LoroValue] that describes the state.
//!
use crate::{
op::OpProxy, snapshot::Snapshot, version::VersionVector, InsertContent, InternalString,
LogStore, Op, SmString, ID,
op::OpProxy, version::VersionVector, InsertContent, InternalString, LogStore, LoroValue, Op,
SmString, ID,
};
use rle::{HasLength, Mergable, Sliceable};
use serde::Serialize;
use std::{
alloc::Layout,
any::{self, Any, TypeId},
@ -26,10 +27,12 @@ pub use manager::*;
pub trait Container: Debug + Any + Unpin {
fn id(&self) -> &ContainerID;
fn container_type(&self) -> ContainerType;
fn type_(&self) -> ContainerType;
fn apply(&mut self, op: &OpProxy);
fn snapshot(&mut self) -> Snapshot;
fn checkout_version(&mut self, vv: &VersionVector, log: &LogStore);
fn checkout_version(&mut self, vv: &VersionVector);
fn get_value(&mut self) -> &LoroValue;
// TODO: need a custom serializer
// fn serialize(&self) -> Vec<u8>;
}
pub(crate) trait Cast<T> {
@ -49,7 +52,7 @@ impl<T: Any> Cast<T> for dyn Container {
}
}
#[derive(Hash, PartialEq, Eq, Debug, Clone)]
#[derive(Hash, PartialEq, Eq, Debug, Clone, Serialize)]
pub enum ContainerID {
/// Root container does not need a insert op to create. It can be created implicitly.
Root {

View file

@ -1,11 +1,12 @@
use crate::{InsertContent, SmString, ID};
use crate::{smstring::SmString, InsertContent, ID};
use rle::{HasLength, Mergable, Sliceable};
use serde::Serialize;
use std::alloc::Layout;
#[derive(Debug, Clone)]
pub(crate) enum Slot {}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
pub enum ContainerType {
/// See [`crate::text::TextContent`]
Text,

View file

@ -1,15 +1,16 @@
use std::{pin::Pin, ptr::NonNull, rc::Weak};
use fxhash::FxHashMap;
use serde::Serialize;
use crate::{
container::{Container, ContainerID, ContainerType},
id::ID,
id::{Counter, ID},
op::{utils::downcast_ref, Op},
op::{OpContent, OpProxy},
value::{InsertValue, LoroValue},
version::TotalOrderStamp,
ClientID, InternalString, Lamport, LogStore, OpType, Snapshot,
ClientID, InternalString, Lamport, LogStore, OpType,
};
use super::MapInsertContent;
@ -22,12 +23,14 @@ pub struct MapContainer {
id: ContainerID,
state: FxHashMap<InternalString, ValueSlot>,
log_store: NonNull<LogStore>,
value: Option<LoroValue>,
}
#[derive(Debug)]
struct ValueSlot {
value: InsertValue,
order: TotalOrderStamp,
counter: Counter,
}
impl MapContainer {
@ -37,6 +40,7 @@ impl MapContainer {
id,
state: FxHashMap::default(),
log_store: store,
value: None,
}
}
@ -53,8 +57,10 @@ impl MapContainer {
lamport: store.next_lamport(),
};
let id = store.next_id(client_id);
let counter = id.counter;
store.append_local_ops(vec![Op {
id: store.next_id(client_id),
id,
content: OpContent::Normal {
container: self_id,
content: Box::new(MapInsertContent {
@ -64,7 +70,14 @@ impl MapContainer {
},
}]);
self.state.insert(key, ValueSlot { value, order });
self.state.insert(
key,
ValueSlot {
value,
order,
counter,
},
);
}
#[inline]
@ -79,7 +92,7 @@ impl Container for MapContainer {
&self.id
}
fn container_type(&self) -> ContainerType {
fn type_(&self) -> ContainerType {
ContainerType::Map
}
@ -104,6 +117,7 @@ impl Container for MapContainer {
ValueSlot {
value: v.value.clone(),
order,
counter: op.id().counter,
},
);
}
@ -112,16 +126,19 @@ impl Container for MapContainer {
}
}
fn snapshot(&mut self) -> Snapshot {
let mut map = FxHashMap::default();
for (key, value) in self.state.iter() {
map.insert(key.clone(), value.value.clone().into());
fn get_value(&mut self) -> &LoroValue {
if self.value.is_none() {
let mut map = FxHashMap::default();
for (key, value) in self.state.iter() {
map.insert(key.clone(), value.value.clone().into());
}
self.value = Some(LoroValue::Map(map));
}
Snapshot::new(LoroValue::Map(map))
self.value.as_ref().unwrap()
}
fn checkout_version(&mut self, _vv: &crate::version::VersionVector, _log: &crate::LogStore) {
fn checkout_version(&mut self, vv: &crate::version::VersionVector) {
todo!()
}
}

View file

@ -1,6 +1,6 @@
use rle::{HasLength, Mergable, Sliceable};
use crate::{value::InsertValue, ContentType, InsertContent, InternalString};
use crate::{id::ID, value::InsertValue, ContentType, InsertContent, InternalString};
#[derive(Clone, Debug, PartialEq)]
pub struct MapInsertContent {

View file

@ -28,7 +28,7 @@ fn basic() {
"haha".into() => LoroValue::Integer(1)
);
assert_eq!(*container.snapshot().value(), LoroValue::Map(ans));
assert_eq!(*container.get_value(), LoroValue::Map(ans));
}
#[cfg(not(no_proptest))]
@ -47,9 +47,8 @@ mod map_proptest {
for (k, v) in key.iter().zip(value.iter()) {
map.insert(k.clone(), v.clone());
container.insert(k.clone().into(), v.clone());
let snapshot = container.snapshot();
let snapshot = snapshot.value().to_map().unwrap();
for (key, value) in snapshot.iter() {
let snapshot = container.get_value();
for (key, value) in snapshot.to_map().unwrap().iter() {
assert_eq!(map.get(&key.to_string()).map(|x|x.clone().into()), Some(value.clone()));
}
}

View file

@ -0,0 +1,11 @@
use thiserror::Error;
#[derive(Error, Debug)]
pub enum LoroError {
// #[error("the data for key `{0}` is not available")]
// Redaction(String),
// #[error("invalid header (expected {expected:?}, found {found:?})")]
// InvalidHeader { expected: String, found: String },
// #[error("unknown data store error")]
// Unknown,
}

View file

@ -1,7 +1,9 @@
use serde::Serialize;
pub type ClientID = u64;
pub type Counter = u32;
#[derive(PartialEq, Eq, Hash, Clone, Debug, Copy, PartialOrd, Ord)]
#[derive(PartialEq, Eq, Hash, Clone, Debug, Copy, PartialOrd, Ord, Serialize)]
pub struct ID {
pub client_id: u64,
pub counter: u32,

View file

@ -10,9 +10,11 @@ pub mod id;
pub mod op;
pub mod version;
mod error;
mod id_span;
mod log_store;
mod loro;
mod smstring;
mod snapshot;
mod tests;
mod value;
@ -20,9 +22,8 @@ mod value;
pub(crate) mod macros;
pub(crate) use change::{Change, Lamport, Timestamp};
pub(crate) use id::{ClientID, ID};
pub(crate) use snapshot::Snapshot;
pub(crate) type SmString = SmartString<LazyCompact>;
pub(crate) use op::{ContentType, InsertContent, Op, OpContent, OpType};
pub(crate) use smstring::SmString;
pub(crate) type InternalString = DefaultAtom;
pub use container::ContainerType;
@ -30,5 +31,4 @@ pub use log_store::LogStore;
pub use loro::*;
pub use value::LoroValue;
use smartstring::{LazyCompact, SmartString};
use string_cache::DefaultAtom;

View file

@ -0,0 +1,46 @@
use std::ops::DerefMut;
use std::ops::Deref;
use serde::Serialize;
use smartstring::LazyCompact;
use smartstring::SmartString;
#[repr(transparent)]
#[derive(Debug, PartialEq, PartialOrd, Ord, Eq, Clone)]
pub struct SmString(pub(crate) SmartString<LazyCompact>);
impl Deref for SmString {
type Target = SmartString<LazyCompact>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for SmString {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl From<SmartString<LazyCompact>> for SmString {
fn from(s: SmartString<LazyCompact>) -> Self {
SmString(s)
}
}
impl From<String> for SmString {
fn from(s: String) -> Self {
SmString(s.into())
}
}
impl Serialize for SmString {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&self.0)
}
}

View file

@ -1,16 +1 @@
use crate::value::LoroValue;
#[derive(Debug, PartialEq, Clone)]
pub struct Snapshot {
value: LoroValue,
}
impl Snapshot {
pub fn new(value: LoroValue) -> Self {
Snapshot { value }
}
pub fn value(&self) -> &LoroValue {
&self.value
}
}

View file

@ -1,9 +1,9 @@
use fxhash::FxHashMap;
use crate::{container::ContainerID, InternalString, SmString};
use crate::{container::ContainerID, smstring::SmString, InternalString};
/// [LoroValue] is used to represents the state of CRDT at a given version
#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Clone, serde::Serialize)]
pub enum LoroValue {
Null,
Bool(bool),

View file

@ -7,3 +7,12 @@ test:
# test without proptest
test-fast:
RUSTFLAGS='--cfg no_proptest' cargo nextest run
check-unsafe:
env RUSTFLAGS="-Funsafe-code --cap-lints=warn" cargo check
deny:
cargo deny check
crev:
cargo crev crate check