Fix/read app (#1808)

* fix: filter out the apps that are deleted

* chore: format code style

* chore: fix clippy wanrings
This commit is contained in:
Nathan.fooo 2023-02-06 21:42:01 +08:00 committed by GitHub
parent 1df2619c9f
commit 3491ffdd08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 114 additions and 111 deletions

View File

@ -12,8 +12,8 @@
"type": "dart", "type": "dart",
"preLaunchTask": "AF: Build Appflowy Core", "preLaunchTask": "AF: Build Appflowy Core",
"env": { "env": {
// "RUST_LOG": "trace" "RUST_LOG": "trace"
"RUST_LOG": "debug" // "RUST_LOG": "debug"
}, },
"cwd": "${workspaceRoot}/app_flowy" "cwd": "${workspaceRoot}/app_flowy"
}, },

View File

@ -1,7 +1,7 @@
#![allow(clippy::unused_unit)] #![allow(clippy::unused_unit)]
use bytes::Bytes; use bytes::Bytes;
use flowy_error::{internal_error, FlowyResult}; use flowy_error::{internal_error, FlowyResult};
use flowy_revision::{RevisionSnapshot, RevisionSnapshotDiskCache}; use flowy_revision::{RevisionSnapshotData, RevisionSnapshotPersistence};
use flowy_sqlite::{ use flowy_sqlite::{
prelude::*, prelude::*,
schema::{grid_rev_snapshot, grid_rev_snapshot::dsl}, schema::{grid_rev_snapshot, grid_rev_snapshot::dsl},
@ -28,7 +28,7 @@ impl SQLiteDatabaseRevisionSnapshotPersistence {
} }
} }
impl RevisionSnapshotDiskCache for SQLiteDatabaseRevisionSnapshotPersistence { impl RevisionSnapshotPersistence for SQLiteDatabaseRevisionSnapshotPersistence {
fn write_snapshot(&self, rev_id: i64, data: Vec<u8>) -> FlowyResult<()> { fn write_snapshot(&self, rev_id: i64, data: Vec<u8>) -> FlowyResult<()> {
let conn = self.pool.get().map_err(internal_error)?; let conn = self.pool.get().map_err(internal_error)?;
let snapshot_id = self.gen_snapshot_id(rev_id); let snapshot_id = self.gen_snapshot_id(rev_id);
@ -72,7 +72,7 @@ impl RevisionSnapshotDiskCache for SQLiteDatabaseRevisionSnapshotPersistence {
// }) // })
} }
fn read_snapshot(&self, rev_id: i64) -> FlowyResult<Option<RevisionSnapshot>> { fn read_snapshot(&self, rev_id: i64) -> FlowyResult<Option<RevisionSnapshotData>> {
let conn = self.pool.get().map_err(internal_error)?; let conn = self.pool.get().map_err(internal_error)?;
let snapshot_id = self.gen_snapshot_id(rev_id); let snapshot_id = self.gen_snapshot_id(rev_id);
let record = dsl::grid_rev_snapshot let record = dsl::grid_rev_snapshot
@ -82,7 +82,7 @@ impl RevisionSnapshotDiskCache for SQLiteDatabaseRevisionSnapshotPersistence {
Ok(Some(record.into())) Ok(Some(record.into()))
} }
fn read_last_snapshot(&self) -> FlowyResult<Option<RevisionSnapshot>> { fn read_last_snapshot(&self) -> FlowyResult<Option<RevisionSnapshotData>> {
let conn = self.pool.get().map_err(internal_error)?; let conn = self.pool.get().map_err(internal_error)?;
let latest_record = dsl::grid_rev_snapshot let latest_record = dsl::grid_rev_snapshot
.filter(dsl::object_id.eq(&self.object_id)) .filter(dsl::object_id.eq(&self.object_id))
@ -106,9 +106,9 @@ struct GridSnapshotRecord {
data: Vec<u8>, data: Vec<u8>,
} }
impl std::convert::From<GridSnapshotRecord> for RevisionSnapshot { impl std::convert::From<GridSnapshotRecord> for RevisionSnapshotData {
fn from(record: GridSnapshotRecord) -> Self { fn from(record: GridSnapshotRecord) -> Self {
RevisionSnapshot { RevisionSnapshotData {
rev_id: record.rev_id, rev_id: record.rev_id,
base_rev_id: record.base_rev_id, base_rev_id: record.base_rev_id,
timestamp: record.timestamp, timestamp: record.timestamp,

View File

@ -1,7 +1,7 @@
use crate::grid::database_editor::DatabaseEditorTest; use crate::grid::database_editor::DatabaseEditorTest;
use flowy_client_sync::client_database::{DatabaseOperations, DatabaseRevisionPad}; use flowy_client_sync::client_database::{DatabaseOperations, DatabaseRevisionPad};
use flowy_revision::{RevisionSnapshot, REVISION_WRITE_INTERVAL_IN_MILLIS}; use flowy_revision::{RevisionSnapshotData, REVISION_WRITE_INTERVAL_IN_MILLIS};
use grid_model::FieldRevision; use grid_model::FieldRevision;
use revision_model::Revision; use revision_model::Revision;
use std::time::Duration; use std::time::Duration;
@ -12,10 +12,10 @@ pub enum SnapshotScript {
#[allow(dead_code)] #[allow(dead_code)]
AssertSnapshot { AssertSnapshot {
rev_id: i64, rev_id: i64,
expected: Option<RevisionSnapshot>, expected: Option<RevisionSnapshotData>,
}, },
AssertSnapshotContent { AssertSnapshotContent {
snapshot: RevisionSnapshot, snapshot: RevisionSnapshotData,
expected: String, expected: String,
}, },
CreateField { CreateField {
@ -28,7 +28,7 @@ pub enum SnapshotScript {
pub struct DatabaseSnapshotTest { pub struct DatabaseSnapshotTest {
inner: DatabaseEditorTest, inner: DatabaseEditorTest,
pub current_snapshot: Option<RevisionSnapshot>, pub current_snapshot: Option<RevisionSnapshotData>,
pub current_revision: Option<Revision>, pub current_revision: Option<Revision>,
} }
@ -56,7 +56,7 @@ impl DatabaseSnapshotTest {
} }
} }
pub async fn get_latest_snapshot(&self) -> Option<RevisionSnapshot> { pub async fn get_latest_snapshot(&self) -> Option<RevisionSnapshotData> {
self.editor.rev_manager().read_snapshot(None).await.unwrap() self.editor.rev_manager().read_snapshot(None).await.unwrap()
} }

View File

@ -1,6 +1,7 @@
use crate::editor::{initial_document_content, AppFlowyDocumentEditor, DocumentRevisionMergeable}; use crate::editor::{initial_document_content, AppFlowyDocumentEditor, DocumentRevisionMergeable};
use crate::entities::{DocumentVersionPB, EditParams}; use crate::entities::{DocumentVersionPB, EditParams};
use crate::old_editor::editor::{DeltaDocumentEditor, DeltaDocumentRevisionMergeable}; use crate::old_editor::editor::{DeltaDocumentEditor, DeltaDocumentRevisionMergeable};
use crate::old_editor::snapshot::DeltaDocumentSnapshotPersistence;
use crate::services::rev_sqlite::{ use crate::services::rev_sqlite::{
SQLiteDeltaDocumentRevisionPersistence, SQLiteDocumentRevisionPersistence, SQLiteDeltaDocumentRevisionPersistence, SQLiteDocumentRevisionPersistence,
SQLiteDocumentRevisionSnapshotPersistence, SQLiteDocumentRevisionSnapshotPersistence,
@ -12,8 +13,7 @@ use document_model::document::DocumentId;
use flowy_client_sync::client_document::initial_delta_document_content; use flowy_client_sync::client_document::initial_delta_document_content;
use flowy_error::FlowyResult; use flowy_error::FlowyResult;
use flowy_revision::{ use flowy_revision::{
PhantomSnapshotPersistence, RevisionCloudService, RevisionManager, RevisionPersistence, RevisionCloudService, RevisionManager, RevisionPersistence, RevisionPersistenceConfiguration, RevisionWebSocket,
RevisionPersistenceConfiguration, RevisionWebSocket,
}; };
use flowy_sqlite::ConnectionPool; use flowy_sqlite::ConnectionPool;
use lib_infra::async_trait::async_trait; use lib_infra::async_trait::async_trait;
@ -292,7 +292,7 @@ impl DocumentManager {
doc_id, doc_id,
rev_persistence, rev_persistence,
DeltaDocumentRevisionMergeable(), DeltaDocumentRevisionMergeable(),
PhantomSnapshotPersistence(), DeltaDocumentSnapshotPersistence(),
)) ))
} }
} }

View File

@ -1,4 +1,5 @@
pub mod conflict; pub mod conflict;
pub mod editor; pub mod editor;
pub mod queue; pub mod queue;
pub mod snapshot;
mod web_socket; mod web_socket;

View File

@ -0,0 +1,18 @@
use flowy_error::FlowyResult;
use flowy_revision::{RevisionSnapshotData, RevisionSnapshotPersistence};
pub struct DeltaDocumentSnapshotPersistence();
impl RevisionSnapshotPersistence for DeltaDocumentSnapshotPersistence {
fn write_snapshot(&self, _rev_id: i64, _data: Vec<u8>) -> FlowyResult<()> {
Ok(())
}
fn read_snapshot(&self, _rev_id: i64) -> FlowyResult<Option<RevisionSnapshotData>> {
Ok(None)
}
fn read_last_snapshot(&self) -> FlowyResult<Option<RevisionSnapshotData>> {
Ok(None)
}
}

View File

@ -1,6 +1,6 @@
use bytes::Bytes; use bytes::Bytes;
use flowy_error::{internal_error, FlowyResult}; use flowy_error::{internal_error, FlowyResult};
use flowy_revision::{RevisionSnapshot, RevisionSnapshotDiskCache}; use flowy_revision::{RevisionSnapshotData, RevisionSnapshotPersistence};
use flowy_sqlite::{ use flowy_sqlite::{
prelude::*, prelude::*,
schema::{document_rev_snapshot, document_rev_snapshot::dsl}, schema::{document_rev_snapshot, document_rev_snapshot::dsl},
@ -27,7 +27,7 @@ impl SQLiteDocumentRevisionSnapshotPersistence {
} }
} }
impl RevisionSnapshotDiskCache for SQLiteDocumentRevisionSnapshotPersistence { impl RevisionSnapshotPersistence for SQLiteDocumentRevisionSnapshotPersistence {
fn should_generate_snapshot_from_range(&self, start_rev_id: i64, current_rev_id: i64) -> bool { fn should_generate_snapshot_from_range(&self, start_rev_id: i64, current_rev_id: i64) -> bool {
(current_rev_id - start_rev_id) >= 150 (current_rev_id - start_rev_id) >= 150
} }
@ -50,7 +50,7 @@ impl RevisionSnapshotDiskCache for SQLiteDocumentRevisionSnapshotPersistence {
Ok(()) Ok(())
} }
fn read_snapshot(&self, rev_id: i64) -> FlowyResult<Option<RevisionSnapshot>> { fn read_snapshot(&self, rev_id: i64) -> FlowyResult<Option<RevisionSnapshotData>> {
let conn = self.pool.get().map_err(internal_error)?; let conn = self.pool.get().map_err(internal_error)?;
let snapshot_id = self.gen_snapshot_id(rev_id); let snapshot_id = self.gen_snapshot_id(rev_id);
let record = dsl::document_rev_snapshot let record = dsl::document_rev_snapshot
@ -60,7 +60,7 @@ impl RevisionSnapshotDiskCache for SQLiteDocumentRevisionSnapshotPersistence {
Ok(Some(record.into())) Ok(Some(record.into()))
} }
fn read_last_snapshot(&self) -> FlowyResult<Option<RevisionSnapshot>> { fn read_last_snapshot(&self) -> FlowyResult<Option<RevisionSnapshotData>> {
let conn = self.pool.get().map_err(internal_error)?; let conn = self.pool.get().map_err(internal_error)?;
let latest_record = dsl::document_rev_snapshot let latest_record = dsl::document_rev_snapshot
.filter(dsl::object_id.eq(&self.object_id)) .filter(dsl::object_id.eq(&self.object_id))
@ -84,9 +84,9 @@ struct DocumentSnapshotRecord {
data: Vec<u8>, data: Vec<u8>,
} }
impl std::convert::From<DocumentSnapshotRecord> for RevisionSnapshot { impl std::convert::From<DocumentSnapshotRecord> for RevisionSnapshotData {
fn from(record: DocumentSnapshotRecord) -> Self { fn from(record: DocumentSnapshotRecord) -> Self {
RevisionSnapshot { RevisionSnapshotData {
rev_id: record.rev_id, rev_id: record.rev_id,
base_rev_id: record.base_rev_id, base_rev_id: record.base_rev_id,
timestamp: record.timestamp, timestamp: record.timestamp,

View File

@ -60,18 +60,16 @@ impl AppController {
Ok(app.into()) Ok(app.into())
} }
pub(crate) async fn read_app(&self, params: AppIdPB) -> Result<AppRevision, FlowyError> { pub(crate) async fn read_app(&self, params: AppIdPB) -> Result<Option<AppRevision>, FlowyError> {
let app = self let app = self
.persistence .persistence
.begin_transaction(|transaction| { .begin_transaction(|transaction| {
let app = transaction.read_app(&params.value)?; let app = transaction.read_app(&params.value)?;
let trash_ids = self.trash_controller.read_trash_ids(&transaction)?; let trash_ids = self.trash_controller.read_trash_ids(&transaction)?;
if trash_ids.contains(&app.id) { if trash_ids.contains(&app.id) {
return Err( return Ok(None);
FlowyError::record_not_found().context(format!("Can not find the app:{}", params.value))
);
} }
Ok(app) Ok(Some(app))
}) })
.await?; .await?;
self.read_app_on_server(params)?; self.read_app_on_server(params)?;
@ -243,7 +241,7 @@ fn notify_apps_changed<'a>(
trash_controller: Arc<TrashController>, trash_controller: Arc<TrashController>,
transaction: &'a (dyn FolderPersistenceTransaction + 'a), transaction: &'a (dyn FolderPersistenceTransaction + 'a),
) -> FlowyResult<()> { ) -> FlowyResult<()> {
let items = read_local_workspace_apps(workspace_id, trash_controller, transaction)? let items = read_workspace_apps(workspace_id, trash_controller, transaction)?
.into_iter() .into_iter()
.map(|app_rev| app_rev.into()) .map(|app_rev| app_rev.into())
.collect(); .collect();
@ -254,7 +252,7 @@ fn notify_apps_changed<'a>(
Ok(()) Ok(())
} }
pub fn read_local_workspace_apps<'a>( pub fn read_workspace_apps<'a>(
workspace_id: &str, workspace_id: &str,
trash_controller: Arc<TrashController>, trash_controller: Arc<TrashController>,
transaction: &'a (dyn FolderPersistenceTransaction + 'a), transaction: &'a (dyn FolderPersistenceTransaction + 'a),

View File

@ -51,8 +51,10 @@ pub(crate) async fn read_app_handler(
view_controller: AFPluginState<Arc<ViewController>>, view_controller: AFPluginState<Arc<ViewController>>,
) -> DataResult<AppPB, FlowyError> { ) -> DataResult<AppPB, FlowyError> {
let params: AppIdPB = data.into_inner(); let params: AppIdPB = data.into_inner();
let mut app_rev = app_controller.read_app(params.clone()).await?; if let Some(mut app_rev) = app_controller.read_app(params.clone()).await? {
app_rev.belongings = view_controller.read_views_belong_to(&params.value).await?; app_rev.belongings = view_controller.read_views_belong_to(&params.value).await?;
data_result(app_rev.into())
data_result(app_rev.into()) } else {
Err(FlowyError::record_not_found())
}
} }

View File

@ -1,7 +1,7 @@
#![allow(clippy::unused_unit)] #![allow(clippy::unused_unit)]
use bytes::Bytes; use bytes::Bytes;
use flowy_error::{internal_error, FlowyResult}; use flowy_error::{internal_error, FlowyResult};
use flowy_revision::{RevisionSnapshot, RevisionSnapshotDiskCache}; use flowy_revision::{RevisionSnapshotData, RevisionSnapshotPersistence};
use flowy_sqlite::{ use flowy_sqlite::{
prelude::*, prelude::*,
schema::{folder_rev_snapshot, folder_rev_snapshot::dsl}, schema::{folder_rev_snapshot, folder_rev_snapshot::dsl},
@ -28,7 +28,7 @@ impl SQLiteFolderRevisionSnapshotPersistence {
} }
} }
impl RevisionSnapshotDiskCache for SQLiteFolderRevisionSnapshotPersistence { impl RevisionSnapshotPersistence for SQLiteFolderRevisionSnapshotPersistence {
fn should_generate_snapshot_from_range(&self, start_rev_id: i64, current_rev_id: i64) -> bool { fn should_generate_snapshot_from_range(&self, start_rev_id: i64, current_rev_id: i64) -> bool {
(current_rev_id - start_rev_id) >= 2 (current_rev_id - start_rev_id) >= 2
} }
@ -51,7 +51,7 @@ impl RevisionSnapshotDiskCache for SQLiteFolderRevisionSnapshotPersistence {
Ok(()) Ok(())
} }
fn read_snapshot(&self, rev_id: i64) -> FlowyResult<Option<RevisionSnapshot>> { fn read_snapshot(&self, rev_id: i64) -> FlowyResult<Option<RevisionSnapshotData>> {
let conn = self.pool.get().map_err(internal_error)?; let conn = self.pool.get().map_err(internal_error)?;
let snapshot_id = self.gen_snapshot_id(rev_id); let snapshot_id = self.gen_snapshot_id(rev_id);
let record = dsl::folder_rev_snapshot let record = dsl::folder_rev_snapshot
@ -61,7 +61,7 @@ impl RevisionSnapshotDiskCache for SQLiteFolderRevisionSnapshotPersistence {
Ok(Some(record.into())) Ok(Some(record.into()))
} }
fn read_last_snapshot(&self) -> FlowyResult<Option<RevisionSnapshot>> { fn read_last_snapshot(&self) -> FlowyResult<Option<RevisionSnapshotData>> {
let conn = self.pool.get().map_err(internal_error)?; let conn = self.pool.get().map_err(internal_error)?;
let latest_record = dsl::folder_rev_snapshot let latest_record = dsl::folder_rev_snapshot
.filter(dsl::object_id.eq(&self.object_id)) .filter(dsl::object_id.eq(&self.object_id))
@ -85,9 +85,9 @@ struct FolderSnapshotRecord {
data: Vec<u8>, data: Vec<u8>,
} }
impl std::convert::From<FolderSnapshotRecord> for RevisionSnapshot { impl std::convert::From<FolderSnapshotRecord> for RevisionSnapshotData {
fn from(record: FolderSnapshotRecord) -> Self { fn from(record: FolderSnapshotRecord) -> Self {
RevisionSnapshot { RevisionSnapshotData {
rev_id: record.rev_id, rev_id: record.rev_id,
base_rev_id: record.base_rev_id, base_rev_id: record.base_rev_id,
timestamp: record.timestamp, timestamp: record.timestamp,

View File

@ -6,7 +6,7 @@ use crate::{
notification::*, notification::*,
services::{ services::{
persistence::{FolderPersistence, FolderPersistenceTransaction, WorkspaceChangeset}, persistence::{FolderPersistence, FolderPersistenceTransaction, WorkspaceChangeset},
read_local_workspace_apps, TrashController, read_workspace_apps, TrashController,
}, },
}; };
use flowy_sqlite::kv::KV; use flowy_sqlite::kv::KV;
@ -69,7 +69,7 @@ impl WorkspaceController {
.begin_transaction(|transaction| { .begin_transaction(|transaction| {
transaction.update_workspace(changeset)?; transaction.update_workspace(changeset)?;
let user_id = self.user.user_id()?; let user_id = self.user.user_id()?;
self.read_local_workspace(workspace_id.clone(), &user_id, &transaction) self.read_workspace(workspace_id.clone(), &user_id, &transaction)
}) })
.await?; .await?;
@ -89,7 +89,7 @@ impl WorkspaceController {
.persistence .persistence
.begin_transaction(|transaction| { .begin_transaction(|transaction| {
transaction.delete_workspace(workspace_id)?; transaction.delete_workspace(workspace_id)?;
self.read_local_workspaces(None, &user_id, &transaction) self.read_workspaces(None, &user_id, &transaction)
}) })
.await?; .await?;
send_notification(&token, FolderNotification::UserDeleteWorkspace) send_notification(&token, FolderNotification::UserDeleteWorkspace)
@ -104,7 +104,7 @@ impl WorkspaceController {
if let Some(workspace_id) = params.value { if let Some(workspace_id) = params.value {
let workspace = self let workspace = self
.persistence .persistence
.begin_transaction(|transaction| self.read_local_workspace(workspace_id, &user_id, &transaction)) .begin_transaction(|transaction| self.read_workspace(workspace_id, &user_id, &transaction))
.await?; .await?;
set_current_workspace(&user_id, &workspace.id); set_current_workspace(&user_id, &workspace.id);
Ok(workspace) Ok(workspace)
@ -119,7 +119,7 @@ impl WorkspaceController {
let app_revs = self let app_revs = self
.persistence .persistence
.begin_transaction(|transaction| { .begin_transaction(|transaction| {
read_local_workspace_apps(&workspace_id, self.trash_controller.clone(), &transaction) read_workspace_apps(&workspace_id, self.trash_controller.clone(), &transaction)
}) })
.await?; .await?;
// TODO: read from server // TODO: read from server
@ -127,38 +127,39 @@ impl WorkspaceController {
} }
#[tracing::instrument(level = "debug", skip(self, transaction), err)] #[tracing::instrument(level = "debug", skip(self, transaction), err)]
pub(crate) fn read_local_workspaces<'a>( pub(crate) fn read_workspaces<'a>(
&self, &self,
workspace_id: Option<String>, workspace_id: Option<String>,
user_id: &str, user_id: &str,
transaction: &'a (dyn FolderPersistenceTransaction + 'a), transaction: &'a (dyn FolderPersistenceTransaction + 'a),
) -> Result<RepeatedWorkspacePB, FlowyError> { ) -> Result<RepeatedWorkspacePB, FlowyError> {
let workspace_id = workspace_id.to_owned(); let workspace_id = workspace_id.to_owned();
let trash_ids = self.trash_controller.read_trash_ids(transaction)?;
let workspaces = transaction let workspaces = transaction
.read_workspaces(user_id, workspace_id)? .read_workspaces(user_id, workspace_id)?
.into_iter() .into_iter()
.map(|workspace_rev| workspace_rev.into()) .map(|mut workspace_rev| {
workspace_rev.apps.retain(|app_rev| !trash_ids.contains(&app_rev.id));
workspace_rev.into()
})
.collect(); .collect();
Ok(RepeatedWorkspacePB { items: workspaces }) Ok(RepeatedWorkspacePB { items: workspaces })
} }
pub(crate) fn read_local_workspace<'a>( pub(crate) fn read_workspace<'a>(
&self, &self,
workspace_id: String, workspace_id: String,
user_id: &str, user_id: &str,
transaction: &'a (dyn FolderPersistenceTransaction + 'a), transaction: &'a (dyn FolderPersistenceTransaction + 'a),
) -> Result<WorkspacePB, FlowyError> { ) -> Result<WorkspacePB, FlowyError> {
let mut workspace_revs = transaction.read_workspaces(user_id, Some(workspace_id.clone()))?; let mut workspaces = self
if workspace_revs.is_empty() { .read_workspaces(Some(workspace_id.clone()), user_id, transaction)?
.items;
if workspaces.is_empty() {
return Err(FlowyError::record_not_found().context(format!("{} workspace not found", workspace_id))); return Err(FlowyError::record_not_found().context(format!("{} workspace not found", workspace_id)));
} }
debug_assert_eq!(workspace_revs.len(), 1); debug_assert_eq!(workspaces.len(), 1);
let workspace = workspace_revs let workspace = workspaces.drain(..1).collect::<Vec<WorkspacePB>>().pop().unwrap();
.drain(..1)
.map(|workspace_rev| workspace_rev.into())
.collect::<Vec<WorkspacePB>>()
.pop()
.unwrap();
Ok(workspace) Ok(workspace)
} }
} }
@ -215,11 +216,10 @@ pub async fn notify_workspace_setting_did_change(
let workspace_setting = folder_manager let workspace_setting = folder_manager
.persistence .persistence
.begin_transaction(|transaction| { .begin_transaction(|transaction| {
let workspace = folder_manager.workspace_controller.read_local_workspace( let workspace =
workspace_id.clone(), folder_manager
&user_id, .workspace_controller
&transaction, .read_workspace(workspace_id.clone(), &user_id, &transaction)?;
)?;
let setting = match transaction.read_view(view_id) { let setting = match transaction.read_view(view_id) {
Ok(latest_view) => WorkspaceSettingPB { Ok(latest_view) => WorkspaceSettingPB {

View File

@ -7,7 +7,7 @@ use crate::{
errors::FlowyError, errors::FlowyError,
manager::FolderManager, manager::FolderManager,
notification::{send_notification, FolderNotification}, notification::{send_notification, FolderNotification},
services::{get_current_workspace, read_local_workspace_apps, WorkspaceController}, services::{get_current_workspace, read_workspace_apps, WorkspaceController},
}; };
use lib_dispatch::prelude::{data_result, AFPluginData, AFPluginState, DataResult}; use lib_dispatch::prelude::{data_result, AFPluginData, AFPluginState, DataResult};
use std::{convert::TryInto, sync::Arc}; use std::{convert::TryInto, sync::Arc};
@ -60,10 +60,9 @@ pub(crate) async fn read_workspaces_handler(
let workspaces = folder let workspaces = folder
.persistence .persistence
.begin_transaction(|transaction| { .begin_transaction(|transaction| {
let mut workspaces = let mut workspaces = workspace_controller.read_workspaces(params.value.clone(), &user_id, &transaction)?;
workspace_controller.read_local_workspaces(params.value.clone(), &user_id, &transaction)?;
for workspace in workspaces.iter_mut() { for workspace in workspaces.iter_mut() {
let apps = read_local_workspace_apps(&workspace.id, trash_controller.clone(), &transaction)? let apps = read_workspace_apps(&workspace.id, trash_controller.clone(), &transaction)?
.into_iter() .into_iter()
.map(|app_rev| app_rev.into()) .map(|app_rev| app_rev.into())
.collect(); .collect();
@ -91,7 +90,7 @@ pub async fn read_cur_workspace_handler(
.begin_transaction(|transaction| { .begin_transaction(|transaction| {
folder folder
.workspace_controller .workspace_controller
.read_local_workspace(workspace_id, &user_id, &transaction) .read_workspace(workspace_id, &user_id, &transaction)
}) })
.await?; .await?;

View File

@ -1,6 +1,6 @@
use crate::rev_queue::{RevCommand, RevCommandSender, RevQueue}; use crate::rev_queue::{RevCommand, RevCommandSender, RevQueue};
use crate::{ use crate::{
RevisionPersistence, RevisionSnapshot, RevisionSnapshotController, RevisionSnapshotDiskCache, RevisionPersistence, RevisionSnapshotController, RevisionSnapshotData, RevisionSnapshotPersistence,
WSDataProviderDataSource, WSDataProviderDataSource,
}; };
use bytes::Bytes; use bytes::Bytes;
@ -83,16 +83,16 @@ pub struct RevisionManager<Connection> {
} }
impl<Connection: 'static> RevisionManager<Connection> { impl<Connection: 'static> RevisionManager<Connection> {
pub fn new<SP, C>( pub fn new<Snapshot, Compress>(
user_id: &str, user_id: &str,
object_id: &str, object_id: &str,
rev_persistence: RevisionPersistence<Connection>, rev_persistence: RevisionPersistence<Connection>,
rev_compress: C, rev_compress: Compress,
snapshot_persistence: SP, snapshot_persistence: Snapshot,
) -> Self ) -> Self
where where
SP: 'static + RevisionSnapshotDiskCache, Snapshot: 'static + RevisionSnapshotPersistence,
C: 'static + RevisionMergeable, Compress: 'static + RevisionMergeable,
{ {
let rev_id_counter = Arc::new(RevIdCounter::new(0)); let rev_id_counter = Arc::new(RevIdCounter::new(0));
let rev_compress = Arc::new(rev_compress); let rev_compress = Arc::new(rev_compress);
@ -128,26 +128,26 @@ impl<Connection: 'static> RevisionManager<Connection> {
} }
#[tracing::instrument(name = "revision_manager_initialize", level = "trace", skip_all, fields(deserializer, object_id, deserialize_revisions) err)] #[tracing::instrument(name = "revision_manager_initialize", level = "trace", skip_all, fields(deserializer, object_id, deserialize_revisions) err)]
pub async fn initialize<B>(&mut self, _cloud: Option<Arc<dyn RevisionCloudService>>) -> FlowyResult<B::Output> pub async fn initialize<De>(&mut self, _cloud: Option<Arc<dyn RevisionCloudService>>) -> FlowyResult<De::Output>
where where
B: RevisionObjectDeserializer, De: RevisionObjectDeserializer,
{ {
let revision_records = self.rev_persistence.load_all_records(&self.object_id)?; let revision_records = self.rev_persistence.load_all_records(&self.object_id)?;
tracing::Span::current().record("object_id", self.object_id.as_str()); tracing::Span::current().record("object_id", self.object_id.as_str());
tracing::Span::current().record("deserializer", std::any::type_name::<B>()); tracing::Span::current().record("deserializer", std::any::type_name::<De>());
let revisions: Vec<Revision> = revision_records.iter().map(|record| record.revision.clone()).collect(); let revisions: Vec<Revision> = revision_records.iter().map(|record| record.revision.clone()).collect();
tracing::Span::current().record("deserialize_revisions", revisions.len()); tracing::Span::current().record("deserialize_revisions", revisions.len());
let current_rev_id = revisions.last().as_ref().map(|revision| revision.rev_id).unwrap_or(0); let current_rev_id = revisions.last().as_ref().map(|revision| revision.rev_id).unwrap_or(0);
match B::deserialize_revisions(&self.object_id, revisions.clone()) { match De::deserialize_revisions(&self.object_id, revisions.clone()) {
Ok(object) => { Ok(object) => {
self.rev_persistence.sync_revision_records(&revision_records).await?; self.rev_persistence.sync_revision_records(&revision_records).await?;
self.rev_id_counter.set(current_rev_id); self.rev_id_counter.set(current_rev_id);
Ok(object) Ok(object)
} }
Err(e) => match self.rev_snapshot.restore_from_snapshot::<B>(current_rev_id) { Err(e) => match self.rev_snapshot.restore_from_snapshot::<De>(current_rev_id) {
None => { None => {
tracing::info!("Restore object from validation revisions"); tracing::info!("Restore object from validation revisions");
B::recover_operations_from_revisions(revisions).ok_or(e) De::recover_operations_from_revisions(revisions).ok_or(e)
} }
Some((object, snapshot_rev)) => { Some((object, snapshot_rev)) => {
let snapshot_rev_id = snapshot_rev.rev_id; let snapshot_rev_id = snapshot_rev.rev_id;
@ -169,7 +169,7 @@ impl<Connection: 'static> RevisionManager<Connection> {
self.rev_snapshot.generate_snapshot().await; self.rev_snapshot.generate_snapshot().await;
} }
pub async fn read_snapshot(&self, rev_id: Option<i64>) -> FlowyResult<Option<RevisionSnapshot>> { pub async fn read_snapshot(&self, rev_id: Option<i64>) -> FlowyResult<Option<RevisionSnapshotData>> {
match rev_id { match rev_id {
None => self.rev_snapshot.read_last_snapshot(), None => self.rev_snapshot.read_last_snapshot(),
Some(rev_id) => self.rev_snapshot.read_snapshot(rev_id), Some(rev_id) => self.rev_snapshot.read_snapshot(rev_id),

View File

@ -9,34 +9,18 @@ use std::sync::atomic::AtomicI64;
use std::sync::atomic::Ordering::SeqCst; use std::sync::atomic::Ordering::SeqCst;
use std::sync::Arc; use std::sync::Arc;
pub trait RevisionSnapshotDiskCache: Send + Sync { pub trait RevisionSnapshotPersistence: Send + Sync {
fn should_generate_snapshot_from_range(&self, start_rev_id: i64, current_rev_id: i64) -> bool { fn should_generate_snapshot_from_range(&self, start_rev_id: i64, current_rev_id: i64) -> bool {
(current_rev_id - start_rev_id) >= AUTO_GEN_SNAPSHOT_PER_10_REVISION (current_rev_id - start_rev_id) >= AUTO_GEN_SNAPSHOT_PER_10_REVISION
} }
fn write_snapshot(&self, rev_id: i64, data: Vec<u8>) -> FlowyResult<()>; fn write_snapshot(&self, rev_id: i64, data: Vec<u8>) -> FlowyResult<()>;
fn read_snapshot(&self, rev_id: i64) -> FlowyResult<Option<RevisionSnapshot>>; fn read_snapshot(&self, rev_id: i64) -> FlowyResult<Option<RevisionSnapshotData>>;
fn read_last_snapshot(&self) -> FlowyResult<Option<RevisionSnapshot>>; fn read_last_snapshot(&self) -> FlowyResult<Option<RevisionSnapshotData>>;
}
/// Do nothing but just used to clam the rust compiler about the generic parameter `SP` of `RevisionManager` // fn generate_snapshot_data(&self) -> Option<RevisionSnapshotData>;
///
pub struct PhantomSnapshotPersistence();
impl RevisionSnapshotDiskCache for PhantomSnapshotPersistence {
fn write_snapshot(&self, rev_id: i64, data: Vec<u8>) -> FlowyResult<()> {
Ok(())
}
fn read_snapshot(&self, rev_id: i64) -> FlowyResult<Option<RevisionSnapshot>> {
Ok(None)
}
fn read_last_snapshot(&self) -> FlowyResult<Option<RevisionSnapshot>> {
Ok(None)
}
} }
const AUTO_GEN_SNAPSHOT_PER_10_REVISION: i64 = 10; const AUTO_GEN_SNAPSHOT_PER_10_REVISION: i64 = 10;
@ -44,7 +28,7 @@ const AUTO_GEN_SNAPSHOT_PER_10_REVISION: i64 = 10;
pub struct RevisionSnapshotController<Connection> { pub struct RevisionSnapshotController<Connection> {
user_id: String, user_id: String,
object_id: String, object_id: String,
rev_snapshot_persistence: Arc<dyn RevisionSnapshotDiskCache>, rev_snapshot_persistence: Arc<dyn RevisionSnapshotPersistence>,
rev_id_counter: Arc<RevIdCounter>, rev_id_counter: Arc<RevIdCounter>,
rev_persistence: Arc<RevisionPersistence<Connection>>, rev_persistence: Arc<RevisionPersistence<Connection>>,
rev_compress: Arc<dyn RevisionMergeable>, rev_compress: Arc<dyn RevisionMergeable>,
@ -64,13 +48,13 @@ where
revision_compress: Arc<dyn RevisionMergeable>, revision_compress: Arc<dyn RevisionMergeable>,
) -> Self ) -> Self
where where
D: RevisionSnapshotDiskCache + 'static, D: RevisionSnapshotPersistence + 'static,
{ {
let disk_cache = Arc::new(disk_cache); let rev_snapshot_persistence = Arc::new(disk_cache);
Self { Self {
user_id: user_id.to_string(), user_id: user_id.to_string(),
object_id: object_id.to_string(), object_id: object_id.to_string(),
rev_snapshot_persistence: disk_cache, rev_snapshot_persistence,
rev_id_counter, rev_id_counter,
start_rev_id: AtomicI64::new(0), start_rev_id: AtomicI64::new(0),
rev_persistence: revision_persistence, rev_persistence: revision_persistence,
@ -168,7 +152,7 @@ where
} }
impl<Connection> std::ops::Deref for RevisionSnapshotController<Connection> { impl<Connection> std::ops::Deref for RevisionSnapshotController<Connection> {
type Target = Arc<dyn RevisionSnapshotDiskCache>; type Target = Arc<dyn RevisionSnapshotPersistence>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.rev_snapshot_persistence &self.rev_snapshot_persistence
@ -176,7 +160,7 @@ impl<Connection> std::ops::Deref for RevisionSnapshotController<Connection> {
} }
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
pub struct RevisionSnapshot { pub struct RevisionSnapshotData {
pub rev_id: i64, pub rev_id: i64,
pub base_rev_id: i64, pub base_rev_id: i64,
pub timestamp: i64, pub timestamp: i64,

View File

@ -2,7 +2,8 @@ use bytes::Bytes;
use flowy_error::{internal_error, FlowyError, FlowyResult}; use flowy_error::{internal_error, FlowyError, FlowyResult};
use flowy_revision::{ use flowy_revision::{
RevisionManager, RevisionMergeable, RevisionObjectDeserializer, RevisionPersistence, RevisionManager, RevisionMergeable, RevisionObjectDeserializer, RevisionPersistence,
RevisionPersistenceConfiguration, RevisionSnapshot, RevisionSnapshotDiskCache, REVISION_WRITE_INTERVAL_IN_MILLIS, RevisionPersistenceConfiguration, RevisionSnapshotData, RevisionSnapshotPersistence,
REVISION_WRITE_INTERVAL_IN_MILLIS,
}; };
use flowy_revision_persistence::{RevisionChangeset, RevisionDiskCache, SyncRecord}; use flowy_revision_persistence::{RevisionChangeset, RevisionDiskCache, SyncRecord};
@ -244,16 +245,16 @@ impl RevisionDiskCache<RevisionConnectionMock> for RevisionDiskCacheMock {
pub struct RevisionConnectionMock {} pub struct RevisionConnectionMock {}
pub struct RevisionSnapshotMock {} pub struct RevisionSnapshotMock {}
impl RevisionSnapshotDiskCache for RevisionSnapshotMock { impl RevisionSnapshotPersistence for RevisionSnapshotMock {
fn write_snapshot(&self, _rev_id: i64, _data: Vec<u8>) -> FlowyResult<()> { fn write_snapshot(&self, _rev_id: i64, _data: Vec<u8>) -> FlowyResult<()> {
todo!() Ok(())
} }
fn read_snapshot(&self, _rev_id: i64) -> FlowyResult<Option<RevisionSnapshot>> { fn read_snapshot(&self, _rev_id: i64) -> FlowyResult<Option<RevisionSnapshotData>> {
todo!() Ok(None)
} }
fn read_last_snapshot(&self) -> FlowyResult<Option<RevisionSnapshot>> { fn read_last_snapshot(&self) -> FlowyResult<Option<RevisionSnapshotData>> {
Ok(None) Ok(None)
} }
} }