Skip to content

Commit 0fea181

Browse files
committed
Started fixing the --in-memory flag
1 parent ed4f330 commit 0fea181

File tree

9 files changed

+109
-25
lines changed

9 files changed

+109
-25
lines changed

crates/cli/tests/server.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,15 @@ mod util;
33
use crate::util::SpacetimeDbGuard;
44
use assert_cmd::cargo::cargo_bin_cmd;
55

6+
#[test]
7+
fn cli_can_ping_spacetimedb_in_memory() {
8+
let spacetime = SpacetimeDbGuard::spawn_in_memory();
9+
let mut cmd = cargo_bin_cmd!("spacetimedb-cli");
10+
cmd.args(["server", "ping", &spacetime.host_url.to_string()])
11+
.assert()
12+
.success();
13+
}
14+
615
#[test]
716
fn cli_can_ping_spacetimedb_on_disk() {
817
let spacetime = SpacetimeDbGuard::spawn_in_temp_data_dir();

crates/cli/tests/util.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ impl SpacetimeDbGuard {
3030
Self::spawn_spacetime_start(&["start", "--data-dir", &data_dir])
3131
}
3232

33+
/// Start `spacetimedb` in-memory via:
34+
/// cargo run -p spacetimedb-cli -- start --in-memory --listen-addr 127.0.0.1:<port>
35+
pub fn spawn_in_memory() -> Self {
36+
Self::spawn_spacetime_start(&["start", "--in-memory"])
37+
}
38+
3339
fn spawn_spacetime_start(extra_args: &[&str]) -> Self {
3440
let port = find_free_port();
3541
let addr: SocketAddr = format!("127.0.0.1:{port}").parse().unwrap();

crates/core/src/db/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub mod update;
1414

1515
/// Whether SpacetimeDB is run in memory, or persists objects and
1616
/// a message log to disk.
17-
#[derive(Clone, Copy)]
17+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1818
pub enum Storage {
1919
/// The object store is in memory, and no message log is kept.
2020
Memory,

crates/core/src/host/disk_storage.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,8 @@ impl ExternalStorage for DiskStorage {
7979
async fn lookup(&self, program_hash: Hash) -> anyhow::Result<Option<Box<[u8]>>> {
8080
self.get(&program_hash).await.map_err(Into::into)
8181
}
82+
83+
async fn put(&self, program_bytes: &[u8]) -> anyhow::Result<Hash> {
84+
self.put(program_bytes).await.map_err(Into::into)
85+
}
8286
}

crates/core/src/host/host_controller.rs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ use spacetimedb_sats::hash::Hash;
3838
use spacetimedb_schema::auto_migrate::{ponder_migrate, AutoMigrateError, MigrationPolicy, PrettyPrintStyle};
3939
use spacetimedb_schema::def::ModuleDef;
4040
use spacetimedb_table::page_pool::PagePool;
41-
use std::future::Future;
4241
use std::ops::Deref;
4342
use std::sync::Arc;
4443
use std::time::{Duration, Instant};
@@ -61,16 +60,7 @@ pub type ExternalDurability = (Arc<dyn Durability<TxData = Txdata>>, DiskSizeFn)
6160
#[async_trait]
6261
pub trait ExternalStorage: Send + Sync + 'static {
6362
async fn lookup(&self, program_hash: Hash) -> anyhow::Result<Option<Box<[u8]>>>;
64-
}
65-
#[async_trait]
66-
impl<F, Fut> ExternalStorage for F
67-
where
68-
F: Fn(Hash) -> Fut + Send + Sync + 'static,
69-
Fut: Future<Output = anyhow::Result<Option<Box<[u8]>>>> + Send,
70-
{
71-
async fn lookup(&self, program_hash: Hash) -> anyhow::Result<Option<Box<[u8]>>> {
72-
self(program_hash).await
73-
}
63+
async fn put(&self, program_bytes: &[u8]) -> anyhow::Result<Hash>;
7464
}
7565

7666
pub type ProgramStorage = Arc<dyn ExternalStorage>;
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
use async_trait::async_trait;
2+
use spacetimedb_lib::{hash_bytes, Hash};
3+
use std::collections::HashMap;
4+
use std::io;
5+
use std::sync::Arc;
6+
use tokio::sync::RwLock;
7+
8+
use super::ExternalStorage;
9+
10+
/// A simple [`ExternalStorage`] that stores programs in memory.
11+
#[derive(Clone, Debug, Default)]
12+
pub struct MemoryStorage {
13+
inner: Arc<RwLock<HashMap<Hash, Box<[u8]>>>>,
14+
}
15+
16+
impl MemoryStorage {
17+
/// Create a new empty `MemoryStorage`.
18+
pub async fn new() -> io::Result<Self> {
19+
Ok(Self {
20+
inner: Arc::new(RwLock::new(HashMap::new())),
21+
})
22+
}
23+
24+
#[tracing::instrument(level = "trace", skip(self))]
25+
pub async fn get(&self, key: &Hash) -> io::Result<Option<Box<[u8]>>> {
26+
let guard = self.inner.read().await;
27+
Ok(guard.get(key).cloned())
28+
}
29+
30+
#[tracing::instrument(level = "trace", skip(self, value))]
31+
pub async fn put(&self, value: &[u8]) -> io::Result<Hash> {
32+
let h = hash_bytes(value);
33+
let mut guard = self.inner.write().await;
34+
guard.insert(h, Box::from(value));
35+
Ok(h)
36+
}
37+
38+
#[tracing::instrument(level = "trace", skip(self))]
39+
pub async fn prune(&self, key: &Hash) -> anyhow::Result<()> {
40+
let mut guard = self.inner.write().await;
41+
guard.remove(key);
42+
Ok(())
43+
}
44+
}
45+
46+
#[async_trait]
47+
impl ExternalStorage for MemoryStorage {
48+
async fn lookup(&self, program_hash: Hash) -> anyhow::Result<Option<Box<[u8]>>> {
49+
self.get(&program_hash).await.map_err(Into::into)
50+
}
51+
52+
async fn put(&self, program_bytes: &[u8]) -> anyhow::Result<Hash> {
53+
self.put(program_bytes).await.map_err(Into::into)
54+
}
55+
}

crates/core/src/host/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use spacetimedb_schema::def::deserialize::{ArgsSeed, FunctionDef};
1111

1212
mod disk_storage;
1313
mod host_controller;
14+
mod memory_storage;
1415
mod module_common;
1516
#[allow(clippy::too_many_arguments)]
1617
pub mod module_host;
@@ -27,6 +28,7 @@ pub use host_controller::{
2728
extract_schema, CallProcedureReturn, ExternalDurability, ExternalStorage, HostController, MigratePlanResult,
2829
ProcedureCallResult, ProgramStorage, ReducerCallResult, ReducerOutcome,
2930
};
31+
pub use memory_storage::MemoryStorage;
3032
pub use module_host::{ModuleHost, NoSuchModule, ProcedureCallError, ReducerCallError, UpdateDatabaseResult};
3133
pub use scheduler::Scheduler;
3234

crates/standalone/src/control_db.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,15 @@ impl ControlDb {
7575
Ok(Self { db })
7676
}
7777

78+
pub fn new_in_memory() -> Result<Self> {
79+
let config = sled::Config::default()
80+
.temporary(true)
81+
.flush_every_ms(Some(50))
82+
.mode(sled::Mode::HighThroughput);
83+
let db = config.open()?;
84+
Ok(Self { db })
85+
}
86+
7887
#[cfg(test)]
7988
pub fn at(path: impl AsRef<std::path::Path>) -> Result<Self> {
8089
let config = sled::Config::default()

crates/standalone/src/lib.rs

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ use spacetimedb::config::{CertificateAuthority, MetadataFile};
1313
use spacetimedb::db;
1414
use spacetimedb::db::persistence::LocalPersistenceProvider;
1515
use spacetimedb::energy::{EnergyBalance, EnergyQuanta, NullEnergyMonitor};
16-
use spacetimedb::host::{DiskStorage, HostController, MigratePlanResult, UpdateDatabaseResult};
16+
use spacetimedb::host::{
17+
DiskStorage, HostController, MemoryStorage, MigratePlanResult, ProgramStorage, UpdateDatabaseResult,
18+
};
1719
use spacetimedb::identity::{AuthCtx, Identity};
1820
use spacetimedb::messages::control_db::{Database, Node, Replica};
1921
use spacetimedb::util::jobs::JobCores;
@@ -41,11 +43,11 @@ pub struct StandaloneOptions {
4143

4244
pub struct StandaloneEnv {
4345
control_db: ControlDb,
44-
program_store: Arc<DiskStorage>,
46+
program_store: ProgramStorage,
4547
host_controller: HostController,
4648
client_actor_index: ClientActorIndex,
4749
metrics_registry: prometheus::Registry,
48-
_pid_file: PidFile,
50+
_pid_file: Option<PidFile>,
4951
auth_provider: auth::DefaultJwtAuthProvider,
5052
websocket_options: WebSocketOptions,
5153
}
@@ -57,17 +59,24 @@ impl StandaloneEnv {
5759
data_dir: Arc<ServerDataDir>,
5860
db_cores: JobCores,
5961
) -> anyhow::Result<Arc<Self>> {
60-
let _pid_file = data_dir.pid_file()?;
61-
let meta_path = data_dir.metadata_toml();
62-
let mut meta = MetadataFile::new("standalone");
63-
if let Some(existing_meta) = MetadataFile::read(&meta_path).context("failed reading metadata.toml")? {
64-
meta = existing_meta.check_compatibility_and_update(meta)?;
65-
}
66-
meta.write(&meta_path).context("failed writing metadata.toml")?;
62+
let (pid_file, control_db, program_store): (Option<PidFile>, ControlDb, ProgramStorage) =
63+
if config.db_config.storage == db::Storage::Disk {
64+
let meta_path = data_dir.metadata_toml();
65+
let mut meta = MetadataFile::new("standalone");
66+
if let Some(existing_meta) = MetadataFile::read(&meta_path).context("failed reading metadata.toml")? {
67+
meta = existing_meta.check_compatibility_and_update(meta)?;
68+
}
69+
meta.write(&meta_path).context("failed writing metadata.toml")?;
70+
let control_db = ControlDb::new(&data_dir.control_db()).context("failed to initialize control db")?;
71+
let program_store = Arc::new(DiskStorage::new(data_dir.program_bytes().0).await?);
72+
(Some(data_dir.pid_file()?), control_db, program_store)
73+
} else {
74+
let control_db = ControlDb::new_in_memory().context("failed to initialize in-memory control db")?;
75+
let program_store = Arc::new(MemoryStorage::new().await?);
76+
(None, control_db, program_store)
77+
};
6778

68-
let control_db = ControlDb::new(&data_dir.control_db()).context("failed to initialize control db")?;
6979
let energy_monitor = Arc::new(NullEnergyMonitor);
70-
let program_store = Arc::new(DiskStorage::new(data_dir.program_bytes().0).await?);
7180

7281
let persistence_provider = Arc::new(LocalPersistenceProvider::new(data_dir.clone()));
7382
let host_controller = HostController::new(
@@ -94,7 +103,7 @@ impl StandaloneEnv {
94103
host_controller,
95104
client_actor_index,
96105
metrics_registry,
97-
_pid_file,
106+
_pid_file: pid_file,
98107
auth_provider: auth_env,
99108
websocket_options: config.websocket,
100109
}))

0 commit comments

Comments
 (0)