1 // Copyright (C) 2023 The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #pragma once 16 17 #include <android-base/logging.h> 18 #include <span> 19 #include <string_view> 20 #include <thread> 21 #include <vector> 22 23 #include <libsnapshot/cow_format.h> 24 #include <storage_literals/storage_literals.h> 25 #include "writer_base.h" 26 27 namespace android { 28 namespace snapshot { 29 30 using namespace android::storage_literals; 31 // This is a multiple on top of the number of data ops that can be stored in our cache at once. This 32 // is added so that we can cache more non-data ops as it takes up less space. 33 static constexpr uint32_t kNonDataOpBufferSize = 16; 34 35 class CowWriterV3 : public CowWriterBase { 36 public: 37 explicit CowWriterV3(const CowOptions& options, android::base::unique_fd&& fd); 38 ~CowWriterV3() override; 39 40 bool Initialize(std::optional<uint64_t> label = {}) override; 41 bool Finalize() override; 42 CowSizeInfo GetCowSizeInfo() const override; 43 44 protected: 45 virtual bool EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override; 46 virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override; 47 virtual bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size, 48 uint32_t old_block, uint16_t offset) override; 49 virtual bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override; 50 virtual bool EmitLabel(uint64_t label) override; 51 virtual bool EmitSequenceData(size_t num_ops, const uint32_t* data) override; 52 53 private: 54 struct CompressedBuffer { 55 size_t compression_factor; 56 std::vector<uint8_t> compressed_data; 57 }; 58 void SetupHeaders(); 59 bool NeedsFlush() const; 60 bool ParseOptions(); 61 bool OpenForWrite(); 62 bool OpenForAppend(uint64_t label); 63 bool WriteOperation(std::span<const CowOperationV3> op, std::span<const struct iovec> data); 64 bool EmitBlocks(uint64_t new_block_start, const void* data, size_t size, uint64_t old_block, 65 uint16_t offset, CowOperationType type); 66 bool ConstructCowOpCompressedBuffers(uint64_t new_block_start, const void* data, 67 uint64_t old_block, uint16_t offset, CowOperationType type, 68 size_t blocks_to_write); 69 bool CheckOpCount(size_t op_count); 70 71 private: 72 std::vector<CompressedBuffer> ProcessBlocksWithNoCompression(const size_t num_blocks, 73 const void* data, 74 CowOperationType type); 75 std::vector<CompressedBuffer> ProcessBlocksWithCompression(const size_t num_blocks, 76 const void* data, 77 CowOperationType type); 78 std::vector<CompressedBuffer> ProcessBlocksWithThreadedCompression(const size_t num_blocks, 79 const void* data, 80 CowOperationType type); 81 std::vector<CompressedBuffer> CompressBlocks(const size_t num_blocks, const void* data, 82 CowOperationType type); 83 size_t GetCompressionFactor(const size_t blocks_to_compress, CowOperationType type) const; 84 IsBlockAligned(const size_t size)85 constexpr bool IsBlockAligned(const size_t size) { 86 // These are the only block size supported. Block size beyond 256k 87 // may impact random read performance post OTA boot. 88 const size_t values[] = {4_KiB, 8_KiB, 16_KiB, 32_KiB, 64_KiB, 128_KiB, 256_KiB}; 89 90 auto it = std::lower_bound(std::begin(values), std::end(values), size); 91 92 if (it != std::end(values) && *it == size) { 93 return true; 94 } 95 return false; 96 } 97 size_t CachedDataSize() const; 98 bool ReadBackVerification(); 99 bool FlushCacheOps(); 100 void InitWorkers(); 101 CowHeaderV3 header_{}; 102 CowCompression compression_; 103 // in the case that we are using one thread for compression, we can store and re-use the same 104 // compressor 105 std::unique_ptr<ICompressor> compressor_; 106 std::vector<std::unique_ptr<CompressWorker>> compress_threads_; 107 // Resume points contain a laebl + cow_op_index. 108 std::shared_ptr<std::vector<ResumePoint>> resume_points_; 109 110 uint64_t next_data_pos_ = 0; 111 112 // in the case that we are using one thread for compression, we can store and re-use the same 113 // compressor 114 int num_compress_threads_ = 1; 115 size_t batch_size_ = 1; 116 std::vector<CowOperationV3> cached_ops_; 117 std::vector<std::vector<uint8_t>> cached_data_; 118 std::vector<struct iovec> data_vec_; 119 120 std::vector<std::thread> threads_; 121 }; 122 123 } // namespace snapshot 124 } // namespace android 125