Skip to content

Commit f2c8c6d

Browse files
Centrilgefjon
andauthored
Extract ModuleCommon + use in wasm & v8 runtimes (#2940)
Signed-off-by: Mazdak Farrokhzad <twingoow@gmail.com> Co-authored-by: Phoebe Goldman <phoebe@clockworklabs.io>
1 parent 63dff57 commit f2c8c6d

File tree

4 files changed

+140
-53
lines changed

4 files changed

+140
-53
lines changed

crates/core/src/host/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use spacetimedb_schema::def::deserialize::ReducerArgsDeserializeSeed;
1212

1313
mod disk_storage;
1414
mod host_controller;
15+
mod module_common;
1516
#[allow(clippy::too_many_arguments)]
1617
pub mod module_host;
1718
pub mod scheduler;

crates/core/src/host/module_common.rs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
//! Module backend infrastructure, shared between different runtimes,
2+
//! like WASM and V8.
3+
4+
use crate::{
5+
energy::EnergyMonitor,
6+
host::{
7+
module_host::{DynModule, ModuleInfo},
8+
Scheduler,
9+
},
10+
module_host_context::ModuleCreationContext,
11+
replica_context::ReplicaContext,
12+
};
13+
use spacetimedb_lib::{Identity, RawModuleDef};
14+
use spacetimedb_schema::{def::ModuleDef, error::ValidationErrors};
15+
use std::sync::Arc;
16+
17+
/// Builds a [`ModuleCommon`] from a [`RawModuleDef`].
18+
pub fn build_common_module_from_raw(
19+
mcc: ModuleCreationContext,
20+
raw_def: RawModuleDef,
21+
) -> Result<ModuleCommon, ValidationErrors> {
22+
// Perform a bunch of validation on the raw definition.
23+
let def: ModuleDef = raw_def.try_into()?;
24+
25+
let replica_ctx = mcc.replica_ctx;
26+
let log_tx = replica_ctx.logger.tx.clone();
27+
28+
// Note: assigns Reducer IDs based on the alphabetical order of reducer names.
29+
let info = ModuleInfo::new(
30+
def,
31+
replica_ctx.owner_identity,
32+
replica_ctx.database_identity,
33+
mcc.program.hash,
34+
log_tx,
35+
replica_ctx.subscriptions.clone(),
36+
);
37+
38+
Ok(ModuleCommon::new(replica_ctx, mcc.scheduler, info, mcc.energy_monitor))
39+
}
40+
41+
/// Non-runtime-specific parts of a module.
42+
#[derive(Clone)]
43+
pub(crate) struct ModuleCommon {
44+
replica_context: Arc<ReplicaContext>,
45+
scheduler: Scheduler,
46+
info: Arc<ModuleInfo>,
47+
energy_monitor: Arc<dyn EnergyMonitor>,
48+
}
49+
50+
impl ModuleCommon {
51+
/// Returns a new common module.
52+
fn new(
53+
replica_context: Arc<ReplicaContext>,
54+
scheduler: Scheduler,
55+
info: Arc<ModuleInfo>,
56+
energy_monitor: Arc<dyn EnergyMonitor>,
57+
) -> Self {
58+
Self {
59+
replica_context,
60+
scheduler,
61+
info,
62+
energy_monitor,
63+
}
64+
}
65+
66+
/// Returns the module info.
67+
pub fn info(&self) -> Arc<ModuleInfo> {
68+
self.info.clone()
69+
}
70+
71+
/// Returns the identity of the database.
72+
pub fn database_identity(&self) -> &Identity {
73+
&self.info.database_identity
74+
}
75+
76+
/// Returns the energy monitor.
77+
pub fn energy_monitor(&self) -> Arc<dyn EnergyMonitor> {
78+
self.energy_monitor.clone()
79+
}
80+
}
81+
82+
impl DynModule for ModuleCommon {
83+
fn replica_ctx(&self) -> &Arc<ReplicaContext> {
84+
&self.replica_context
85+
}
86+
87+
fn scheduler(&self) -> &Scheduler {
88+
&self.scheduler
89+
}
90+
}

crates/core/src/host/v8/mod.rs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::{
22
host::{
3+
module_common::{build_common_module_from_raw, ModuleCommon},
34
module_host::{DynModule, Module, ModuleInfo, ModuleInstance, ModuleRuntime},
45
Scheduler,
56
},
@@ -44,21 +45,39 @@ impl V8RuntimeInner {
4445
Self { _priv: () }
4546
}
4647

47-
fn make_actor(&self, _: ModuleCreationContext<'_>) -> anyhow::Result<impl Module> {
48-
Err::<JsModule, _>(anyhow!("v8_todo"))
48+
fn make_actor(&self, mcc: ModuleCreationContext<'_>) -> anyhow::Result<impl Module> {
49+
#![allow(unreachable_code, unused_variables)]
50+
51+
log::trace!(
52+
"Making new V8 module host actor for database {} with module {}",
53+
mcc.replica_ctx.database_identity,
54+
mcc.program.hash,
55+
);
56+
57+
if true {
58+
return Err::<JsModule, _>(anyhow!("v8_todo"));
59+
}
60+
61+
let desc = todo!();
62+
// Validate and create a common module rom the raw definition.
63+
let common = build_common_module_from_raw(mcc, desc)?;
64+
65+
Ok(JsModule { common })
4966
}
5067
}
5168

5269
#[derive(Clone)]
53-
struct JsModule;
70+
struct JsModule {
71+
common: ModuleCommon,
72+
}
5473

5574
impl DynModule for JsModule {
5675
fn replica_ctx(&self) -> &Arc<ReplicaContext> {
57-
todo!()
76+
self.common.replica_ctx()
5877
}
5978

6079
fn scheduler(&self) -> &Scheduler {
61-
todo!()
80+
self.common.scheduler()
6281
}
6382
}
6483

crates/core/src/host/wasm_common/module_host_actor.rs

Lines changed: 25 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ use bytes::Bytes;
22
use prometheus::IntGauge;
33
use spacetimedb_lib::db::raw_def::v9::Lifecycle;
44
use spacetimedb_schema::auto_migrate::ponder_migrate;
5-
use spacetimedb_schema::def::ModuleDef;
65
use std::sync::Arc;
76
use std::time::Duration;
87

98
use super::instrumentation::CallTimes;
109
use crate::database_logger::{self, SystemLogger};
1110
use crate::energy::{EnergyMonitor, EnergyQuanta, ReducerBudget, ReducerFingerprint};
1211
use crate::host::instance_env::InstanceEnv;
12+
use crate::host::module_common::{build_common_module_from_raw, ModuleCommon};
1313
use crate::host::module_host::{
1414
CallReducerParams, DatabaseUpdate, DynModule, EventStatus, Module, ModuleEvent, ModuleFunctionCall, ModuleInfo,
1515
ModuleInstance,
@@ -81,11 +81,8 @@ pub struct ExecuteResult<E> {
8181
pub(crate) struct WasmModuleHostActor<T: WasmModule> {
8282
module: T::InstancePre,
8383
initial_instance: Option<Box<WasmModuleInstance<T::Instance>>>,
84-
replica_context: Arc<ReplicaContext>,
85-
scheduler: Scheduler,
84+
common: ModuleCommon,
8685
func_names: Arc<FuncNames>,
87-
info: Arc<ModuleInfo>,
88-
energy_monitor: Arc<dyn EnergyMonitor>,
8986
}
9087

9188
#[derive(thiserror::Error, Debug)]
@@ -126,56 +123,35 @@ pub enum DescribeError {
126123

127124
impl<T: WasmModule> WasmModuleHostActor<T> {
128125
pub fn new(mcc: ModuleCreationContext, module: T) -> Result<Self, InitializationError> {
129-
let ModuleCreationContext {
130-
replica_ctx: replica_context,
131-
scheduler,
132-
program,
133-
energy_monitor,
134-
} = mcc;
135-
let module_hash = program.hash;
136126
log::trace!(
137-
"Making new module host actor for database {} with module {}",
138-
replica_context.database_identity,
139-
module_hash,
127+
"Making new WASM module host actor for database {} with module {}",
128+
mcc.replica_ctx.database_identity,
129+
mcc.program.hash,
140130
);
141-
let log_tx = replica_context.logger.tx.clone();
142-
143-
FuncNames::check_required(|name| module.get_export(name))?;
144-
let mut func_names = FuncNames::default();
145-
module.for_each_export(|sym, ty| func_names.update_from_general(sym, ty))?;
146-
func_names.preinits.sort_unstable();
147131

132+
let func_names = {
133+
FuncNames::check_required(|name| module.get_export(name))?;
134+
let mut func_names = FuncNames::default();
135+
module.for_each_export(|sym, ty| func_names.update_from_general(sym, ty))?;
136+
func_names.preinits.sort_unstable();
137+
func_names
138+
};
148139
let uninit_instance = module.instantiate_pre()?;
149-
let mut instance = uninit_instance.instantiate(
150-
InstanceEnv::new(replica_context.clone(), scheduler.clone()),
151-
&func_names,
152-
)?;
140+
let instance_env = InstanceEnv::new(mcc.replica_ctx.clone(), mcc.scheduler.clone());
141+
let mut instance = uninit_instance.instantiate(instance_env, &func_names)?;
153142

154143
let desc = instance.extract_descriptions()?;
155144
let desc: RawModuleDef = bsatn::from_slice(&desc).map_err(DescribeError::Decode)?;
156145

157-
// Perform a bunch of validation on the raw definition.
158-
let def: ModuleDef = desc.try_into()?;
159-
160-
// Note: assigns Reducer IDs based on the alphabetical order of reducer names.
161-
let info = ModuleInfo::new(
162-
def,
163-
replica_context.owner_identity,
164-
replica_context.database_identity,
165-
module_hash,
166-
log_tx,
167-
replica_context.subscriptions.clone(),
168-
);
146+
// Validate and create a common module rom the raw definition.
147+
let common = build_common_module_from_raw(mcc, desc)?;
169148

170149
let func_names = Arc::new(func_names);
171150
let mut module = WasmModuleHostActor {
172151
module: uninit_instance,
173152
initial_instance: None,
174153
func_names,
175-
info,
176-
replica_context,
177-
scheduler,
178-
energy_monitor,
154+
common,
179155
};
180156
module.initial_instance = Some(Box::new(module.make_from_instance(instance)));
181157

@@ -187,25 +163,25 @@ impl<T: WasmModule> WasmModuleHostActor<T> {
187163
fn make_from_instance(&self, instance: T::Instance) -> WasmModuleInstance<T::Instance> {
188164
WasmModuleInstance {
189165
instance,
190-
info: self.info.clone(),
191-
energy_monitor: self.energy_monitor.clone(),
166+
info: self.common.info(),
167+
energy_monitor: self.common.energy_monitor(),
192168
// will be updated on the first reducer call
193169
allocated_memory: 0,
194170
metric_wasm_memory_bytes: WORKER_METRICS
195171
.wasm_memory_bytes
196-
.with_label_values(&self.info.database_identity),
172+
.with_label_values(self.common.database_identity()),
197173
trapped: false,
198174
}
199175
}
200176
}
201177

202178
impl<T: WasmModule> DynModule for WasmModuleHostActor<T> {
203179
fn replica_ctx(&self) -> &Arc<ReplicaContext> {
204-
&self.replica_context
180+
self.common.replica_ctx()
205181
}
206182

207183
fn scheduler(&self) -> &Scheduler {
208-
&self.scheduler
184+
self.common.scheduler()
209185
}
210186
}
211187

@@ -219,11 +195,12 @@ impl<T: WasmModule> Module for WasmModuleHostActor<T> {
219195
}
220196

221197
fn info(&self) -> Arc<ModuleInfo> {
222-
self.info.clone()
198+
self.common.info()
223199
}
224200

225201
fn create_instance(&self) -> Self::Instance {
226-
let env = InstanceEnv::new(self.replica_context.clone(), self.scheduler.clone());
202+
let common = &self.common;
203+
let env = InstanceEnv::new(common.replica_ctx().clone(), common.scheduler().clone());
227204
// this shouldn't fail, since we already called module.create_instance()
228205
// before and it didn't error, and ideally they should be deterministic
229206
let mut instance = self

0 commit comments

Comments
 (0)