Skip to content

Commit 6425997

Browse files
committed
chore: merge lagging revisions when close the document
1 parent ebdd28c commit 6425997

File tree

16 files changed

+154
-88
lines changed

16 files changed

+154
-88
lines changed

frontend/rust-lib/flowy-document/src/editor/editor.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,13 @@ fn spawn_edit_queue(
8383
}
8484

8585
impl DocumentEditor for Arc<AppFlowyDocumentEditor> {
86-
fn close(&self) {}
86+
#[tracing::instrument(name = "close document editor", level = "trace", skip_all)]
87+
fn close(&self) {
88+
let rev_manager = self.rev_manager.clone();
89+
tokio::spawn(async move {
90+
rev_manager.close().await;
91+
});
92+
}
8793

8894
fn export(&self) -> FutureResult<String, FlowyError> {
8995
let this = self.clone();

frontend/rust-lib/flowy-document/src/manager.rs

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::services::rev_sqlite::{SQLiteDeltaDocumentRevisionPersistence, SQLite
55
use crate::services::DocumentPersistence;
66
use crate::{errors::FlowyError, DocumentCloudService};
77
use bytes::Bytes;
8-
use dashmap::DashMap;
8+
99
use flowy_database::ConnectionPool;
1010
use flowy_error::FlowyResult;
1111
use flowy_revision::{
@@ -16,9 +16,11 @@ use flowy_sync::client_document::initial_delta_document_content;
1616
use flowy_sync::entities::{document::DocumentIdPB, revision::Revision, ws_data::ServerRevisionWSData};
1717
use flowy_sync::util::md5;
1818
use lib_infra::future::FutureResult;
19+
use lib_infra::ref_map::{RefCountHashMap, RefCountValue};
1920
use lib_ws::WSConnectState;
2021
use std::any::Any;
2122
use std::{convert::TryInto, sync::Arc};
23+
use tokio::sync::RwLock;
2224

2325
pub trait DocumentUser: Send + Sync {
2426
fn user_dir(&self) -> Result<String, FlowyError>;
@@ -76,7 +78,7 @@ impl std::default::Default for DocumentConfig {
7678
pub struct DocumentManager {
7779
cloud_service: Arc<dyn DocumentCloudService>,
7880
rev_web_socket: Arc<dyn RevisionWebSocket>,
79-
editor_map: Arc<DocumentEditorMap>,
81+
editor_map: Arc<RwLock<RefCountHashMap<RefCountDocumentHandler>>>,
8082
user: Arc<dyn DocumentUser>,
8183
persistence: Arc<DocumentPersistence>,
8284
#[allow(dead_code)]
@@ -94,7 +96,7 @@ impl DocumentManager {
9496
Self {
9597
cloud_service,
9698
rev_web_socket,
97-
editor_map: Arc::new(DocumentEditorMap::new()),
99+
editor_map: Arc::new(RwLock::new(RefCountHashMap::new())),
98100
user: document_user,
99101
persistence: Arc::new(DocumentPersistence::new(database)),
100102
config,
@@ -124,10 +126,10 @@ impl DocumentManager {
124126
}
125127

126128
#[tracing::instrument(level = "trace", skip(self, editor_id), fields(editor_id), err)]
127-
pub fn close_document_editor<T: AsRef<str>>(&self, editor_id: T) -> Result<(), FlowyError> {
129+
pub async fn close_document_editor<T: AsRef<str>>(&self, editor_id: T) -> Result<(), FlowyError> {
128130
let editor_id = editor_id.as_ref();
129131
tracing::Span::current().record("editor_id", &editor_id);
130-
self.editor_map.remove(editor_id);
132+
self.editor_map.write().await.remove(editor_id);
131133
Ok(())
132134
}
133135

@@ -149,9 +151,9 @@ impl DocumentManager {
149151
pub async fn receive_ws_data(&self, data: Bytes) {
150152
let result: Result<ServerRevisionWSData, protobuf::ProtobufError> = data.try_into();
151153
match result {
152-
Ok(data) => match self.editor_map.get(&data.object_id) {
154+
Ok(data) => match self.editor_map.read().await.get(&data.object_id) {
153155
None => tracing::error!("Can't find any source handler for {:?}-{:?}", data.object_id, data.ty),
154-
Some(editor) => match editor.receive_ws_data(data).await {
156+
Some(handler) => match handler.0.receive_ws_data(data).await {
155157
Ok(_) => {}
156158
Err(e) => tracing::error!("{}", e),
157159
},
@@ -180,13 +182,13 @@ impl DocumentManager {
180182
/// returns: Result<Arc<DocumentEditor>, FlowyError>
181183
///
182184
async fn get_document_editor(&self, doc_id: &str) -> FlowyResult<Arc<dyn DocumentEditor>> {
183-
match self.editor_map.get(doc_id) {
185+
match self.editor_map.read().await.get(doc_id) {
184186
None => {
185187
//
186188
tracing::warn!("Should call init_document_editor first");
187189
self.init_document_editor(doc_id).await
188190
}
189-
Some(editor) => Ok(editor),
191+
Some(handler) => Ok(handler.0.clone()),
190192
}
191193
}
192194

@@ -216,14 +218,20 @@ impl DocumentManager {
216218
DeltaDocumentEditor::new(doc_id, user, rev_manager, self.rev_web_socket.clone(), cloud_service)
217219
.await?,
218220
);
219-
self.editor_map.insert(doc_id, editor.clone());
221+
self.editor_map
222+
.write()
223+
.await
224+
.insert(doc_id.to_string(), RefCountDocumentHandler(editor.clone()));
220225
Ok(editor)
221226
}
222227
DocumentVersionPB::V1 => {
223228
let rev_manager = self.make_document_rev_manager(doc_id, pool.clone())?;
224229
let editor: Arc<dyn DocumentEditor> =
225230
Arc::new(AppFlowyDocumentEditor::new(doc_id, user, rev_manager, cloud_service).await?);
226-
self.editor_map.insert(doc_id, editor.clone());
231+
self.editor_map
232+
.write()
233+
.await
234+
.insert(doc_id.to_string(), RefCountDocumentHandler(editor.clone()));
227235
Ok(editor)
228236
}
229237
}
@@ -247,7 +255,7 @@ impl DocumentManager {
247255
) -> Result<RevisionManager<Arc<ConnectionPool>>, FlowyError> {
248256
let user_id = self.user.user_id()?;
249257
let disk_cache = SQLiteDocumentRevisionPersistence::new(&user_id, pool.clone());
250-
let configuration = RevisionPersistenceConfiguration::new(100);
258+
let configuration = RevisionPersistenceConfiguration::new(100, true);
251259
let rev_persistence = RevisionPersistence::new(&user_id, doc_id, disk_cache, configuration);
252260
// let history_persistence = SQLiteRevisionHistoryPersistence::new(doc_id, pool.clone());
253261
let snapshot_persistence = SQLiteRevisionSnapshotPersistence::new(doc_id, pool);
@@ -268,7 +276,7 @@ impl DocumentManager {
268276
) -> Result<RevisionManager<Arc<ConnectionPool>>, FlowyError> {
269277
let user_id = self.user.user_id()?;
270278
let disk_cache = SQLiteDeltaDocumentRevisionPersistence::new(&user_id, pool.clone());
271-
let configuration = RevisionPersistenceConfiguration::new(100);
279+
let configuration = RevisionPersistenceConfiguration::new(100, true);
272280
let rev_persistence = RevisionPersistence::new(&user_id, doc_id, disk_cache, configuration);
273281
// let history_persistence = SQLiteRevisionHistoryPersistence::new(doc_id, pool.clone());
274282
let snapshot_persistence = SQLiteRevisionSnapshotPersistence::new(doc_id, pool);
@@ -309,40 +317,32 @@ impl RevisionCloudService for DocumentRevisionCloudService {
309317
}
310318
}
311319

312-
pub struct DocumentEditorMap {
313-
inner: DashMap<String, Arc<dyn DocumentEditor>>,
314-
}
315-
316-
impl DocumentEditorMap {
317-
fn new() -> Self {
318-
Self { inner: DashMap::new() }
319-
}
320+
#[derive(Clone)]
321+
struct RefCountDocumentHandler(Arc<dyn DocumentEditor>);
320322

321-
pub(crate) fn insert(&self, editor_id: &str, editor: Arc<dyn DocumentEditor>) {
322-
if self.inner.contains_key(editor_id) {
323-
log::warn!("Editor:{} already open", editor_id);
324-
}
325-
self.inner.insert(editor_id.to_string(), editor);
323+
impl RefCountValue for RefCountDocumentHandler {
324+
fn did_remove(&self) {
325+
self.0.close();
326326
}
327+
}
327328

328-
pub(crate) fn get(&self, editor_id: &str) -> Option<Arc<dyn DocumentEditor>> {
329-
Some(self.inner.get(editor_id)?.clone())
330-
}
329+
impl std::ops::Deref for RefCountDocumentHandler {
330+
type Target = Arc<dyn DocumentEditor>;
331331

332-
pub(crate) fn remove(&self, editor_id: &str) {
333-
if let Some(editor) = self.get(editor_id) {
334-
editor.close()
335-
}
336-
self.inner.remove(editor_id);
332+
fn deref(&self) -> &Self::Target {
333+
&self.0
337334
}
338335
}
339336

340337
#[tracing::instrument(level = "trace", skip(web_socket, handlers))]
341-
fn listen_ws_state_changed(web_socket: Arc<dyn RevisionWebSocket>, handlers: Arc<DocumentEditorMap>) {
338+
fn listen_ws_state_changed(
339+
web_socket: Arc<dyn RevisionWebSocket>,
340+
handlers: Arc<RwLock<RefCountHashMap<RefCountDocumentHandler>>>,
341+
) {
342342
tokio::spawn(async move {
343343
let mut notify = web_socket.subscribe_state_changed().await;
344344
while let Ok(state) = notify.recv().await {
345-
handlers.inner.iter().for_each(|handler| {
345+
handlers.read().await.values().iter().for_each(|handler| {
346346
handler.receive_ws_state(&state);
347347
})
348348
}

frontend/rust-lib/flowy-folder/src/manager.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ impl FolderManager {
168168
let pool = self.persistence.db_pool()?;
169169
let object_id = folder_id.as_ref();
170170
let disk_cache = SQLiteFolderRevisionPersistence::new(user_id, pool.clone());
171-
let configuration = RevisionPersistenceConfiguration::new(100);
171+
let configuration = RevisionPersistenceConfiguration::new(100, false);
172172
let rev_persistence = RevisionPersistence::new(user_id, object_id, disk_cache, configuration);
173173
let rev_compactor = FolderRevisionCompress();
174174
// let history_persistence = SQLiteRevisionHistoryPersistence::new(object_id, pool.clone());

frontend/rust-lib/flowy-folder/tests/workspace/script.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ pub enum FolderScript {
7070
DeleteAllTrash,
7171

7272
// Sync
73+
#[allow(dead_code)]
7374
AssertCurrentRevId(i64),
7475
AssertNextSyncRevId(Option<i64>),
7576
AssertRevisionState {

frontend/rust-lib/flowy-grid/src/manager.rs

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
use crate::entities::GridLayout;
2-
use crate::services::block_editor::GridBlockRevisionCompress;
2+
33
use crate::services::grid_editor::{GridRevisionCompress, GridRevisionEditor};
44
use crate::services::grid_view_manager::make_grid_view_rev_manager;
55
use crate::services::persistence::block_index::BlockIndexCache;
66
use crate::services::persistence::kv::GridKVPersistence;
77
use crate::services::persistence::migration::GridMigration;
8-
use crate::services::persistence::rev_sqlite::{SQLiteGridBlockRevisionPersistence, SQLiteGridRevisionPersistence};
8+
use crate::services::persistence::rev_sqlite::SQLiteGridRevisionPersistence;
99
use crate::services::persistence::GridDatabase;
1010
use crate::services::tasks::GridTaskScheduler;
1111
use bytes::Bytes;
12-
use dashmap::DashMap;
12+
1313
use flowy_database::ConnectionPool;
1414
use flowy_error::{FlowyError, FlowyResult};
1515
use flowy_grid_data_model::revision::{BuildGridContext, GridRevision, GridViewRevision};
@@ -20,7 +20,8 @@ use flowy_revision::{
2020
use flowy_sync::client_grid::{make_grid_block_operations, make_grid_operations, make_grid_view_operations};
2121
use flowy_sync::entities::revision::Revision;
2222
use lib_infra::ref_map::{RefCountHashMap, RefCountValue};
23-
use std::collections::HashMap;
23+
24+
use crate::services::block_manager::make_grid_block_rev_manager;
2425
use std::sync::Arc;
2526
use tokio::sync::RwLock;
2627

@@ -92,8 +93,7 @@ impl GridManager {
9293
#[tracing::instrument(level = "debug", skip_all, err)]
9394
pub async fn create_grid_block<T: AsRef<str>>(&self, block_id: T, revisions: Vec<Revision>) -> FlowyResult<()> {
9495
let block_id = block_id.as_ref();
95-
let db_pool = self.grid_user.db_pool()?;
96-
let rev_manager = self.make_grid_block_rev_manager(block_id, db_pool)?;
96+
let rev_manager = make_grid_block_rev_manager(&self.grid_user, block_id)?;
9797
let _ = rev_manager.reset_object(revisions).await?;
9898
Ok(())
9999
}
@@ -119,13 +119,13 @@ impl GridManager {
119119
pub async fn get_grid_editor(&self, grid_id: &str) -> FlowyResult<Arc<GridRevisionEditor>> {
120120
match self.grid_editors.read().await.get(grid_id) {
121121
None => Err(FlowyError::internal().context("Should call open_grid function first")),
122-
Some(editor) => Ok(editor.clone()),
122+
Some(editor) => Ok(editor),
123123
}
124124
}
125125

126126
async fn get_or_create_grid_editor(&self, grid_id: &str) -> FlowyResult<Arc<GridRevisionEditor>> {
127127
if let Some(editor) = self.grid_editors.read().await.get(grid_id) {
128-
return Ok(editor.clone());
128+
return Ok(editor);
129129
}
130130

131131
let db_pool = self.grid_user.db_pool()?;
@@ -164,29 +164,13 @@ impl GridManager {
164164
) -> FlowyResult<RevisionManager<Arc<ConnectionPool>>> {
165165
let user_id = self.grid_user.user_id()?;
166166
let disk_cache = SQLiteGridRevisionPersistence::new(&user_id, pool.clone());
167-
let configuration = RevisionPersistenceConfiguration::new(2);
167+
let configuration = RevisionPersistenceConfiguration::new(2, false);
168168
let rev_persistence = RevisionPersistence::new(&user_id, grid_id, disk_cache, configuration);
169169
let snapshot_persistence = SQLiteRevisionSnapshotPersistence::new(grid_id, pool);
170170
let rev_compactor = GridRevisionCompress();
171171
let rev_manager = RevisionManager::new(&user_id, grid_id, rev_persistence, rev_compactor, snapshot_persistence);
172172
Ok(rev_manager)
173173
}
174-
175-
fn make_grid_block_rev_manager(
176-
&self,
177-
block_id: &str,
178-
pool: Arc<ConnectionPool>,
179-
) -> FlowyResult<RevisionManager<Arc<ConnectionPool>>> {
180-
let user_id = self.grid_user.user_id()?;
181-
let disk_cache = SQLiteGridBlockRevisionPersistence::new(&user_id, pool.clone());
182-
let configuration = RevisionPersistenceConfiguration::new(4);
183-
let rev_persistence = RevisionPersistence::new(&user_id, block_id, disk_cache, configuration);
184-
let rev_compactor = GridBlockRevisionCompress();
185-
let snapshot_persistence = SQLiteRevisionSnapshotPersistence::new(block_id, pool);
186-
let rev_manager =
187-
RevisionManager::new(&user_id, block_id, rev_persistence, rev_compactor, snapshot_persistence);
188-
Ok(rev_manager)
189-
}
190174
}
191175

192176
pub async fn make_grid_view_data(

frontend/rust-lib/flowy-grid/src/services/block_manager.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::services::persistence::block_index::BlockIndexCache;
66
use crate::services::persistence::rev_sqlite::SQLiteGridBlockRevisionPersistence;
77
use crate::services::row::{block_from_row_orders, make_row_from_row_rev, GridBlockSnapshot};
88
use dashmap::DashMap;
9+
use flowy_database::ConnectionPool;
910
use flowy_error::FlowyResult;
1011
use flowy_grid_data_model::revision::{
1112
GridBlockMetaRevision, GridBlockMetaRevisionChangeset, RowChangeset, RowRevision,
@@ -46,7 +47,7 @@ impl GridBlockManager {
4647
match self.block_editors.get(block_id) {
4748
None => {
4849
tracing::error!("This is a fatal error, block with id:{} is not exist", block_id);
49-
let editor = Arc::new(make_block_editor(&self.user, block_id).await?);
50+
let editor = Arc::new(make_grid_block_editor(&self.user, block_id).await?);
5051
self.block_editors.insert(block_id.to_owned(), editor.clone());
5152
Ok(editor)
5253
}
@@ -261,24 +262,32 @@ async fn make_block_editors(
261262
) -> FlowyResult<DashMap<String, Arc<GridBlockRevisionEditor>>> {
262263
let editor_map = DashMap::new();
263264
for block_meta_rev in block_meta_revs {
264-
let editor = make_block_editor(user, &block_meta_rev.block_id).await?;
265+
let editor = make_grid_block_editor(user, &block_meta_rev.block_id).await?;
265266
editor_map.insert(block_meta_rev.block_id.clone(), Arc::new(editor));
266267
}
267268

268269
Ok(editor_map)
269270
}
270271

271-
async fn make_block_editor(user: &Arc<dyn GridUser>, block_id: &str) -> FlowyResult<GridBlockRevisionEditor> {
272+
async fn make_grid_block_editor(user: &Arc<dyn GridUser>, block_id: &str) -> FlowyResult<GridBlockRevisionEditor> {
272273
tracing::trace!("Open block:{} editor", block_id);
273274
let token = user.token()?;
274275
let user_id = user.user_id()?;
275-
let pool = user.db_pool()?;
276+
let rev_manager = make_grid_block_rev_manager(user, block_id)?;
277+
GridBlockRevisionEditor::new(&user_id, &token, block_id, rev_manager).await
278+
}
276279

280+
pub fn make_grid_block_rev_manager(
281+
user: &Arc<dyn GridUser>,
282+
block_id: &str,
283+
) -> FlowyResult<RevisionManager<Arc<ConnectionPool>>> {
284+
let user_id = user.user_id()?;
285+
let pool = user.db_pool()?;
277286
let disk_cache = SQLiteGridBlockRevisionPersistence::new(&user_id, pool.clone());
278-
let configuration = RevisionPersistenceConfiguration::new(4);
287+
let configuration = RevisionPersistenceConfiguration::new(4, false);
279288
let rev_persistence = RevisionPersistence::new(&user_id, block_id, disk_cache, configuration);
280289
let rev_compactor = GridBlockRevisionCompress();
281290
let snapshot_persistence = SQLiteRevisionSnapshotPersistence::new(block_id, pool);
282291
let rev_manager = RevisionManager::new(&user_id, block_id, rev_persistence, rev_compactor, snapshot_persistence);
283-
GridBlockRevisionEditor::new(&user_id, &token, block_id, rev_manager).await
292+
Ok(rev_manager)
284293
}

frontend/rust-lib/flowy-grid/src/services/grid_editor.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,13 @@ impl GridRevisionEditor {
9494
Ok(editor)
9595
}
9696

97-
pub fn close(&self) {}
97+
#[tracing::instrument(name = "close grid editor", level = "trace", skip_all)]
98+
pub fn close(&self) {
99+
let rev_manager = self.rev_manager.clone();
100+
tokio::spawn(async move {
101+
rev_manager.close().await;
102+
});
103+
}
98104

99105
/// Save the type-option data to disk and send a `GridNotification::DidUpdateField` notification
100106
/// to dart side.

frontend/rust-lib/flowy-grid/src/services/grid_view_manager.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ pub async fn make_grid_view_rev_manager(
255255
let pool = user.db_pool()?;
256256

257257
let disk_cache = SQLiteGridViewRevisionPersistence::new(&user_id, pool.clone());
258-
let configuration = RevisionPersistenceConfiguration::new(2);
258+
let configuration = RevisionPersistenceConfiguration::new(2, false);
259259
let rev_persistence = RevisionPersistence::new(&user_id, view_id, disk_cache, configuration);
260260
let rev_compactor = GridViewRevisionCompress();
261261

frontend/rust-lib/flowy-grid/src/services/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
mod util;
22

33
pub mod block_editor;
4-
mod block_manager;
4+
pub mod block_manager;
55
mod block_manager_trait_impl;
66
pub mod cell;
77
pub mod field;

0 commit comments

Comments
 (0)