Merge "Support ZSTD in userspace COW"
This commit is contained in:
commit
9f6e88567b
|
@ -196,6 +196,7 @@ cc_binary {
|
||||||
"libfastbootshim",
|
"libfastbootshim",
|
||||||
"libsnapshot_cow",
|
"libsnapshot_cow",
|
||||||
"liblz4",
|
"liblz4",
|
||||||
|
"libzstd",
|
||||||
"libsnapshot_nobinder",
|
"libsnapshot_nobinder",
|
||||||
"update_metadata-protos",
|
"update_metadata-protos",
|
||||||
"liburing",
|
"liburing",
|
||||||
|
|
|
@ -163,6 +163,7 @@ cc_defaults {
|
||||||
"libbrotli",
|
"libbrotli",
|
||||||
"libz",
|
"libz",
|
||||||
"liblz4",
|
"liblz4",
|
||||||
|
"libzstd",
|
||||||
],
|
],
|
||||||
export_include_dirs: ["include"],
|
export_include_dirs: ["include"],
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,7 +157,8 @@ enum CowCompressionAlgorithm : uint8_t {
|
||||||
kCowCompressNone = 0,
|
kCowCompressNone = 0,
|
||||||
kCowCompressGz = 1,
|
kCowCompressGz = 1,
|
||||||
kCowCompressBrotli = 2,
|
kCowCompressBrotli = 2,
|
||||||
kCowCompressLz4 = 3
|
kCowCompressLz4 = 3,
|
||||||
|
kCowCompressZstd = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr uint8_t kCowReadAheadNotStarted = 0;
|
static constexpr uint8_t kCowReadAheadNotStarted = 0;
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include <libsnapshot/cow_writer.h>
|
#include <libsnapshot/cow_writer.h>
|
||||||
#include <lz4.h>
|
#include <lz4.h>
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
#include <zstd.h>
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
namespace snapshot {
|
namespace snapshot {
|
||||||
|
@ -40,6 +41,8 @@ std::optional<CowCompressionAlgorithm> CompressionAlgorithmFromString(std::strin
|
||||||
return {kCowCompressBrotli};
|
return {kCowCompressBrotli};
|
||||||
} else if (name == "lz4") {
|
} else if (name == "lz4") {
|
||||||
return {kCowCompressLz4};
|
return {kCowCompressLz4};
|
||||||
|
} else if (name == "zstd") {
|
||||||
|
return {kCowCompressZstd};
|
||||||
} else if (name == "none" || name.empty()) {
|
} else if (name == "none" || name.empty()) {
|
||||||
return {kCowCompressNone};
|
return {kCowCompressNone};
|
||||||
} else {
|
} else {
|
||||||
|
@ -112,6 +115,23 @@ std::basic_string<uint8_t> CompressWorker::Compress(CowCompressionAlgorithm comp
|
||||||
}
|
}
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
case kCowCompressZstd: {
|
||||||
|
std::basic_string<uint8_t> buffer(ZSTD_compressBound(length), '\0');
|
||||||
|
const auto compressed_size =
|
||||||
|
ZSTD_compress(buffer.data(), buffer.size(), data, length, 0);
|
||||||
|
if (compressed_size <= 0) {
|
||||||
|
LOG(ERROR) << "ZSTD compression failed " << compressed_size;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
// Don't run compression if the compressed output is larger
|
||||||
|
if (compressed_size >= length) {
|
||||||
|
buffer.resize(length);
|
||||||
|
memcpy(buffer.data(), data, length);
|
||||||
|
} else {
|
||||||
|
buffer.resize(compressed_size);
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
LOG(ERROR) << "unhandled compression type: " << compression;
|
LOG(ERROR) << "unhandled compression type: " << compression;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -17,12 +17,15 @@
|
||||||
#include "cow_decompress.h"
|
#include "cow_decompress.h"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <cstring>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <android-base/logging.h>
|
#include <android-base/logging.h>
|
||||||
#include <brotli/decode.h>
|
#include <brotli/decode.h>
|
||||||
#include <lz4.h>
|
#include <lz4.h>
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
#include <zstd.h>
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
namespace snapshot {
|
namespace snapshot {
|
||||||
|
@ -336,9 +339,56 @@ class Lz4Decompressor final : public IDecompressor {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ZstdDecompressor final : public IDecompressor {
|
||||||
|
public:
|
||||||
|
ssize_t Decompress(void* buffer, size_t buffer_size, size_t decompressed_size,
|
||||||
|
size_t ignore_bytes = 0) override {
|
||||||
|
if (buffer_size < decompressed_size - ignore_bytes) {
|
||||||
|
LOG(INFO) << "buffer size " << buffer_size
|
||||||
|
<< " is not large enough to hold decompressed data. Decompressed size "
|
||||||
|
<< decompressed_size << ", ignore_bytes " << ignore_bytes;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (ignore_bytes == 0) {
|
||||||
|
if (!Decompress(buffer, decompressed_size)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return decompressed_size;
|
||||||
|
}
|
||||||
|
std::vector<unsigned char> ignore_buf(decompressed_size);
|
||||||
|
if (!Decompress(buffer, decompressed_size)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memcpy(buffer, ignore_buf.data() + ignore_bytes, buffer_size);
|
||||||
|
return decompressed_size;
|
||||||
|
}
|
||||||
|
bool Decompress(void* output_buffer, const size_t output_size) {
|
||||||
|
std::string input_buffer;
|
||||||
|
input_buffer.resize(stream_->Size());
|
||||||
|
size_t bytes_read = stream_->Read(input_buffer.data(), input_buffer.size());
|
||||||
|
if (bytes_read != input_buffer.size()) {
|
||||||
|
LOG(ERROR) << "Failed to read all input at once. Expected: " << input_buffer.size()
|
||||||
|
<< " actual: " << bytes_read;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto bytes_decompressed = ZSTD_decompress(output_buffer, output_size,
|
||||||
|
input_buffer.data(), input_buffer.size());
|
||||||
|
if (bytes_decompressed != output_size) {
|
||||||
|
LOG(ERROR) << "Failed to decompress ZSTD block, expected output size: " << output_size
|
||||||
|
<< ", actual: " << bytes_decompressed;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
std::unique_ptr<IDecompressor> IDecompressor::Lz4() {
|
std::unique_ptr<IDecompressor> IDecompressor::Lz4() {
|
||||||
return std::make_unique<Lz4Decompressor>();
|
return std::make_unique<Lz4Decompressor>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<IDecompressor> IDecompressor::Zstd() {
|
||||||
|
return std::make_unique<ZstdDecompressor>();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace snapshot
|
} // namespace snapshot
|
||||||
} // namespace android
|
} // namespace android
|
||||||
|
|
|
@ -47,6 +47,7 @@ class IDecompressor {
|
||||||
static std::unique_ptr<IDecompressor> Gz();
|
static std::unique_ptr<IDecompressor> Gz();
|
||||||
static std::unique_ptr<IDecompressor> Brotli();
|
static std::unique_ptr<IDecompressor> Brotli();
|
||||||
static std::unique_ptr<IDecompressor> Lz4();
|
static std::unique_ptr<IDecompressor> Lz4();
|
||||||
|
static std::unique_ptr<IDecompressor> Zstd();
|
||||||
|
|
||||||
static std::unique_ptr<IDecompressor> FromString(std::string_view compressor);
|
static std::unique_ptr<IDecompressor> FromString(std::string_view compressor);
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
#include "cow_decompress.h"
|
#include "cow_decompress.h"
|
||||||
|
#include "libsnapshot/cow_format.h"
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
namespace snapshot {
|
namespace snapshot {
|
||||||
|
@ -777,6 +778,11 @@ ssize_t CowReader::ReadData(const CowOperation* op, void* buffer, size_t buffer_
|
||||||
case kCowCompressBrotli:
|
case kCowCompressBrotli:
|
||||||
decompressor = IDecompressor::Brotli();
|
decompressor = IDecompressor::Brotli();
|
||||||
break;
|
break;
|
||||||
|
case kCowCompressZstd:
|
||||||
|
if (header_.block_size != op->data_length) {
|
||||||
|
decompressor = IDecompressor::Zstd();
|
||||||
|
}
|
||||||
|
break;
|
||||||
case kCowCompressLz4:
|
case kCowCompressLz4:
|
||||||
if (header_.block_size != op->data_length) {
|
if (header_.block_size != op->data_length) {
|
||||||
decompressor = IDecompressor::Lz4();
|
decompressor = IDecompressor::Lz4();
|
||||||
|
|
|
@ -112,6 +112,7 @@ cc_defaults {
|
||||||
"liblz4",
|
"liblz4",
|
||||||
"libext4_utils",
|
"libext4_utils",
|
||||||
"liburing",
|
"liburing",
|
||||||
|
"libzstd",
|
||||||
],
|
],
|
||||||
|
|
||||||
header_libs: [
|
header_libs: [
|
||||||
|
|
|
@ -169,6 +169,7 @@ libinit_cc_defaults {
|
||||||
"libfsverity_init",
|
"libfsverity_init",
|
||||||
"liblmkd_utils",
|
"liblmkd_utils",
|
||||||
"liblz4",
|
"liblz4",
|
||||||
|
"libzstd",
|
||||||
"libmini_keyctl_static",
|
"libmini_keyctl_static",
|
||||||
"libmodprobe",
|
"libmodprobe",
|
||||||
"libprocinfo",
|
"libprocinfo",
|
||||||
|
@ -370,6 +371,7 @@ cc_binary {
|
||||||
"libprotobuf-cpp-lite",
|
"libprotobuf-cpp-lite",
|
||||||
"libsnapshot_cow",
|
"libsnapshot_cow",
|
||||||
"liblz4",
|
"liblz4",
|
||||||
|
"libzstd",
|
||||||
"libsnapshot_init",
|
"libsnapshot_init",
|
||||||
"update_metadata-protos",
|
"update_metadata-protos",
|
||||||
"libprocinfo",
|
"libprocinfo",
|
||||||
|
|
Loading…
Reference in New Issue