mirror of
https://github.com/clockworklabs/SpacetimeDB.git
synced 2026-05-08 00:30:03 -04:00
52b6c66fa1
# Description of Changes This adds C++ server bindings (/crate/bindings-cpp) to allow writing C++ 20 modules. - Emscripten WASM build system integration with CMake - Macro-based code generation (SPACETIMEDB_TABLE, SPACETIMEDB_REDUCER, etc) - All SpacetimeDB types supported (primitives, Timestamp, Identity, Uuid, etc) - Product types via SPACETIMEDB_STRUCT - Sum types via SPACETIMEDB_ENUM - Constraints marked with FIELD* macros # API and ABI breaking changes None # Expected complexity level and risk 2 - Doesn't heavily impact any other areas but is complex macro C++ structure to support a similar developer experience, did have a small impact on init command # Testing - [x] modules/module-test-cpp - heavily tested every reducer - [x] modules/benchmarks-cpp - tested through the standalone (~6x faster than C#, ~6x slower than Rust) - [x] modules/sdk-test-cpp - [x] modules/sdk-test-procedure-cpp - [x] modules/sdk-test-view-cpp - [x] Wrote several test modules myself - [x] Quickstart smoketest [Currently in progress] - [ ] Write Blackholio C++ server module --------- Signed-off-by: Jason Larabie <jason@clockworklabs.io> Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com> Co-authored-by: Ryan <r.ekhoff@clockworklabs.io> Co-authored-by: John Detter <4099508+jdetter@users.noreply.github.com>
482 lines
17 KiB
C++
482 lines
17 KiB
C++
//! STDB module used for benchmarks.
|
|
//!
|
|
//! This file provides pure database operations with various indexing strategies for performance testing.
|
|
//!
|
|
//! We instantiate multiple copies of each table with different indexing:
|
|
//! - unique_0_*: single unique key on first field
|
|
//! - no_index_*: no indexes at all
|
|
//! - btree_each_column_*: btree index on every column
|
|
|
|
#include "common.h"
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
// =============================================================================
|
|
// SYNTHETIC BENCHMARK - TABLE VARIANTS FOR u32_u64_str (id, age, name)
|
|
// =============================================================================
|
|
|
|
// Unique indexed version
|
|
struct unique_0_u32_u64_str_t {
|
|
uint32_t id;
|
|
uint64_t age;
|
|
std::string name;
|
|
};
|
|
SPACETIMEDB_STRUCT(unique_0_u32_u64_str_t, id, age, name)
|
|
SPACETIMEDB_TABLE(unique_0_u32_u64_str_t, unique_0_u32_u64_str, Public)
|
|
FIELD_Unique(unique_0_u32_u64_str, id)
|
|
|
|
// No index version
|
|
struct no_index_u32_u64_str_t {
|
|
uint32_t id;
|
|
uint64_t age;
|
|
std::string name;
|
|
};
|
|
SPACETIMEDB_STRUCT(no_index_u32_u64_str_t, id, age, name)
|
|
SPACETIMEDB_TABLE(no_index_u32_u64_str_t, no_index_u32_u64_str, Public)
|
|
|
|
// BTree index on each column version
|
|
struct btree_each_column_u32_u64_str_t {
|
|
uint32_t id;
|
|
uint64_t age;
|
|
std::string name;
|
|
};
|
|
SPACETIMEDB_STRUCT(btree_each_column_u32_u64_str_t, id, age, name)
|
|
SPACETIMEDB_TABLE(btree_each_column_u32_u64_str_t, btree_each_column_u32_u64_str, Public)
|
|
FIELD_Index(btree_each_column_u32_u64_str, id)
|
|
FIELD_Index(btree_each_column_u32_u64_str, age)
|
|
FIELD_Index(btree_each_column_u32_u64_str, name)
|
|
|
|
// =============================================================================
|
|
// SYNTHETIC BENCHMARK - TABLE VARIANTS FOR u32_u64_u64 (id, x, y)
|
|
// =============================================================================
|
|
|
|
// Unique indexed version
|
|
struct unique_0_u32_u64_u64_t {
|
|
uint32_t id;
|
|
uint64_t x;
|
|
uint64_t y;
|
|
};
|
|
SPACETIMEDB_STRUCT(unique_0_u32_u64_u64_t, id, x, y)
|
|
SPACETIMEDB_TABLE(unique_0_u32_u64_u64_t, unique_0_u32_u64_u64, Public)
|
|
FIELD_Unique(unique_0_u32_u64_u64, id)
|
|
|
|
// No index version
|
|
struct no_index_u32_u64_u64_t {
|
|
uint32_t id;
|
|
uint64_t x;
|
|
uint64_t y;
|
|
};
|
|
SPACETIMEDB_STRUCT(no_index_u32_u64_u64_t, id, x, y)
|
|
SPACETIMEDB_TABLE(no_index_u32_u64_u64_t, no_index_u32_u64_u64, Public)
|
|
|
|
// BTree index on each column version
|
|
struct btree_each_column_u32_u64_u64_t {
|
|
uint32_t id;
|
|
uint64_t x;
|
|
uint64_t y;
|
|
};
|
|
SPACETIMEDB_STRUCT(btree_each_column_u32_u64_u64_t, id, x, y)
|
|
SPACETIMEDB_TABLE(btree_each_column_u32_u64_u64_t, btree_each_column_u32_u64_u64, Public)
|
|
FIELD_Index(btree_each_column_u32_u64_u64, id)
|
|
FIELD_Index(btree_each_column_u32_u64_u64, x)
|
|
FIELD_Index(btree_each_column_u32_u64_u64, y)
|
|
|
|
// =============================================================================
|
|
// SYNTHETIC BENCHMARK - EMPTY REDUCER FOR BASELINE
|
|
// =============================================================================
|
|
|
|
// Empty reducer for baseline measurement
|
|
SPACETIMEDB_REDUCER(empty, ReducerContext& ctx) {
|
|
return Ok();
|
|
}
|
|
|
|
// =============================================================================
|
|
// SYNTHETIC BENCHMARK - SINGLE INSERT OPERATIONS FOR STRING TABLES
|
|
// =============================================================================
|
|
|
|
SPACETIMEDB_REDUCER(insert_unique_0_u32_u64_str, ReducerContext& ctx, uint32_t id, uint64_t age, std::string name) {
|
|
unique_0_u32_u64_str_t record = {id, age, name};
|
|
ctx.db[unique_0_u32_u64_str].insert(record);
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(insert_no_index_u32_u64_str, ReducerContext& ctx, uint32_t id, uint64_t age, std::string name) {
|
|
no_index_u32_u64_str_t record = {id, age, name};
|
|
ctx.db[no_index_u32_u64_str].insert(record);
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(insert_btree_each_column_u32_u64_str, ReducerContext& ctx, uint32_t id, uint64_t age, std::string name) {
|
|
btree_each_column_u32_u64_str_t record = {id, age, name};
|
|
ctx.db[btree_each_column_u32_u64_str].insert(record);
|
|
return Ok();
|
|
}
|
|
|
|
// =============================================================================
|
|
// SYNTHETIC BENCHMARK - SINGLE INSERT OPERATIONS FOR NUMERIC TABLES
|
|
// =============================================================================
|
|
|
|
SPACETIMEDB_REDUCER(insert_unique_0_u32_u64_u64, ReducerContext& ctx, uint32_t id, uint64_t x, uint64_t y) {
|
|
unique_0_u32_u64_u64_t record = {id, x, y};
|
|
ctx.db[unique_0_u32_u64_u64].insert(record);
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(insert_no_index_u32_u64_u64, ReducerContext& ctx, uint32_t id, uint64_t x, uint64_t y) {
|
|
no_index_u32_u64_u64_t record = {id, x, y};
|
|
ctx.db[no_index_u32_u64_u64].insert(record);
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(insert_btree_each_column_u32_u64_u64, ReducerContext& ctx, uint32_t id, uint64_t x, uint64_t y) {
|
|
btree_each_column_u32_u64_u64_t record = {id, x, y};
|
|
ctx.db[btree_each_column_u32_u64_u64].insert(record);
|
|
return Ok();
|
|
}
|
|
|
|
// =============================================================================
|
|
// SYNTHETIC BENCHMARK - BULK INSERT OPERATIONS FOR NUMERIC TABLES
|
|
// =============================================================================
|
|
|
|
SPACETIMEDB_REDUCER(insert_bulk_unique_0_u32_u64_u64, ReducerContext& ctx, std::vector<unique_0_u32_u64_u64_t> locs) {
|
|
for (const auto& loc : locs) {
|
|
ctx.db[unique_0_u32_u64_u64].insert(loc);
|
|
}
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(insert_bulk_no_index_u32_u64_u64, ReducerContext& ctx, std::vector<no_index_u32_u64_u64_t> locs) {
|
|
for (const auto& loc : locs) {
|
|
ctx.db[no_index_u32_u64_u64].insert(loc);
|
|
}
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(insert_bulk_btree_each_column_u32_u64_u64, ReducerContext& ctx, std::vector<btree_each_column_u32_u64_u64_t> locs) {
|
|
for (const auto& loc : locs) {
|
|
ctx.db[btree_each_column_u32_u64_u64].insert(loc);
|
|
}
|
|
return Ok();
|
|
}
|
|
|
|
// =============================================================================
|
|
// SYNTHETIC BENCHMARK - BULK INSERT OPERATIONS FOR STRING TABLES
|
|
// =============================================================================
|
|
|
|
SPACETIMEDB_REDUCER(insert_bulk_unique_0_u32_u64_str, ReducerContext& ctx, std::vector<unique_0_u32_u64_str_t> people) {
|
|
for (const auto& person : people) {
|
|
ctx.db[unique_0_u32_u64_str].insert(person);
|
|
}
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(insert_bulk_no_index_u32_u64_str, ReducerContext& ctx, std::vector<no_index_u32_u64_str_t> people) {
|
|
for (const auto& person : people) {
|
|
ctx.db[no_index_u32_u64_str].insert(person);
|
|
}
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(insert_bulk_btree_each_column_u32_u64_str, ReducerContext& ctx, std::vector<btree_each_column_u32_u64_str_t> people) {
|
|
for (const auto& person : people) {
|
|
ctx.db[btree_each_column_u32_u64_str].insert(person);
|
|
}
|
|
return Ok();
|
|
}
|
|
|
|
// =============================================================================
|
|
// SYNTHETIC BENCHMARK - UPDATE OPERATIONS
|
|
// =============================================================================
|
|
|
|
SPACETIMEDB_REDUCER(update_bulk_unique_0_u32_u64_u64, ReducerContext& ctx, uint32_t row_count) {
|
|
uint32_t hit = 0;
|
|
for (const auto& u32_u64_u64 : ctx.db[unique_0_u32_u64_u64]) {
|
|
if (hit >= row_count) break;
|
|
++hit;
|
|
unique_0_u32_u64_u64_t updated_loc = {u32_u64_u64.id, u32_u64_u64.x + 1, u32_u64_u64.y};
|
|
ctx.db[unique_0_u32_u64_u64_id].update(updated_loc);
|
|
}
|
|
if (hit != row_count) {
|
|
return Err("Not enough rows to perform requested amount of updates");
|
|
}
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(update_bulk_unique_0_u32_u64_str, ReducerContext& ctx, uint32_t row_count) {
|
|
uint32_t hit = 0;
|
|
for (const auto& u32_u64_str : ctx.db[unique_0_u32_u64_str]) {
|
|
if (hit >= row_count) break;
|
|
++hit;
|
|
unique_0_u32_u64_str_t updated = {u32_u64_str.id, u32_u64_str.age + 1, u32_u64_str.name};
|
|
ctx.db[unique_0_u32_u64_str_id].update(updated);
|
|
}
|
|
if (hit != row_count) {
|
|
return Err("Not enough rows to perform requested amount of updates");
|
|
}
|
|
return Ok();
|
|
}
|
|
|
|
// =============================================================================
|
|
// SYNTHETIC BENCHMARK - ITERATION OPERATIONS
|
|
// =============================================================================
|
|
|
|
SPACETIMEDB_REDUCER(iterate_unique_0_u32_u64_str, ReducerContext& ctx) {
|
|
for (const auto& u32_u64_str : ctx.db[unique_0_u32_u64_str]) {
|
|
black_box(u32_u64_str);
|
|
}
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(iterate_unique_0_u32_u64_u64, ReducerContext& ctx) {
|
|
for (const auto& u32_u64_u64 : ctx.db[unique_0_u32_u64_u64]) {
|
|
black_box(u32_u64_u64);
|
|
}
|
|
return Ok();
|
|
}
|
|
|
|
// =============================================================================
|
|
// SYNTHETIC BENCHMARK - FILTERING BY ID OPERATIONS FOR STRING TABLES
|
|
// =============================================================================
|
|
|
|
SPACETIMEDB_REDUCER(filter_unique_0_u32_u64_str_by_id, ReducerContext& ctx, uint32_t id) {
|
|
auto result = ctx.db[unique_0_u32_u64_str_id].find(id);
|
|
if (result) {
|
|
black_box(*result);
|
|
}
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(filter_no_index_u32_u64_str_by_id, ReducerContext& ctx, uint32_t id) {
|
|
for (const auto& r : ctx.db[no_index_u32_u64_str]) {
|
|
if (r.id == id) {
|
|
black_box(r);
|
|
}
|
|
}
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(filter_btree_each_column_u32_u64_str_by_id, ReducerContext& ctx, uint32_t id) {
|
|
for (const auto& r : ctx.db[btree_each_column_u32_u64_str_id].filter(id)) {
|
|
black_box(r);
|
|
}
|
|
return Ok();
|
|
}
|
|
|
|
// =============================================================================
|
|
// SYNTHETIC BENCHMARK - FILTERING BY NAME OPERATIONS FOR STRING TABLES
|
|
// =============================================================================
|
|
|
|
SPACETIMEDB_REDUCER(filter_unique_0_u32_u64_str_by_name, ReducerContext& ctx, std::string name) {
|
|
for (const auto& p : ctx.db[unique_0_u32_u64_str]) {
|
|
if (p.name == name) {
|
|
black_box(p);
|
|
}
|
|
}
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(filter_no_index_u32_u64_str_by_name, ReducerContext& ctx, std::string name) {
|
|
for (const auto& p : ctx.db[no_index_u32_u64_str]) {
|
|
if (p.name == name) {
|
|
black_box(p);
|
|
}
|
|
}
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(filter_btree_each_column_u32_u64_str_by_name, ReducerContext& ctx, std::string name) {
|
|
for (const auto& p : ctx.db[btree_each_column_u32_u64_str_name].filter(name)) {
|
|
black_box(p);
|
|
}
|
|
return Ok();
|
|
}
|
|
|
|
// =============================================================================
|
|
// SYNTHETIC BENCHMARK - FILTERING BY ID OPERATIONS FOR NUMERIC TABLES
|
|
// =============================================================================
|
|
|
|
SPACETIMEDB_REDUCER(filter_unique_0_u32_u64_u64_by_id, ReducerContext& ctx, uint32_t id) {
|
|
auto result = ctx.db[unique_0_u32_u64_u64_id].find(id);
|
|
if (result) {
|
|
black_box(*result);
|
|
}
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(filter_no_index_u32_u64_u64_by_id, ReducerContext& ctx, uint32_t id) {
|
|
for (const auto& loc : ctx.db[no_index_u32_u64_u64]) {
|
|
if (loc.id == id) {
|
|
black_box(loc);
|
|
}
|
|
}
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(filter_btree_each_column_u32_u64_u64_by_id, ReducerContext& ctx, uint32_t id) {
|
|
for (const auto& loc : ctx.db[btree_each_column_u32_u64_u64_id].filter(id)) {
|
|
black_box(loc);
|
|
}
|
|
return Ok();
|
|
}
|
|
|
|
// =============================================================================
|
|
// SYNTHETIC BENCHMARK - FILTERING BY X COORDINATE FOR NUMERIC TABLES
|
|
// =============================================================================
|
|
|
|
SPACETIMEDB_REDUCER(filter_unique_0_u32_u64_u64_by_x, ReducerContext& ctx, uint64_t x) {
|
|
for (const auto& loc : ctx.db[unique_0_u32_u64_u64]) {
|
|
if (loc.x == x) {
|
|
black_box(loc);
|
|
}
|
|
}
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(filter_no_index_u32_u64_u64_by_x, ReducerContext& ctx, uint64_t x) {
|
|
for (const auto& loc : ctx.db[no_index_u32_u64_u64]) {
|
|
if (loc.x == x) {
|
|
black_box(loc);
|
|
}
|
|
}
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(filter_btree_each_column_u32_u64_u64_by_x, ReducerContext& ctx, uint64_t x) {
|
|
for (const auto& loc : ctx.db[btree_each_column_u32_u64_u64_x].filter(x)) {
|
|
black_box(loc);
|
|
}
|
|
return Ok();
|
|
}
|
|
|
|
// =============================================================================
|
|
// SYNTHETIC BENCHMARK - FILTERING BY Y COORDINATE FOR NUMERIC TABLES
|
|
// =============================================================================
|
|
|
|
SPACETIMEDB_REDUCER(filter_unique_0_u32_u64_u64_by_y, ReducerContext& ctx, uint64_t y) {
|
|
for (const auto& loc : ctx.db[unique_0_u32_u64_u64]) {
|
|
if (loc.y == y) {
|
|
black_box(loc);
|
|
}
|
|
}
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(filter_no_index_u32_u64_u64_by_y, ReducerContext& ctx, uint64_t y) {
|
|
for (const auto& loc : ctx.db[no_index_u32_u64_u64]) {
|
|
if (loc.y == y) {
|
|
black_box(loc);
|
|
}
|
|
}
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(filter_btree_each_column_u32_u64_u64_by_y, ReducerContext& ctx, uint64_t y) {
|
|
for (const auto& loc : ctx.db[btree_each_column_u32_u64_u64_y].filter(y)) {
|
|
black_box(loc);
|
|
}
|
|
return Ok();
|
|
}
|
|
|
|
// =============================================================================
|
|
// SYNTHETIC BENCHMARK - DELETE OPERATIONS
|
|
// =============================================================================
|
|
|
|
SPACETIMEDB_REDUCER(delete_unique_0_u32_u64_str_by_id, ReducerContext& ctx, uint32_t id) {
|
|
ctx.db[unique_0_u32_u64_str_id].delete_by_value(id);
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(delete_unique_0_u32_u64_u64_by_id, ReducerContext& ctx, uint32_t id) {
|
|
ctx.db[unique_0_u32_u64_u64_id].delete_by_value(id);
|
|
return Ok();
|
|
}
|
|
|
|
// =============================================================================
|
|
// SYNTHETIC BENCHMARK - CLEAR TABLE OPERATIONS (UNIMPLEMENTED)
|
|
// =============================================================================
|
|
|
|
SPACETIMEDB_REDUCER(clear_table_unique_0_u32_u64_str, ReducerContext& ctx) {
|
|
return Err("Modules currently have no interface to clear a table");
|
|
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(clear_table_no_index_u32_u64_str, ReducerContext& ctx) {
|
|
return Err("Modules currently have no interface to clear a table");
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(clear_table_btree_each_column_u32_u64_str, ReducerContext& ctx) {
|
|
return Err("Modules currently have no interface to clear a table");
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(clear_table_unique_0_u32_u64_u64, ReducerContext& ctx) {
|
|
return Err("Modules currently have no interface to clear a table");
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(clear_table_no_index_u32_u64_u64, ReducerContext& ctx) {
|
|
return Err("Modules currently have no interface to clear a table");
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(clear_table_btree_each_column_u32_u64_u64, ReducerContext& ctx) {
|
|
return Err("Modules currently have no interface to clear a table");
|
|
}
|
|
|
|
// =============================================================================
|
|
// SYNTHETIC BENCHMARK - COUNT OPERATIONS
|
|
// =============================================================================
|
|
|
|
SPACETIMEDB_REDUCER(count_unique_0_u32_u64_str, ReducerContext& ctx) {
|
|
LOG_INFO("COUNT: " + std::to_string(ctx.db[unique_0_u32_u64_str].count()));
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(count_no_index_u32_u64_str, ReducerContext& ctx) {
|
|
LOG_INFO("COUNT: " + std::to_string(ctx.db[no_index_u32_u64_str].count()));
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(count_btree_each_column_u32_u64_str, ReducerContext& ctx) {
|
|
LOG_INFO("COUNT: " + std::to_string(ctx.db[btree_each_column_u32_u64_str].count()));
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(count_unique_0_u32_u64_u64, ReducerContext& ctx) {
|
|
LOG_INFO("COUNT: " + std::to_string(ctx.db[unique_0_u32_u64_u64].count()));
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(count_no_index_u32_u64_u64, ReducerContext& ctx) {
|
|
LOG_INFO("COUNT: " + std::to_string(ctx.db[no_index_u32_u64_u64].count()));
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(count_btree_each_column_u32_u64_u64, ReducerContext& ctx) {
|
|
LOG_INFO("COUNT: " + std::to_string(ctx.db[btree_each_column_u32_u64_u64].count()));
|
|
return Ok();
|
|
}
|
|
|
|
// =============================================================================
|
|
// SYNTHETIC BENCHMARK - MODULE-SPECIFIC STRESS TESTING
|
|
// =============================================================================
|
|
|
|
SPACETIMEDB_REDUCER(fn_with_1_args, ReducerContext& ctx, std::string arg) {
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(fn_with_32_args, ReducerContext& ctx,
|
|
std::string arg1, std::string arg2, std::string arg3, std::string arg4,
|
|
std::string arg5, std::string arg6, std::string arg7, std::string arg8,
|
|
std::string arg9, std::string arg10, std::string arg11, std::string arg12,
|
|
std::string arg13, std::string arg14, std::string arg15, std::string arg16,
|
|
std::string arg17, std::string arg18, std::string arg19, std::string arg20,
|
|
std::string arg21, std::string arg22, std::string arg23, std::string arg24,
|
|
std::string arg25, std::string arg26, std::string arg27, std::string arg28,
|
|
std::string arg29, std::string arg30, std::string arg31, std::string arg32) {
|
|
return Ok();
|
|
}
|
|
|
|
SPACETIMEDB_REDUCER(print_many_things, ReducerContext& ctx, uint32_t n) {
|
|
for (uint32_t i = 0; i < n; ++i) {
|
|
LOG_INFO("hello again!");
|
|
}
|
|
return Ok();
|
|
} |