mirror of
https://github.com/denoland/deno.git
synced 2025-03-03 17:34:47 -05:00
perf: improve localStorage throughput (#11709)
This PR improves localStorage write throughput by around 150x by caching the prepared statements for SQLite and adding some DB pragmas. Co-authored-by: Divy Srivastava <dj.srivastava23@gmail.com>
This commit is contained in:
parent
370c5013c5
commit
4010b84675
1 changed files with 40 additions and 28 deletions
|
@ -1,5 +1,7 @@
|
||||||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
// NOTE to all: use **cached** prepared statements when interfacing with SQLite.
|
||||||
|
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::include_js_files;
|
use deno_core::include_js_files;
|
||||||
use deno_core::op_sync;
|
use deno_core::op_sync;
|
||||||
|
@ -64,11 +66,25 @@ fn get_webstorage(
|
||||||
})?;
|
})?;
|
||||||
std::fs::create_dir_all(&path.0)?;
|
std::fs::create_dir_all(&path.0)?;
|
||||||
let conn = Connection::open(path.0.join("local_storage"))?;
|
let conn = Connection::open(path.0.join("local_storage"))?;
|
||||||
conn.execute(
|
// Enable write-ahead-logging and tweak some other stuff.
|
||||||
"CREATE TABLE IF NOT EXISTS data (key VARCHAR UNIQUE, value VARCHAR)",
|
let initial_pragmas = "
|
||||||
params![],
|
-- enable write-ahead-logging mode
|
||||||
)?;
|
PRAGMA journal_mode=WAL;
|
||||||
|
PRAGMA synchronous=NORMAL;
|
||||||
|
PRAGMA temp_store=memory;
|
||||||
|
PRAGMA page_size=4096;
|
||||||
|
PRAGMA mmap_size=6000000;
|
||||||
|
PRAGMA optimize;
|
||||||
|
";
|
||||||
|
|
||||||
|
conn.execute_batch(initial_pragmas)?;
|
||||||
|
conn.set_prepared_statement_cache_capacity(128);
|
||||||
|
{
|
||||||
|
let mut stmt = conn.prepare_cached(
|
||||||
|
"CREATE TABLE IF NOT EXISTS data (key VARCHAR UNIQUE, value VARCHAR)",
|
||||||
|
)?;
|
||||||
|
stmt.execute(params![])?;
|
||||||
|
}
|
||||||
state.put(LocalStorage(conn));
|
state.put(LocalStorage(conn));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,11 +92,12 @@ fn get_webstorage(
|
||||||
} else {
|
} else {
|
||||||
if state.try_borrow::<SessionStorage>().is_none() {
|
if state.try_borrow::<SessionStorage>().is_none() {
|
||||||
let conn = Connection::open_in_memory()?;
|
let conn = Connection::open_in_memory()?;
|
||||||
conn.execute(
|
{
|
||||||
"CREATE TABLE data (key VARCHAR UNIQUE, value VARCHAR)",
|
let mut stmt = conn.prepare_cached(
|
||||||
params![],
|
"CREATE TABLE data (key VARCHAR UNIQUE, value VARCHAR)",
|
||||||
)?;
|
)?;
|
||||||
|
stmt.execute(params![])?;
|
||||||
|
}
|
||||||
state.put(SessionStorage(conn));
|
state.put(SessionStorage(conn));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,8 +114,7 @@ pub fn op_webstorage_length(
|
||||||
) -> Result<u32, AnyError> {
|
) -> Result<u32, AnyError> {
|
||||||
let conn = get_webstorage(state, persistent)?;
|
let conn = get_webstorage(state, persistent)?;
|
||||||
|
|
||||||
let mut stmt = conn.prepare("SELECT COUNT(*) FROM data")?;
|
let mut stmt = conn.prepare_cached("SELECT COUNT(*) FROM data")?;
|
||||||
|
|
||||||
let length: u32 = stmt.query_row(params![], |row| row.get(0))?;
|
let length: u32 = stmt.query_row(params![], |row| row.get(0))?;
|
||||||
|
|
||||||
Ok(length)
|
Ok(length)
|
||||||
|
@ -111,7 +127,8 @@ pub fn op_webstorage_key(
|
||||||
) -> Result<Option<String>, AnyError> {
|
) -> Result<Option<String>, AnyError> {
|
||||||
let conn = get_webstorage(state, persistent)?;
|
let conn = get_webstorage(state, persistent)?;
|
||||||
|
|
||||||
let mut stmt = conn.prepare("SELECT key FROM data LIMIT 1 OFFSET ?")?;
|
let mut stmt =
|
||||||
|
conn.prepare_cached("SELECT key FROM data LIMIT 1 OFFSET ?")?;
|
||||||
|
|
||||||
let key: Option<String> = stmt
|
let key: Option<String> = stmt
|
||||||
.query_row(params![index], |row| row.get(0))
|
.query_row(params![index], |row| row.get(0))
|
||||||
|
@ -134,8 +151,8 @@ pub fn op_webstorage_set(
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let conn = get_webstorage(state, persistent)?;
|
let conn = get_webstorage(state, persistent)?;
|
||||||
|
|
||||||
let mut stmt =
|
let mut stmt = conn
|
||||||
conn.prepare("SELECT SUM(pgsize) FROM dbstat WHERE name = 'data'")?;
|
.prepare_cached("SELECT SUM(pgsize) FROM dbstat WHERE name = 'data'")?;
|
||||||
let size: u32 = stmt.query_row(params![], |row| row.get(0))?;
|
let size: u32 = stmt.query_row(params![], |row| row.get(0))?;
|
||||||
|
|
||||||
if size >= MAX_STORAGE_BYTES {
|
if size >= MAX_STORAGE_BYTES {
|
||||||
|
@ -147,10 +164,9 @@ pub fn op_webstorage_set(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
conn.execute(
|
let mut stmt = conn
|
||||||
"INSERT OR REPLACE INTO data (key, value) VALUES (?, ?)",
|
.prepare_cached("INSERT OR REPLACE INTO data (key, value) VALUES (?, ?)")?;
|
||||||
params![args.key_name, args.key_value],
|
stmt.execute(params![args.key_name, args.key_value])?;
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -162,8 +178,7 @@ pub fn op_webstorage_get(
|
||||||
) -> Result<Option<String>, AnyError> {
|
) -> Result<Option<String>, AnyError> {
|
||||||
let conn = get_webstorage(state, persistent)?;
|
let conn = get_webstorage(state, persistent)?;
|
||||||
|
|
||||||
let mut stmt = conn.prepare("SELECT value FROM data WHERE key = ?")?;
|
let mut stmt = conn.prepare_cached("SELECT value FROM data WHERE key = ?")?;
|
||||||
|
|
||||||
let val = stmt
|
let val = stmt
|
||||||
.query_row(params![key_name], |row| row.get(0))
|
.query_row(params![key_name], |row| row.get(0))
|
||||||
.optional()?;
|
.optional()?;
|
||||||
|
@ -178,7 +193,8 @@ pub fn op_webstorage_remove(
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let conn = get_webstorage(state, persistent)?;
|
let conn = get_webstorage(state, persistent)?;
|
||||||
|
|
||||||
conn.execute("DELETE FROM data WHERE key = ?", params![key_name])?;
|
let mut stmt = conn.prepare_cached("DELETE FROM data WHERE key = ?")?;
|
||||||
|
stmt.execute(params![key_name])?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -190,11 +206,8 @@ pub fn op_webstorage_clear(
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let conn = get_webstorage(state, persistent)?;
|
let conn = get_webstorage(state, persistent)?;
|
||||||
|
|
||||||
conn.execute("DROP TABLE data", params![])?;
|
let mut stmt = conn.prepare_cached("DELETE FROM data")?;
|
||||||
conn.execute(
|
stmt.execute(params![])?;
|
||||||
"CREATE TABLE data (key VARCHAR UNIQUE, value VARCHAR)",
|
|
||||||
params![],
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -206,8 +219,7 @@ pub fn op_webstorage_iterate_keys(
|
||||||
) -> Result<Vec<String>, AnyError> {
|
) -> Result<Vec<String>, AnyError> {
|
||||||
let conn = get_webstorage(state, persistent)?;
|
let conn = get_webstorage(state, persistent)?;
|
||||||
|
|
||||||
let mut stmt = conn.prepare("SELECT key FROM data")?;
|
let mut stmt = conn.prepare_cached("SELECT key FROM data")?;
|
||||||
|
|
||||||
let keys = stmt
|
let keys = stmt
|
||||||
.query_map(params![], |row| row.get::<_, String>(0))?
|
.query_map(params![], |row| row.get::<_, String>(0))?
|
||||||
.map(|r| r.unwrap())
|
.map(|r| r.unwrap())
|
||||||
|
|
Loading…
Add table
Reference in a new issue