From 4ca69466adc7dc4ba6679330f26e2f73fb762d1d Mon Sep 17 00:00:00 2001 From: Spxg Date: Sun, 25 May 2025 15:37:08 +0800 Subject: [PATCH] Use only a single DB --- src/app/header.rs | 18 ++++--------- src/bin/worker.rs | 12 ++++----- src/lib.rs | 30 +++++++++------------ src/worker/mod.rs | 68 +++++++++++++++++++++++------------------------ 4 files changed, 55 insertions(+), 73 deletions(-) diff --git a/src/app/header.rs b/src/app/header.rs index 9bf6e87..bddae78 100644 --- a/src/app/header.rs +++ b/src/app/header.rs @@ -6,8 +6,8 @@ use wasm_bindgen::{JsCast, prelude::Closure}; use web_sys::{Blob, Event, FileReader, HtmlInputElement, Url, UrlSearchParams}; use crate::{ - DownloadDbOptions, FragileComfirmed, LoadDbOptions, PrepareOptions, SQLightError, - SQLiteStatementResult, WorkerRequest, + FragileComfirmed, LoadDbOptions, PrepareOptions, SQLightError, SQLiteStatementResult, + WorkerRequest, app::{ ImportProgress, advanced_options_menu::AdvancedOptionsMenu, @@ -89,7 +89,6 @@ pub fn execute(state: Store) -> Box { if let Some(worker) = &*state.worker().read_untracked() { worker.send_task(WorkerRequest::Prepare(PrepareOptions { - id: String::new(), sql: if !selected_code.is_empty() && run_selected_code { selected_code } else { @@ -97,7 +96,7 @@ pub fn execute(state: Store) -> Box { }, clear_on_prepare: !*state.keep_ctx().read_untracked(), })); - worker.send_task(WorkerRequest::Continue(String::new())); + worker.send_task(WorkerRequest::Continue); } }) } @@ -149,10 +148,7 @@ fn DownloadButton() -> impl IntoView { let on_click = move |_| { if let Some(worker) = &*state.worker().read() { - worker.send_task(WorkerRequest::DownloadDb(DownloadDbOptions { - // FIXME: multi db - id: String::new(), - })); + worker.send_task(WorkerRequest::DownloadDb); } }; @@ -204,11 +200,7 @@ fn LoadButton(input_ref: NodeRef) -> impl IntoView { let array_buffer = result.unchecked_into::(); let data = js_sys::Uint8Array::new(&array_buffer); if let Some(worker) = &*state.worker().read() { - worker.send_task(WorkerRequest::LoadDb(LoadDbOptions { - // FIXME: multi db - id: String::new(), - data, - })); + worker.send_task(WorkerRequest::LoadDb(LoadDbOptions { data })); } }) as Box)); diff --git a/src/bin/worker.rs b/src/bin/worker.rs index 36e4f3b..2de16fd 100644 --- a/src/bin/worker.rs +++ b/src/bin/worker.rs @@ -32,16 +32,14 @@ async fn execute_task(scope: DedicatedWorkerGlobalScope, mut rx: UnboundedReceiv WorkerRequest::Prepare(options) => { WorkerResponse::Prepare(worker::prepare(options).await) } - WorkerRequest::Continue(id) => WorkerResponse::Continue(worker::r#continue(&id)), - WorkerRequest::StepOver(id) => WorkerResponse::StepOver(worker::step_over(&id)), - WorkerRequest::StepIn(id) => WorkerResponse::StepIn(worker::step_in(&id)), - WorkerRequest::StepOut(id) => WorkerResponse::StepOut(worker::step_out(&id)), + WorkerRequest::Continue => WorkerResponse::Continue(worker::r#continue().await), + WorkerRequest::StepOver => WorkerResponse::StepOver(worker::step_over().await), + WorkerRequest::StepIn => WorkerResponse::StepIn(worker::step_in().await), + WorkerRequest::StepOut => WorkerResponse::StepOut(worker::step_out().await), WorkerRequest::LoadDb(options) => { WorkerResponse::LoadDb(worker::load_db(options).await) } - WorkerRequest::DownloadDb(options) => { - WorkerResponse::DownloadDb(worker::download_db(options).await) - } + WorkerRequest::DownloadDb => WorkerResponse::DownloadDb(worker::download_db().await), }; if let Err(err) = scope.post_message(&serde_wasm_bindgen::to_value(&resp).unwrap()) { log::error!("Failed to send task to window: {resp:?}, {err:?}"); diff --git a/src/lib.rs b/src/lib.rs index b34f82f..e0fc720 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -77,7 +77,7 @@ impl SQLightError { pub enum WorkerError { #[error(transparent)] SQLite(#[from] SQLitendError), - #[error("Not found database by id")] + #[error("Not found database")] NotFound, #[error("Execute sqlite with invaild state")] InvaildState, @@ -95,18 +95,18 @@ pub enum WorkerError { pub enum WorkerRequest { Open(OpenOptions), Prepare(PrepareOptions), - Continue(String), - StepOver(String), - StepIn(String), - StepOut(String), + Continue, + StepOver, + StepIn, + StepOut, LoadDb(LoadDbOptions), - DownloadDb(DownloadDbOptions), + DownloadDb, } #[derive(Debug, Serialize, Deserialize)] pub enum WorkerResponse { Ready, - Open(Result), + Open(Result<()>), Prepare(Result<()>), Continue(Result>), StepOver(Result), @@ -131,16 +131,10 @@ pub struct OpenOptions { #[derive(Debug, Serialize, Deserialize)] pub struct LoadDbOptions { - pub id: String, #[serde(with = "serde_wasm_bindgen::preserve")] pub data: Uint8Array, } -#[derive(Debug, Serialize, Deserialize)] -pub struct DownloadDbOptions { - pub id: String, -} - impl OpenOptions { pub fn uri(&self) -> String { format!( @@ -153,7 +147,6 @@ impl OpenOptions { #[derive(Debug, Serialize, Deserialize)] pub struct PrepareOptions { - pub id: String, pub sql: String, pub clear_on_prepare: bool, } @@ -255,10 +248,11 @@ pub async fn handle_state(state: Store, mut rx: UnboundedReceiver unreachable!(), - WorkerResponse::Open(result) => match result { - Ok(_) => (), - Err(err) => state.last_error().set(Some(SQLightError::new_worker(err))), - }, + WorkerResponse::Open(result) => { + if let Err(err) = result { + state.last_error().set(Some(SQLightError::new_worker(err))); + } + } WorkerResponse::Prepare(result) => { if let Err(err) = result { state.last_error().set(Some(SQLightError::new_worker(err))); diff --git a/src/worker/mod.rs b/src/worker/mod.rs index 1d38452..3b6f598 100644 --- a/src/worker/mod.rs +++ b/src/worker/mod.rs @@ -1,24 +1,23 @@ mod sqlitend; use crate::{ - DownloadDbOptions, DownloadDbResponse, LoadDbOptions, OpenOptions, PERSIST_VFS, PrepareOptions, + DownloadDbResponse, LoadDbOptions, OpenOptions, PERSIST_VFS, PrepareOptions, SQLiteStatementResult, WorkerError, }; use once_cell::sync::Lazy; -use parking_lot::Mutex; use sqlite_wasm_rs::{ export::{OpfsSAHPoolCfgBuilder, OpfsSAHPoolUtil}, mem_vfs::MemVfsUtil, utils::{copy_to_uint8_array, copy_to_vec}, }; use sqlitend::{SQLiteDb, SQLitePreparedStatement, SQLiteStatements}; -use std::{collections::HashMap, sync::Arc}; +use std::sync::Arc; +use tokio::sync::Mutex; use tokio::sync::OnceCell; type Result = std::result::Result; -static DB_POOL: Lazy>> = - Lazy::new(|| Mutex::new(HashMap::new())); +static DB: Lazy>> = Lazy::new(|| Mutex::new(None)); static FS_UTIL: Lazy = Lazy::new(|| FSUtil { mem: MemVfsUtil::new(), @@ -31,7 +30,6 @@ struct FSUtil { } struct SQLiteWorker { - id: String, db: Option>, open_options: OpenOptions, state: SQLiteState, @@ -47,11 +45,11 @@ struct PreparedState { prepared: Option, } -fn with_worker(id: &str, mut f: F) -> Result +async fn with_worker(mut f: F) -> Result where F: FnMut(&mut SQLiteWorker) -> Result, { - f(DB_POOL.lock().get_mut(id).ok_or(WorkerError::NotFound)?) + f(DB.lock().await.as_mut().ok_or(WorkerError::NotFound)?) } async fn init_opfs_util() -> Result<&'static OpfsSAHPoolUtil> { @@ -77,8 +75,8 @@ fn get_opfs_util() -> Result<&'static OpfsSAHPoolUtil> { FS_UTIL.opfs.get().ok_or(WorkerError::Unexpected) } -pub async fn download_db(options: DownloadDbOptions) -> Result { - with_worker(&options.id, |worker| { +pub async fn download_db() -> Result { + with_worker(|worker| { let filename = &worker.open_options.filename; let db = if worker.open_options.persist { get_opfs_util()? @@ -95,12 +93,13 @@ pub async fn download_db(options: DownloadDbOptions) -> Result Result<()> { let db = copy_to_vec(&options.data); - with_worker(&options.id, |worker| { + with_worker(|worker| { worker.db.take(); let filename = &worker.open_options.filename; @@ -122,35 +121,29 @@ pub async fn load_db(options: LoadDbOptions) -> Result<()> { worker.state = SQLiteState::Idie; Ok(()) }) + .await } -pub async fn open(options: OpenOptions) -> Result { - if let Some(worker) = DB_POOL.lock().get(&options.filename) { - return Ok(worker.id.clone()); - } +pub async fn open(options: OpenOptions) -> Result<()> { + let mut locker = DB.lock().await; + locker.take(); + if options.persist { - let util = init_opfs_util().await?; - if util.get_capacity() - util.get_file_count() * 3 < 3 { - util.add_capacity(3) - .await - .map_err(|_| WorkerError::Unexpected)?; - } + init_opfs_util().await?; } - // FIXME: multi db support - let id = String::new(); + let db = SQLiteDb::open(&options.uri())?; let worker = SQLiteWorker { - id: id.clone(), db: Some(db), open_options: options, state: SQLiteState::Idie, }; - DB_POOL.lock().insert(id.clone(), worker); - Ok(id) + *locker = Some(worker); + Ok(()) } pub async fn prepare(options: PrepareOptions) -> Result<()> { - with_worker(&options.id, |worker| { + with_worker(|worker| { if options.clear_on_prepare { worker.db.take(); @@ -178,10 +171,11 @@ pub async fn prepare(options: PrepareOptions) -> Result<()> { }); Ok(()) }) + .await } -pub fn r#continue(id: &str) -> Result> { - with_worker(id, |worker| { +pub async fn r#continue() -> Result> { + with_worker(|worker| { let state = std::mem::replace(&mut worker.state, SQLiteState::Idie); let mut result = match state { SQLiteState::Idie => return Err(WorkerError::InvaildState), @@ -197,10 +191,11 @@ pub fn r#continue(id: &str) -> Result> { result.push(SQLiteStatementResult::Finish); Ok(result) }) + .await } -pub fn step_over(id: &str) -> Result { - with_worker(id, |worker| match &mut worker.state { +pub async fn step_over() -> Result { + with_worker(|worker| match &mut worker.state { SQLiteState::Idie => Err(WorkerError::InvaildState), SQLiteState::Prepared(prepared_state) => { if let Some(prepared) = &mut prepared_state.prepared { @@ -218,10 +213,11 @@ pub fn step_over(id: &str) -> Result { } } }) + .await } -pub fn step_in(id: &str) -> Result<()> { - with_worker(id, |worker| { +pub async fn step_in() -> Result<()> { + with_worker(|worker| { match &mut worker.state { SQLiteState::Idie => return Err(WorkerError::InvaildState), SQLiteState::Prepared(prepared_state) => { @@ -237,10 +233,11 @@ pub fn step_in(id: &str) -> Result<()> { }; Ok(()) }) + .await } -pub fn step_out(id: &str) -> Result { - with_worker(id, |worker| match &mut worker.state { +pub async fn step_out() -> Result { + with_worker(|worker| match &mut worker.state { SQLiteState::Idie => Err(WorkerError::InvaildState), SQLiteState::Prepared(prepared_state) => { if let Some(prepared) = prepared_state.prepared.take() { @@ -250,4 +247,5 @@ pub fn step_out(id: &str) -> Result { } } }) + .await }