diff --git a/crates/loro-internal/src/encoding/fast_snapshot.rs b/crates/loro-internal/src/encoding/fast_snapshot.rs index e5a9f6c7..11e62a83 100644 --- a/crates/loro-internal/src/encoding/fast_snapshot.rs +++ b/crates/loro-internal/src/encoding/fast_snapshot.rs @@ -157,6 +157,10 @@ impl OpLog { } pub(crate) fn encode_snapshot(doc: &LoroDoc, w: &mut W) { + // events should be emitted before encode snapshot + assert!(doc.drop_pending_events().is_empty()); + let old_state_frontiers = doc.state_frontiers(); + let was_detached = doc.is_detached(); let mut state = doc.app_state().try_lock().unwrap(); let oplog = doc.oplog().try_lock().unwrap(); let is_gc = state.store.gc_store().is_some(); @@ -169,11 +173,7 @@ pub(crate) fn encode_snapshot(doc: &LoroDoc, w: &mut W) { return; } assert!(!state.is_in_txn()); - assert_eq!(oplog.frontiers(), &state.frontiers); - let oplog_bytes = oplog.encode_change_store(); - state.ensure_all_alive_containers(); - if oplog.is_trimmed() { assert_eq!( oplog.trimmed_frontiers(), @@ -181,6 +181,15 @@ pub(crate) fn encode_snapshot(doc: &LoroDoc, w: &mut W) { ); } + if was_detached { + let latest = oplog.frontiers().clone(); + drop(oplog); + drop(state); + doc.checkout_without_emitting(&latest).unwrap(); + state = doc.app_state().try_lock().unwrap(); + } + + state.ensure_all_alive_containers(); let state_bytes = state.store.encode(); _encode_snapshot( Snapshot { @@ -190,6 +199,12 @@ pub(crate) fn encode_snapshot(doc: &LoroDoc, w: &mut W) { }, w, ); + + if was_detached { + drop(state); + doc.checkout_without_emitting(&old_state_frontiers).unwrap(); + doc.drop_pending_events(); + } } pub(crate) fn encode_snapshot_at( diff --git a/crates/loro-internal/src/loro.rs b/crates/loro-internal/src/loro.rs index fe88a843..3ee7d3f4 100644 --- a/crates/loro-internal/src/loro.rs +++ b/crates/loro-internal/src/loro.rs @@ -44,7 +44,7 @@ use crate::{ undo::DiffBatch, utils::subscription::{SubscriberSet, Subscription}, version::{shrink_frontiers, Frontiers, ImVersionVector}, - HandlerTrait, InternalString, ListHandler, LoroError, MapHandler, VersionVector, + DocDiff, HandlerTrait, InternalString, ListHandler, LoroError, MapHandler, VersionVector, }; pub use crate::encoding::ExportMode; @@ -546,11 +546,9 @@ impl LoroDoc { } } - pub(crate) fn drop_pending_events(&self) { - let _events = { - let mut state = self.state.lock().unwrap(); - state.take_events() - }; + pub(crate) fn drop_pending_events(&self) -> Vec { + let mut state = self.state.lock().unwrap(); + state.take_events() } #[instrument(skip_all)] diff --git a/crates/loro/tests/loro_rust_test.rs b/crates/loro/tests/loro_rust_test.rs index 86026525..be25da4d 100644 --- a/crates/loro/tests/loro_rust_test.rs +++ b/crates/loro/tests/loro_rust_test.rs @@ -1729,3 +1729,21 @@ fn change_peer_id() { doc.set_peer_id(4).unwrap(); assert_eq!(received_peer_id.load(Ordering::SeqCst), 3); } + +#[test] +fn test_encode_snapshot_when_checkout() { + let doc = LoroDoc::new(); + doc.get_text("text").insert(0, "Hello").unwrap(); + doc.commit(); + let f = doc.state_frontiers(); + doc.get_text("text").insert(5, " World").unwrap(); + doc.commit(); + doc.checkout(&f).unwrap(); + let snapshot = doc.export(loro::ExportMode::snapshot()); + let new_doc = LoroDoc::new(); + new_doc.import(&snapshot).unwrap(); + assert_eq!( + new_doc.get_deep_value().to_json_value(), + json!({"text": "Hello World"}) + ); +}