blob: cde4bfc35c42bc1bea576ee4a0b209a3084930f3 [file] [log] [blame]
Alex Deymoaea4c1c2015-08-19 20:24:43 -07001//
2// Copyright (C) 2015 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//
Allie Woodcd514b52015-02-19 13:56:07 -080016
17#include "update_engine/payload_generator/inplace_generator.h"
18
Alex Deymo14158572015-06-13 03:37:08 -070019#include <map>
Allie Woodcd514b52015-02-19 13:56:07 -080020#include <set>
21#include <sstream>
22#include <string>
23#include <utility>
24#include <vector>
25
Alex Deymo896fdba2015-07-16 15:25:18 -070026#include <base/format_macros.h>
Allie Woodcd514b52015-02-19 13:56:07 -080027#include <base/logging.h>
28#include <base/strings/string_util.h>
Alex Deymo896fdba2015-07-16 15:25:18 -070029#include <base/strings/stringprintf.h>
Allie Woodcd514b52015-02-19 13:56:07 -080030#include <gtest/gtest.h>
31
Alex Deymo39910dc2015-11-09 17:04:30 -080032#include "update_engine/common/test_utils.h"
33#include "update_engine/common/utils.h"
Allie Woodcd514b52015-02-19 13:56:07 -080034#include "update_engine/payload_generator/cycle_breaker.h"
35#include "update_engine/payload_generator/delta_diff_generator.h"
Alex Deymo1beda782015-06-07 23:01:25 +020036#include "update_engine/payload_generator/extent_ranges.h"
Allie Woodcd514b52015-02-19 13:56:07 -080037#include "update_engine/payload_generator/graph_types.h"
Alex Deymo5c6c6552015-06-03 19:06:50 +020038#include "update_engine/payload_generator/graph_utils.h"
Allie Woodcd514b52015-02-19 13:56:07 -080039
Alex Deymo14158572015-06-13 03:37:08 -070040using std::map;
Allie Woodcd514b52015-02-19 13:56:07 -080041using std::set;
42using std::string;
43using std::stringstream;
44using std::vector;
45
46namespace chromeos_update_engine {
47
Alex Deymo6b9e38e2015-06-05 00:26:37 +020048using Block = InplaceGenerator::Block;
Allie Woodcd514b52015-02-19 13:56:07 -080049
50namespace {
51
Allie Woodcd514b52015-02-19 13:56:07 -080052void GenVertex(Vertex* out,
53 const vector<Extent>& src_extents,
54 const vector<Extent>& dst_extents,
55 const string& path,
Alex Deymoa12ee112015-08-12 22:19:32 -070056 InstallOperation_Type type) {
Alex Deymo3b2c7d02015-07-16 16:08:16 -070057 out->aop.op.set_type(type);
58 out->aop.name = path;
59 StoreExtents(src_extents, out->aop.op.mutable_src_extents());
60 StoreExtents(dst_extents, out->aop.op.mutable_dst_extents());
Allie Woodcd514b52015-02-19 13:56:07 -080061}
62
63vector<Extent> VectOfExt(uint64_t start_block, uint64_t num_blocks) {
64 return vector<Extent>(1, ExtentForRange(start_block, num_blocks));
65}
66
67EdgeProperties EdgeWithReadDep(const vector<Extent>& extents) {
68 EdgeProperties ret;
69 ret.extents = extents;
70 return ret;
71}
72
73EdgeProperties EdgeWithWriteDep(const vector<Extent>& extents) {
74 EdgeProperties ret;
75 ret.write_extents = extents;
76 return ret;
77}
78
79template<typename T>
80void DumpVect(const vector<T>& vect) {
81 stringstream ss(stringstream::out);
82 for (typename vector<T>::const_iterator it = vect.begin(), e = vect.end();
83 it != e; ++it) {
84 ss << *it << ", ";
85 }
86 LOG(INFO) << "{" << ss.str() << "}";
87}
88
89void AppendExtent(vector<Extent>* vect, uint64_t start, uint64_t length) {
90 vect->resize(vect->size() + 1);
91 vect->back().set_start_block(start);
92 vect->back().set_num_blocks(length);
93}
94
Alex Deymoa12ee112015-08-12 22:19:32 -070095void OpAppendExtent(InstallOperation* op, uint64_t start, uint64_t length) {
Allie Woodcd514b52015-02-19 13:56:07 -080096 Extent* extent = op->add_src_extents();
97 extent->set_start_block(start);
98 extent->set_num_blocks(length);
99}
100
101} // namespace
102
103class InplaceGeneratorTest : public ::testing::Test {
Alex Deymo896fdba2015-07-16 15:25:18 -0700104 protected:
105 // Initialize |blob_path_|, |blob_file_size_| and |blob_file_fd_| variables
106 // with a new blob file. The file is closed and removed automatically when
107 // the test finishes.
108 void CreateBlobFile() {
109 // blob_fd_closer_ takes a pointer to blob_fd_. Make sure we destroy a
110 // previous instance before overriding blob_fd_.
111 blob_fd_closer_.reset();
112 EXPECT_TRUE(utils::MakeTempFile(
113 "InplaceGenerator_blob_file.XXXXXX", &blob_path_, &blob_fd_));
114 blob_path_unlinker_.reset(new ScopedPathUnlinker(blob_path_));
115 blob_fd_closer_.reset(new ScopedFdCloser(&blob_fd_));
116 blob_file_size_ = 0;
117 EXPECT_GE(blob_fd_, 0);
Sen Jiang8cc502d2015-08-10 10:04:54 -0700118 blob_file_.reset(new BlobFileWriter(blob_fd_, &blob_file_size_));
Alex Deymo896fdba2015-07-16 15:25:18 -0700119 }
120
121 // Blob file name, file descriptor and file size used to store operation
122 // blobs.
123 string blob_path_;
124 int blob_fd_{-1};
125 off_t blob_file_size_{0};
Sen Jiang8cc502d2015-08-10 10:04:54 -0700126 std::unique_ptr<BlobFileWriter> blob_file_;
Alex Deymo896fdba2015-07-16 15:25:18 -0700127 std::unique_ptr<ScopedPathUnlinker> blob_path_unlinker_;
128 std::unique_ptr<ScopedFdCloser> blob_fd_closer_;
Allie Woodcd514b52015-02-19 13:56:07 -0800129};
130
Alex Deymo6b9e38e2015-06-05 00:26:37 +0200131TEST_F(InplaceGeneratorTest, BlockDefaultValues) {
132 // Tests that a Block is initialized with the default values as a
133 // Vertex::kInvalidIndex. This is required by the delta generators.
134 Block block;
135 EXPECT_EQ(Vertex::kInvalidIndex, block.reader);
136 EXPECT_EQ(Vertex::kInvalidIndex, block.writer);
137}
138
Allie Woodcd514b52015-02-19 13:56:07 -0800139TEST_F(InplaceGeneratorTest, SubstituteBlocksTest) {
140 vector<Extent> remove_blocks;
141 AppendExtent(&remove_blocks, 3, 3);
142 AppendExtent(&remove_blocks, 7, 1);
143 vector<Extent> replace_blocks;
144 AppendExtent(&replace_blocks, 10, 2);
145 AppendExtent(&replace_blocks, 13, 2);
146 Vertex vertex;
Alex Deymoa12ee112015-08-12 22:19:32 -0700147 InstallOperation& op = vertex.aop.op;
Allie Woodcd514b52015-02-19 13:56:07 -0800148 OpAppendExtent(&op, 4, 3);
149 OpAppendExtent(&op, kSparseHole, 4); // Sparse hole in file
150 OpAppendExtent(&op, 3, 1);
151 OpAppendExtent(&op, 7, 3);
152
153 InplaceGenerator::SubstituteBlocks(&vertex, remove_blocks, replace_blocks);
154
155 EXPECT_EQ(7, op.src_extents_size());
Alex Deymo80f70ff2016-02-10 16:08:11 -0800156 EXPECT_EQ(11U, op.src_extents(0).start_block());
157 EXPECT_EQ(1U, op.src_extents(0).num_blocks());
158 EXPECT_EQ(13U, op.src_extents(1).start_block());
159 EXPECT_EQ(1U, op.src_extents(1).num_blocks());
160 EXPECT_EQ(6U, op.src_extents(2).start_block());
161 EXPECT_EQ(1U, op.src_extents(2).num_blocks());
Allie Woodcd514b52015-02-19 13:56:07 -0800162 EXPECT_EQ(kSparseHole, op.src_extents(3).start_block());
Alex Deymo80f70ff2016-02-10 16:08:11 -0800163 EXPECT_EQ(4U, op.src_extents(3).num_blocks());
164 EXPECT_EQ(10U, op.src_extents(4).start_block());
165 EXPECT_EQ(1U, op.src_extents(4).num_blocks());
166 EXPECT_EQ(14U, op.src_extents(5).start_block());
167 EXPECT_EQ(1U, op.src_extents(5).num_blocks());
168 EXPECT_EQ(8U, op.src_extents(6).start_block());
169 EXPECT_EQ(2U, op.src_extents(6).num_blocks());
Allie Woodcd514b52015-02-19 13:56:07 -0800170}
171
172TEST_F(InplaceGeneratorTest, CutEdgesTest) {
173 Graph graph;
174 vector<Block> blocks(9);
175
176 // Create nodes in graph
177 {
178 graph.resize(graph.size() + 1);
Alex Deymoa12ee112015-08-12 22:19:32 -0700179 graph.back().aop.op.set_type(InstallOperation::MOVE);
Allie Woodcd514b52015-02-19 13:56:07 -0800180 // Reads from blocks 3, 5, 7
181 vector<Extent> extents;
Alex Deymo5c6c6552015-06-03 19:06:50 +0200182 AppendBlockToExtents(&extents, 3);
183 AppendBlockToExtents(&extents, 5);
184 AppendBlockToExtents(&extents, 7);
Alex Deymo3b2c7d02015-07-16 16:08:16 -0700185 StoreExtents(extents, graph.back().aop.op.mutable_src_extents());
Allie Woodcd514b52015-02-19 13:56:07 -0800186 blocks[3].reader = graph.size() - 1;
187 blocks[5].reader = graph.size() - 1;
188 blocks[7].reader = graph.size() - 1;
189
190 // Writes to blocks 1, 2, 4
191 extents.clear();
Alex Deymo5c6c6552015-06-03 19:06:50 +0200192 AppendBlockToExtents(&extents, 1);
193 AppendBlockToExtents(&extents, 2);
194 AppendBlockToExtents(&extents, 4);
Alex Deymo3b2c7d02015-07-16 16:08:16 -0700195 StoreExtents(extents, graph.back().aop.op.mutable_dst_extents());
Allie Woodcd514b52015-02-19 13:56:07 -0800196 blocks[1].writer = graph.size() - 1;
197 blocks[2].writer = graph.size() - 1;
198 blocks[4].writer = graph.size() - 1;
199 }
200 {
201 graph.resize(graph.size() + 1);
Alex Deymoa12ee112015-08-12 22:19:32 -0700202 graph.back().aop.op.set_type(InstallOperation::MOVE);
Allie Woodcd514b52015-02-19 13:56:07 -0800203 // Reads from blocks 1, 2, 4
204 vector<Extent> extents;
Alex Deymo5c6c6552015-06-03 19:06:50 +0200205 AppendBlockToExtents(&extents, 1);
206 AppendBlockToExtents(&extents, 2);
207 AppendBlockToExtents(&extents, 4);
Alex Deymo3b2c7d02015-07-16 16:08:16 -0700208 StoreExtents(extents, graph.back().aop.op.mutable_src_extents());
Allie Woodcd514b52015-02-19 13:56:07 -0800209 blocks[1].reader = graph.size() - 1;
210 blocks[2].reader = graph.size() - 1;
211 blocks[4].reader = graph.size() - 1;
212
213 // Writes to blocks 3, 5, 6
214 extents.clear();
Alex Deymo5c6c6552015-06-03 19:06:50 +0200215 AppendBlockToExtents(&extents, 3);
216 AppendBlockToExtents(&extents, 5);
217 AppendBlockToExtents(&extents, 6);
Alex Deymo3b2c7d02015-07-16 16:08:16 -0700218 StoreExtents(extents, graph.back().aop.op.mutable_dst_extents());
Allie Woodcd514b52015-02-19 13:56:07 -0800219 blocks[3].writer = graph.size() - 1;
220 blocks[5].writer = graph.size() - 1;
221 blocks[6].writer = graph.size() - 1;
222 }
223
224 // Create edges
225 InplaceGenerator::CreateEdges(&graph, blocks);
226
227 // Find cycles
228 CycleBreaker cycle_breaker;
229 set<Edge> cut_edges;
230 cycle_breaker.BreakCycles(graph, &cut_edges);
231
Alex Deymo80f70ff2016-02-10 16:08:11 -0800232 EXPECT_EQ(1U, cut_edges.size());
Allie Woodcd514b52015-02-19 13:56:07 -0800233 EXPECT_TRUE(cut_edges.end() != cut_edges.find(
234 std::pair<Vertex::Index, Vertex::Index>(1, 0)));
235
236 vector<CutEdgeVertexes> cuts;
237 EXPECT_TRUE(InplaceGenerator::CutEdges(&graph, cut_edges, &cuts));
238
Alex Deymo80f70ff2016-02-10 16:08:11 -0800239 EXPECT_EQ(3U, graph.size());
Allie Woodcd514b52015-02-19 13:56:07 -0800240
241 // Check new node in graph:
Alex Deymoa12ee112015-08-12 22:19:32 -0700242 EXPECT_EQ(InstallOperation::MOVE, graph.back().aop.op.type());
Alex Deymo3b2c7d02015-07-16 16:08:16 -0700243 EXPECT_EQ(2, graph.back().aop.op.src_extents_size());
244 EXPECT_EQ(1, graph.back().aop.op.dst_extents_size());
245 EXPECT_EQ(kTempBlockStart, graph.back().aop.op.dst_extents(0).start_block());
Alex Deymo80f70ff2016-02-10 16:08:11 -0800246 EXPECT_EQ(2U, graph.back().aop.op.dst_extents(0).num_blocks());
Allie Woodcd514b52015-02-19 13:56:07 -0800247 EXPECT_TRUE(graph.back().out_edges.empty());
248
249 // Check that old node reads from new blocks
Alex Deymo3b2c7d02015-07-16 16:08:16 -0700250 EXPECT_EQ(2, graph[0].aop.op.src_extents_size());
251 EXPECT_EQ(kTempBlockStart, graph[0].aop.op.src_extents(0).start_block());
Alex Deymo80f70ff2016-02-10 16:08:11 -0800252 EXPECT_EQ(2U, graph[0].aop.op.src_extents(0).num_blocks());
253 EXPECT_EQ(7U, graph[0].aop.op.src_extents(1).start_block());
254 EXPECT_EQ(1U, graph[0].aop.op.src_extents(1).num_blocks());
Allie Woodcd514b52015-02-19 13:56:07 -0800255
256 // And that the old dst extents haven't changed
Alex Deymo3b2c7d02015-07-16 16:08:16 -0700257 EXPECT_EQ(2, graph[0].aop.op.dst_extents_size());
Alex Deymo80f70ff2016-02-10 16:08:11 -0800258 EXPECT_EQ(1U, graph[0].aop.op.dst_extents(0).start_block());
259 EXPECT_EQ(2U, graph[0].aop.op.dst_extents(0).num_blocks());
260 EXPECT_EQ(4U, graph[0].aop.op.dst_extents(1).start_block());
261 EXPECT_EQ(1U, graph[0].aop.op.dst_extents(1).num_blocks());
Allie Woodcd514b52015-02-19 13:56:07 -0800262
263 // Ensure it only depends on the next node and the new temp node
Alex Deymo80f70ff2016-02-10 16:08:11 -0800264 EXPECT_EQ(2U, graph[0].out_edges.size());
Allie Woodcd514b52015-02-19 13:56:07 -0800265 EXPECT_TRUE(graph[0].out_edges.end() != graph[0].out_edges.find(1));
266 EXPECT_TRUE(graph[0].out_edges.end() != graph[0].out_edges.find(graph.size() -
267 1));
268
269 // Check second node has unchanged extents
Alex Deymo3b2c7d02015-07-16 16:08:16 -0700270 EXPECT_EQ(2, graph[1].aop.op.src_extents_size());
Alex Deymo80f70ff2016-02-10 16:08:11 -0800271 EXPECT_EQ(1U, graph[1].aop.op.src_extents(0).start_block());
272 EXPECT_EQ(2U, graph[1].aop.op.src_extents(0).num_blocks());
273 EXPECT_EQ(4U, graph[1].aop.op.src_extents(1).start_block());
274 EXPECT_EQ(1U, graph[1].aop.op.src_extents(1).num_blocks());
Allie Woodcd514b52015-02-19 13:56:07 -0800275
Alex Deymo3b2c7d02015-07-16 16:08:16 -0700276 EXPECT_EQ(2, graph[1].aop.op.dst_extents_size());
Alex Deymo80f70ff2016-02-10 16:08:11 -0800277 EXPECT_EQ(3U, graph[1].aop.op.dst_extents(0).start_block());
278 EXPECT_EQ(1U, graph[1].aop.op.dst_extents(0).num_blocks());
279 EXPECT_EQ(5U, graph[1].aop.op.dst_extents(1).start_block());
280 EXPECT_EQ(2U, graph[1].aop.op.dst_extents(1).num_blocks());
Allie Woodcd514b52015-02-19 13:56:07 -0800281
282 // Ensure it only depends on the next node
Alex Deymo80f70ff2016-02-10 16:08:11 -0800283 EXPECT_EQ(1U, graph[1].out_edges.size());
Allie Woodcd514b52015-02-19 13:56:07 -0800284 EXPECT_TRUE(graph[1].out_edges.end() != graph[1].out_edges.find(2));
285}
286
Alex Deymo6b9e38e2015-06-05 00:26:37 +0200287TEST_F(InplaceGeneratorTest, AssignTempBlocksReuseTest) {
Allie Woodcd514b52015-02-19 13:56:07 -0800288 Graph graph(9);
289
290 const vector<Extent> empt;
291 uint64_t tmp = kTempBlockStart;
292 const string kFilename = "/foo";
293
294 vector<CutEdgeVertexes> cuts;
295 cuts.resize(3);
296
297 // Simple broken loop:
Alex Deymoa12ee112015-08-12 22:19:32 -0700298 GenVertex(
299 &graph[0], VectOfExt(0, 1), VectOfExt(1, 1), "", InstallOperation::MOVE);
300 GenVertex(&graph[1],
301 VectOfExt(tmp, 1),
302 VectOfExt(0, 1),
303 "",
304 InstallOperation::MOVE);
305 GenVertex(&graph[2],
306 VectOfExt(1, 1),
307 VectOfExt(tmp, 1),
308 "",
309 InstallOperation::MOVE);
Allie Woodcd514b52015-02-19 13:56:07 -0800310 // Corresponding edges:
311 graph[0].out_edges[2] = EdgeWithReadDep(VectOfExt(1, 1));
312 graph[1].out_edges[2] = EdgeWithWriteDep(VectOfExt(tmp, 1));
313 graph[1].out_edges[0] = EdgeWithReadDep(VectOfExt(0, 1));
314 // Store the cut:
315 cuts[0].old_dst = 1;
316 cuts[0].old_src = 0;
317 cuts[0].new_vertex = 2;
318 cuts[0].tmp_extents = VectOfExt(tmp, 1);
319 tmp++;
320
321 // Slightly more complex pair of loops:
Alex Deymoa12ee112015-08-12 22:19:32 -0700322 GenVertex(
323 &graph[3], VectOfExt(4, 2), VectOfExt(2, 2), "", InstallOperation::MOVE);
324 GenVertex(
325 &graph[4], VectOfExt(6, 1), VectOfExt(7, 1), "", InstallOperation::MOVE);
326 GenVertex(&graph[5],
327 VectOfExt(tmp, 3),
328 VectOfExt(4, 3),
329 kFilename,
330 InstallOperation::MOVE);
331 GenVertex(&graph[6],
332 VectOfExt(2, 2),
333 VectOfExt(tmp, 2),
334 "",
335 InstallOperation::MOVE);
336 GenVertex(&graph[7],
337 VectOfExt(7, 1),
338 VectOfExt(tmp + 2, 1),
339 "",
340 InstallOperation::MOVE);
Allie Woodcd514b52015-02-19 13:56:07 -0800341 // Corresponding edges:
342 graph[3].out_edges[6] = EdgeWithReadDep(VectOfExt(2, 2));
343 graph[4].out_edges[7] = EdgeWithReadDep(VectOfExt(7, 1));
344 graph[5].out_edges[6] = EdgeWithWriteDep(VectOfExt(tmp, 2));
345 graph[5].out_edges[7] = EdgeWithWriteDep(VectOfExt(tmp + 2, 1));
346 graph[5].out_edges[3] = EdgeWithReadDep(VectOfExt(4, 2));
347 graph[5].out_edges[4] = EdgeWithReadDep(VectOfExt(6, 1));
348 // Store the cuts:
349 cuts[1].old_dst = 5;
350 cuts[1].old_src = 3;
351 cuts[1].new_vertex = 6;
352 cuts[1].tmp_extents = VectOfExt(tmp, 2);
353 cuts[2].old_dst = 5;
354 cuts[2].old_src = 4;
355 cuts[2].new_vertex = 7;
356 cuts[2].tmp_extents = VectOfExt(tmp + 2, 1);
357
358 // Supplier of temp block:
Alex Deymoa12ee112015-08-12 22:19:32 -0700359 GenVertex(&graph[8], empt, VectOfExt(8, 1), "", InstallOperation::REPLACE);
Allie Woodcd514b52015-02-19 13:56:07 -0800360
361 // Specify the final order:
362 vector<Vertex::Index> op_indexes;
363 op_indexes.push_back(2);
364 op_indexes.push_back(0);
365 op_indexes.push_back(1);
366 op_indexes.push_back(6);
367 op_indexes.push_back(3);
368 op_indexes.push_back(7);
369 op_indexes.push_back(4);
370 op_indexes.push_back(5);
371 op_indexes.push_back(8);
372
373 vector<vector<Vertex::Index>::size_type> reverse_op_indexes;
374 InplaceGenerator::GenerateReverseTopoOrderMap(op_indexes,
375 &reverse_op_indexes);
376
Alex Deymo896fdba2015-07-16 15:25:18 -0700377 CreateBlobFile();
Allie Woodcd514b52015-02-19 13:56:07 -0800378 EXPECT_TRUE(InplaceGenerator::AssignTempBlocks(&graph,
Allie Wood56873452015-03-27 17:48:40 -0700379 "/dev/zero",
Sen Jiang8cc502d2015-08-10 10:04:54 -0700380 blob_file_.get(),
Allie Woodcd514b52015-02-19 13:56:07 -0800381 &op_indexes,
382 &reverse_op_indexes,
383 cuts));
384 EXPECT_FALSE(graph[6].valid);
385 EXPECT_FALSE(graph[7].valid);
Alex Deymo3b2c7d02015-07-16 16:08:16 -0700386 EXPECT_EQ(1, graph[1].aop.op.src_extents_size());
Alex Deymo80f70ff2016-02-10 16:08:11 -0800387 EXPECT_EQ(2U, graph[1].aop.op.src_extents(0).start_block());
388 EXPECT_EQ(1U, graph[1].aop.op.src_extents(0).num_blocks());
Alex Deymoa12ee112015-08-12 22:19:32 -0700389 EXPECT_EQ(InstallOperation::REPLACE_BZ, graph[5].aop.op.type());
Allie Woodcd514b52015-02-19 13:56:07 -0800390}
391
Alex Deymo3b2c7d02015-07-16 16:08:16 -0700392TEST_F(InplaceGeneratorTest, MoveAndSortFullOpsToBackTest) {
Allie Woodcd514b52015-02-19 13:56:07 -0800393 Graph graph(4);
Alex Deymo3b2c7d02015-07-16 16:08:16 -0700394 graph[0].aop.name = "A";
Alex Deymoa12ee112015-08-12 22:19:32 -0700395 graph[0].aop.op.set_type(InstallOperation::REPLACE);
Alex Deymo3b2c7d02015-07-16 16:08:16 -0700396 graph[1].aop.name = "B";
Alex Deymoa12ee112015-08-12 22:19:32 -0700397 graph[1].aop.op.set_type(InstallOperation::BSDIFF);
Alex Deymo3b2c7d02015-07-16 16:08:16 -0700398 graph[2].aop.name = "C";
Alex Deymoa12ee112015-08-12 22:19:32 -0700399 graph[2].aop.op.set_type(InstallOperation::REPLACE_BZ);
Alex Deymo3b2c7d02015-07-16 16:08:16 -0700400 graph[3].aop.name = "D";
Alex Deymoa12ee112015-08-12 22:19:32 -0700401 graph[3].aop.op.set_type(InstallOperation::MOVE);
Allie Woodcd514b52015-02-19 13:56:07 -0800402
403 vector<Vertex::Index> vect(graph.size());
404
405 for (vector<Vertex::Index>::size_type i = 0; i < vect.size(); ++i) {
406 vect[i] = i;
407 }
Alex Deymo3b2c7d02015-07-16 16:08:16 -0700408 InplaceGenerator::MoveAndSortFullOpsToBack(&graph, &vect);
Allie Woodcd514b52015-02-19 13:56:07 -0800409 EXPECT_EQ(vect.size(), graph.size());
Alex Deymo3b2c7d02015-07-16 16:08:16 -0700410 EXPECT_EQ(graph[vect[0]].aop.name, "B");
411 EXPECT_EQ(graph[vect[1]].aop.name, "D");
412 EXPECT_EQ(graph[vect[2]].aop.name, "A");
413 EXPECT_EQ(graph[vect[3]].aop.name, "C");
Allie Woodcd514b52015-02-19 13:56:07 -0800414}
415
Alex Deymo6b9e38e2015-06-05 00:26:37 +0200416TEST_F(InplaceGeneratorTest, AssignTempBlocksTest) {
Allie Woodcd514b52015-02-19 13:56:07 -0800417 Graph graph(9);
418 const vector<Extent> empt; // empty
419 const string kFilename = "/foo";
420
421 // Some scratch space:
Alex Deymoa12ee112015-08-12 22:19:32 -0700422 GenVertex(&graph[0], empt, VectOfExt(200, 1), "", InstallOperation::REPLACE);
423 GenVertex(&graph[1], empt, VectOfExt(210, 10), "", InstallOperation::REPLACE);
424 GenVertex(&graph[2], empt, VectOfExt(220, 1), "", InstallOperation::REPLACE);
Allie Woodcd514b52015-02-19 13:56:07 -0800425
426 // A cycle that requires 10 blocks to break:
Alex Deymoa12ee112015-08-12 22:19:32 -0700427 GenVertex(&graph[3],
428 VectOfExt(10, 11),
429 VectOfExt(0, 9),
430 "",
431 InstallOperation::BSDIFF);
Allie Woodcd514b52015-02-19 13:56:07 -0800432 graph[3].out_edges[4] = EdgeWithReadDep(VectOfExt(0, 9));
Alex Deymoa12ee112015-08-12 22:19:32 -0700433 GenVertex(&graph[4],
434 VectOfExt(0, 9),
435 VectOfExt(10, 11),
436 "",
437 InstallOperation::BSDIFF);
Allie Woodcd514b52015-02-19 13:56:07 -0800438 graph[4].out_edges[3] = EdgeWithReadDep(VectOfExt(10, 11));
439
440 // A cycle that requires 9 blocks to break:
Alex Deymoa12ee112015-08-12 22:19:32 -0700441 GenVertex(&graph[5],
442 VectOfExt(40, 11),
443 VectOfExt(30, 10),
444 "",
445 InstallOperation::BSDIFF);
Allie Woodcd514b52015-02-19 13:56:07 -0800446 graph[5].out_edges[6] = EdgeWithReadDep(VectOfExt(30, 10));
Alex Deymoa12ee112015-08-12 22:19:32 -0700447 GenVertex(&graph[6],
448 VectOfExt(30, 10),
449 VectOfExt(40, 11),
450 "",
451 InstallOperation::BSDIFF);
Allie Woodcd514b52015-02-19 13:56:07 -0800452 graph[6].out_edges[5] = EdgeWithReadDep(VectOfExt(40, 11));
453
454 // A cycle that requires 40 blocks to break (which is too many):
455 GenVertex(&graph[7],
456 VectOfExt(120, 50),
457 VectOfExt(60, 40),
458 "",
Alex Deymoa12ee112015-08-12 22:19:32 -0700459 InstallOperation::BSDIFF);
Allie Woodcd514b52015-02-19 13:56:07 -0800460 graph[7].out_edges[8] = EdgeWithReadDep(VectOfExt(60, 40));
461 GenVertex(&graph[8],
462 VectOfExt(60, 40),
463 VectOfExt(120, 50),
464 kFilename,
Alex Deymoa12ee112015-08-12 22:19:32 -0700465 InstallOperation::BSDIFF);
Allie Woodcd514b52015-02-19 13:56:07 -0800466 graph[8].out_edges[7] = EdgeWithReadDep(VectOfExt(120, 50));
467
468 graph_utils::DumpGraph(graph);
469
470 vector<Vertex::Index> final_order;
471
Alex Deymo896fdba2015-07-16 15:25:18 -0700472 CreateBlobFile();
Allie Woodcd514b52015-02-19 13:56:07 -0800473 EXPECT_TRUE(InplaceGenerator::ConvertGraphToDag(&graph,
Allie Wood56873452015-03-27 17:48:40 -0700474 "/dev/zero",
Sen Jiang8cc502d2015-08-10 10:04:54 -0700475 blob_file_.get(),
Allie Woodcd514b52015-02-19 13:56:07 -0800476 &final_order,
477 Vertex::kInvalidIndex));
478
Allie Woodcd514b52015-02-19 13:56:07 -0800479 Graph expected_graph(12);
Alex Deymoa12ee112015-08-12 22:19:32 -0700480 GenVertex(&expected_graph[0],
481 empt,
482 VectOfExt(200, 1),
483 "",
484 InstallOperation::REPLACE);
485 GenVertex(&expected_graph[1],
486 empt,
487 VectOfExt(210, 10),
488 "",
489 InstallOperation::REPLACE);
490 GenVertex(&expected_graph[2],
491 empt,
492 VectOfExt(220, 1),
493 "",
494 InstallOperation::REPLACE);
Allie Woodcd514b52015-02-19 13:56:07 -0800495 GenVertex(&expected_graph[3],
496 VectOfExt(10, 11),
497 VectOfExt(0, 9),
498 "",
Alex Deymoa12ee112015-08-12 22:19:32 -0700499 InstallOperation::BSDIFF);
Allie Woodcd514b52015-02-19 13:56:07 -0800500 expected_graph[3].out_edges[9] = EdgeWithReadDep(VectOfExt(0, 9));
501 GenVertex(&expected_graph[4],
502 VectOfExt(60, 9),
503 VectOfExt(10, 11),
504 "",
Alex Deymoa12ee112015-08-12 22:19:32 -0700505 InstallOperation::BSDIFF);
Allie Woodcd514b52015-02-19 13:56:07 -0800506 expected_graph[4].out_edges[3] = EdgeWithReadDep(VectOfExt(10, 11));
507 expected_graph[4].out_edges[9] = EdgeWithWriteDep(VectOfExt(60, 9));
508 GenVertex(&expected_graph[5],
509 VectOfExt(40, 11),
510 VectOfExt(30, 10),
511 "",
Alex Deymoa12ee112015-08-12 22:19:32 -0700512 InstallOperation::BSDIFF);
Allie Woodcd514b52015-02-19 13:56:07 -0800513 expected_graph[5].out_edges[10] = EdgeWithReadDep(VectOfExt(30, 10));
514
515 GenVertex(&expected_graph[6],
516 VectOfExt(60, 10),
517 VectOfExt(40, 11),
518 "",
Alex Deymoa12ee112015-08-12 22:19:32 -0700519 InstallOperation::BSDIFF);
Allie Woodcd514b52015-02-19 13:56:07 -0800520 expected_graph[6].out_edges[5] = EdgeWithReadDep(VectOfExt(40, 11));
521 expected_graph[6].out_edges[10] = EdgeWithWriteDep(VectOfExt(60, 10));
522
523 GenVertex(&expected_graph[7],
524 VectOfExt(120, 50),
525 VectOfExt(60, 40),
526 "",
Alex Deymoa12ee112015-08-12 22:19:32 -0700527 InstallOperation::BSDIFF);
Allie Woodcd514b52015-02-19 13:56:07 -0800528 expected_graph[7].out_edges[6] = EdgeWithReadDep(VectOfExt(60, 10));
529
Alex Deymoa12ee112015-08-12 22:19:32 -0700530 GenVertex(&expected_graph[8],
531 empt,
532 VectOfExt(0, 50),
533 "/foo",
534 InstallOperation::REPLACE_BZ);
Allie Woodcd514b52015-02-19 13:56:07 -0800535 expected_graph[8].out_edges[7] = EdgeWithReadDep(VectOfExt(120, 50));
536
537 GenVertex(&expected_graph[9],
538 VectOfExt(0, 9),
539 VectOfExt(60, 9),
540 "",
Alex Deymoa12ee112015-08-12 22:19:32 -0700541 InstallOperation::MOVE);
Allie Woodcd514b52015-02-19 13:56:07 -0800542
543 GenVertex(&expected_graph[10],
544 VectOfExt(30, 10),
545 VectOfExt(60, 10),
546 "",
Alex Deymoa12ee112015-08-12 22:19:32 -0700547 InstallOperation::MOVE);
Allie Woodcd514b52015-02-19 13:56:07 -0800548 expected_graph[10].out_edges[4] = EdgeWithReadDep(VectOfExt(60, 9));
549
Alex Deymo80f70ff2016-02-10 16:08:11 -0800550 EXPECT_EQ(12U, graph.size());
Allie Woodcd514b52015-02-19 13:56:07 -0800551 EXPECT_FALSE(graph.back().valid);
552 for (Graph::size_type i = 0; i < graph.size() - 1; i++) {
553 EXPECT_TRUE(graph[i].out_edges == expected_graph[i].out_edges);
554 if (i == 8) {
555 // special case
556 } else {
557 // EXPECT_TRUE(graph[i] == expected_graph[i]) << "i = " << i;
558 }
559 }
560}
561
Allie Woodcd514b52015-02-19 13:56:07 -0800562TEST_F(InplaceGeneratorTest, CreateScratchNodeTest) {
563 Vertex vertex;
564 InplaceGenerator::CreateScratchNode(12, 34, &vertex);
Alex Deymoa12ee112015-08-12 22:19:32 -0700565 EXPECT_EQ(InstallOperation::REPLACE_BZ, vertex.aop.op.type());
Alex Deymo80f70ff2016-02-10 16:08:11 -0800566 EXPECT_EQ(0U, vertex.aop.op.data_offset());
567 EXPECT_EQ(0U, vertex.aop.op.data_length());
Alex Deymo3b2c7d02015-07-16 16:08:16 -0700568 EXPECT_EQ(1, vertex.aop.op.dst_extents_size());
Alex Deymo80f70ff2016-02-10 16:08:11 -0800569 EXPECT_EQ(12U, vertex.aop.op.dst_extents(0).start_block());
570 EXPECT_EQ(34U, vertex.aop.op.dst_extents(0).num_blocks());
Allie Woodcd514b52015-02-19 13:56:07 -0800571}
572
Alex Deymo14158572015-06-13 03:37:08 -0700573TEST_F(InplaceGeneratorTest, ApplyMapTest) {
574 vector<uint64_t> collection = {1, 2, 3, 4, 6};
575 vector<uint64_t> expected_values = {1, 2, 5, 4, 8};
576 map<uint64_t, uint64_t> value_map;
577 value_map[3] = 5;
578 value_map[6] = 8;
579 value_map[5] = 10;
580
581 InplaceGenerator::ApplyMap(&collection, value_map);
582 EXPECT_EQ(expected_values, collection);
583}
584
Alex Deymo896fdba2015-07-16 15:25:18 -0700585// We can't produce MOVE operations with a source or destination in the block 0.
586// This test checks that the cycle breaker procedure doesn't produce such
587// operations.
588TEST_F(InplaceGeneratorTest, ResolveReadAfterWriteDependenciesAvoidMoveToZero) {
589 size_t block_size = 4096;
590 size_t num_blocks = 4;
591 vector<AnnotatedOperation> aops;
592
593 // Create a REPLACE_BZ for block 0, and a circular dependency among all other
594 // blocks. This situation would prefer to issue a MOVE to scratch space and
595 // the only available block is 0.
596 aops.emplace_back();
597 aops.back().name = base::StringPrintf("<bz-block-0>");
Alex Deymoa12ee112015-08-12 22:19:32 -0700598 aops.back().op.set_type(InstallOperation::REPLACE_BZ);
Alex Deymo896fdba2015-07-16 15:25:18 -0700599 StoreExtents({ExtentForRange(0, 1)}, aops.back().op.mutable_dst_extents());
600
601 for (size_t i = 1; i < num_blocks; i++) {
602 AnnotatedOperation aop;
603 aop.name = base::StringPrintf("<op-%" PRIuS ">", i);
Alex Deymoa12ee112015-08-12 22:19:32 -0700604 aop.op.set_type(InstallOperation::BSDIFF);
Alex Deymo896fdba2015-07-16 15:25:18 -0700605 StoreExtents({ExtentForRange(1 + i % (num_blocks - 1), 1)},
606 aop.op.mutable_src_extents());
607 StoreExtents({ExtentForRange(i, 1)}, aop.op.mutable_dst_extents());
608 aops.push_back(aop);
609 }
610
Sen Jiang625406c2015-09-16 16:35:23 -0700611 PartitionConfig part("part");
Alex Deymo896fdba2015-07-16 15:25:18 -0700612 part.path = "/dev/zero";
613 part.size = num_blocks * block_size;
614
615 CreateBlobFile();
616
617 // We ran two tests here. The first one without enough blocks for the scratch
618 // space, forcing it to create a new full operation and the second case with
619 // one extra block in the partition that can be used for the move operation.
620 for (const auto part_blocks : vector<uint64_t>{num_blocks, num_blocks + 1}) {
621 SCOPED_TRACE(base::StringPrintf("Using partition_blocs=%" PRIu64,
622 part_blocks));
623 vector<AnnotatedOperation> result_aops = aops;
624 EXPECT_TRUE(InplaceGenerator::ResolveReadAfterWriteDependencies(
Sen Jiang8cc502d2015-08-10 10:04:54 -0700625 part, part_blocks * block_size, block_size, blob_file_.get(),
Alex Deymo896fdba2015-07-16 15:25:18 -0700626 &result_aops));
627
628 size_t full_ops = 0;
629 for (const auto& aop : result_aops) {
Alex Deymoa12ee112015-08-12 22:19:32 -0700630 if (aop.op.type() == InstallOperation::REPLACE ||
631 aop.op.type() == InstallOperation::REPLACE_BZ) {
Alex Deymo896fdba2015-07-16 15:25:18 -0700632 full_ops++;
Alex Deymoa12ee112015-08-12 22:19:32 -0700633 }
Alex Deymo896fdba2015-07-16 15:25:18 -0700634
Alex Deymoa12ee112015-08-12 22:19:32 -0700635 if (aop.op.type() != InstallOperation::MOVE)
Alex Deymo896fdba2015-07-16 15:25:18 -0700636 continue;
637 for (const Extent& extent : aop.op.src_extents()) {
Alex Deymo80f70ff2016-02-10 16:08:11 -0800638 EXPECT_NE(0U, extent.start_block())
639 << "On src extents for aop: " << aop;
Alex Deymo896fdba2015-07-16 15:25:18 -0700640 }
641 for (const Extent& extent : aop.op.dst_extents()) {
Alex Deymo80f70ff2016-02-10 16:08:11 -0800642 EXPECT_NE(0U, extent.start_block())
643 << "On dst extents for aop: " << aop;
Alex Deymo896fdba2015-07-16 15:25:18 -0700644 }
645 }
646
647 // If there's extra space in the partition, it should not use a new full
648 // operation for it.
Alex Deymo80f70ff2016-02-10 16:08:11 -0800649 EXPECT_EQ(part_blocks == num_blocks ? 2U : 1U, full_ops);
Alex Deymo896fdba2015-07-16 15:25:18 -0700650
651 if (HasNonfatalFailure()) {
652 LOG(INFO) << "Result operation list:";
653 for (const auto& aop : result_aops) {
654 LOG(INFO) << aop;
655 }
656 }
657 }
658}
659
Allie Woodcd514b52015-02-19 13:56:07 -0800660} // namespace chromeos_update_engine