From 8be59659d82f18a82dd4430efda5bda80d185a09 Mon Sep 17 00:00:00 2001 From: Oscar Beaumont Date: Sat, 13 Apr 2024 02:15:56 +0800 Subject: [PATCH] DB Vacuum Button (#2312) * Do the thing * Retry * fix types --------- Co-authored-by: Brendan Allan --- core/src/api/libraries.rs | 23 ++++++++++++ interface/app/$libraryId/debug/sync.tsx | 37 +++++++++---------- .../$libraryId/settings/library/general.tsx | 27 +++++++++++++- interface/locales/en/common.json | 3 ++ packages/client/src/core.ts | 1 + 5 files changed, 71 insertions(+), 20 deletions(-) diff --git a/core/src/api/libraries.rs b/core/src/api/libraries.rs index d304339382dd..0905964d93b4 100644 --- a/core/src/api/libraries.rs +++ b/core/src/api/libraries.rs @@ -7,11 +7,13 @@ use crate::{ }; use futures::StreamExt; +use prisma_client_rust::raw; use sd_cache::{Model, Normalise, NormalisedResult, NormalisedResults}; use sd_file_ext::kind::ObjectKind; use sd_p2p::RemoteIdentity; use sd_prisma::prisma::{indexer_rule, object, statistics}; use tokio_stream::wrappers::IntervalStream; +use tracing::{info, warn}; use std::{ collections::{hash_map::Entry, HashMap}, @@ -385,6 +387,27 @@ pub(crate) fn mount() -> AlphaRouter { Ok(()) }), ) + .procedure( + "vaccumDb", + R.with2(library()) + .mutation(|(_, library), _: ()| async move { + // We retry a few times because if the DB is being actively used, the vacuum will fail + for _ in 0..5 { + match library.db._execute_raw(raw!("VACUUM;")).exec().await { + Ok(_) => break, + Err(err) => { + warn!( + "Failed to vacuum DB for library '{}', retrying...: {err:#?}", + library.id + ); + tokio::time::sleep(Duration::from_millis(500)).await; + } + } + } + info!("Successfully vacuumed DB for library '{}'", library.id); + Ok(()) + }), + ) } async fn update_statistics_loop( diff --git a/interface/app/$libraryId/debug/sync.tsx b/interface/app/$libraryId/debug/sync.tsx index 3ad070162c65..24d4f99563fe 100644 --- a/interface/app/$libraryId/debug/sync.tsx +++ b/interface/app/$libraryId/debug/sync.tsx @@ -88,31 +88,30 @@ const OperationGroup = ({ group }: { group: MessageGroup }) => { function calculateGroups(messages: CRDTOperation[]) { return messages.reduce((acc, op) => { - // TODO: fix Typescript - // const { data } = op; + const { data } = op; - // const id = JSON.stringify(op.record_id); + const id = JSON.stringify(op.record_id); - // const latest = (() => { - // const latest = acc[acc.length - 1]; + const latest = (() => { + const latest = acc[acc.length - 1]; - // if (!latest || latest.model !== op.model || latest.id !== id) { - // const group: MessageGroup = { - // model: op.model, - // id, - // messages: [] - // }; + if (!latest || latest.model !== op.model || latest.id !== id) { + const group: MessageGroup = { + model: op.model, + id, + messages: [] + }; - // acc.push(group); + acc.push(group); - // return group; - // } else return latest; - // })(); + return group; + } else return latest; + })(); - // latest.messages.push({ - // data, - // timestamp: op.timestamp - // }); + latest.messages.push({ + data, + timestamp: op.timestamp + }); return acc; }, []); diff --git a/interface/app/$libraryId/settings/library/general.tsx b/interface/app/$libraryId/settings/library/general.tsx index ed9a27616055..6498ccffec6b 100644 --- a/interface/app/$libraryId/settings/library/general.tsx +++ b/interface/app/$libraryId/settings/library/general.tsx @@ -1,4 +1,10 @@ -import { MaybeUndefined, useBridgeMutation, useLibraryContext, useZodForm } from '@sd/client'; +import { + MaybeUndefined, + useBridgeMutation, + useLibraryContext, + useLibraryMutation, + useZodForm +} from '@sd/client'; import { Button, dialogManager, Form, InputField, Switch, Tooltip, z } from '@sd/ui'; import { useDebouncedFormWatch, useLocale } from '~/hooks'; @@ -20,6 +26,7 @@ function toMaybeUndefined(v: T | null | undefined): MaybeUndefined { export const Component = () => { const { library } = useLibraryContext(); const editLibrary = useBridgeMutation('library.edit'); + const vaccumLibrary = useLibraryMutation('library.vaccumDb'); const { t } = useLocale(); @@ -94,6 +101,24 @@ export const Component = () => { + +
+ +
+
+ , result: null } | { key: "library.stopActor", input: LibraryArgs, result: null } | + { key: "library.vaccumDb", input: LibraryArgs, result: null } | { key: "locations.addLibrary", input: LibraryArgs, result: number | null } | { key: "locations.create", input: LibraryArgs, result: number | null } | { key: "locations.delete", input: LibraryArgs, result: null } |