Files
Joe ElliottandGitHub ba1d670445 Compressed Blocks? Compressed Blocks! (#504)
* Added basic structure for compression

Signed-off-by: Joe Elliott <[email protected]>

* AppenderBuffered impl

Signed-off-by: Joe Elliott <[email protected]>

* mild commenting

Signed-off-by: Joe Elliott <[email protected]>

* moved encoding to meta json

Signed-off-by: Joe Elliott <[email protected]>

* Added pagedReader and backend.ReaderAt

Signed-off-by: Joe Elliott <[email protected]>

* dedupingfinder => pagedfinder

Signed-off-by: Joe Elliott <[email protected]>

* Abstracted away index reading.  Used pagedFinder in backend block

Signed-off-by: Joe Elliott <[email protected]>

* Abstracted PagedIterator to use indexReader

Signed-off-by: Joe Elliott <[email protected]>

* improved comments

Signed-off-by: Joe Elliott <[email protected]>

* created versioned encoding

Signed-off-by: Joe Elliott <[email protected]>

* removed findmetrics

Signed-off-by: Joe Elliott <[email protected]>

* Moved backend block to encoding

Signed-off-by: Joe Elliott <[email protected]>

* Moved indexreader records to common

Signed-off-by: Joe Elliott <[email protected]>

* Added index reader

Signed-off-by: Joe Elliott <[email protected]>

* jpe cleanup

Signed-off-by: Joe Elliott <[email protected]>

* v1 LIVES

Signed-off-by: Joe Elliott <[email protected]>

* Tests pass on v1

Signed-off-by: Joe Elliott <[email protected]>

* encoding tests pass

Signed-off-by: Joe Elliott <[email protected]>

* wooo snappy tests

Signed-off-by: Joe Elliott <[email protected]>

* Moved block config to its own struct

Signed-off-by: Joe Elliott <[email protected]>

* Add custom marshaller

Signed-off-by: Joe Elliott <[email protected]>

* updated configs added default

Signed-off-by: Joe Elliott <[email protected]>

* Test all encodings

Signed-off-by: Joe Elliott <[email protected]>

* Added benchmark.  Default to snappy

Signed-off-by: Joe Elliott <[email protected]>

* fixed panic in reader

Signed-off-by: Joe Elliott <[email protected]>

* Fleshed out benchmarks

Signed-off-by: Joe Elliott <[email protected]>

* lint

Signed-off-by: Joe Elliott <[email protected]>

* backend_block => benchmark_block

Signed-off-by: Joe Elliott <[email protected]>

* Added 256 and 1M LZ4 tests

Signed-off-by: Joe Elliott <[email protected]>

* Removed findmetrics from operational

Signed-off-by: Joe Elliott <[email protected]>

* indexreaderbytes => indexreader

Signed-off-by: Joe Elliott <[email protected]>

* jpe cleanup

Signed-off-by: Joe Elliott <[email protected]>

* Fixed bytes flushed metric

Signed-off-by: Joe Elliott <[email protected]>

* Changed default encoding

Signed-off-by: Joe Elliott <[email protected]>

* Pass tracker correctly.  Add guard code

Signed-off-by: Joe Elliott <[email protected]>

* Added marshal tests

Signed-off-by: Joe Elliott <[email protected]>

* lint

Signed-off-by: Joe Elliott <[email protected]>

* page reader tests

Signed-off-by: Joe Elliott <[email protected]>

* actually add tests

Signed-off-by: Joe Elliott <[email protected]>

* Added reader tess

Signed-off-by: Joe Elliott <[email protected]>

* changelog

Signed-off-by: Joe Elliott <[email protected]>

* zstd

Signed-off-by: Joe Elliott <[email protected]>

* vendor

Signed-off-by: Joe Elliott <[email protected]>
2021-02-05 14:58:39 -05:00

4.5 KiB

Finite State Entropy

This package provides Finite State Entropy encoding and decoding.

Finite State Entropy (also referenced as tANS) encoding provides a fast near-optimal symbol encoding/decoding for byte blocks as implemented in zstandard.

This can be used for compressing input with a lot of similar input values to the smallest number of bytes. This does not perform any multi-byte dictionary coding as LZ coders, but it can be used as a secondary step to compressors (like Snappy) that does not do entropy encoding.

News

  • Feb 2018: First implementation released. Consider this beta software for now.

Usage

This package provides a low level interface that allows to compress single independent blocks.

Each block is separate, and there is no built in integrity checks. This means that the caller should keep track of block sizes and also do checksums if needed.

Compressing a block is done via the Compress function. You must provide input and will receive the output and maybe an error.

These error values can be returned:

Error Description
<nil> Everything ok, output is returned
ErrIncompressible Returned when input is judged to be too hard to compress
ErrUseRLE Returned from the compressor when the input is a single byte value repeated
(error) An internal error occurred.

As can be seen above there are errors that will be returned even under normal operation so it is important to handle these.

To reduce allocations you can provide a Scratch object that can be re-used for successive calls. Both compression and decompression accepts a Scratch object, and the same object can be used for both.

Be aware, that when re-using a Scratch object that the output buffer is also re-used, so if you are still using this you must set the Out field in the scratch to nil. The same buffer is used for compression and decompression output.

Decompressing is done by calling the Decompress function. You must provide the output from the compression stage, at exactly the size you got back. If you receive an error back your input was likely corrupted.

It is important to note that a successful decoding does not mean your output matches your original input. There are no integrity checks, so relying on errors from the decompressor does not assure your data is valid.

For more detailed usage, see examples in the godoc documentation.

Performance

A lot of factors are affecting speed. Block sizes and compressibility of the material are primary factors.
All compression functions are currently only running on the calling goroutine so only one core will be used per block.

The compressor is significantly faster if symbols are kept as small as possible. The highest byte value of the input is used to reduce some of the processing, so if all your input is above byte value 64 for instance, it may be beneficial to transpose all your input values down by 64.

With moderate block sizes around 64k speed are typically 200MB/s per core for compression and around 300MB/s decompression speed.

The same hardware typically does Huffman (deflate) encoding at 125MB/s and decompression at 100MB/s.

Plans

At one point, more internals will be exposed to facilitate more "expert" usage of the components.

A streaming interface is also likely to be implemented. Likely compatible with FSE stream format.

Contributing

Contributions are always welcome. Be aware that adding public functions will require good justification and breaking changes will likely not be accepted. If in doubt open an issue before writing the PR.