Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,6 @@ examples/*/public/
!examples/multiplayer-game-patterns/public/**
!examples/multiplayer-game-patterns-vercel/public/
!examples/multiplayer-game-patterns-vercel/public/**

# Native addon binaries
*.node
7 changes: 7 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ docker-compose up -d
git commit -m "chore(my-pkg): foo bar"
```

- We use Graphite for stacked PRs. Diff against the parent branch (`gt ls` to see the stack), not `main`.
- To revert a file to the version before this branch's changes, checkout from the first child branch (below in the stack), not from `main` or the parent. Child branches contain the pre-this-branch state of files modified by branches further down the stack.

**Never push to `main` unless explicitly specified by the user.**

## Dependency Management
Expand Down Expand Up @@ -339,6 +342,10 @@ When making changes to the engine or RivetKit, ensure the corresponding document
- **Landing page changes**: When updating the landing page (`website/src/pages/index.astro` and its section components in `website/src/components/marketing/sections/`), update `README.md` to reflect the same headlines, features, benchmarks, and talking points where applicable.
- **Sandbox provider changes**: When adding, removing, or modifying sandbox providers in `rivetkit-typescript/packages/rivetkit/src/sandbox/providers/`, update `website/src/content/docs/actors/sandbox.mdx` to keep provider documentation, option tables, and custom provider guidance in sync.

### CLAUDE.md conventions

- When adding entries to any CLAUDE.md file, keep them concise. Ideally a single bullet point or minimal bullet points. Do not write paragraphs.

### Comments

- Write comments as normal, complete sentences. Avoid fragmented structures with parentheticals and dashes like `// Spawn engine (if configured) - regardless of start kind`. Instead, write `// Spawn the engine if configured`. Especially avoid dashes (hyphens are OK).
Expand Down
4 changes: 4 additions & 0 deletions engine/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ When changing a versioned VBARE schema, follow the existing migration pattern.
- When adding fields to epoxy workflow state structs, mark them `#[serde(default)]` so Gasoline can replay older serialized state.
- Epoxy integration tests that spin up `tests/common::TestCtx` must call `shutdown()` before returning.

## Concurrent containers

Never use `Mutex<HashMap<...>>` or `RwLock<HashMap<...>>`. Use `scc::HashMap` (preferred), `moka::Cache` (for TTL/bounded), or `DashMap`. Same for sets: use `scc::HashSet` instead of `Mutex<HashSet<...>>`. Note that `scc` async methods do not hold locks across `.await` points. Use `entry_async` for atomic read-then-write.

## Test snapshots

Use `test-snapshot-gen` to generate and load RocksDB snapshots of the full UDB KV store for migration and integration tests. Scenarios produce per-replica RocksDB checkpoints stored under `engine/packages/test-snapshot-gen/snapshots/` (git LFS tracked). In tests, use `test_snapshot::SnapshotTestCtx::from_snapshot("scenario-name")` to boot a cluster from snapshot data. See `docs-internal/engine/TEST_SNAPSHOTS.md` for the full guide.
17 changes: 1 addition & 16 deletions engine/packages/epoxy/src/ops/kv/read_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@ pub(crate) struct LocalValueRead {
/// 1. **V2 value** (`EPOXY_V2/replica/{id}/kv/{key}/value`). The current write path.
/// 2. **Legacy committed value** (`EPOXY_V1/replica/{id}/kv/{key}/committed_value`). Written by
/// the original EPaxos protocol. Deserialized as raw bytes with version 0 and mutable=false.
/// 3. **Legacy v2-format value** (`EPOXY_V1/replica/{id}/kv/{key}/value`). Written during the
/// intermediate v1-to-v2 transition where the key layout matched v2 but the subspace was
/// still v1.
/// 4. **Optimistic cache** (`EPOXY_V2/replica/{id}/kv/{key}/cache`). Only checked when
/// 3. **Optimistic cache** (`EPOXY_V2/replica/{id}/kv/{key}/cache`). Only checked when
/// `include_cache` is true. Contains values fetched from remote replicas for the optimistic
/// read path.
///
Expand All @@ -38,24 +35,20 @@ pub(crate) async fn read_local_value(
) -> Result<LocalValueRead> {
let value_key = KvValueKey::new(key.clone());
let legacy_value_key = LegacyCommittedValueKey::new(key.clone());
let legacy_v2_value_key = KvValueKey::new(key.clone());
let cache_key = KvOptimisticCacheKey::new(key);
let subspace = keys::subspace(replica_id);
let legacy_subspace = keys::legacy_subspace(replica_id);
let packed_value_key = subspace.pack(&value_key);
let packed_legacy_value_key = legacy_subspace.pack(&legacy_value_key);
let packed_legacy_v2_value_key = legacy_subspace.pack(&legacy_v2_value_key);
let packed_cache_key = subspace.pack(&cache_key);

ctx.udb()?
.run(|tx| {
let packed_value_key = packed_value_key.clone();
let packed_legacy_value_key = packed_legacy_value_key.clone();
let packed_legacy_v2_value_key = packed_legacy_v2_value_key.clone();
let packed_cache_key = packed_cache_key.clone();
let value_key = value_key.clone();
let legacy_value_key = legacy_value_key.clone();
let legacy_v2_value_key = legacy_v2_value_key.clone();
let cache_key = cache_key.clone();

async move {
Expand All @@ -79,14 +72,6 @@ pub(crate) async fn read_local_value(
});
}

// Legacy v2-format value (v1 subspace, v2 key layout)
if let Some(value) = tx.get(&packed_legacy_v2_value_key, Serializable).await? {
return Ok(LocalValueRead {
value: Some(legacy_v2_value_key.deserialize(&value)?),
cache_value: None,
});
}

let cache_value = if include_cache {
tx.get(&packed_cache_key, Serializable)
.await?
Expand Down
2 changes: 1 addition & 1 deletion engine/packages/pegboard-envoy/src/conn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ pub async fn handle_init(
// Read existing data
let (create_ts_entry, old_last_ping_ts_entry, version_entry) = tokio::try_join!(
tx.read_opt(&create_ts_key, Serializable),
tx.read_opt(&create_ts_key, Serializable),
tx.read_opt(&last_ping_ts_key, Serializable),
tx.read_opt(&version_key, Serializable),
)?;

Expand Down
Loading
Loading