Skip to content

Commit 4272cfd

Browse files
authored
Merge branch 'master' into bradley/fix-validate-goldens-ci
2 parents 65e4539 + 2fd8a87 commit 4272cfd

34 files changed

Lines changed: 813 additions & 313 deletions

.github/workflows/ci.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,9 @@ jobs:
271271
needs: [lints]
272272
name: Keynote Bench
273273
runs-on: spacetimedb-benchmark-runner
274+
concurrency:
275+
group: ci-benchmark-runner
276+
queue: max
274277
timeout-minutes: 60
275278
env:
276279
CARGO_TARGET_DIR: ${{ github.workspace }}/target
@@ -325,6 +328,50 @@ jobs:
325328
- name: Run keynote-2 benchmark regression check
326329
run: cargo ci keynote-bench
327330

331+
index_scan_bench:
332+
needs: [lints]
333+
name: Index Scan Bench
334+
runs-on: spacetimedb-benchmark-runner
335+
concurrency:
336+
group: ci-benchmark-runner
337+
queue: max
338+
timeout-minutes: 60
339+
env:
340+
CARGO_TARGET_DIR: ${{ github.workspace }}/target
341+
RUST_BACKTRACE: full
342+
steps:
343+
- name: Find Git ref
344+
env:
345+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
346+
run: |
347+
PR_NUMBER="${{ github.event.inputs.pr_number || null }}"
348+
if test -n "${PR_NUMBER}"; then
349+
GIT_REF="$( gh pr view --repo clockworklabs/SpacetimeDB $PR_NUMBER --json headRefName --jq .headRefName )"
350+
else
351+
GIT_REF="${{ github.ref }}"
352+
fi
353+
echo "GIT_REF=${GIT_REF}" >>"$GITHUB_ENV"
354+
355+
- name: Checkout sources
356+
uses: actions/checkout@v4
357+
with:
358+
ref: ${{ env.GIT_REF }}
359+
360+
- uses: dsherret/rust-toolchain-file@v1
361+
- name: Set default rust toolchain
362+
run: rustup default $(rustup show active-toolchain | cut -d' ' -f1)
363+
364+
- name: Cache Rust dependencies
365+
uses: Swatinem/rust-cache@v2
366+
with:
367+
workspaces: ${{ github.workspace }}
368+
shared-key: spacetimedb
369+
save-if: false
370+
prefix-key: v1
371+
372+
- name: Run index scan benchmark regression check
373+
run: cargo bench -p spacetimedb-bench --bench index_scan_gate
374+
328375
lints:
329376
name: Lints
330377
runs-on: spacetimedb-new-runner-2

.github/workflows/cla-gate.yml

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
name: CLA Gate
2+
3+
# This workflow makes CLA checks work with merge queue entries. Merge groups get
4+
# a repository-owned `CLA Gate` commit status on the synthetic queue SHA, while
5+
# pull request/status events use this Actions job result based on CLA Assistant's
6+
# raw `license/cla` status.
7+
#
8+
# SECURITY: Pull request runs must still check out trusted base-branch code, not
9+
# PR code, before running repository scripts.
10+
11+
on:
12+
pull_request:
13+
types: [opened, reopened]
14+
status:
15+
merge_group:
16+
17+
permissions:
18+
contents: read
19+
pull-requests: read
20+
statuses: write
21+
22+
jobs:
23+
publish-cla-gate-status:
24+
name: CLA status
25+
runs-on: ubuntu-latest
26+
if: github.event_name != 'status' || github.event.context == 'license/cla'
27+
28+
steps:
29+
- name: Check out trusted base code
30+
uses: actions/checkout@v4
31+
with:
32+
ref: ${{ github.event.repository.default_branch }}
33+
34+
- uses: dsherret/rust-toolchain-file@v1
35+
36+
- name: Publish CLA Gate status
37+
uses: actions/github-script@v7
38+
env:
39+
GITHUB_TOKEN: ${{ github.token }}
40+
with:
41+
script: |
42+
const { execFileSync } = require("child_process");
43+
44+
function claStatus(args) {
45+
const output = execFileSync("cargo", ["ci", "cla-assistant", "status", ...args], {
46+
encoding: "utf8",
47+
env: process.env,
48+
});
49+
return JSON.parse(output);
50+
}
51+
52+
async function postStatus({ sha, state, description, targetUrl }) {
53+
const statusContext = "CLA Gate";
54+
core.info(
55+
`Publishing ${statusContext}=${state} for ${sha}: ${description}`
56+
);
57+
58+
await github.rest.repos.createCommitStatus({
59+
owner: context.repo.owner,
60+
repo: context.repo.repo,
61+
sha,
62+
state,
63+
description,
64+
context: statusContext,
65+
target_url: targetUrl,
66+
});
67+
}
68+
69+
let targetSha;
70+
let claStatusArgs;
71+
72+
if (context.eventName === "merge_group") {
73+
await postStatus({
74+
sha: process.env.GITHUB_SHA,
75+
state: "success",
76+
description: "Merge group entry; CLA already checked before queue",
77+
});
78+
return;
79+
}
80+
81+
if (context.eventName === "status") {
82+
targetSha = context.payload.sha;
83+
claStatusArgs = ["--sha", targetSha];
84+
} else if (context.eventName === "pull_request") {
85+
const pr = context.payload.pull_request;
86+
targetSha = pr.head.sha;
87+
claStatusArgs = ["--pr", String(pr.number)];
88+
} else {
89+
core.setFailed(`Unsupported event type: ${context.eventName}`);
90+
return;
91+
}
92+
93+
const status = claStatus(claStatusArgs);
94+
95+
if (!status.state) {
96+
core.info(`No CLA Gate status to publish for ${targetSha}`);
97+
return;
98+
}
99+
100+
if (status.state === "success") {
101+
core.info(`license/cla is success for ${targetSha}`);
102+
return;
103+
}
104+
105+
const state = status.state || "missing";
106+
const description = status.description || "license/cla status is missing";
107+
const targetUrl = status.target_url ? ` (${status.target_url})` : "";
108+
core.setFailed(`license/cla is ${state}: ${description}${targetUrl}`);

