blob: b70dcdfa3045ca05015640c18d05f6794a16b115 [file] [log] [blame]
Kelvin Zhangb05e4e22020-09-25 16:16:19 -04001//
2// Copyright (C) 2020 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include <algorithm>
18#include <array>
19#include <initializer_list>
20
21#include <gtest/gtest.h>
22
23#include "update_engine/common/cow_operation_convert.h"
24#include "update_engine/payload_generator/extent_ranges.h"
25#include "update_engine/update_metadata.pb.h"
26
27namespace chromeos_update_engine {
28using OperationList = ::google::protobuf::RepeatedPtrField<
29 ::chromeos_update_engine::InstallOperation>;
30using MergeOplist = ::google::protobuf::RepeatedPtrField<
31 ::chromeos_update_engine::CowMergeOperation>;
32
33std::ostream& operator<<(std::ostream& out, CowOperation::Type op) {
34 switch (op) {
35 case CowOperation::Type::CowCopy:
36 out << "CowCopy";
37 break;
38 case CowOperation::Type::CowReplace:
39 out << "CowReplace";
40 break;
41 default:
42 out << op;
43 break;
44 }
45 return out;
46}
47
48std::ostream& operator<<(std::ostream& out, const CowOperation& c) {
49 out << "{" << c.op << ", " << c.src_block << ", " << c.dst_block << "}";
50 return out;
51}
52
53class CowOperationConvertTest : public testing::Test {
54 public:
55 void VerifyCowMergeOp(const std::vector<CowOperation>& cow_ops) {
56 // Build a set of all extents covered by InstallOps.
57 ExtentRanges src_extent_set;
58 ExtentRanges dst_extent_set;
59 for (auto&& op : operations_) {
60 src_extent_set.AddRepeatedExtents(op.src_extents());
61 dst_extent_set.AddRepeatedExtents(op.dst_extents());
62 }
63 ExtentRanges modified_extents;
64 for (auto&& cow_op : cow_ops) {
65 if (cow_op.op == CowOperation::CowCopy) {
66 EXPECT_TRUE(src_extent_set.ContainsBlock(cow_op.src_block));
67 // converted operations should be conflict free.
68 EXPECT_FALSE(modified_extents.ContainsBlock(cow_op.src_block))
69 << "SOURCE_COPY operation " << cow_op
70 << " read from a modified block";
71 src_extent_set.SubtractExtent(ExtentForRange(cow_op.src_block, 1));
72 }
73 EXPECT_TRUE(dst_extent_set.ContainsBlock(cow_op.dst_block));
74 dst_extent_set.SubtractExtent(ExtentForRange(cow_op.dst_block, 1));
75 modified_extents.AddBlock(cow_op.dst_block);
76 }
77 // The generated CowOps should cover all extents in InstallOps.
78 EXPECT_EQ(dst_extent_set.blocks(), 0UL);
79 // It's possible that src_extent_set is non-empty, because some operations
80 // will be converted to CowReplace, and we don't count the source extent for
81 // those.
82 }
83 OperationList operations_;
84 MergeOplist merge_operations_;
85};
86
87void AddOperation(OperationList* operations,
88 ::chromeos_update_engine::InstallOperation_Type op_type,
89 std::initializer_list<std::array<int, 2>> src_extents,
90 std::initializer_list<std::array<int, 2>> dst_extents) {
91 auto&& op = operations->Add();
92 op->set_type(op_type);
93 for (const auto& extent : src_extents) {
94 *op->add_src_extents() = ExtentForRange(extent[0], extent[1]);
95 }
96 for (const auto& extent : dst_extents) {
97 *op->add_dst_extents() = ExtentForRange(extent[0], extent[1]);
98 }
99}
100
101void AddMergeOperation(MergeOplist* operations,
102 ::chromeos_update_engine::CowMergeOperation_Type op_type,
103 std::array<int, 2> src_extent,
104 std::array<int, 2> dst_extent) {
105 auto&& op = operations->Add();
106 op->set_type(op_type);
107 *op->mutable_src_extent() = ExtentForRange(src_extent[0], src_extent[1]);
108 *op->mutable_dst_extent() = ExtentForRange(dst_extent[0], dst_extent[1]);
109}
110
111TEST_F(CowOperationConvertTest, NoConflict) {
112 AddOperation(
113 &operations_, InstallOperation::SOURCE_COPY, {{20, 1}}, {{30, 1}});
114 AddOperation(
115 &operations_, InstallOperation::SOURCE_COPY, {{10, 1}}, {{20, 1}});
116 AddOperation(
117 &operations_, InstallOperation::SOURCE_COPY, {{0, 1}}, {{10, 1}});
118
119 AddMergeOperation(
120 &merge_operations_, CowMergeOperation::COW_COPY, {20, 1}, {30, 1});
121 AddMergeOperation(
122 &merge_operations_, CowMergeOperation::COW_COPY, {10, 1}, {20, 1});
123 AddMergeOperation(
124 &merge_operations_, CowMergeOperation::COW_COPY, {0, 1}, {10, 1});
125
126 auto cow_ops = ConvertToCowOperations(operations_, merge_operations_);
127 ASSERT_EQ(cow_ops.size(), 3UL);
128 ASSERT_TRUE(std::all_of(cow_ops.begin(), cow_ops.end(), [](auto&& cow_op) {
129 return cow_op.op == CowOperation::CowCopy;
130 }));
131 VerifyCowMergeOp(cow_ops);
132}
133
134TEST_F(CowOperationConvertTest, CowReplace) {
135 AddOperation(
136 &operations_, InstallOperation::SOURCE_COPY, {{30, 1}}, {{0, 1}});
137 AddOperation(
138 &operations_, InstallOperation::SOURCE_COPY, {{20, 1}}, {{30, 1}});
139 AddOperation(
140 &operations_, InstallOperation::SOURCE_COPY, {{10, 1}}, {{20, 1}});
141 AddOperation(
142 &operations_, InstallOperation::SOURCE_COPY, {{0, 1}}, {{10, 1}});
143
144 AddMergeOperation(
145 &merge_operations_, CowMergeOperation::COW_COPY, {20, 1}, {30, 1});
146 AddMergeOperation(
147 &merge_operations_, CowMergeOperation::COW_COPY, {10, 1}, {20, 1});
148 AddMergeOperation(
149 &merge_operations_, CowMergeOperation::COW_COPY, {0, 1}, {10, 1});
150
151 auto cow_ops = ConvertToCowOperations(operations_, merge_operations_);
152 ASSERT_EQ(cow_ops.size(), 4UL);
153 // Expect 3 COW_COPY and 1 COW_REPLACE
154 ASSERT_EQ(std::count_if(cow_ops.begin(),
155 cow_ops.end(),
156 [](auto&& cow_op) {
157 return cow_op.op == CowOperation::CowCopy;
158 }),
159 3);
160 ASSERT_EQ(std::count_if(cow_ops.begin(),
161 cow_ops.end(),
162 [](auto&& cow_op) {
163 return cow_op.op == CowOperation::CowReplace;
164 }),
165 1);
166 VerifyCowMergeOp(cow_ops);
167}
168
169TEST_F(CowOperationConvertTest, ReOrderSourceCopy) {
170 AddOperation(
171 &operations_, InstallOperation::SOURCE_COPY, {{30, 1}}, {{20, 1}});
172 AddOperation(
173 &operations_, InstallOperation::SOURCE_COPY, {{20, 1}}, {{10, 1}});
174 AddOperation(
175 &operations_, InstallOperation::SOURCE_COPY, {{10, 1}}, {{0, 1}});
176
177 AddMergeOperation(
178 &merge_operations_, CowMergeOperation::COW_COPY, {10, 1}, {0, 1});
179 AddMergeOperation(
180 &merge_operations_, CowMergeOperation::COW_COPY, {20, 1}, {10, 1});
181 AddMergeOperation(
182 &merge_operations_, CowMergeOperation::COW_COPY, {30, 1}, {20, 1});
183
184 auto cow_ops = ConvertToCowOperations(operations_, merge_operations_);
185 ASSERT_EQ(cow_ops.size(), 3UL);
186 // Expect 3 COW_COPY
187 ASSERT_TRUE(std::all_of(cow_ops.begin(), cow_ops.end(), [](auto&& cow_op) {
188 return cow_op.op == CowOperation::CowCopy;
189 }));
190 VerifyCowMergeOp(cow_ops);
191}
192
193TEST_F(CowOperationConvertTest, InterleavingSrcExtent) {
194 AddOperation(&operations_,
195 InstallOperation::SOURCE_COPY,
196 {{30, 5}, {35, 5}},
197 {{20, 10}});
198 AddOperation(
199 &operations_, InstallOperation::SOURCE_COPY, {{20, 1}}, {{10, 1}});
200 AddOperation(
201 &operations_, InstallOperation::SOURCE_COPY, {{10, 1}}, {{0, 1}});
202
203 AddMergeOperation(
204 &merge_operations_, CowMergeOperation::COW_COPY, {10, 1}, {0, 1});
205 AddMergeOperation(
206 &merge_operations_, CowMergeOperation::COW_COPY, {20, 1}, {10, 1});
207 AddMergeOperation(
208 &merge_operations_, CowMergeOperation::COW_COPY, {30, 5}, {20, 5});
209 AddMergeOperation(
210 &merge_operations_, CowMergeOperation::COW_COPY, {35, 5}, {25, 5});
211
212 auto cow_ops = ConvertToCowOperations(operations_, merge_operations_);
213 // Expect 4 COW_COPY
214 ASSERT_EQ(cow_ops.size(), 12UL);
215 ASSERT_TRUE(std::all_of(cow_ops.begin(), cow_ops.end(), [](auto&& cow_op) {
216 return cow_op.op == CowOperation::CowCopy;
217 }));
218 VerifyCowMergeOp(cow_ops);
219}
220} // namespace chromeos_update_engine