Commit Graph

98 Commits

Author SHA1 Message Date
Noa bb43213245 Typescript module API (#3327)
# Description of Changes

Currently based on #3361 

Implements most of the TS module API (not yet a function for type
aliases).

# Expected complexity level and risk

<!--
How complicated do you think these changes are? Grade on a scale from 1
to 5,
where 1 is a trivial change, and 5 is a deep-reaching and complex
change.

This complexity rating applies not only to the complexity apparent in
the diff,
but also to its interactions with existing and future code.

If you answered more than a 2, explain what is complex about the PR,
and what other components it interacts with in potentially concerning
ways. -->

# Testing

<!-- Describe any testing you've done, and any testing you'd like your
reviewers to do,
so that you're confident that all the changes work as expected! -->

- [x] Extremely basic module stuff works
- [ ] <!-- maybe a test you want a reviewer to do, so they can check it
off when they're satisfied. -->

---------

Signed-off-by: Noa <coolreader18@gmail.com>
Co-authored-by: Tyler Cloutier <cloutiertyler@aol.com>
Co-authored-by: = <cloutiertyler@gmail.com>
Co-authored-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
2025-10-16 14:58:50 +00:00
Phoebe Goldman aa295825f6 async-ify Wasmtime (and v8) execution (#3263)
# Description of Changes

In service of adding procedures, which will need to execute WASM code in
an `async` environment so as to suspend execution while making HTTP
requests and whatnot.

Prior to this PR, `JobCores` worked by spawning an OS thread for each
database. These threads would then each be pinned to a specific core,
and in multi-tenant deployments multiple threads could be pinned to the
same core. Now, instead, we spawn one thread per available core at
startup. Each of these threads runs a single-threaded Tokio executor.
Each database is assigned to one of these executors, and runs tasks on
it via `tokio::spawn`.

When we run without core pinning (usually due to having too few hardware
cores), we won't spawn any additional threads or Tokio runtimes at all;
instead we will run database jobs on the "global" Tokio executor. These
jobs may block Tokio worker threads, which might be an issue if a very
core-constrained device runs multiple databases with very long-running
reducers. If this is an issue, we could in this case instead build a
second Tokio runtime only for running database jobs, and let the OS
scheduler figure things out like it did previously.

Previously, we implemented load-balancing among the database cores by
occasionally instructing per-database threads to re-pin themselves. Now,
we instead periodically send the database a new
`wasmtime::runtime::Handle`, which they will `spawn` future jobs into.

Previously, it was possible for a database thread to become canceled,
most likely as a result of `ModuleHost::exit`, after which calls would
fail with `NoSuchModule`. Cancellation is no longer meaningful, as the
database holds a `Handle` to a long-lived `tokio::runtime::Runtime`,
which should always outlive the `ModuleHost`. I have added an
`AtomicBool` flag to `ModuleHost` which is flipped by `exit` and checked
by calls to maintain the previous functionality.

Within this PR, the jobs run on the database-execution Tokio tasks are
not actually asynchronous; they will never yield. This is important
because these jobs may (will) hold a transaction open, and attempting to
swap execution to another job which wants a transaction on the same
database would be undesirable.

Note that this may regress our multi-tenant performance / fairness:
previously, in multi-tenant environments, the OS scheduler would divide
the database cores' time between the per-database threads, potentially
causing one high-load database to be interrupted in the middle of a
reducer in order to run other databases pinned to the same core. Now, a
high-load database will instead run its entire reducer to completion
before any other database gets to run.

We could, in the future, change this by instructing Wasmtime to yield
periodically, either via [epoch
interruption](https://docs.wasmtime.dev/api/wasmtime/struct.Store.html#method.epoch_deadline_async_yield_and_update)
or
[fuel](https://docs.wasmtime.dev/api/wasmtime/struct.Store.html#method.fuel_async_yield_interval),
both of which we're already configuring Wasmtime to track. We'd need (or
at least want) to (re-)introduce a queue s.t. we only attempt to run one
job for each database at a time. I have chosen not to do so within this
patch because I felt the changeset was complex enough already, and we
have so far not treated fairness in multi-tenant environments as a high
priority.

I have also reworked our module host machinery to no longer use dynamic
dispatch and trait polymorphism to manage modules and their instances,
and instead introduced `enum Module` and `enum Instance`, each of which
has a variant for Wasm and another for V8.

During this rewrite, I reworked `AutoReplacingModuleInstance`, which
previously used type-erased trait generics in a way that was brittle and
hard to re-use in the new `async` context. (Specifically, the module
instance no longer lives on the job thread, rather, the database grabs
the instance and sends it to the job thread, then gets it back when the
job exits. This is necessary to allow the re-worked load balancing
described above, as we can't have a single long-lived async task.) While
refactoring, I replaced it with `ModuleInstanceManager`, which can now
maintain multiple instances of the same module. This is not yet useful,
but will become necessary with procedures, as each concurrent procedure
will need its own instance. Relatedly, I changed
`ModuleHost::on_module_thread` (used by one-off and initial subscription
queries) to no longer acquire the/an instance. I discussed this with the
team, and consensus was that "locking" the module instance in that path
was not a useful behavior, just an artifact of the previous
implementation.

I have also switched our Wasmtime configuration to set
`async_support(true)`. This causes a variety of methods, notably
`InstancePre::instantiate` and `TypedFunc::call`, to panic, and requires
that we instead call their `_async` variants. As mentioned above, I have
not yet introduced any actual asynchronicity or concurrency, so these
methods should never yield. Rather than `.await`ing their futures, I
have defined a degenerate `async` executor, `poll_once_executor`, which
polls a future exactly once, failing if it does not return
`Poll::Ready`. This means that we will panic if one of these futures
returns `Poll::Pending` unexpectedly.

The previous `trait Module` had a method `initial_instances`. `Module`
is now a concrete type, and I gave it this method, but it appears to be
unused. This is causing lints to fail. I am unsure what, if anything,
that method was for.

The previous `AutoReplacingModuleInstance` called `create_instance` on
the job thread. I am unsure if this was intentional, or just an artifact
of the previous implementation, where the `AutoReplacingModuleInstance`
lived on the job thread. I have written the new `ModuleInstanceManager`
to call `create_instance` on the calling thread, but it would be easy to
move that call into the job executor if that behavior is desired.

# API and ABI breaking changes

None user-facing

# Expected complexity level and risk

4: significant rewrite of performance-sensitive fiddly concurrency code.

Note specifically in above description:
- Running database jobs on the global Tokio runtime when not using core
pinning.
- Multi-tenant fairness issue: no longer possible to interrupt a
performance-intensive database mid-reducer to run another database
pinned to the same core.
- Unused method `module_instances`.
- Running `create_instance` on the calling thread rather than the
database thread.

# Testing

<!-- Describe any testing you've done, and any testing you'd like your
reviewers to do,
so that you're confident that all the changes work as expected! -->

- [x] Will arrange for a bot test.
- [ ] Determine to what extent we can run with real or synthetic
multi-tenant load in a test or staging environment.

---------

Signed-off-by: Phoebe Goldman <phoebe@goldman-tribe.org>
Co-authored-by: Mazdak Farrokhzad <twingoow@gmail.com>
Co-authored-by: joshua-spacetime <josh@clockworklabs.io>
2025-10-08 17:02:56 +00:00
Jason Larabie 26e99fe5e5 Added the Unreal SDK work for codegen, testing, and the plugin (#3223)
# Description of Changes

Closes #3219 
This adds the Unreal SDK, the new Unreal test cases, updates the test
runner to handle Unreal, codegen updates for Unreal, and a QuickStart
Chat.

# API and ABI breaking changes

No breaking changes.

# Expected complexity level and risk

2 - This impacts the subcommand generate.rs to include unrealcpp and
crates/testing to expand for Unreal

# Testing

- [x] Run the new Unreal tests 
- [x] Run any previous automation testing - with all the changes to
generate/testing I'm uncertain if there is an impact
- [x] Review the new CLI generate documentation changes

---------

Co-authored-by: Phoebe Goldman <phoebe@goldman-tribe.org>
Co-authored-by: Zeke Foppa <196249+bfops@users.noreply.github.com>
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
Co-authored-by: John Detter <4099508+jdetter@users.noreply.github.com>
2025-09-19 22:52:53 +00:00
Jeffrey Dallatezza 1d08167ebd Store client credentials in a new system table (#2983)
# Description of Changes

This adds a new system table to store the jwt payloads of connected
clients. I'm planning to use this system table to expose client claims
to modules in subsequent PRs.

The new table is called `st_connection_credentials`. It is a **private**
system table which stores a mapping from `connection_id` to
`jwt_payload`. Note that a jwt payload is a json representation of the
clients claims, not a fully signed token.

The times when we need to insert and delete these rows closely mirrors
that of the existing `st_client` table, with 1.5 exceptions:
1. We weren't previously inserting to `st_client` until after the
`OnConnect` reducer ran (even though it was in the same transaction). We
want `st_connection_credentials` to be populated before calling the
reducer, so that the reducer can use it get the credentials, so I made a
change to insert to `st_client` and `st_connection_credentials` before
calling the reducer.
2. This difference has not actualized, but when clients start sending
refresh tokens, we will probably need to update the credentials stored
in this table.

This also enforces uniqueness of connection ids. A duplicate connection
id will now make the on-connect reducer fail (since it will violate
uniqueness when trying to insert to `st_connection_credentials`).

# Expected complexity level and risk

2.5

Adding a system table is a bit risky. This is almost rollback safe, with
one annoying case that is worth calling out:

If a database is created with this system table, opening it with an
older version of spacetimedb will only work if there is a snapshot of
the database. If we try to load a table without a snapshot, replaying
will fail on the first row for that table. This is because we don't
write the table schema information to the commit log when creating a
database. In practice, this is unlikely to be an issue, because new
databases asynchronously trigger a snapshot immediately after creation.

Migrating existing databases will be fine. On startup this will detect
that there is a missing system table, and add it in a way that writes it
to the commit log. Since it is in the commit log, we can open the
database with an older version and still understand the data for that
table.

# Testing

There are unit tests that cover opening a database created with an older
version (which doesn't have this table).

I manually tested opening a migrated database with an older version of
spacetimedb.
2025-09-19 15:39:45 +00:00
Shubham Mishra 2c74f73550 Endpoint for pretty print migration plan (#3137)
# Description of Changes
- Adds endpoint for for pretty printing migration plan.
- It also changes current `publish` endpoint to optionally provide
`MigrationToken` and `MigrationPolicy` to allow migration with breaking
clients.

# API and ABI breaking changes
Backward compatible change to existing API and new Api

# Expected complexity level and risk
2

# Testing
- Existing smoketest should cover changes for `publish` endpoint.
- For pretty print endpoint, smoketests can be written only after cli
changes.

---------

Signed-off-by: Shubham Mishra <shivam828787@gmail.com>
Co-authored-by: James Gilles <jameshgilles@gmail.com>
Co-authored-by: Phoebe Goldman <phoebe@clockworklabs.io>
2025-09-09 06:53:37 +00:00
Zeke Foppa f6f0909ea4 Update all licenses (#3002)
# Description of Changes

We recently merged several repos together. This PR clarifies the license
terms for several subdirectories, as well as the relationship between
the licenses.

The licenses in our subdirectories have become symbolic links to
licenses in our toplevel `licenses` directory. For any particular
subdirectory's license file in the diff, you can click `... -> View
file` and then click on the text that says "Symbolic Link" on that page.
This will take you to the license file that it links to.

I have also updated the `tools/upgrade-version` script to update the
change date in the new `licenses/BSL.txt` file.

# API and ABI breaking changes

None.

# Expected complexity level and risk

1

# Testing

None. Only changes to license files.

---------

Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
2025-08-12 18:20:58 +00:00
Kim Altintop 61b54ef723 Upgrade jemalloc_pprof and tempfile crates (#2982) 2025-07-24 15:57:57 +00:00
Kim Altintop 09717e97ad Make websocket configurable via config.toml (#2944) 2025-07-16 19:31:07 +00:00
Noa 742303ca49 Bump rust-toolchain to rust 1.88 (#2749)
Co-authored-by: Mazdak Farrokhzad <twingoow@gmail.com>
2025-07-15 17:39:41 +00:00
Noa 967e82a5f8 Pin db threads to cores (#2801)
Signed-off-by: Noa <coolreader18@gmail.com>
Co-authored-by: Jeffrey Dallatezza <jeffreydallatezza@gmail.com>
Co-authored-by: joshua-spacetime <josh@clockworklabs.io>
Co-authored-by: Phoebe Goldman <phoebe@clockworklabs.io>
2025-06-06 18:37:35 +00:00
Kim Altintop c729c2100d Reintroduce replication factor parameter (#2718) 2025-05-19 06:55:09 +00:00
Mazdak Farrokhzad 373e47db39 PagePool::{default -> new_for_test} + temporary hack for IN_MEMORY_CONFIG / test_index_scans (#2707) 2025-05-12 13:15:07 +00:00
Noa c5f1d8d0dd Use spacetimedb-standalone to get schema for spacetime generate (#2644) 2025-05-07 21:56:53 +00:00
Mazdak Farrokhzad eb589728c6 Allocate pages using a mult-tenant lock-free pool (#2587) 2025-04-28 17:35:19 +00:00
Noa 483a9488e2 Update rand (#2568) 2025-04-11 17:39:41 +00:00
Mario Montoya f9f38543c8 Add readmes to all implementation crates specifying that they do no offer stable interfaces (#2320) 2025-03-06 19:50:17 +00:00
Mario Montoya 04fd294627 Add missing LICENSE (#2319) 2025-02-28 14:32:59 +00:00
Noa 6a8375260f Refactor HTTP api to better adhere to REST guidelines (real) (#2243) 2025-02-11 02:59:45 +00:00
Phoebe Goldman aedc601145 Rename Address to ConnectionId (#2220)
Signed-off-by: Phoebe Goldman <phoebe@goldman-tribe.org>
Co-authored-by: James Gilles <jameshgilles@gmail.com>
Co-authored-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com>
2025-02-10 00:40:16 +00:00
Tyler Cloutier e54a28584a Standardized module names and added module-test-cs based on module-test (#2232) 2025-02-09 05:58:19 +00:00
Noa e6775eb93a Finish spacetimedb-update functionality (#2126) 2025-02-06 20:32:46 +00:00
Noa 293aebaef9 Bump to Rust 1.84 (#2001) 2025-01-28 23:11:29 +00:00
Zeke Foppa a54ea3a391 CLI - Replace clippy with a manual check (#1928)
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
2025-01-17 00:03:11 +00:00
Noa c24042609e Split binaries (#2011) 2025-01-15 18:45:14 +00:00
Ingvar Stepanyan 40faad6e2e Implement ctx.Identity for C# (#2091) 2025-01-07 20:45:27 +00:00
Shubham Mishra 9c64d1fbd1 Durability Provider (#1864)
Signed-off-by: Shubham Mishra <shubham@clockworklabs.io>
Co-authored-by: Kim Altintop <kim@eagain.io>
2024-11-19 09:06:52 +00:00
Ingvar Stepanyan a7a1d36535 Run and test benchmarks against C# as well (#1965)
Co-authored-by: Zeke Foppa <196249+bfops@users.noreply.github.com>
2024-11-15 17:27:11 +00:00
Noa f136670420 Directory structure impl (#1879)
Co-authored-by: Jeffrey Dallatezza <jeffreydallatezza@gmail.com>
2024-11-12 04:24:43 +00:00
Mario Montoya 17423a4cf0 Add missing LICENSE (#1960) 2024-11-07 22:33:15 +00:00
Ingvar Stepanyan 6d712b4b0d Simplify benchmarking wrappers (#1951) 2024-11-06 17:21:56 +00:00
Mario Montoya cb9e0176e6 Fix benches for ia_loop, circles (#1922) 2024-11-05 14:50:31 +00:00
Mazdak Farrokhzad ac0053caab Websocket API: Light transaction updates & NoSuccessNotify (#1812)
Signed-off-by: Mazdak Farrokhzad <twingoow@gmail.com>
Co-authored-by: Phoebe Goldman <phoebe@clockworklabs.io>
2024-11-04 15:59:11 +00:00
Zeke Foppa 61360387be CLI - Login flow (#1878)
Co-authored-by: Jeffrey Dallatezza <jeffreydallatezza@gmail.com>
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
2024-10-29 20:28:45 +00:00
Tyler Cloutier fa960b3be9 Small naming fixes. Fixes database identity creation. (#1892) 2024-10-24 23:02:21 +00:00
Tyler Cloutier 83fc5c33d4 The banishment of Address (#1880)
Co-authored-by: Jeffrey Dallatezza <jeffreydallatezza@gmail.com>
2024-10-23 01:56:20 +00:00
Shubham Mishra 0a86b46152 Fix Build: Use default() to init custom hash based datastructures (#1871)
Signed-off-by: Shubham Mishra <shubham@clockworklabs.io>
Co-authored-by: Mazdak Farrokhzad <twingoow@gmail.com>
2024-10-17 14:41:38 +00:00
Noa c4e637e98b Energy metering for persistent memory usage (#766) 2024-10-15 17:58:34 +00:00
Jeffrey Dallatezza 83310eb6a7 Remove email and recovery related identity endpoints (#1833) 2024-10-15 00:13:18 +00:00
Tyler Cloutier d6bb05b072 Renamed database instance to replica (#1806) 2024-10-05 18:53:20 +00:00
Mazdak Farrokhzad 1ac741aa6b Generic and optimized WebSocket API (#1761)
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
2024-09-30 21:57:00 +00:00
Zeke Foppa 0375bcb80a CLI stabilization (#1741)
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
2024-09-30 20:57:38 +00:00
Zeke Foppa 09ad4decd0 CLI - publish and generate take a --build-options param (#1742)
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
2024-09-30 01:10:44 +00:00
Noa 53758420ec Rust module API rework (#1660) 2024-09-27 20:09:36 +00:00
Kim Altintop 711a6717c6 client-api: Remove publisher address (#1564) 2024-08-05 06:02:07 +00:00
Noa 10b151b999 Protobufectomy: server (#1077)
Co-authored-by: Phoebe Goldman <phoebe@goldman-tribe.org>
Co-authored-by: Jeremie Pelletier <jeremiep@gmail.com>
2024-07-12 18:02:18 +00:00
Mario Montoya 814dd5b738 Add small 'realistic' workload benchmark integration test (#714) 2024-06-13 18:28:35 +00:00
Ingvar Stepanyan 4b7eff66da Generate tagged enums in C# client code (#1421) 2024-06-13 16:32:46 +00:00
Kim Altintop 1044ebc652 core: Store address, owner and program bytes in st_module (#1305) 2024-06-10 10:25:16 +00:00
Zeke Foppa b06b2e59f1 Fix bug with Lockfile sticking around (#1341)
* [bfops/fix-config-lock]: do thing

* [bfops/fix-config-lock]: review

* [bfops/fix-config-lock]: review

* [bfops/fix-config-lock]: fix

* [bfops/fix-config-lock]: TODOs

* [bfops/fix-config-lock]: review

* [bfops/fix-config-lock]: review

* [bfops/fix-config-lock]: review

* [bfops/fix-config-lock]: review

---------

Co-authored-by: Zeke Foppa <github.com/bfops>
2024-06-05 22:40:24 +00:00
Noa 6b1a3d3896 Module hotswapping (#1147) 2024-05-22 17:49:35 +00:00