diff --git a/Cargo.toml b/Cargo.toml index 9ff0700..25ab4f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,12 @@ path = "src/test.rs" [dependencies] marine-rs-sdk = "0.7.0" +eyre = "0.6.8" +cid = "0.8.6" +thiserror = "1.0.37" +fstrings = "0.2.3" +serde = "1.0.149" +serde_json = "1.0.89" bytesize = "1.1.0" [dev-dependencies] diff --git a/leak_launcher/Config_spell.toml b/leak_launcher/Config_spell.toml new file mode 100644 index 0000000..c2cbc26 --- /dev/null +++ b/leak_launcher/Config_spell.toml @@ -0,0 +1,15 @@ +modules_dir = "./artifacts/" + +[[module]] + name = "sqlite3" + mem_pages_count = 100 + logger_enabled = false + + [module.wasi] + preopened_files = ["./tmp"] + mapped_dirs = { "tmp" = "./tmp" } + +[[module]] + name = "spell" + mem_pages_count = 1 + logger_enabled = false diff --git a/leak_launcher/Config.toml b/leak_launcher/Config_test.toml similarity index 100% rename from leak_launcher/Config.toml rename to leak_launcher/Config_test.toml diff --git a/leak_launcher/artifacts/leak_test.wasm b/leak_launcher/artifacts/leak_test.wasm index 4c77cfc..5bd9094 100755 Binary files a/leak_launcher/artifacts/leak_test.wasm and b/leak_launcher/artifacts/leak_test.wasm differ diff --git a/leak_launcher/artifacts/spell.wasm b/leak_launcher/artifacts/spell.wasm new file mode 100755 index 0000000..230fa4b Binary files /dev/null and b/leak_launcher/artifacts/spell.wasm differ diff --git a/leak_launcher/artifacts/sqlite3.wasm b/leak_launcher/artifacts/sqlite3.wasm index 80c833e..a651d0c 100755 Binary files a/leak_launcher/artifacts/sqlite3.wasm and b/leak_launcher/artifacts/sqlite3.wasm differ diff --git a/leak_launcher/main.rs b/leak_launcher/main.rs index 03db0bb..f60a352 100644 --- a/leak_launcher/main.rs +++ b/leak_launcher/main.rs @@ -1,48 +1,90 @@ -use std::convert::TryInto; use fluence_app_service::AppService; use fluence_app_service::TomlMarineConfig; use fluence_app_service::AppServiceConfig; use serde_json::json; +use std::convert::TryInto; fn main() { + let config = TomlMarineConfig::load("Config_spell.toml").unwrap(); + let config = AppServiceConfig { + service_base_dir: std::path::PathBuf::new(), + marine_config: config.try_into().unwrap() + }; - let config = TomlMarineConfig::load("./Config.toml").unwrap(); + let service_name = "spell_service"; + let mut spell_service = AppService::new(config, service_name, <_>::default()).unwrap(); + + let config = TomlMarineConfig::load("Config_test.toml").unwrap(); let config = AppServiceConfig { service_base_dir: std::path::PathBuf::new(), marine_config: config.try_into().unwrap() }; let service_name = "test_service"; - let mut service = AppService::new(config, service_name, <_>::default()).unwrap(); + let mut test_service = AppService::new(config, service_name, <_>::default()).unwrap(); let db_path = "./tmp/db.sqlite"; - service.call("create", json!(db_path), <_>::default()).unwrap(); + test_service.call("create_4", json!(db_path), <_>::default()).unwrap(); + //test_service.call("set_limit", json!(1*1024*1024), <_>::default()).unwrap(); + /* for i in 0..500 { if i % 50 == 0 { - println!("insert_1 {}:\n{}", i, service.module_memory_stats()); + println!("test list_push_string_1 {}:\n{}", i, test_service.module_memory_stats()); } - service.call("insert_1", json!(db_path), <_>::default()).unwrap(); + let result = test_service.call("list_push_string_1", json!(["asdasd", "sadsad"]), <_>::default()).unwrap(); + } + */ + for i in 0..500 { + if i % 50 == 0 { + println!("test insert_5 {}:\n{}", i, test_service.module_memory_stats()); + } + let result = test_service.call("insert_5", json!(["asdasd", "sadsad"]), <_>::default()).unwrap(); } for i in 0..500 { if i % 50 == 0 { - println!("insert_2: {} - {}", i, service.module_memory_stats()); + println!("test list_push_string_6 {}:\n{}", i, test_service.module_memory_stats()); } - service.call("insert_2", json!(db_path), <_>::default()).unwrap(); + let result = test_service.call("list_push_string_6", json!(["asdasd", "sadsad"]), <_>::default()).unwrap(); } for i in 0..500 { if i % 50 == 0 { - println!("select_1 {}:\n{}", i, service.module_memory_stats()); + println!("test list_push_string_5 {}:\n{}", i, test_service.module_memory_stats()); } - service.call("select_1", json!(db_path), <_>::default()).unwrap(); + let unique_key = create_unique_key(500 + i); + let result = test_service.call("list_push_string_5", json!([unique_key, "sadsad"]), <_>::default()).unwrap(); } for i in 0..500 { if i % 50 == 0 { - println!("select_2 {}:\n{}", i, service.module_memory_stats()); + println!("get_all_errors {}:\n{}", i, spell_service.module_memory_stats()); } - service.call("select_2", json!(db_path), <_>::default()).unwrap(); + let result = spell_service.call("insert_2", json!([]), <_>::default()).unwrap(); + } + + for i in 0..500 { + if i % 50 == 0 { + println!("select_1 {}:\n{}", i, spell_service.module_memory_stats()); + } + let result = spell_service.call("select_1", json!([]), <_>::default()).unwrap(); + } + + for i in 0..500 { + if i % 50 == 0 { + println!("select_5 {}:\n{}", i, spell_service.module_memory_stats()); + } + let result = spell_service.call("select_5", json!([]), <_>::default()).unwrap(); } } + +fn create_unique_key(index: i32) -> String { + let mut first = String::new(); + + for _ in 0..(index+1) { + first += "a"; + } + + first +} diff --git a/leak_launcher/spell_service/tmp/spell.sqlite b/leak_launcher/spell_service/tmp/spell.sqlite new file mode 100644 index 0000000..d823aad Binary files /dev/null and b/leak_launcher/spell_service/tmp/spell.sqlite differ diff --git a/leak_launcher/test_service/tmp/db-1.sqlite b/leak_launcher/test_service/tmp/db-1.sqlite new file mode 100644 index 0000000..1af06ec Binary files /dev/null and b/leak_launcher/test_service/tmp/db-1.sqlite differ diff --git a/leak_launcher/test_service/tmp/db-2.sqlite b/leak_launcher/test_service/tmp/db-2.sqlite new file mode 100644 index 0000000..824ee7d Binary files /dev/null and b/leak_launcher/test_service/tmp/db-2.sqlite differ diff --git a/leak_launcher/test_service/tmp/db-3.sqlite b/leak_launcher/test_service/tmp/db-3.sqlite new file mode 100644 index 0000000..b0d5a14 Binary files /dev/null and b/leak_launcher/test_service/tmp/db-3.sqlite differ diff --git a/leak_launcher/test_service/tmp/db-3.sqlite-journal b/leak_launcher/test_service/tmp/db-3.sqlite-journal new file mode 100644 index 0000000..ef13436 Binary files /dev/null and b/leak_launcher/test_service/tmp/db-3.sqlite-journal differ diff --git a/leak_launcher/test_service/tmp/db-4.sqlite b/leak_launcher/test_service/tmp/db-4.sqlite new file mode 100644 index 0000000..5f106d3 Binary files /dev/null and b/leak_launcher/test_service/tmp/db-4.sqlite differ diff --git a/leak_launcher/test_service/tmp/db-4.sqlite-journal b/leak_launcher/test_service/tmp/db-4.sqlite-journal new file mode 100644 index 0000000..3d78a28 Binary files /dev/null and b/leak_launcher/test_service/tmp/db-4.sqlite-journal differ diff --git a/leak_launcher/test_service/tmp/db-5.sqlite b/leak_launcher/test_service/tmp/db-5.sqlite new file mode 100644 index 0000000..35f27c1 Binary files /dev/null and b/leak_launcher/test_service/tmp/db-5.sqlite differ diff --git a/leak_launcher/test_service/tmp/db-5.sqlite-journal b/leak_launcher/test_service/tmp/db-5.sqlite-journal new file mode 100644 index 0000000..c5389b3 Binary files /dev/null and b/leak_launcher/test_service/tmp/db-5.sqlite-journal differ diff --git a/leak_launcher/test_service/tmp/db.sqlite b/leak_launcher/test_service/tmp/db.sqlite index 5826464..06d509a 100644 Binary files a/leak_launcher/test_service/tmp/db.sqlite and b/leak_launcher/test_service/tmp/db.sqlite differ diff --git a/leak_launcher/test_service/tmp/dbb.sqlite b/leak_launcher/test_service/tmp/dbb.sqlite new file mode 100644 index 0000000..ef0b08d Binary files /dev/null and b/leak_launcher/test_service/tmp/dbb.sqlite differ diff --git a/leak_launcher/test_service/tmp/dbb.sqlite-journal b/leak_launcher/test_service/tmp/dbb.sqlite-journal new file mode 100644 index 0000000..04a6bd9 Binary files /dev/null and b/leak_launcher/test_service/tmp/dbb.sqlite-journal differ diff --git a/leak_launcher/test_service/tmp/spell.sqlite b/leak_launcher/test_service/tmp/spell.sqlite new file mode 100644 index 0000000..e155cc5 Binary files /dev/null and b/leak_launcher/test_service/tmp/spell.sqlite differ diff --git a/leak_launcher/test_service/tmp/spell_1.sqlite b/leak_launcher/test_service/tmp/spell_1.sqlite new file mode 100644 index 0000000..e69de29 diff --git a/leak_test/main.rs b/leak_test/main.rs index 8a81679..87ed438 100644 --- a/leak_test/main.rs +++ b/leak_test/main.rs @@ -1,10 +1,30 @@ +#![feature(try_blocks)] + use marine_rs_sdk::marine; use marine_sqlite_connector::State; +mod schema; + +use serde::Serialize; +use serde::Deserialize; +use schema::db; +use fstrings::f; + fn main() {} #[marine] -pub fn create(path: String) { +#[derive(Debug, Clone, Deserialize)] +#[allow(dead_code)] +pub struct UnitValue { + pub success: bool, + pub error: String, +} + + +#[marine] +pub fn create_4(path: String) { + schema::create(); + /* let conn_create = marine_sqlite_connector::open(&path).expect("Open database connection"); conn_create @@ -80,6 +100,7 @@ pub fn create(path: String) { ", ) .expect("running schema queries"); + */ } #[marine] @@ -111,6 +132,56 @@ fn insert_2(path: String) { } } +#[marine] +fn insert_3() { + let conn = db(); + + let key = "some"; + let value = "other"; + let mut statement = conn + .prepare("INSERT OR REPLACE INTO kv (key, string) VALUES (?, ?)") + .expect("prep rand 0..3"); + statement.bind(1, key).expect("bind 1"); + statement.bind(2, value).expect("bind 2"); + statement.next().expect("next"); +} + +#[marine] +fn insert_4(key: &str, value: String) { + let conn = db(); + + let mut statement = conn + .prepare("INSERT OR REPLACE INTO kv (key, string) VALUES (?, ?)") + .expect("prep rand 0..3"); + statement.bind(1, key).expect("bind 1"); + statement.bind(2, value.as_str()).expect("bind 2"); + statement.next().expect("next"); +} + +#[marine] +fn insert_5(key: &str, value: String) { + let mut statement = db().prepare("INSERT OR REPLACE INTO kv (key, string) VALUES (?, ?)") + .expect("prep rand 0..3"); + statement.bind(1, key).expect("bind 1"); + statement.bind(2, value.as_str()).expect("bind 2"); + statement.next().expect("next"); +} + +/* +#[marine] +pub fn list_push_string_5(key: &str, value: String) { + let mut statement = db().prepare( + r#" + INSERT INTO kv (key, string) + VALUES (?, ?) + "#, + ).unwrap(); + statement.bind(1, key).unwrap(); + statement.bind(2, value.as_str()).unwrap(); + statement.next().unwrap(); +} + */ + #[marine] fn select_1(path: String) { let conn = marine_sqlite_connector::open(path).expect("Open database connection"); @@ -126,19 +197,170 @@ fn select_1(path: String) { } #[marine] -fn select_2(path: String) { +fn select_5(path: String) { let conn = marine_sqlite_connector::open(path).expect("Open database connection"); - - let mut statement = conn - .prepare("SELECT u32 FROM kv WHERE key = ?") - .expect("prep rand 8..9"); - statement.bind(1, 42).expect("8..9 bind"); - if let State::Row = statement.next().expect("8..9 next") { - statement.read::(0).expect("8..9 read") as u32; - } } #[marine] fn set_limit(limit: i64) -> i64 { marine_sqlite_connector::set_hard_memory_limit(limit) } + +#[marine] +pub fn list_push_string_1(key: &str, value: String) -> UnitValue { + let result: eyre::Result<()> = try { + let mut statement = db().prepare( + r#" + INSERT INTO kv (key, string, list_index) + VALUES ( + ?, + ?, + 42 + ) + "#, + )?; + statement.bind(1, key)?; + statement.bind(2, value.as_str())?; + //statement.bind(3, key)?; + statement.next()?; + }; + + result.into() +} + +#[marine] +pub fn list_push_string_2(key: &str, value: String) -> UnitValue { + let mut statement = db().prepare( + r#" + INSERT INTO kv (key, string, list_index) + VALUES ( + ?, + ?, + 42 + ) + "#, + ).unwrap(); + statement.bind(1, key).unwrap(); + statement.bind(2, value.as_str()).unwrap(); + statement.next().unwrap(); + + UnitValue::ok() +} + +#[marine] +pub fn list_push_string_3(key: &str, value: String) { + let mut statement = db().prepare( + r#" + INSERT INTO kv (key, string, list_index) + VALUES ( + ?, + ?, + 42 + ) + "#, + ).unwrap(); + statement.bind(1, key).unwrap(); + statement.bind(2, value.as_str()).unwrap(); + statement.next().unwrap(); +} + +#[marine] +pub fn list_push_string_4(key: &str, value: String) { + let mut statement = db().prepare( + r#" + INSERT INTO kv (key, string) + VALUES ( + ?, + ? + ) + "#, + ).unwrap(); + statement.bind(1, key).unwrap(); + statement.bind(2, value.as_str()).unwrap(); + statement.next().unwrap(); +} + +#[marine] +pub fn list_push_string_5(key: &str, value: String) { + let mut statement = db().prepare( + r#" + INSERT INTO kv (key, string) + VALUES (?, ?) + "#, + ).unwrap(); + statement.bind(1, key).unwrap(); + statement.bind(2, value.as_str()).unwrap(); + statement.next().unwrap(); +} + +#[marine] +pub fn list_push_string_6(key: &str, value: String) { + let mut statement = db().prepare( + r#" + INSERT OR REPLACE INTO kv (key, string) + VALUES (?,?) + "#, + ).unwrap(); + statement.bind(1, key).unwrap(); + statement.bind(2, value.as_str()).unwrap(); + statement.next().unwrap(); +} + +impl UnitValue { + pub fn ok() -> Self { + Self { + success: true, + error: String::new(), + } + } + + pub fn error(error: impl AsRef) -> Self { + Self { + success: false, + error: error.as_ref().to_string(), + } + } + + pub fn spell_error(error: SpellError) -> Self { + Self::error(format_error(error)) + } +} + +impl From> for UnitValue { + fn from(value: eyre::Result<()>) -> Self { + match value { + Ok(_) => UnitValue::ok(), + Err(e) => UnitValue::error(format_error(e)), + } + } +} + +use marine_sqlite_connector::Error as SqliteError; +use thiserror::Error as ThisError; + +#[derive(ThisError, Debug)] +pub enum SpellError { + #[error("Internal Sqlite error: {0}")] + SqliteError( + #[from] + #[source] + SqliteError, + ), + #[error("Key '{0}' does not exist")] + KeyNotExists(String), + #[error("Location not available: relay was not set")] + NoRelay, + #[error("Only owner of the spell can set relay peer id")] + SetRelayForbidden, + #[error("Relay was already set and cannot be changed")] + RelayAlreadySet, + #[error("Only owner of the spell can set trigger config")] + SetTriggerConfigForbidden, + #[error("Trigger Config is not set. Use set_trigger_config to set it.")] + NoTriggerConfig, +} + +pub fn format_error(e: impl std::fmt::Debug) -> String { + format!("{:?}", e) +} + diff --git a/leak_test/schema.rs b/leak_test/schema.rs new file mode 100644 index 0000000..d7ff26f --- /dev/null +++ b/leak_test/schema.rs @@ -0,0 +1,32 @@ +use fstrings::f; +use fstrings::format_args_f; +use marine_sqlite_connector::Connection; + +pub const DEFAULT_MAX_ERR_PARTICLES: usize = 50; +pub const DB_FILE: &'static str = "/tmp/db-5.sqlite"; + +pub fn db() -> Connection { + // use rand::prelude::*; + // + // let db_path = if std::path::Path::new("/tmp/this_is_test").exists() { + // format!("/tmp/{}_spell.sqlite", rand::random::()) + // } else { + // format!(DB_FILE) + // }; + marine_sqlite_connector::open(DB_FILE).expect("open sqlite db") +} + +pub fn create() { + db().execute( + f!(r#" + CREATE TABLE IF NOT EXISTS kv ( + key TEXT NOT NULL, + string TEXT, + list_index INTEGER DEFAULT -1, + + PRIMARY KEY(key, list_index) + ); + "#), + ) + .expect("init sqlite db"); +}