blob: 71e64dcdf421ca6d2162798e4e780e932d452351 [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 <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.
class Lz4Decoder : public Decoder {
public:
Lz4Decoder();
virtual ~Lz4Decoder();
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:
// Decodes the next chunk in the block. Returns whether the block should be further decoded.
//
// A chunk is made of two consecutive parts: (1) the size of the encoded message and (2) the
// encoded message itself. block_ptr points to the start of the chunk (to be decoded) while
// block_end points to 1-byte past the last element of the block (analogous to std::vector::end)
bool DecodeNextChunk(const char* block_end, const char** block_ptr, std::string* decoded_chunk,
std::string* err_msg);
LZ4_streamDecode_t* stream_;
RingBuffer ring_;
};
} // namespace system_log_recorder
} // namespace feedback_data
} // namespace forensics
#endif // SRC_DEVELOPER_FORENSICS_FEEDBACK_DATA_SYSTEM_LOG_RECORDER_ENCODING_LZ4_DECODER_H_