.github/workflows/retry-cla-assistant.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,6 @@ jobs:
7777
run: |
7878
while read -r pr_number; do
7979
if [ -n "${pr_number}" ]; then
80-
cargo ci retry-cla-assistant --pr-number "${pr_number}"
80+
cargo ci cla-assistant retry --pr-number "${pr_number}"
8181
fi
8282
done < "${{ steps.prs.outputs.path }}"

.github/workflows/tag-release.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ on:
22
release:
33
types: [published]
44

5+
permissions: {}
6+
57
jobs:
68
on-release:
79
name: Re-tag latest
@@ -21,3 +23,18 @@ jobs:
2123
run: |
2224
VERSION=${GITHUB_REF#refs/*/}
2325
docker buildx imagetools create clockworklabs/spacetimedb:$VERSION --tag clockworklabs/spacetimedb:latest
26+
27+
announce-release:
28+
name: Announce GitHub release
29+
runs-on: ubuntu-latest
30+
needs: on-release
31+
if: always()
32+
steps:
33+
- name: Send Discord notification
34+
run: |
35+
set -euo pipefail
36+
37+
message="SpacetimeDB GitHub release published: [${{ github.event.release.name }}](<${{ github.event.release.html_url }}>)"
38+
39+
data="$(jq --null-input --arg msg "$message" '.content=$msg')"
40+
curl -X POST -H 'Content-Type: application/json' -d "$data" "${{ secrets.DISCORD_WEBHOOK_RELEASE_ANNOUNCE_URL }}"

crates/bench/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ harness = false
3030
name = "index"
3131
harness = false
3232

33+
[[bench]]
34+
name = "index_scan_gate"
35+
harness = false
36+
3337
[[bin]]
3438
name = "summarize"
3539

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
use std::time::Duration;
2+
3+
use anyhow::{bail, Context, Result};
4+
use spacetimedb_sats::product;
5+
use spacetimedb_testing::modules::{start_runtime, CompilationMode, CompiledModule, IN_MEMORY_CONFIG};
6+
7+
#[cfg(not(target_env = "msvc"))]
8+
use tikv_jemallocator::Jemalloc;
9+
10+
#[cfg(not(target_env = "msvc"))]
11+
#[global_allocator]
12+
static GLOBAL: Jemalloc = Jemalloc;
13+
14+
const WARMUP_RUNS: usize = 5;
15+
const MEASURED_RUNS: usize = 31;
16+
const MEDIAN_THRESHOLD: Duration = Duration::from_micros(100);
17+
18+
const REDUCERS: &[&str] = &[
19+
"test_index_scan_on_id",
20+
"test_index_scan_on_chunk",
21+
"test_index_scan_on_x_z_dimension",
22+
"test_index_scan_on_x_z",
23+
];
24+
25+
fn main() -> Result<()> {
26+
let module = CompiledModule::compile("perf-test", CompilationMode::Release);
27+
let runtime = start_runtime();
28+
29+
runtime.block_on(async {
30+
let module = module.load_module(IN_MEMORY_CONFIG, None).await;
31+
let no_args = product![];
32+
33+
println!("loading perf-test location table...");
34+
module
35+
.call_reducer_binary("load_location_table", &no_args)
36+
.await
37+
.context("failed to load perf-test location table")?;
38+
39+
let mut failures = Vec::new();
40+
for &reducer in REDUCERS {
41+
for _ in 0..WARMUP_RUNS {
42+
module
43+
.call_reducer_binary_result(reducer, &no_args)
44+
.await
45+
.with_context(|| format!("failed during warmup for {reducer}"))?;
46+
}
47+
48+
let mut samples = Vec::with_capacity(MEASURED_RUNS);
49+
for _ in 0..MEASURED_RUNS {
50+
let result = module
51+
.call_reducer_binary_result(reducer, &no_args)
52+
.await
53+
.with_context(|| format!("failed during measured run for {reducer}"))?;
54+
samples.push(result.execution_duration);
55+
}
56+
57+
samples.sort_unstable();
58+
let median = samples[samples.len() / 2];
59+
60+
println!("{reducer:<36} median={median:?}");
61+
if median >= MEDIAN_THRESHOLD {
62+
failures.push(format!("{reducer} median {median:?}"));
63+
}
64+
}
65+
66+
if !failures.is_empty() {
67+
bail!(
68+
"index scan benchmark failed; median threshold is {:?}; failures: {}",
69+
MEDIAN_THRESHOLD,
70+
failures.join(", ")
71+
);
72+
}
73+
74+
println!(
75+
"index scan benchmark passed; all medians are below {:?}",
76+
MEDIAN_THRESHOLD
77+
);
78+
Ok(())
79+
})
80+
}

crates/core/src/db/update.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -558,9 +558,18 @@ mod test {
558558
Ok(())
559559
}
560560

561+
fn with_snapshotting(manual: bool) -> anyhow::Result<TestDB> {
562+
Ok(if manual {
563+
TestDB::durable_without_snapshot_repo()?
564+
} else {
565+
TestDB::durable()?
566+
})
567+
}
568+
561569
fn replay_event_table_schema_change(snapshot: TakeSnapshot) -> anyhow::Result<()> {
562570
let auth_ctx = AuthCtx::for_testing();
563-
let stdb = TestDB::durable()?;
571+
let with_snapshot = matches!(snapshot, TakeSnapshot::BeforeAutomigration);
572+
let stdb = with_snapshotting(with_snapshot)?;
564573

565574
let module_v1 = event_table_module(ProductType::from([
566575
("old_payload", AlgebraicType::U64),
@@ -576,7 +585,7 @@ mod test {
576585
stdb.commit_tx(tx)?;
577586
}
578587

579-
if matches!(snapshot, TakeSnapshot::BeforeAutomigration) {
588+
if with_snapshot {
580589
take_snapshot(&stdb)?;
581590
}
582591

@@ -635,7 +644,8 @@ mod test {
635644
/// permanently preventing the database from reopening.
636645
fn replay_event_table_drop(snapshot: TakeSnapshot) -> anyhow::Result<()> {
637646
let auth_ctx = AuthCtx::for_testing();
638-
let stdb = TestDB::durable()?;
647+
let with_snapshot = matches!(snapshot, TakeSnapshot::BeforeAutomigration);
648+
let stdb = with_snapshotting(with_snapshot)?;
639649

640650
let module_v1 = event_table_module(ProductType::from([("payload", AlgebraicType::U64)]));
641651
let module_v2 = empty_module();
@@ -659,7 +669,7 @@ mod test {
659669
stdb.commit_tx(tx)?;
660670
}
661671

662-
if matches!(snapshot, TakeSnapshot::BeforeAutomigration) {
672+
if with_snapshot {
663673
take_snapshot(&stdb)?;
664674
}
665675

crates/runtime/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ rust-version.workspace = true
1010
workspace = true
1111

1212
[dependencies]
13-
tokio = { workspace = true, optional = true }
13+
tokio.workspace = true
1414
async-task = { version = "4.4", default-features = false, optional = true }
1515
spin = { version = "0.9", default-features = false, features = ["mutex", "spin_mutex"], optional = true }
1616
libc = { version = "0.2", optional = true }
@@ -20,5 +20,5 @@ futures.workspace = true
2020

2121
[features]
2222
default = ["tokio"]
23-
tokio = ["dep:tokio"]
23+
tokio = []
2424
simulation = ["dep:async-task", "dep:spin", "dep:libc"]

0 commit comments

Comments
 (0)