blob: 474de468e6e6a8c1616aefc2b1d0ec28da8d83be [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_DEVELOPER_FORENSICS_FEEDBACK_DATA_SYSTEM_LOG_RECORDER_ENCODING_LZ4_DECODER_H_
#define SRC_DEVELOPER_FORENSICS_FEEDBACK_DATA_SYSTEM_LOG_RECORDER_ENCODING_LZ4_DECODER_H_
#include <memory>
#include <optional>
#include <string>
#include <lz4/lz4.h>
#include "src/developer/forensics/feedback_data/system_log_recorder/encoding/decoder.h"
#include "src/developer/forensics/feedback_data/system_log_recorder/encoding/ring_buffer.h"
#include "src/developer/forensics/feedback_data/system_log_recorder/encoding/version.h"
namespace forensics {
namespace feedback_data {
namespace system_log_recorder {
// The Lz4Decoder::Decode() decodes a block previously encoded with the Lz4Encoder. The block is
// processed one chunk at a time as required by LZ4. One chunk is created on every invocation to
// LZ4_compress_fast_continue(). The decoding algorithm further requires that the previous 64KB of
// decoded data remain in memory (unchanged) thus a ring buffer is used for this purpose. The ring
// buffer wraps around when there is not enough data left and we guarantee that there is at least
// 64KB of previous decoded data (it is very likely that the decoded data will be larger than 64KB
// if the encoded block size is 64KB and the compression ratio is greater than 1x). In addition,
// the state for the current block decompression needed by the LZ4 algorithm is kept in the
// “stream” variable.
//
// |output_preallocation_hint| allows callers to suggest how the decoder should preallocate its
// output string when decoding.
class Lz4Decoder : public Decoder {
public:
explicit Lz4Decoder(std::optional<size_t> output_preallocation_hint = std::nullopt);
virtual ~Lz4Decoder() = default;
virtual EncodingVersion GetEncodingVersion() const { return EncodingVersion::kLz4; }
// |Decoder|
virtual std::string Decode(const std::string& block);
protected:
// Increases testing flow control.
//
// Decoding a block automatically resets the decoder. For testing however it is useful to decode
// every message. This is because decoding large blocks can spam the test logs with tens of
// thousands of characters and finding when or how a test fails becomes needlessly onerous.
// Breaking a large block into smaller blocks also decreases the probability of finding errors
// since the encoder, the decoder and the buffers get reset on every block.
std::string DecodeWithoutReset(const std::string& chunk);
void Reset();
private:
RingBuffer ring_;
std::unique_ptr<LZ4_streamDecode_t, decltype(&LZ4_freeStreamDecode)> stream_;
std::optional<size_t> output_preallocation_hint_;
};
} // namespace system_log_recorder
} // namespace feedback_data
} // namespace forensics
#endif // SRC_DEVELOPER_FORENSICS_FEEDBACK_DATA_SYSTEM_LOG_RECORDER_ENCODING_LZ4_DECODER_H_