October in TigerLand
Dear friends,
We hope your October was outstanding. Last month, we rewrote the state machine fuzzer (it swiftly found some bugs!), introduced a lightweight, epoll-only IO backend for Linux clients, and published our Rust client! We also spent time with TigerBeetle friends in London, our icon landed on devicon.dev, and we shared the story of building the fastest object storage client (that we know of).
The next TigerBeetle release contains breaking client changes! Details below.
Let’s go!
“Program testing can be used to show the presence of bugs, but never to show their absence!”
— Edsger W. Dijkstra
The state machine fuzzer tests TigerBeetle’s core – the logic that validates and processes accounts and transfers. Previously, it was effectively stateless: storage was not wired up, and it only ever submitted empty batches of accounts and transfers. Last month, it underwent a rewrite and evolution!
- The
rewritten fuzzer is stateful: it exercises both compaction and
checkpointing. Additionally, it generates realistic accounts
and transfers, and uses swarm
testing for better state-space exploration. It quickly detected:
- A poison pill request that could have crashed every replica executing it! Previously, when importing events with user-defined timestamps, we validated each imported timestamp against the timestamp of the whole batch but asserted against the timestamp of the individual event. An imported timestamp that fell between the two would have passed validation but tripped the assertion. Now, such imported events are validated against the event’s timestamp.
- Two bugs we had already fixed:
- An overly strict assertion that would fire while posting or voiding a pending transfer whose creation had failed. Fortunately, the assertion was only reachable in testing, not in release builds.
- A transfer imported with a timestamp before an expiry that the cluster had already applied could be missed by Change Data Capture.
Our clients got a lot of attention last month:
- We published our Rust
client! It features a new zero-allocation
request API available through the
*_reusablevariants for all operations. For example,create_accounts_reusableallows users to pass in their own request/response buffers, so it allocates nothing. By contrast, we measured 1.3MB of allocations in a full batch ofcreate_accounts. - Like the replicas, the Linux client used
io_uringfor high-performance networking. However, some environments, such as restricted container setups, disableio_uring. Additionally, the client (unlike the replicas) is not particularly demanding of IO performance. So, last month, we added a lightweight, epoll-only IO backend for the Linux client. Thanks for the initial implementation, Matthias!- We also observed some mysterious connection hangs with the new
backend. It turned out that the epoll backend used
CLOCK_MONOTONIC, which stops during suspend, while timeout deadlines were computed usingCLOCK_BOOTTIME, which doesn’t. This led to hung connections on systems with accumulated suspend time – 14 hours on the machine where this was observed! We fixed this discrepancy by switching the epoll backend’s timers toCLOCK_BOOTTIMEas well.
- We also observed some mysterious connection hangs with the new
backend. It turned out that the epoll backend used
Finally, please note that the next TigerBeetle release contains breaking client changes:
- The .NET, Go, Java, and Node.js clients will take
replica addresses as a single comma-separated string (e.g.
"3000,3001,3002") instead of an array. - In the C client,
tb_packet_twill be renamed totb_batch_tand theTB_PACKET_*status codes will beTB_BATCH_*. - The Go client will require Go 1.26+.
- Thank you, @shioyama, for the detailed bug report on potentially missed CDC imports!
Last month on IronBeetle, Matklad and Tobi streamed about rewriting our state machine fuzzer! They also wired up storage, used swarm testing, and tracked which return codes the generated workload actually reaches…
Then, in episode three of arguably their most ambitious project yet, redesigning consensus from scratch, their deterministic simulator caught its first bugs! What if consensus only needed a single kind of message and kept working even when replicas can’t talk to each other directly?
Join us live every Friday at 3pm UTC (new time) on Twitch, YouTube, and X!
Benchmark In Milliseconds, Oct 5
The purpose of benchmarking isn’t to have a precise measurement of performance, but rather to provide the author with “enough intuition to make a correct decision”. Last month, matklad shared his rule of thumb for how long a microbenchmark should run.
The Fastest Object Storage Client (That We Know Of), P99 CONF, Oct 22
A tale of TigerStyle:
TigerBeetle needed object storage but the official SDKs didn’t compose
with our completion-based event loop or Deterministic Simulation
Testing. So, we built everything from scratch in Zig: custom DNS, TLS,
and HTTP, with static allocation, zero-copy io_uring, and a
single thread. The result is fast; 4–10× faster than the official GCP
and AWS SDKs… Watch the talk on
YouTube!
TigerBeetle Icon Released on Devicon, Oct 25
For those building with TigerBeetle, our icon was approved on devicon.dev! May the official TigerBeetle icon force be (now more readily) with you.
Munich Database Meetup, Oct 27
Last month, another excellent edition of the Munich Database Meetup! TigerBeetle’s Dr. Tobias Ziegler served up a sizzler on how to build mission-critical systems, including why unit, fuzz, and deterministic simulation are the testing trifecta for TigerBeetle. Danke to Alex Petrov and his fellow organizers for hosting!
The Conference on Innovative Data Systems Research (CIDR), Jan 24–27
The 17th edition of CIDR, the systems-oriented conference founded in 2002 by Michael Stonebraker, Jim Gray (of Turing Award and DebitCredit fame), and David DeWitt, takes place in January 2027 in Amsterdam. Registration is open and accommodation is booking up fast! We’ll see you there.
’Till next time… (ah-ah, ah-ah-ah) THUNDER!
The TigerBeetle Team











