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