# 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 `/tmp` on 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](development.adoc#run-measurements) for reproduction commands.