Performance measurements
These development measurements describe one workload on one machine. They are not throughput guarantees or comparisons with another object store.
Conditions
-
AMD Ryzen 9 7950X3D, Linux x86-64, OpenJDK 27.
-
A 32 MiB byte array from
java.util.Random, seed 42. -
Five warmups and seven timed samples per operation. Reported times are medians.
-
SHA2-256, with FastCDC minimum 256 KiB, target 1 MiB and maximum 4 MiB.
-
Files under
/tmpon ZFS, with warmed caches. -
Native-storage measurements at commit
b55b618. Catalog operations were not timed.
Input creation is outside timing. Publication timings exclude preparation. Fresh-file publication includes database creation and commit syncs. Preparation timings include temporary staging and cleanup but do not force durable writes.
Preparation
| Operation | MiB/s | Milliseconds |
|---|---|---|
Read cached file |
9,514 |
3.363 |
Read cached file and hash twice |
1,057 |
30.287 |
Prepare cached file |
631 |
50.697 |
Prepare byte array with spill |
536 |
59.703 |
Try zlib on random file content |
58 |
556.209 |
The read controls use a reusable 64 KiB buffer. The two-hash control updates two SHA2-256 states but does not find chunk cuts. Random content compresses poorly, so the zlib case pays for compression attempts without a useful reduction in stored size.
Publication and reads
| Operation | MiB/s | Milliseconds |
|---|---|---|
Publish to a fresh memory database |
791 |
40.480 |
Publish to a fresh file database |
380 |
84.179 |
Publish an existing payload again |
1,298 |
24.659 |
Read a cached payload with verification |
1,589 |
20.140 |
Open and read a 32 KiB range |
Not reported |
2.197 |
Publish after changing one byte |
845 |
37.887 |
Duplicate publication still checks the prepared source. Opening a stream checks the complete manifest. A range read verifies every covering chunk.
The one-byte edit reused 24 of 25 chunks, covering 32,898,057 bytes. It appended 672,605 bytes including metadata. Its throughput counts the full logical payload, not just the new bytes.
Small payloads
Each sample uses 2,000 distinct 256-byte payloads in a memory database. Publication uses one transaction for the whole batch.
| Operation | Median batch time | Objects/s |
|---|---|---|
Publish |
43.549 ms |
45,900 |
Open and read |
19.107 ms |
104,700 |
Median-sample thread allocation was 166,706,416 bytes for publication and 80,516,520 bytes for reads.
These are cumulative allocations, not peak live heap.
Read allocation includes the per-stream buffer used by InputStream.transferTo.
The results do not measure one durable transaction per small object.
Memory
Fresh JVM runs prepared, published and verified a 256 MiB file-backed payload with a 128 MiB heap limit. The source generator used a reusable 64 KiB buffer.
| Payload | Peak process RSS in three runs, KiB |
|---|---|
256 bytes |
227,744 / 218,632 / 200,828 |
256 MiB |
220,676 / 226,344 / 244,792 |
RSS includes the JVM, compiled code and native allocations. It is neither peak live heap nor filesystem cache usage. Startup variation prevents a precise estimate of per-object memory from these runs.
The benchmark and large-payload check also completed on OpenJDK 17.0.20.1. The tables above report OpenJDK 27.
Limits of the evidence
The throughput runs use no independent JVM forks, CPU pinning or confidence intervals. They do not establish uncached device bandwidth. Concurrent-reader throughput and durable per-object latency have not been measured.
See Run measurements for reproduction commands.