Compression
July 15, 2026 ยท View on GitHub
ZoneTree supports compression in two different storage paths:
- WAL compression for recent log records,
- disk segment compression for persistent random-access sorted data.
Both use the same compression method/level model, but they serve different workloads and have different default block sizes.
Compression Methods
ZoneTree supports:
LZ4ZstdBrotliGzipNone
Compression levels are validated against the selected method. The default profile uses Zstd compression because it is a good general-purpose balance for storage-engine workloads.
WAL Compression
The default WAL mode is AsyncCompressed.
Default WAL compression:
method: Zstd
level: Zstd0
block: 256 KB
Compressed WALs reduce log size and can improve write-path IO when data compresses well. They also add compression work. The async compressed mode is the default because it keeps WAL protection enabled while preserving high write throughput for most applications.
Sync compressed WAL uses the same compressed-block WAL file shape and tail behavior. Use Sync WAL when the application specifically needs the plain synchronous WAL path; use sync-compressed WAL when compressed WAL storage or throughput matters and its tail durability tradeoff is acceptable.
Disk Segment Compression
Disk segment compression is block-based random-access compression.
Default disk compression:
method: Zstd
level: Zstd0
block: 4 MB
Compressed disk segment files store sorted data in compressed blocks. ZoneTree can seek to a block, read it, decompress it, and then serve keys or values from the decompressed block.
This is different from compressing a whole file as one stream. ZoneTree keeps random access.
Block Cache Interaction
Compressed disk reads use a decompressed block cache. When a block is read, ZoneTree can keep the decompressed block in memory so nearby or repeated reads do not have to read and decompress the same block again.
The important relationship is:
disk compression block size -> decompressed block cache unit size
Larger disk compression blocks can improve compression ratio and sequential read behavior, but each cached block keeps more decompressed data in memory. Smaller blocks can make random reads cheaper, but may reduce compression density and increase metadata overhead.
Block cache cleanup is controlled by the maintainer:
BlockCacheLifeTimeInactiveBlockCacheCleanupInterval
See read path caching.
Why WAL And Disk Defaults Differ
ZoneTree intentionally uses smaller blocks for WAL and larger blocks for disk segments.
WAL blocks serve recent writes and recovery. Smaller blocks keep log recovery and tail handling more responsive.
Disk segment blocks serve persistent sorted data. Larger blocks can improve compression density and are often a better fit for range reads, sparse lookups, and block cache reuse.
When Compression Helps
Compression can help when:
- values are text, JSON, repeated structures, or otherwise compressible,
- storage bandwidth is more expensive than CPU,
- disk space matters,
- read workloads repeatedly touch nearby compressed blocks,
- large disk segments benefit from smaller physical files.
When Compression Costs More
Compression may cost more than it saves when:
- payloads are already compressed,
- CPU is the bottleneck,
- values are tiny and mostly random,
- random reads constantly touch cold blocks,
- compression block size is too large for the read pattern.
For large values, compression should be tested with real payloads. A large JSON value and a large already-compressed image have very different storage behavior.
Configuration
Configure WAL compression through WriteAheadLogOptions:
using ZoneTree.Options;
using var zoneTree = new ZoneTreeFactory<int, string>()
.SetDataDirectory("data/app")
.ConfigureWriteAheadLogOptions(options =>
{
options.CompressionMethod = CompressionMethod.Zstd;
options.CompressionLevel = CompressionLevels.Zstd0;
options.CompressionBlockSize = 256 * 1024;
})
.OpenOrCreate();
Configure disk segment compression through DiskSegmentOptions:
using ZoneTree.Options;
using var zoneTree = new ZoneTreeFactory<int, string>()
.SetDataDirectory("data/app")
.ConfigureDiskSegmentOptions(options =>
{
options.CompressionMethod = CompressionMethod.Zstd;
options.CompressionLevel = CompressionLevels.Zstd0;
options.CompressionBlockSize = 4 * 1024 * 1024;
})
.OpenOrCreate();
SetDiskSegmentCompressionBlockSize is also available as a convenience method on ZoneTreeFactory.
Practical Model
Think about compression in ZoneTree this way:
- WAL compression optimizes recent durable log records.
- Disk compression optimizes persistent sorted segment files.
- Disk compression block size also defines the main read-cache unit.
- The maintainer controls inactive decompressed block cleanup.
- Real payloads matter more than generic compression claims.