From 4683dbee45bd6904949dfe71becae0b17884751d Mon Sep 17 00:00:00 2001 From: appflowy Date: Tue, 16 Aug 2022 11:24:37 +0800 Subject: [PATCH 1/2] chore: add revision reset helper --- frontend/rust-lib/Cargo.lock | 1 + .../src/services/persistence/migration.rs | 80 ++++++++---- .../src/services/persistence/mod.rs | 5 +- frontend/rust-lib/flowy-grid/src/manager.rs | 5 +- .../flowy-grid/src/services/grid_editor.rs | 4 +- .../src/services/grid_view_manager.rs | 15 +-- frontend/rust-lib/flowy-revision/Cargo.toml | 1 + .../flowy-revision/src/cache/disk/mod.rs | 47 ++++++- .../rust-lib/flowy-revision/src/cache/mod.rs | 1 + .../flowy-revision/src/cache/reset.rs | 115 ++++++++++++++++++ .../flowy-revision/src/rev_persistence.rs | 10 +- frontend/rust-lib/flowy-sdk/src/lib.rs | 1 + frontend/rust-lib/lib-dispatch/src/data.rs | 2 +- .../src/revision/view_rev.rs | 2 +- .../src/revision/grid_rev.rs | 6 +- .../src/client_folder/folder_pad.rs | 9 +- .../src/client_grid/grid_builder.rs | 10 +- 17 files changed, 259 insertions(+), 55 deletions(-) create mode 100644 frontend/rust-lib/flowy-revision/src/cache/reset.rs diff --git a/frontend/rust-lib/Cargo.lock b/frontend/rust-lib/Cargo.lock index fba225a3a3..7534492ab0 100644 --- a/frontend/rust-lib/Cargo.lock +++ b/frontend/rust-lib/Cargo.lock @@ -1039,6 +1039,7 @@ dependencies = [ "lib-ot", "lib-ws", "serde", + "serde_json", "strum", "strum_macros", "tokio", diff --git a/frontend/rust-lib/flowy-folder/src/services/persistence/migration.rs b/frontend/rust-lib/flowy-folder/src/services/persistence/migration.rs index d67d062d25..b8be0b1e19 100644 --- a/frontend/rust-lib/flowy-folder/src/services/persistence/migration.rs +++ b/frontend/rust-lib/flowy-folder/src/services/persistence/migration.rs @@ -6,14 +6,20 @@ use crate::{ use flowy_database::kv::KV; use flowy_error::{FlowyError, FlowyResult}; -use flowy_folder_data_model::revision::{AppRevision, ViewRevision, WorkspaceRevision}; +use flowy_folder_data_model::revision::{AppRevision, FolderRevision, ViewRevision, WorkspaceRevision}; use flowy_revision::disk::SQLiteTextBlockRevisionPersistence; -use flowy_revision::{RevisionLoader, RevisionPersistence}; +use flowy_revision::reset::{RevisionResettable, RevisionStructReset}; + +use flowy_sync::client_folder::make_folder_rev_json_str; +use flowy_sync::entities::revision::Revision; use flowy_sync::{client_folder::FolderPad, entities::revision::md5}; + use std::sync::Arc; const V1_MIGRATION: &str = "FOLDER_V1_MIGRATION"; const V2_MIGRATION: &str = "FOLDER_V2_MIGRATION"; +#[allow(dead_code)] +const V3_MIGRATION: &str = "FOLDER_V3_MIGRATION"; pub(crate) struct FolderMigration { user_id: String, @@ -79,32 +85,58 @@ impl FolderMigration { Ok(Some(folder)) } - pub async fn run_v2_migration(&self, user_id: &str, folder_id: &FolderId) -> FlowyResult> { + pub async fn run_v2_migration(&self, folder_id: &FolderId) -> FlowyResult<()> { let key = md5(format!("{}{}", self.user_id, V2_MIGRATION)); if KV::get_bool(&key) { - return Ok(None); + return Ok(()); } - let pool = self.database.db_pool()?; - let disk_cache = SQLiteTextBlockRevisionPersistence::new(user_id, pool); - let rev_persistence = Arc::new(RevisionPersistence::new(user_id, folder_id.as_ref(), disk_cache)); - let (revisions, _) = RevisionLoader { - object_id: folder_id.as_ref().to_owned(), - user_id: self.user_id.clone(), - cloud: None, - rev_persistence, - } - .load() - .await?; - - if revisions.is_empty() { - tracing::trace!("Run folder v2 migration, but revision is empty"); - KV::set_bool(&key, true); - return Ok(None); - } - - let pad = FolderPad::from_revisions(revisions)?; + let _ = self.migration_folder_rev_struct_if_need(folder_id).await?; KV::set_bool(&key, true); tracing::trace!("Run folder v2 migration"); - Ok(Some(pad)) + Ok(()) + } + #[allow(dead_code)] + pub async fn run_v3_migration(&self, folder_id: &FolderId) -> FlowyResult<()> { + let key = md5(format!("{}{}", self.user_id, V3_MIGRATION)); + if KV::get_bool(&key) { + return Ok(()); + } + let _ = self.migration_folder_rev_struct_if_need(folder_id).await?; + KV::set_bool(&key, true); + tracing::trace!("Run folder v3 migration"); + Ok(()) + } + + pub async fn migration_folder_rev_struct_if_need(&self, folder_id: &FolderId) -> FlowyResult<()> { + let object = FolderRevisionResettable { + folder_id: folder_id.as_ref().to_owned(), + }; + + let pool = self.database.db_pool()?; + let disk_cache = SQLiteTextBlockRevisionPersistence::new(&self.user_id, pool); + let reset = RevisionStructReset::new(&self.user_id, object, Arc::new(disk_cache)); + reset.run().await + } +} + +pub struct FolderRevisionResettable { + folder_id: String, +} + +impl RevisionResettable for FolderRevisionResettable { + fn target_id(&self) -> &str { + &self.folder_id + } + + fn target_reset_rev_str(&self, revisions: Vec) -> FlowyResult { + let pad = FolderPad::from_revisions(revisions)?; + let json = pad.to_json()?; + Ok(json) + } + + fn default_target_rev_str(&self) -> FlowyResult { + let folder = FolderRevision::default(); + let json = make_folder_rev_json_str(&folder)?; + Ok(json) } } diff --git a/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs b/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs index ffa5219aa8..dcd28d1906 100644 --- a/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs +++ b/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs @@ -100,10 +100,9 @@ impl FolderPersistence { self.save_folder(user_id, folder_id, migrated_folder).await?; } - if let Some(migrated_folder) = migrations.run_v2_migration(user_id, folder_id).await? { - self.save_folder(user_id, folder_id, migrated_folder).await?; - } + let _ = migrations.run_v2_migration(folder_id).await?; + // let _ = migrations.run_v3_migration(folder_id).await?; Ok(()) } diff --git a/frontend/rust-lib/flowy-grid/src/manager.rs b/frontend/rust-lib/flowy-grid/src/manager.rs index 4b4ea3b167..048fc58415 100644 --- a/frontend/rust-lib/flowy-grid/src/manager.rs +++ b/frontend/rust-lib/flowy-grid/src/manager.rs @@ -193,7 +193,7 @@ pub async fn make_grid_view_data( grid_manager: Arc, build_context: BuildGridContext, ) -> FlowyResult { - for block_meta_data in &build_context.blocks_meta_data { + for block_meta_data in &build_context.blocks { let block_id = &block_meta_data.block_id; // Indexing the block's rows block_meta_data.rows.iter().for_each(|row| { @@ -208,6 +208,7 @@ pub async fn make_grid_view_data( let _ = grid_manager.create_grid_block(&block_id, repeated_revision).await?; } + // Will replace the grid_id with the value returned by the gen_grid_id() let grid_id = view_id.to_owned(); let grid_rev = GridRevision::from_build_context(&grid_id, build_context); @@ -219,7 +220,7 @@ pub async fn make_grid_view_data( let _ = grid_manager.create_grid(&grid_id, repeated_revision).await?; // Create grid view - let grid_view = GridViewRevision::new(view_id.to_owned(), view_id.to_owned()); + let grid_view = GridViewRevision::new(grid_id, view_id.to_owned()); let grid_view_delta = make_grid_view_delta(&grid_view); let grid_view_delta_bytes = grid_view_delta.json_bytes(); let repeated_revision: RepeatedRevision = diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs index cb35819b55..d1aa57a2a0 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -546,8 +546,8 @@ impl GridRevisionEditor { Ok(BuildGridContext { field_revs: duplicated_fields.into_iter().map(Arc::new).collect(), - blocks: duplicated_blocks, - blocks_meta_data, + block_metas: duplicated_blocks, + blocks: blocks_meta_data, }) } diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_view_manager.rs b/frontend/rust-lib/flowy-grid/src/services/grid_view_manager.rs index 70768ef3a4..cdaf72665e 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_view_manager.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_view_manager.rs @@ -1,23 +1,18 @@ +use crate::entities::{CreateRowParams, GridFilterConfiguration, GridSettingPB, RepeatedGridGroupPB, RowPB}; use crate::manager::GridUser; +use crate::services::block_manager::GridBlockManager; +use crate::services::grid_editor_task::GridServiceTaskScheduler; use crate::services::grid_view_editor::{GridViewRevisionDataSource, GridViewRevisionDelegate, GridViewRevisionEditor}; use bytes::Bytes; - -use crate::entities::{CreateRowParams, GridFilterConfiguration, GridSettingPB, RepeatedGridGroupPB, RowPB}; -use crate::services::grid_editor_task::GridServiceTaskScheduler; - -use crate::services::block_manager::GridBlockManager; use dashmap::DashMap; use flowy_error::FlowyResult; use flowy_grid_data_model::revision::{FieldRevision, RowRevision}; use flowy_revision::disk::SQLiteGridViewRevisionPersistence; use flowy_revision::{RevisionCompactor, RevisionManager, RevisionPersistence, SQLiteRevisionSnapshotPersistence}; use flowy_sync::client_grid::GridRevisionPad; -use flowy_sync::entities::revision::Revision; - -use flowy_sync::util::make_text_delta_from_revisions; - use flowy_sync::entities::grid::GridSettingChangesetParams; - +use flowy_sync::entities::revision::Revision; +use flowy_sync::util::make_text_delta_from_revisions; use lib_infra::future::{wrap_future, AFFuture}; use std::sync::Arc; use tokio::sync::RwLock; diff --git a/frontend/rust-lib/flowy-revision/Cargo.toml b/frontend/rust-lib/flowy-revision/Cargo.toml index 90257699db..e0fdde3271 100644 --- a/frontend/rust-lib/flowy-revision/Cargo.toml +++ b/frontend/rust-lib/flowy-revision/Cargo.toml @@ -23,6 +23,7 @@ dashmap = "5" serde = { version = "1.0", features = ["derive"] } futures-util = "0.3.15" async-stream = "0.3.2" +serde_json = {version = "1.0"} [features] flowy_unit_test = ["lib-ot/flowy_unit_test"] \ No newline at end of file diff --git a/frontend/rust-lib/flowy-revision/src/cache/disk/mod.rs b/frontend/rust-lib/flowy-revision/src/cache/disk/mod.rs index 94c76fab11..501d1e591b 100644 --- a/frontend/rust-lib/flowy-revision/src/cache/disk/mod.rs +++ b/frontend/rust-lib/flowy-revision/src/cache/disk/mod.rs @@ -8,9 +8,10 @@ pub use grid_block_impl::*; pub use grid_impl::*; pub use grid_view_impl::*; -use flowy_error::FlowyResult; +use flowy_error::{FlowyError, FlowyResult}; use flowy_sync::entities::revision::{RevId, Revision, RevisionRange}; use std::fmt::Debug; +use std::sync::Arc; pub trait RevisionDiskCache: Sync + Send { type Error: Debug; @@ -45,6 +46,50 @@ pub trait RevisionDiskCache: Sync + Send { ) -> Result<(), Self::Error>; } +impl RevisionDiskCache for Arc +where + T: RevisionDiskCache, +{ + type Error = FlowyError; + + fn create_revision_records(&self, revision_records: Vec) -> Result<(), Self::Error> { + (**self).create_revision_records(revision_records) + } + + fn read_revision_records( + &self, + object_id: &str, + rev_ids: Option>, + ) -> Result, Self::Error> { + (**self).read_revision_records(object_id, rev_ids) + } + + fn read_revision_records_with_range( + &self, + object_id: &str, + range: &RevisionRange, + ) -> Result, Self::Error> { + (**self).read_revision_records_with_range(object_id, range) + } + + fn update_revision_record(&self, changesets: Vec) -> FlowyResult<()> { + (**self).update_revision_record(changesets) + } + + fn delete_revision_records(&self, object_id: &str, rev_ids: Option>) -> Result<(), Self::Error> { + (**self).delete_revision_records(object_id, rev_ids) + } + + fn delete_and_insert_records( + &self, + object_id: &str, + deleted_rev_ids: Option>, + inserted_records: Vec, + ) -> Result<(), Self::Error> { + (**self).delete_and_insert_records(object_id, deleted_rev_ids, inserted_records) + } +} + #[derive(Clone, Debug)] pub struct RevisionRecord { pub revision: Revision, diff --git a/frontend/rust-lib/flowy-revision/src/cache/mod.rs b/frontend/rust-lib/flowy-revision/src/cache/mod.rs index 3e592c49b1..4f3ee5c19f 100644 --- a/frontend/rust-lib/flowy-revision/src/cache/mod.rs +++ b/frontend/rust-lib/flowy-revision/src/cache/mod.rs @@ -1,2 +1,3 @@ pub mod disk; pub(crate) mod memory; +pub mod reset; diff --git a/frontend/rust-lib/flowy-revision/src/cache/reset.rs b/frontend/rust-lib/flowy-revision/src/cache/reset.rs new file mode 100644 index 0000000000..cc9228e9ff --- /dev/null +++ b/frontend/rust-lib/flowy-revision/src/cache/reset.rs @@ -0,0 +1,115 @@ +use crate::disk::{RevisionDiskCache, RevisionRecord}; +use crate::{RevisionLoader, RevisionPersistence}; +use flowy_database::kv::KV; +use flowy_error::{FlowyError, FlowyResult}; +use flowy_sync::entities::revision::Revision; +use lib_ot::core::TextDeltaBuilder; +use serde::{Deserialize, Serialize}; +use std::str::FromStr; +use std::sync::Arc; + +pub trait RevisionResettable { + fn target_id(&self) -> &str; + // String in json format + fn target_reset_rev_str(&self, revisions: Vec) -> FlowyResult; + + // String in json format + fn default_target_rev_str(&self) -> FlowyResult; +} + +pub struct RevisionStructReset { + user_id: String, + target: T, + disk_cache: Arc>, +} + +impl RevisionStructReset +where + T: RevisionResettable, +{ + pub fn new(user_id: &str, object: T, disk_cache: Arc>) -> Self { + Self { + user_id: user_id.to_owned(), + target: object, + disk_cache, + } + } + + pub async fn run(&self) -> FlowyResult<()> { + match KV::get_str(self.target.target_id()) { + None => { + tracing::trace!("😁 reset object"); + let _ = self.reset_object().await?; + let _ = self.save_migrate_record()?; + } + Some(s) => { + let mut record = MigrationGridRecord::from_str(&s)?; + let rev_str = self.target.default_target_rev_str()?; + if record.len < rev_str.len() { + let _ = self.reset_object().await?; + record.len = rev_str.len(); + KV::set_str(self.target.target_id(), record.to_string()); + } + } + } + Ok(()) + } + + async fn reset_object(&self) -> FlowyResult<()> { + let rev_persistence = Arc::new(RevisionPersistence::from_disk_cache( + &self.user_id, + self.target.target_id(), + self.disk_cache.clone(), + )); + let (revisions, _) = RevisionLoader { + object_id: self.target.target_id().to_owned(), + user_id: self.user_id.clone(), + cloud: None, + rev_persistence, + } + .load() + .await?; + + let s = self.target.target_reset_rev_str(revisions)?; + let delta_data = TextDeltaBuilder::new().insert(&s).build().json_bytes(); + let revision = Revision::initial_revision(&self.user_id, self.target.target_id(), delta_data); + let record = RevisionRecord::new(revision); + + tracing::trace!("Reset {} revision record object", self.target.target_id()); + let _ = self + .disk_cache + .delete_and_insert_records(self.target.target_id(), None, vec![record]); + + Ok(()) + } + + fn save_migrate_record(&self) -> FlowyResult<()> { + let rev_str = self.target.default_target_rev_str()?; + let record = MigrationGridRecord { + object_id: self.target.target_id().to_owned(), + len: rev_str.len(), + }; + KV::set_str(self.target.target_id(), record.to_string()); + Ok(()) + } +} + +#[derive(Serialize, Deserialize)] +struct MigrationGridRecord { + object_id: String, + len: usize, +} + +impl FromStr for MigrationGridRecord { + type Err = serde_json::Error; + + fn from_str(s: &str) -> Result { + serde_json::from_str::(s) + } +} + +impl ToString for MigrationGridRecord { + fn to_string(&self) -> String { + serde_json::to_string(self).unwrap_or_else(|_| "".to_string()) + } +} diff --git a/frontend/rust-lib/flowy-revision/src/rev_persistence.rs b/frontend/rust-lib/flowy-revision/src/rev_persistence.rs index eb3da339b7..01f4a4189d 100644 --- a/frontend/rust-lib/flowy-revision/src/rev_persistence.rs +++ b/frontend/rust-lib/flowy-revision/src/rev_persistence.rs @@ -28,9 +28,17 @@ impl RevisionPersistence { where C: 'static + RevisionDiskCache, { + let disk_cache = Arc::new(disk_cache) as Arc>; + Self::from_disk_cache(user_id, object_id, disk_cache) + } + + pub fn from_disk_cache( + user_id: &str, + object_id: &str, + disk_cache: Arc>, + ) -> RevisionPersistence { let object_id = object_id.to_owned(); let user_id = user_id.to_owned(); - let disk_cache = Arc::new(disk_cache) as Arc>; let sync_seq = RwLock::new(RevisionSyncSequence::new()); let memory_cache = Arc::new(RevisionMemoryCache::new(&object_id, Arc::new(disk_cache.clone()))); Self { diff --git a/frontend/rust-lib/flowy-sdk/src/lib.rs b/frontend/rust-lib/flowy-sdk/src/lib.rs index 00a3785122..602e1d2092 100644 --- a/frontend/rust-lib/flowy-sdk/src/lib.rs +++ b/frontend/rust-lib/flowy-sdk/src/lib.rs @@ -75,6 +75,7 @@ fn crate_log_filter(level: String) -> String { filters.push(format!("lib_ws={}", level)); filters.push(format!("lib_infra={}", level)); filters.push(format!("flowy_sync={}", level)); + filters.push(format!("flowy_revision={}", level)); // filters.push(format!("lib_dispatch={}", level)); filters.push(format!("dart_ffi={}", "info")); diff --git a/frontend/rust-lib/lib-dispatch/src/data.rs b/frontend/rust-lib/lib-dispatch/src/data.rs index 15f9684a16..74d5ab6f17 100644 --- a/frontend/rust-lib/lib-dispatch/src/data.rs +++ b/frontend/rust-lib/lib-dispatch/src/data.rs @@ -57,7 +57,7 @@ where match self.into_inner().into_bytes() { Ok(bytes) => { log::trace!("Serialize Data: {:?} to event response", std::any::type_name::()); - return ResponseBuilder::Ok().data(bytes).build(); + ResponseBuilder::Ok().data(bytes).build() } Err(e) => e.into(), } diff --git a/shared-lib/flowy-folder-data-model/src/revision/view_rev.rs b/shared-lib/flowy-folder-data-model/src/revision/view_rev.rs index e542fb9bbd..84b447a384 100644 --- a/shared-lib/flowy-folder-data-model/src/revision/view_rev.rs +++ b/shared-lib/flowy-folder-data-model/src/revision/view_rev.rs @@ -18,7 +18,7 @@ pub struct ViewRevision { #[serde(default)] pub data_type: ViewDataTypeRevision, - pub version: i64, + pub version: i64, // Deprecated pub belongings: Vec, diff --git a/shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs b/shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs index 31e6265757..f8303c973d 100644 --- a/shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs +++ b/shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs @@ -38,7 +38,7 @@ impl GridRevision { Self { grid_id: grid_id.to_owned(), fields: context.field_revs, - blocks: context.blocks.into_iter().map(Arc::new).collect(), + blocks: context.block_metas.into_iter().map(Arc::new).collect(), } } } @@ -186,8 +186,8 @@ pub trait TypeOptionDataDeserializer { #[derive(Clone, Default, Deserialize, Serialize)] pub struct BuildGridContext { pub field_revs: Vec>, - pub blocks: Vec, - pub blocks_meta_data: Vec, + pub block_metas: Vec, + pub blocks: Vec, } impl BuildGridContext { diff --git a/shared-lib/flowy-sync/src/client_folder/folder_pad.rs b/shared-lib/flowy-sync/src/client_folder/folder_pad.rs index 63df0ce828..acef097250 100644 --- a/shared-lib/flowy-sync/src/client_folder/folder_pad.rs +++ b/shared-lib/flowy-sync/src/client_folder/folder_pad.rs @@ -319,11 +319,16 @@ impl FolderPad { } pub fn to_json(&self) -> CollaborateResult { - serde_json::to_string(&self.folder_rev) - .map_err(|e| CollaborateError::internal().context(format!("serial trash to json failed: {}", e))) + make_folder_rev_json_str(&self.folder_rev) } } +pub fn make_folder_rev_json_str(folder_rev: &FolderRevision) -> CollaborateResult { + let json = serde_json::to_string(folder_rev) + .map_err(|err| internal_error(format!("Serialize folder to json str failed. {:?}", err)))?; + Ok(json) +} + impl FolderPad { fn modify_workspaces(&mut self, f: F) -> CollaborateResult> where diff --git a/shared-lib/flowy-sync/src/client_grid/grid_builder.rs b/shared-lib/flowy-sync/src/client_grid/grid_builder.rs index ea5d5a9332..ad3f443505 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_builder.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_builder.rs @@ -18,8 +18,8 @@ impl std::default::Default for GridBuilder { rows: vec![], }; - build_context.blocks.push(block_meta); - build_context.blocks_meta_data.push(block_meta_data); + build_context.block_metas.push(block_meta); + build_context.blocks.push(block_meta_data); GridBuilder { build_context } } @@ -34,8 +34,8 @@ impl GridBuilder { } pub fn add_row(&mut self, row_rev: RowRevision) { - let block_meta_rev = self.build_context.blocks.first_mut().unwrap(); - let block_rev = self.build_context.blocks_meta_data.first_mut().unwrap(); + let block_meta_rev = self.build_context.block_metas.first_mut().unwrap(); + let block_rev = self.build_context.blocks.first_mut().unwrap(); block_rev.rows.push(Arc::new(row_rev)); block_meta_rev.row_count += 1; } @@ -50,7 +50,7 @@ impl GridBuilder { } pub fn block_id(&self) -> &str { - &self.build_context.blocks.first().unwrap().block_id + &self.build_context.block_metas.first().unwrap().block_id } pub fn build(self) -> BuildGridContext { From 03a70bbdb953a46bb771e1f6962125ad6b969d58 Mon Sep 17 00:00:00 2001 From: appflowy Date: Tue, 16 Aug 2022 11:37:34 +0800 Subject: [PATCH 2/2] chore: update grid migration --- .../src/services/persistence/migration.rs | 20 +-- frontend/rust-lib/flowy-grid/src/manager.rs | 2 +- .../src/services/persistence/migration.rs | 114 ++++++------------ 3 files changed, 49 insertions(+), 87 deletions(-) diff --git a/frontend/rust-lib/flowy-folder/src/services/persistence/migration.rs b/frontend/rust-lib/flowy-folder/src/services/persistence/migration.rs index b8be0b1e19..7b211fb54a 100644 --- a/frontend/rust-lib/flowy-folder/src/services/persistence/migration.rs +++ b/frontend/rust-lib/flowy-folder/src/services/persistence/migration.rs @@ -5,15 +5,12 @@ use crate::{ }; use flowy_database::kv::KV; use flowy_error::{FlowyError, FlowyResult}; - use flowy_folder_data_model::revision::{AppRevision, FolderRevision, ViewRevision, WorkspaceRevision}; use flowy_revision::disk::SQLiteTextBlockRevisionPersistence; use flowy_revision::reset::{RevisionResettable, RevisionStructReset}; - use flowy_sync::client_folder::make_folder_rev_json_str; use flowy_sync::entities::revision::Revision; use flowy_sync::{client_folder::FolderPad, entities::revision::md5}; - use std::sync::Arc; const V1_MIGRATION: &str = "FOLDER_V1_MIGRATION"; @@ -35,7 +32,7 @@ impl FolderMigration { } pub fn run_v1_migration(&self) -> FlowyResult> { - let key = md5(format!("{}{}", self.user_id, V1_MIGRATION)); + let key = migration_flag_key(&self.user_id, V1_MIGRATION); if KV::get_bool(&key) { return Ok(None); } @@ -86,28 +83,29 @@ impl FolderMigration { } pub async fn run_v2_migration(&self, folder_id: &FolderId) -> FlowyResult<()> { - let key = md5(format!("{}{}", self.user_id, V2_MIGRATION)); + let key = migration_flag_key(&self.user_id, V2_MIGRATION); if KV::get_bool(&key) { return Ok(()); } - let _ = self.migration_folder_rev_struct_if_need(folder_id).await?; + let _ = self.migration_folder_rev_struct(folder_id).await?; KV::set_bool(&key, true); tracing::trace!("Run folder v2 migration"); Ok(()) } + #[allow(dead_code)] pub async fn run_v3_migration(&self, folder_id: &FolderId) -> FlowyResult<()> { - let key = md5(format!("{}{}", self.user_id, V3_MIGRATION)); + let key = migration_flag_key(&self.user_id, V3_MIGRATION); if KV::get_bool(&key) { return Ok(()); } - let _ = self.migration_folder_rev_struct_if_need(folder_id).await?; + let _ = self.migration_folder_rev_struct(folder_id).await?; KV::set_bool(&key, true); tracing::trace!("Run folder v3 migration"); Ok(()) } - pub async fn migration_folder_rev_struct_if_need(&self, folder_id: &FolderId) -> FlowyResult<()> { + pub async fn migration_folder_rev_struct(&self, folder_id: &FolderId) -> FlowyResult<()> { let object = FolderRevisionResettable { folder_id: folder_id.as_ref().to_owned(), }; @@ -119,6 +117,10 @@ impl FolderMigration { } } +fn migration_flag_key(user_id: &str, version: &str) -> String { + md5(format!("{}{}", user_id, version,)) +} + pub struct FolderRevisionResettable { folder_id: String, } diff --git a/frontend/rust-lib/flowy-grid/src/manager.rs b/frontend/rust-lib/flowy-grid/src/manager.rs index 048fc58415..9e4556b793 100644 --- a/frontend/rust-lib/flowy-grid/src/manager.rs +++ b/frontend/rust-lib/flowy-grid/src/manager.rs @@ -96,7 +96,7 @@ impl GridManager { pub async fn open_grid>(&self, grid_id: T) -> FlowyResult> { let grid_id = grid_id.as_ref(); tracing::Span::current().record("grid_id", &grid_id); - let _ = self.migration.migration_grid_if_need(grid_id).await; + let _ = self.migration.run_v1_migration(grid_id).await; self.get_or_create_grid_editor(grid_id).await } diff --git a/frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs b/frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs index bf3aa7adfb..cb99d8eb6d 100644 --- a/frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs +++ b/frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs @@ -1,19 +1,17 @@ use crate::manager::GridUser; - use crate::services::persistence::GridDatabase; use flowy_database::kv::KV; use flowy_error::FlowyResult; use flowy_grid_data_model::revision::GridRevision; -use flowy_revision::disk::{RevisionRecord, SQLiteGridRevisionPersistence}; -use flowy_revision::{mk_grid_block_revision_disk_cache, RevisionLoader, RevisionPersistence}; +use flowy_revision::disk::SQLiteGridRevisionPersistence; +use flowy_revision::reset::{RevisionResettable, RevisionStructReset}; use flowy_sync::client_grid::{make_grid_rev_json_str, GridRevisionPad}; use flowy_sync::entities::revision::Revision; - -use lib_ot::core::TextDeltaBuilder; -use serde::{Deserialize, Serialize}; -use std::str::FromStr; +use flowy_sync::util::md5; use std::sync::Arc; +const V1_MIGRATION: &str = "GRID_V1_MIGRATION"; + pub(crate) struct GridMigration { user: Arc, database: Arc, @@ -24,90 +22,52 @@ impl GridMigration { Self { user, database } } - pub async fn migration_grid_if_need(&self, grid_id: &str) -> FlowyResult<()> { - match KV::get_str(grid_id) { - None => { - let _ = self.reset_grid_rev(grid_id).await?; - let _ = self.save_migrate_record(grid_id)?; - } - Some(s) => { - let mut record = MigrationGridRecord::from_str(&s)?; - let empty_json = self.empty_grid_rev_json()?; - if record.len < empty_json.len() { - let _ = self.reset_grid_rev(grid_id).await?; - record.len = empty_json.len(); - KV::set_str(grid_id, record.to_string()); - } - } - } - Ok(()) - } - - async fn reset_grid_rev(&self, grid_id: &str) -> FlowyResult<()> { + pub async fn run_v1_migration(&self, grid_id: &str) -> FlowyResult<()> { let user_id = self.user.user_id()?; - let pool = self.database.db_pool()?; - let grid_rev_pad = self.get_grid_revision_pad(grid_id).await?; - let json = grid_rev_pad.json_str()?; - let delta_data = TextDeltaBuilder::new().insert(&json).build().json_bytes(); - let revision = Revision::initial_revision(&user_id, grid_id, delta_data); - let record = RevisionRecord::new(revision); - // - let disk_cache = mk_grid_block_revision_disk_cache(&user_id, pool); - let _ = disk_cache.delete_and_insert_records(grid_id, None, vec![record]); + let key = migration_flag_key(&user_id, V1_MIGRATION, grid_id); + if KV::get_bool(&key) { + return Ok(()); + } + let _ = self.migration_grid_rev_struct(grid_id).await?; + tracing::trace!("Run grid:{} v1 migration", grid_id); + KV::set_bool(&key, true); Ok(()) } - fn save_migrate_record(&self, grid_id: &str) -> FlowyResult<()> { - let empty_json_str = self.empty_grid_rev_json()?; - let record = MigrationGridRecord { + pub async fn migration_grid_rev_struct(&self, grid_id: &str) -> FlowyResult<()> { + let object = GridRevisionResettable { grid_id: grid_id.to_owned(), - len: empty_json_str.len(), }; - KV::set_str(grid_id, record.to_string()); - Ok(()) - } - - fn empty_grid_rev_json(&self) -> FlowyResult { - let empty_grid_rev = GridRevision::default(); - let empty_json = make_grid_rev_json_str(&empty_grid_rev)?; - Ok(empty_json) - } - - async fn get_grid_revision_pad(&self, grid_id: &str) -> FlowyResult { - let pool = self.database.db_pool()?; let user_id = self.user.user_id()?; + let pool = self.database.db_pool()?; let disk_cache = SQLiteGridRevisionPersistence::new(&user_id, pool); - let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, grid_id, disk_cache)); - let (revisions, _) = RevisionLoader { - object_id: grid_id.to_owned(), - user_id, - cloud: None, - rev_persistence, - } - .load() - .await?; - - let pad = GridRevisionPad::from_revisions(revisions)?; - Ok(pad) + let reset = RevisionStructReset::new(&user_id, object, Arc::new(disk_cache)); + reset.run().await } } -#[derive(Serialize, Deserialize)] -struct MigrationGridRecord { +fn migration_flag_key(user_id: &str, version: &str, grid_id: &str) -> String { + md5(format!("{}{}{}", user_id, version, grid_id,)) +} + +pub struct GridRevisionResettable { grid_id: String, - len: usize, } -impl FromStr for MigrationGridRecord { - type Err = serde_json::Error; +impl RevisionResettable for GridRevisionResettable { + fn target_id(&self) -> &str { + &self.grid_id + } - fn from_str(s: &str) -> Result { - serde_json::from_str::(s) - } -} - -impl ToString for MigrationGridRecord { - fn to_string(&self) -> String { - serde_json::to_string(self).unwrap_or_else(|_| "".to_string()) + fn target_reset_rev_str(&self, revisions: Vec) -> FlowyResult { + let pad = GridRevisionPad::from_revisions(revisions)?; + let json = pad.json_str()?; + Ok(json) + } + + fn default_target_rev_str(&self) -> FlowyResult { + let grid_rev = GridRevision::default(); + let json = make_grid_rev_json_str(&grid_rev)?; + Ok(json) } }