pledge

Performance

pledge is benchmarked against pgledger, a double-entry ledger written in PL/pgSQL, with pgbench. Both run in the same PostgreSQL 18 container on the same laptop, with the same accounts and the same workload. Higher is better.

Transfers per second #

One client, synchronous_commit off so the numbers show the work each ledger does, not the disk:

Single transfer, 1 client
pledge
5361
pgledger
3547
Batch of two transfers, 1 client
pledge
6841
pgledger
4327
Retry of an existing transfer, 1 client
pledge
4606
pgledger
3141

Eight clients at once, same settings:

Single transfer, 8 clients
pledge
19517
pgledger
13579
Batch of two transfers, 8 clients
pledge
18005
pgledger
10089

Bigger batches #

With durable commits on, larger batches pay off most: create_transfers writes a whole batch in one statement. Transfers per second at 8 clients, median of three runs:

Batches of 10 transfers
pledge
7956
pgledger
5362
Batches of 100 transfers
pledge
10633
pgledger
4913

Storage #

Each transfer and its two entries take about 16% less space:

Bytes per transfer
pledge
627B
pgledger
748B

Where the speed comes from #

  • One statement per call. Locking the accounts, checking balances and writing the transfer and both entries happen in one SQL statement, prepared once per connection.
  • No replanning. The write function always uses its cached plan; before, PostgreSQL replanned every call, which cost about 30% of the server time.
  • 16-byte ids. Ids are stored as UUIDv7 values and shown as text like pla_01K9... only when you read them.

Tested for correctness #

Speed only counts if the books stay straight. Besides the unit tests, three validation suites run against a real database (just validate):

Suite What it does Result
Bank Concurrent transfers while connections are killed at random 18,726 transfers, 197 killed connections, 0 violations
Model Random operations checked against a simple in-memory ledger 8,000 operations, 0 mismatches
Berka Replays the PKDD’99 Czech bank dataset 1,056,304 transfers, 904,603 running balances match the dataset exactly

After each suite pledge.verify() passes, every currency sums to zero and every balance matches the expected value.

Run it yourself #

just docker-bench PROFILE=quick   # about a minute
just docker-bench PROFILE=cpu     # the numbers above
just validate                     # the three validation suites

Results are written to bench/results/. See bench/README.md for every option.