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