Compression¶
Compression is designed to support different types of compression algorithms with no or minimal impact on query performance. Compression is lossless.
Supported dataset types¶
Compression option is available only for selected dataset types
- Spatial domain must be gridded. Mesh spatial domain is not supported yet.
- Only timestep storage type is supported. Timeseries cannot be compressed.
Compression algorithms¶
-
Deflate compression : standard .Net deflate algorithm, supports all datatypes (float, double, int,...)
-
DeflateFast: deflate optimized for speed DeflateOptimal: deflate optimized for sizeLZ4: block compression optimized for speed, supports all datatypesDeflateOptimalAuto: Deflate (Optimal) with an automatic per-tile transform (byte shuffle, 1-D/2-D delta, byte delta, float quantization detection) - best ratio for all datatypes: 30-45 % smaller thanDeflateOptimalon smooth integer data such as scaled Int16 satellite/ocean grids, 35-60 % smaller on quantised floats (GRIB), never worse elsewhere; reads as fast asDeflateOptimalor faster (smaller blocks, vectorized transforms), writes at 0.6-1.0x of its throughput - the transforms are compared on every 32nd tile only (DeflateAutoCompressor.DefaultProbeStride) and the winner is kept for the tiles in between and across the slices of the same item (AutoTransformState)ZstdAuto(the default for new gridded datasets): the same automatic per-tile transform with Zstandard (level 9, RFC 8878 frames) as the backend codec - matches or slightly beatsDeflateOptimalAutoon ratio and reads 1.3-2x faster; write throughput is comparable. LikeDeflateOptimalAutoit is a new block format: every deployment that reads MD data must understand it before a dataset is written with it.ZstdFastAuto:ZstdAutowritten at zstd level 3 - 3-6x faster writes for ~1 percentage point of ratio. The level is a write-side choice only, the block format is identical toZstdAuto- but the name is stored in the dataset metadata, so a build has to know the name to read the dataset (see "Compatibility" below). Meant for ingest-speed-critical conversions. For data written once and read often, which is the common case, the defaultZstdAutois the better choice.
Default compression¶
New gridded datasets stored per timestep get the default compression of the environment (MDWriterOptions.DefaultGridCompression),
set through the environment variable MD_DEFAULT_GRID_COMPRESSION (forwarded to transfer jobs via TransferOptions.DefaultGridCompression).
The code default is None, so a freshly deployed build never starts writing a block format on its own; the intended
production setting is ZstdAuto. Set it in an environment only after every deployment that reads MD data runs a build that
knows it (see "Compatibility"): deploy the build everywhere, verify the readers, then set the variable. An older build ignores
the variable, so setting it early does not break the old build - the datasets written by the new build in the meantime would.
The default is applied only when the writer parameter Compression is not given; pass "Compression": "None" to store a dataset uncompressed.
Mesh datasets, the TimeSeries storage type, an explicitly requested MultiTimestep storage and datasets with items holding more than
one value per element (z-level items) are never compressed - requesting compression for them is rejected. Existing datasets keep the settings they were created with (append/update follows the dataset, not the default).
Enabling compression stores the dataset as SingleTimestep (one blob per time step, item and layer) instead of MultiTimestep.
Tiles of one slice are encoded by up to 4 workers in parallel (CompressedGridIndex.MaxEncodeWorkers, one per available CPU);
MD_ENCODE_WORKERS (forwarded via TransferOptions.EncodeWorkers) sets the count explicitly, 1 makes the encoding serial.
Compatibility¶
The compression is stored by name in the dataset metadata (ItemStorage.Compression) and read by every deployment that
loads MD datasets: the multidimensional service, the multidimensional cron jobs (data cleanup) and the transfer jobs
(append, update, export). A build that does not know a name loads the dataset with CompressionType.Unknown
(CompressionTypeConverter): the dataset stays visible and its metadata is left untouched, only reading or writing its
data fails with a message saying the compression is not known to this build. Writing such a dataset's metadata back is
refused, so an older build can never replace the name it does not know.
A newer build's writer accepts a new name as soon as it is deployed - through the environment default or an explicit
writer parameter - so the order per environment is: deploy the build to all readers, then enable the compression.
The second compatibility boundary is the kind of dataset: compression is currently read and written for gridded datasets
with SingleTimestep storage and single-value items only (CompressionExtensions.IsCompressionSupported). A compressed
dataset of any other kind (mesh, MultiTimestep, TimeSeries, z-level items - as a newer build may write) loads, but every
data read or write is refused by DatasetStorage with a message saying this build cannot read it; without that guard the
storage classes for those kinds would read the compressed blobs as raw data. The rollout of such an extension is the same as
for a new name: deploy the build to all readers first, then enable the compression for that kind.
Extending compression to another kind of dataset¶
- Implement the compressed read and write path of the storage class for that kind (as
SingleTimestepStorageandCompressedGridIndexdo for grids) and relaxCompressionExtensions.IsCompressionSupportedfor it - that single predicate gates the writer validation,DatasetStorage.StoreAsyncand the read-side refusal above. - Keep the refusal test (
DatasetStorageTests.CompressedDatasetOfAKindThisBuildCannotReadStillLoadsButRefusesItsData) for the kinds that remain unsupported and add a round-trip test for the new one. - Enable it per environment after the build rollout:
MD_DEFAULT_GRID_COMPRESSIONis applied toIGrid2Ddomains only (MDWriter.GetCompression), so relaxing the predicate does not switch the new kind on anywhere - it stays opt-in through the writer parameter until it gets its own default setting, which is what makes the rollout of the read path and the switch-on two separate steps.
Adding a compression type¶
- Add the value to
CompressionType(ItemStorageOptions.cs) - the name is the persisted format identifier, keep it stable. - Implement
ICompressor(or derive fromDeflateAutoCompressorfor a new backend codec, asZstdAutoCompressordoes) and add the branch toCompressionExtensions.CreateCompressor. A compression built onDeflateAutoCompressormust also be listed inCompressionExtensions.IsAutoTransform, otherwise it does not get the per-item probe state.CompressionTypeTests.EverySelectableCompressionResolvesToACompressorfails until both are done. - Tests: round trip (
CompressorRoundTripTests), the garbage patterns (CompressorStressTests),CreateCompressorresolves the type, and a pinned block format if the type must stay readable by an existing reader. - Describe it above and in
conversion.dedicated.writers.import.json(writer parameter description). - Roll out as described under "Compatibility"; do not make it the default in the same release. A write-side variant of an existing format (a different level) is still a new name, i.e. a new compatibility boundary - prefer a separate option (e.g. a level) that older builds ignore over a new enum value.
Enabling compression in conversion¶
Compression is enabled by adding writer parameter Compression with the name of Compression algorithm (see above).
Example:
"writerParameters": [
{
"name": "Compression",
"value": "DeflateFast"
}
Specific datasets¶
HYCOM, COPERNICUS¶
Hycom and Copernicus use Int16 internal storage. Use LZ4.
"writerParameters": [
{
"name": "Compression",
"value": "LZ4"
}
```
### NOAA
NOAA is highly (lossy with JPEG2000) compressed format.
Storing it as uncompressed doubles is not optimal. Float precision is sufficient.
NOAA Reader adds reader parameter DoubleAsFloat, which forces converting and storing double value as float.
NOAA can use only deflate compression now.