Changelog
[Unreleased]
Added
- CockroachDB SQL variants for TPC-B and TPC-C (
--sql-file tpcb/crdb.sqlortpcc/crdb.sql) retain native workload metrics. (#166) - Export native transaction, iteration and query throughput over the measured workload window, including explicit zero error counters. (#166)
Fixed
- CockroachDB TPC-C loads ignore the PostgreSQL-only unlogged option instead of issuing unsupported durability changes. (#166)
- Yandex Cloud dedicated connections load the internal CA before the first IAM-token handshake; explicit credentials are never replaced by VM metadata credentials after an error. (#166)
- TPC-C population validation retries transient read failures within the configured attempt limit and reports setup retries separately; data mismatches still fail validation. (#166)
- Retry YDB overload errors even when the SDK also reports cancellation of its query stream; explicit caller cancellation still stops the workload. (#166)
- TPC-C population checks now log the underlying database query error, and setup failures report zero measurement time when execution never started. (#166)
- The simple workload uses YDB-compatible table definitions and accepts unsigned row counts. (#166)
- Picodata now honors pgx pool and query execution options supplied through config files or driver flags. (#166)
- Picodata reads exact decimal values in text format to avoid a legacy numeric-zero decoding hang. (#166)
- TPC-C population validation handles fractional Picodata percentages without decimal encoding errors. (#166)
- Retry MySQL/MariaDB snapshot conflicts (error 1020) according to the workload's serialization retry policy. (#166)
- Count the final partial SQL insert batch once in load progress, keeping generated and confirmed row counts consistent. (#166)
- Keep concurrent benchmark metrics distinct and preserve run metadata when exporting through OTLP to Prometheus-compatible storage. (#166)
- Count expected TPC-C procedure rollbacks as successful logical transactions on PostgreSQL and MySQL, while preserving rollback failures. (#166)
[6.0.0] - 2026-09-08
Added
- New
stroppy baselinecommand measures stroppy's own performance ceiling on the current machine without a database: a noop-driver framework tier and a pg-wire protocol tier against the pg-noop blackhole server, each reporting load throughput plus single-VU and parallel transaction rates. Verdicts check hardware-independent invariants (parallel scaling, loopback latency floor, measurement sanity), every run saves a versioned JSON report under~/.stroppy/baselines/with a delta versus the previous run, and the pg-noop server ships embedded in release builds or downloads with consent (sha256-verified) otherwise. (#162) --query-timeout(alsoQUERY_TIMEOUTand configrun.queryTimeout) bounds each executed statement with a per-statement deadline;0(the default) disables it. Timed-out statements are reported distinctly from a canceled run, and MySQL adds a server-sideMAX_EXECUTION_TIMEhint so a timed-out query keeps its pooled connection. (#153)- All TPC-C runs now emit text and JSON reports with per-transaction count, mix, throughput, and p50/p90/p95/p99 response times; paced runs additionally receive §5.2.5 response-time and transaction-mix verdicts, statistical-validity status, and a steady-state assessment, while unpaced runs mark compliance not applicable. (#147)
- Restored the
tpcb/procsworkload: TPC-B ships bothtxandprocsvariants again, withtpcb/procsrunning each transaction as one server-side stored-procedure call (tpcb_transaction) on PostgreSQL and MySQL. (#146) stroppy probenow lists registered workload parameter flags, and its JSON output includes each workload's typed schema for tooling and discovery. (#128)- Typed scenario and workload parameters can be set with
--nameflags or native JSON values in the config file'srunandparamsobjects, andstroppy run <workload> --helplists the available parameters. (#128) - Go workloads can declare typed string, boolean, numeric, and duration parameters with defaults, descriptions, source tracking, and discoverable schemas. (#128)
- Database errors are classified by each driver into shared facts, and Go workloads can override the default retry, error, ignore, or fatal action for each fact without matching backend-specific codes or messages. (#127)
- Reusable generation primitives now live in
pkg/gen, whilepkg/datagen/sourcedefines the row-production seam andpkg/datagen/tpchgenandpkg/datagen/tpcdsgenadapt the canonical TPC-H and TPC-DS generators. (#126) pkg/gennow provides typed direct-output batches: a reusable columnar [Batch] with bound [Column] handles and an [IndexedSource] that fills rows through a plain Go row callback, so workload formulas write straight into prepared storage with zero generation-time allocations after preparation. (#126)- Insert-method ownership moves to the driver package:
driver.InsertMethodis the Go-native enum for the typed insert path, withParseInsertMethodfor authoring strings (plain_query,plain_bulk,columnar,native). (#126) - Typed insert path:
driver.InsertRequest+Driver.Insert+Bench.Insertstream rows from a workload-authoredgen.BatchSourcethrough every driver (postgres, mysql, picodata, ydb, noop, csv), with a typed parallel runner inpkg/driver/common. (#126) - The
simpleworkload loadsstroppy_demothrough the typed insert path: a plain Go row formula (id, 8-char label, uniform value) over a versionedgensource replaces the relational InsertSpec struct literal. (#126) - TPC-B loads
pgbench_branches,pgbench_tellers, andpgbench_accountsthrough the typed insert path: per-tablegensources preserve the bid fan-out arithmetic (floor(entity/perBranch)+1), fixed-width ASCII fillers, and the legacy per-table seeds. (#126) - TPC-C loads all eight tables (
warehouse,district,customer,item,stock,orders,order_line,new_order) through typed plain-Go sources, preserving NURand surnames, per-district customer permutations, fixed-width fields, decimal scales, credit and delivery splits, and ORIGINAL markers. (#126) - TPC-H loads through the typed insert path: all eight tables (
region,nation,part,supplier,partsupp,customer,orders,lineitem) stream from the canonical dbgen generator throughpkg/datagen/tpchgenandgen.BatchSource. Canonical seeds, partition seeking, entity fan-out, and SF=1 output are unchanged; dbgen'sMake*layer remains the documented internal allocation boundary. (#126) - TPC-DS loads through the typed insert path: all 24 tables (18 dimension tables, inventory, and 6 fan-out sales/returns fact tables) stream from the canonical dsdgen generator through
pkg/datagen/tpcdsgenandgen.BatchSource, preserving text output, null semantics, ticket fan-out, partition seeking, and nominal fact-row reporting. (#126) - The legacy
InsertSpecload path is gone.Driver.InsertSpec,Bench.InsertSpec,loadsource.Build, the per-driverInsertSpecmethods,RunParallelByWorkers, and the dgproto↔driverMethodFromProto/MethodToProtoboundary converters are removed; every workload now loads exclusively through the typeddriver.Insert/Bench.Insertpath overgen.BatchSource. The sharedChunk/SplitChunkshelpers moved topkg/driver/common/chunks.go; per-driverrunInsertChunk/bulk/COPY helpers are unchanged. Insert-method strings (plain_query,plain_bulk,columnar,native), probe output, and progress/metrics semantics are preserved. (#126) - Metrics can again be exported to an OpenTelemetry collector through the existing
global.exporter.otlpExportgRPC or HTTP configuration. (#125)
Changed
- Benchmark duration histograms add sub-100µs buckets (5–50µs) so loopback-scale latencies are no longer clamped to the coarsest 100µs bucket. (#162)
- Nonfatal transaction and query-set errors now keep virtual users running, exit successfully, and appear in bounded warnings, terminal-error metrics, and a prominent final summary; the unused driver
errorModeoption has been removed and is now rejected. (#156) - Logging now uses one safely replaceable process-wide logger, with configurable level and output mode precedence plus redacted database connection diagnostics. (#154)
- Driver insert-method defaults now fill only load requests that leave their method unset, preserving methods selected by workloads. (#152)
- SIGINT and SIGTERM now cancel the running workload and trigger graceful teardown; a second signal forces immediate exit. Exit status is 130 (SIGINT) or 143 (SIGTERM) after a graceful cancellation, 2 after a forced exit, and 1 for other errors. (#148)
- Built-in workloads expose their tuning options as typed parameters while preserving the existing environment-variable names. (#128)
- TPC-DS typed loads format common cell types directly into reusable buffers. (#126)
- Benchmark metrics now use standard OpenTelemetry counters, gauges, and fixed-bucket histograms. Query throughput and error rates are derived from monotonic
*_totalcounters instead of k6-style sampled rates. (#125) - The
stroppy help <topic>topics (drivers, config-file, steps, resolution, sql, envs, datagen, probe) now describe the Go-native binary — the previous text still documented the removed TypeScript/k6 workflow (k6Args,declareDriverSetup,.tsscript mode, the--passthrough). - Stroppy configuration is now plain Go under
pkg/configinstead of frozen application protobuf types. Existing v5 lower-camel and snake_case JSON field names, nullable fields, int32 number forms, and logger enum names/ordinals remain compatible, while duplicate, colliding, mis-cased, unknown, malformed, and trailing input is rejected recursively across config files and raw driver JSON.global.seedis the sole accepted-form change and now requires a bare unsigned JSON integer. The generated schema documents the completestroppy-config.jsonenvelope, includingrun.queryTimeoutand workload parameters. (#150) - Inputs now resolve once through typed parameters and pass directly to workloads and drivers instead of using process-environment bridges for step filters, execute-SQL sources, pool sizing, CSV workload identity, or serialized driver config. Process environment variables remain supported as typed input sources, space-separated
--sql-bodyaccepts query text beginning with a--= namemarker, and SQL sources without named queries report a source-neutral error. The historicalk6Args,k6Config, and driverdefaultTxIsolationfields are now rejected as unknown; use typed executor settings and each workload's--tx-isolationparameter instead. (#151)
Fixed
- Unknown run flags and arguments after
--now point to workload help and supported typed flags instead of recommending a removed passthrough. (#164) - Baseline runs now reject empty measurements and invalid negative inputs, isolate concurrent benchmark state, cancel and bound pg-noop downloads, use target-specific authoritative server caches, verify embedded release assets against Stroppy-pinned checksums, and preserve report output and history integrity. (#162)
- CSV output now publishes shards, merged files, and manifests atomically across fresh and repeated loads, so canceled or failed loads retain recoverable shards and never expose partial output as complete. (#157)
- Query helpers now return an empty result instead of panicking when a driver supplies no result set, and query timeouts that surface while closing result sets are reported once instead of repeating the same error. (#153)
- Empty, whitespace-only, or comma-only step filters no longer conflict with a real opposite filter;
--steps=still clears configured steps before--no-stepsis applied. (#149) - The
workloadstep is silent on the console again (noStart/Endrecord per transaction), while setup/load/schema steps still log a single start/end and thesimpleworkload now honors--steps/--no-stepslike the other workloads. (#149) --stepsand--no-stepsare rejected as mutually exclusive even when one is set in the config file and the other on the command line. (#149)- TPC-B fails fast with a named missing query/section instead of running a silent noop iteration when a custom SQL file omits required statements. (#145)
- TPC-C treats absent customer, warehouse, item, and stock rows as transaction errors, propagates rollback failures instead of reporting an unknown outcome as success, and fails population-validation checks whose aggregate queries error. (#145)
stroppy versionnow reports the real build version for Docker images (pushed tag), nightly artifacts (nightly-<short-sha>), and release archives (release tag), instead of the generic0.0.0fallback. (#144)- Workload help and shell completion expose typed flags accurately, including explicit booleans and contextual defaults, and SQL override positionals reach registered workload bindings. (#128)
- Typed run parameters and SQL sources keep CLI-over-environment precedence, config env names reject case-only collisions, shared driver pool settings remain active alongside driver-specific settings, and invalid pool fields fail clearly instead of being ignored. (#128)
- Typed inserts reject malformed requests consistently, and generator ranges remain correct at integer boundaries. (#126)
- Long high-throughput workloads keep bounded metric memory instead of retaining every latency observation until the final summary. (#125)
Removed
- The relational data-generation expression framework is gone.
pkg/datagen/{compile,expr,runtime,lookup,cohort,stdlib,seed}and the frozenpkg/datagen/dgprotoprotobuf types (InsertSpec, Expr, StreamDraw, …) are deleted. Reusable generation primitives now live inpkg/gen;pkg/datagen/sourceis the row-production seam, andpkg/datagen/tpchgenandpkg/datagen/tpcdsgenadapt the surviving canonical generators. Thedatagen-framework.mdandproto.mdguides were removed —docs/parallelism.mdis the load-parallelism reference. (#126) - Stroppy no longer depends on k6, TypeScript, sobek, esbuild, or node/npm. The engine is now a single plain Go binary built with
go build— authoring benchmarks in TypeScript, the--k6-args passthrough, thegenscaffolding command, and the cloud status gRPC service are all gone. Configure runs primarily with--executor,--vus,--iterations,--duration, and--query-timeout, or the matching typedrunconfig fields; environment variables remain compatibility inputs. Workloads are Go-native (tpcc/tx,tpcb/tx,tpch/tx,tpcds,simple,execute_sql);.sqlfiles and inline SQL still work.
[5.7.3] - 2026-07-29
Fixed
PACING=truenow applies keying and think-time delays totpcc/procsas well astpcc/tx. The pacing code lived only in thetxvariant, so stored-procedure runs ignored it entirely and ran unpaced regardless of the flag. (#114)
Changed
- The
tpcc/txandtpcc/procsworkloads now share their driver setup, load/prepare lifecycle, retry policy, pacing, weighted dispatch, and post-run summary throughtpcc_common.ts(matching the existingtpcblayout), instead of each carrying its own copy. Both variants now surface database errors as exceptions consistently (previouslyprocsthrew whiletxonly logged). (#114)
[5.7.2] - 2026-07-27
Changed
- PostgreSQL data loads now keep tables
LOGGEDby default instead of flipping them toUNLOGGEDfor the bulk load. TheUNLOGGEDoptimization (WAL-free load, then flip back) is now opt-in via-e PG_UNLOGGED=true. It traded load speed for a sharp footgun: apreparethat ran twice on the same schema failed withcould not change table "warehouse" to unlogged because it references logged table "district" (42P16), because the foreign keys added at the end of the first prepare block the unlogged flip at the start of the second — so re-running a workload without dropping the schema aborted every iteration. Logged-by-default removes that failure mode entirely. (#111) - Stroppy allocates far less memory in the hot transaction loop. Every reference to a named import (
Step,ENV,Rel,Draw,retry,DriverX, …) had k6 rebuild the full module exports table from scratch, which a 30s heap profile showed as the single largest allocator. The exports table is now built once per VU and reused, cutting that churn entirely. (#110)
[5.7.1] - 2026-07-23
Changed
- Stroppy runs scale better at high VU counts. A single shared mutex guarded the active-step tag and was write-locked on every
Step()plus read on every metric sample, so all VUs serialized on it — a 30s CPU profile of atpcbrun showed ~940 of ~1000 goroutines parked waiting for it while the database sat idle. The step tag now lives per-VU (lock-free), and the per-transaction metrics snapshot path no longer takes a mutex (pointers are immutable after one-time registration). Microbenchmarks of both paths drop ~140 ns/op to under 1 ns/op at 8 cores. (#109)
Fixed
- TPC-B transactions now retry on serialization conflicts instead of failing the run. The
tpcb/txworkload issued its transaction with no retry wrapper, so under concurrent VUs the first serializable abort — PostgreSQL40001/40P01, MySQL1213, or YDBTransaction locks invalidated— was thrown straight to the error log and aborted the whole run, even though every other transactional workload (tpcc/tpch/tpcds) already retries these. tpcb now applies the same retry policy, so transient contention is replayed instead of surfaced (visible as the newtpcb_retry_attemptscounter). (#108)
[5.7.0] - 2026-07-22
Added
- TPC-DS now runs on Picodata:
stroppy run tpcds -d pico -D url=postgres://admin:...@host:1336/admin -e SCALE_FACTOR=0.1. Ships a typed sbroad schema (schema.pico.sql:char→varchar,date→datetime, aPRIMARY KEYper Tarantool space, no FK) and a picodata SQL port of the query suite (pico.sql) that rewrites sbroad-incompatible constructs (explicitJOIN ONinstead of comma joins, bare date strings, etc.). 95 of the 103 queries run; the 8 that needrank/dense_rank/lag/lead(query_36,query_44,query_47,query_49,query_57,query_67,query_70,query_86) are skipped with a one-time log line, since sbroad has no window-function support. Answer-set validation stays PostgreSQL/MySQL-only. (#100) - The
columnarinsert method is now accepted by the YDB driver and redirected to the nativeBulkUpsert(already a struct-of-arrays, limit-free payload), logging a one-time warning, instead of being rejected.columnaris now listed for YDB instroppy probe. MySQL and Picodata keep their existing insert methods: on MySQLcolumnarshowed no throughput benefit over multi-rowplain_bulk(measured against TPC-C/H/DS at SF 1), and Picodata's SQL has no array/JSON-expansion path. (#99) - TPC-DS now runs on YDB:
stroppy run tpcds/tpcds -d ydb -D url=grpc://host:2136/database. Ships a typed YQL schema (schema.ydb.sql, column-store default with row-store as an option via-e YDB_STORE_MODE=row) and the 103-query suite ported to YQL (ydb.sql). The loader now feeds YDB's native bulk upsert directly from the generator. Answer-set validation and the in-process query-stream generator stay PostgreSQL/MySQL-only, so YDB runs the baked power test. (#97) stroppy probe(no arguments) now also lists which insert methods each driver supports —plain_query,plain_bulk,columnar,nativeper database — as aDRIVERSblock in the human output and adriverskey in-o json, so external tooling can discover validdefaultInsertMethodvalues per target without reading stroppy source. (#96)
Fixed
- TPC-H queries now run on Picodata (
stroppy run tpch/tx -d pico ...). Every one of the 22 queries failed to even parse against current picodata: sbroad rejects implicit comma joins (FROM a, b), the typeddate '...'literal,intervalarithmetic,extract(year FROM ...),NOT LIKE, and correlated subqueries. The picodata SQL port now uses explicitJOIN ON, bare date strings,substring(cast(... AS string) FROM 1 FOR 4)for year extraction,NOT (x LIKE ...)for negation, and JOIN-on-aggregate CTEs to decorrelate q2/q17/q20/q21 — each rewrite is answer-checked against PostgreSQL on identical data at SF=0.01 (all 22 result sets match row-for-row). The tmpfs-all compose init also raises sbroad'ssql_vdbe_opcode_maxandsql_motion_row_max, without which the wide multi-join aggregates (q3/q10/q21) blow past the default caps. (#105) - The Grafana dashboard (
docs/dashboard.json) shows data again. Its panel queries were written for an older metric-naming scheme and no longer matched what stroppy exports through OpenTelemetry: the metric prefix isstroppy_(the scenario is now a label, not baked into the name), counters carry a_totalsuffix, duration histograms a_milliseconds_bucketsuffix, anddata_received/data_sentare_bytes_total. It also filtered on aservice.namelabel that the collector emits asjob. All queries, template variables, and the default${prefix}were updated to the current names. The load-phase "Insert rows/s" panels additionally filterevent="progress"so they track the live row counter instead of the flat final-value series. (#103) - Pressing Ctrl-C twice during a data load now stops the run instead of leaving the process stuck and unkillable except by
kill -9. Every InsertSpec drain loop (noop, mysql, postgres bulk/columnar, ydb, csv) never consulted its context at all, so a worker kept generating rows until the whole table drained before noticing the run was aborted — one long uninterruptible native call that k6 cannot preempt. The drain loops now check cancellation per row via a sharedinsertprogress.Canceledhelper, so k6's abort (which cancels the VU context on Ctrl-C) unblocks the load promptly. (#102) - Wide-table bulk loads on Picodata (and the latent YDB
plain_bulkpath) no longer hit the bound-parameter limit. The batch-size-by-column-count clamp that kept multi-row INSERTs under 65535 bound parameters lived in the MySQL driver only; it now runs centrally in the sharedsqldriver.RunBulkInsert, so every sql.DB-backed dialect is protected. Previously TPC-DSdate_dim(28 cols),catalog_sales, andweb_sales(34 cols) aborted withextended protocol limited to 65535 parametersand loaded zero rows. (#100)
[5.6.0] - 2026-07-01
Added
- New PostgreSQL insert method
columnar: pass one array per column and let the database expand it back to rows (unnest), so a batch binds as many parameters as there are columns instead of rows × columns. This clears PostgreSQL's 65535 bind-parameter limit that plain multi-row inserts hit on wide tables, and loads roughly 2.5–3× faster thanplain_bulk— close toCOPYwhile still being an ordinaryINSERT. Select it with-D defaultInsertMethod=columnar(or"defaultInsertMethod": "columnar"in a driver config). (#93) - Each completed step now reports how long it took, e.g.
End of 'create_schema' step (took 1.23s). (#83) - The
create_indexesandset_loggedsteps now log one progress line per statement, with elapsed time, so you can see which index or table flip is slow instead of waiting on one opaque step boundary. (#83)
Changed
- The per-iteration
workloadstep no longer prints aStart/End of 'workload' stepline on every transaction — that pair was flooding the log. The step still runs and reports its status as before; it is just silent on the console. (#83)
Fixed
- A failed TPC-C
validate_populationcheck now makes the run exit non-zero instead of reporting success. The check detected a bad population and logged every failed assertion, butstroppy runstill exited0, so CI and matrix runs that gate on the exit code saw a false pass. The run now aborts with a dedicated exit code (108) on any population mismatch; a skipped check (--no-steps validate_population) still exits0. (#92)
[5.5.2] - 2026-06-30
Fixed
- Fixed-duration throughput runs (with
DURATIONset) no longer fail to start. The run selects k6's constant-VUs executor, which does not accept themaxDurationoption the workload was still passing, so it aborted at startup withjson: unknown field "maxDuration".maxDurationis now applied only to power tests, where it belongs. (#82) - Power tests with more than one VU (
VUS>1) and the default iteration count no longer fail to start withthe number of iterations can't be less than the number of VUs. The iteration count is now raised to at leastVUS. (#82) - The TPC-DS workload can now be re-run against a database that still holds its schema from a previous run.
drop_schemadrops withCASCADE, so it no longer fails withcannot drop table item because other objects depend on it(SQLSTATE 2BP01). (#82) - The published Docker image (
ghcr.io) builds again. Its build stage used Go 1.25 while the module requires Go 1.26, so image publishing had failed since v5.4.0.
[5.5.1] - 2026-06-29
Fixed
- The default
UNLOGGEDfast bulk-load (PG_UNLOGGED=true) on PostgreSQL no longer fails while preparing TPC-C or TPC-B. PostgreSQL refuses to flip a table toUNLOGGED/LOGGEDwhile it shares a foreign key with a table in the other persistence state (in either direction), so TPC-C errored onset_unlogged(could not change table … because it references logged table …, SQLSTATE 42P16) and TPC-B would hit the same onset_logged. Foreign keys are now created in acreate_foreign_keysstep that runs afterset_logged, once every table is back toLOGGED. The unlogged fast-load path now works for all workloads; previously onlyPG_UNLOGGED=falsesucceeded. Runs that pass an explicitstepsallowlist must addcreate_foreign_keysto it.
[5.5.0] - 2026-06-27
Added
-
All four TPC workloads (B, C, H, DS) now share one consistent lifecycle. Every workload builds its indexes in a dedicated
create_indexesstep after the bulk load and runsANALYZE(analyzestep) so the planner has fresh statistics — previously some workloads built indexes during schema creation, some not at all. On PostgreSQL the bulk load now runs againstUNLOGGEDtables and flips them back toLOGGEDafterwards (set_unlogged/set_loggedsteps) for a much faster, WAL-free load; disable withPG_UNLOGGED=false. -
TPC-C now defines the two spec-permitted secondary indexes (
idx_customer_name,idx_order) on PostgreSQL and MySQL — they serve the mandatory by-last-name customer lookup and the customer's-latest-order path (TPC-C Clause 1.4 / §2.5.2.2 / §2.6.2.2). Previously only the YDB dialect had them. -
Workloads accept unified run knobs:
VUS,DURATION,ITER, andMAX_DURATION. SettingDURATIONruns a fixed-duration throughput test (constant VUs); leaving it unset runs a power test (ITERiterations).MAX_DURATION(default 24h) lifts k6's 10-minute per-iteration cap so large loads never time out. -
TPC-DS data can now be generated by a faithful Go port of the official
dsdgen, validated byte-for-byte against the reference C generator across all 24 base tables. Generation is parallel and streaming — any table (including the multi-million-row sales/returns fact tables) can be produced in independent partitions with identical output. Thetpcdsworkload now creates the schema and generates/loads all 24 tables itself (create_schema+load_datasteps) before running the query set, mirroring the TPC-H workload; scale viaSCALE_FACTOR. -
The TPC-DS query set now runs on PostgreSQL and MySQL out of the box. The 99 queries ship as per-dialect SQL (
pg.sql,mysql.sql) generated from the official query templates, replacing the old non-portable pre-baked blobs. After loading, the workload builds single-table indexes and runsANALYZEso the heavy queries have usable plans; correlated subqueries that were O(n²) without indexes are pre-aggregated so they stay fast at scale. -
TPC-DS query parameters can be regenerated as seed-reproducible streams of varied-but-valid values (
QUERY_STREAM/QUERY_SEED), and the workload can drive several concurrent query streams (STREAMS), each running its own seeded permutation of the 99 queries — closer to the TPC-DS throughput test. -
TPC-DS results can be validated for correctness: results are checked against the official SF1 answer set, and a cross-database diff tool (
tpcds-diff) compares the same queries run on two engines (e.g. PostgreSQL vs MySQL) using a multiset comparator with numeric tolerance, so engine-specific null/tie ordering isn't flagged as a mismatch. -
TPC-H data is now generated by a faithful port of the official
dbgen, producing correct query answers (validated against the official SF1 answer set) and finalizingo_totalpriceat generation time so no post-load fix-up step is needed. It is also markedly faster — lineitem generation runs several times quicker. Selectable viaTPCH_GENERATOR(gotpcby default,relgenfor the previous generator). (#75) -
Release binaries are now published for arm64 (
aarch64) in addition to x86-64.
Changed
- Data loading moved out of k6's
setup()and into the workload phase for every workload, so load progress now emits live metrics (k6 emits none duringsetup()). The measured workload is a single skippableworkloadstep, which enables a clean two-run flow: load once with--no-steps workload, then measure against the loaded data with--steps workload(the throughput number is then uncontaminated by load time). A normal single run still loads and measures in one pass.
Fixed
-
TPC-B now declares the canonical pgbench
--foreign-keysconstraints (tellers/accounts/history → branches, history → tellers/accounts) on PostgreSQL and MySQL, added post-load in acreate_foreign_keysstep. They were missing — the schema had thebidindexes that exist to back those references but not the references themselves. (YDB/Picodata don't support foreign keys, so the step is a no-op there.) -
Loading wide tables on MySQL no longer fails with
Error 1390(too many placeholders). Bulk-insert batches are now clamped by column count, so wide tables such as TPC-DScatalog_sales(34 columns) load correctly. -
Generated data now loads on YDB. The bulk-upsert path coerces generated cells to the table's declared column types (ISO date strings →
Timestamp, integral quantities →Double), so TPC-H loads on YDB with zero errors; previously these failed withSCHEME_ERROR.
Removed
- The pre-baked TPC-DS query blobs (
tpcds-scale-1.sql…tpcds-scale-100000.sql) are gone — the workload now generates and loads its own data and ships per-dialect query files. Usestroppy run tpcds/tpcds -e SCALE_FACTOR=<n>instead ofstroppy run tpcds tpcds-scale-<n>.
[5.4.0] - 2026-06-22
Added
stroppy probewith no script argument now lists the available preset catalog. (#73)
Fixed
- Clearer error when a probed script has no
optionsexport. (#73) - Fatal log lines no longer dump a goroutine stacktrace. (#73)
[5.3.4] - 2026-06-16
Changed
- Faster data generation and bulk inserts: TPC-H lineitem loading now runs significantly quicker and uses far less memory, with up to ~38% higher throughput on the insert path and large reductions in allocations during generation. (#72)
[5.3.3] - 2026-05-29
Changed
- TPC-H now prepares the database once per run instead of repeating setup work.
Fixed
- Insert throughput is now reported from live progress metrics for more accurate numbers.
[5.3.2] - 2026-05-27
Added
- TPC-H now reports per-query timings for the workload.
Fixed
- Worked around a YDB error that could interrupt TPC-H runs.
[5.3.1] - 2026-05-27
Fixed
- TPC-H totals no longer apply YDB column coalescing, producing correct results.
[5.3.0] - 2026-05-27
Added
- TPC-H can now run against YDB column-store tables.
[5.2.0] - 2026-05-26
Added
- Live insert progress is now reported while data loads. (#71)
- A single TPC-C test can now drive multiple tool instances at once.
- k6 logger settings are now synced with the runner configuration.
Changed
- Faster data generation through performance refactoring.
- YDB data ingestion, table partitioning, and index partitioning settings improved for better load performance.
- YDB now uses lazy transactions and parameter-based IN queries.
- Query arguments now go through dialect conversion, with YDB list parameters still normalized to typed slices.
- TPC-H finalize step is now dynamic.
Fixed
- YDB now retries UNAVAILABLE errors instead of failing.
[5.1.3] - 2026-05-20
Fixed
- TPC-H scale-factor 1 queries now pass on YDB.