OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <sys/types.h> | 5 #include <sys/types.h> |
6 #include <sys/stat.h> | 6 #include <sys/stat.h> |
7 #include <fcntl.h> | 7 #include <fcntl.h> |
8 #include <unistd.h> | 8 #include <unistd.h> |
9 #include <set> | 9 #include <set> |
| 10 #include <sstream> |
10 #include <string> | 11 #include <string> |
11 #include <utility> | 12 #include <utility> |
12 #include <vector> | 13 #include <vector> |
13 #include <gtest/gtest.h> | 14 #include <gtest/gtest.h> |
14 #include "base/logging.h" | 15 #include "base/logging.h" |
15 #include "update_engine/cycle_breaker.h" | 16 #include "update_engine/cycle_breaker.h" |
16 #include "update_engine/delta_diff_generator.h" | 17 #include "update_engine/delta_diff_generator.h" |
17 #include "update_engine/delta_performer.h" | 18 #include "update_engine/delta_performer.h" |
| 19 #include "update_engine/extent_ranges.h" |
18 #include "update_engine/graph_types.h" | 20 #include "update_engine/graph_types.h" |
19 #include "update_engine/graph_utils.h" | 21 #include "update_engine/graph_utils.h" |
20 #include "update_engine/subprocess.h" | 22 #include "update_engine/subprocess.h" |
21 #include "update_engine/test_utils.h" | 23 #include "update_engine/test_utils.h" |
| 24 #include "update_engine/topological_sort.h" |
22 #include "update_engine/utils.h" | 25 #include "update_engine/utils.h" |
23 | 26 |
24 using std::make_pair; | 27 using std::make_pair; |
25 using std::set; | 28 using std::set; |
26 using std::string; | 29 using std::string; |
| 30 using std::stringstream; |
27 using std::vector; | 31 using std::vector; |
28 | 32 |
29 namespace chromeos_update_engine { | 33 namespace chromeos_update_engine { |
30 | 34 |
31 typedef DeltaDiffGenerator::Block Block; | 35 typedef DeltaDiffGenerator::Block Block; |
32 | 36 |
33 namespace { | 37 namespace { |
34 int64_t BlocksInExtents( | 38 int64_t BlocksInExtents( |
35 const google::protobuf::RepeatedPtrField<Extent>& extents) { | 39 const google::protobuf::RepeatedPtrField<Extent>& extents) { |
36 int64_t ret = 0; | 40 int64_t ret = 0; |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
154 } | 158 } |
155 } | 159 } |
156 | 160 |
157 TEST_F(DeltaDiffGeneratorTest, SubstituteBlocksTest) { | 161 TEST_F(DeltaDiffGeneratorTest, SubstituteBlocksTest) { |
158 vector<Extent> remove_blocks; | 162 vector<Extent> remove_blocks; |
159 AppendExtent(&remove_blocks, 3, 3); | 163 AppendExtent(&remove_blocks, 3, 3); |
160 AppendExtent(&remove_blocks, 7, 1); | 164 AppendExtent(&remove_blocks, 7, 1); |
161 vector<Extent> replace_blocks; | 165 vector<Extent> replace_blocks; |
162 AppendExtent(&replace_blocks, 10, 2); | 166 AppendExtent(&replace_blocks, 10, 2); |
163 AppendExtent(&replace_blocks, 13, 2); | 167 AppendExtent(&replace_blocks, 13, 2); |
164 DeltaArchiveManifest_InstallOperation op; | 168 Vertex vertex; |
| 169 DeltaArchiveManifest_InstallOperation& op = vertex.op; |
165 OpAppendExtent(&op, 4, 3); | 170 OpAppendExtent(&op, 4, 3); |
166 OpAppendExtent(&op, kSparseHole, 4); // Sparse hole in file | 171 OpAppendExtent(&op, kSparseHole, 4); // Sparse hole in file |
167 OpAppendExtent(&op, 3, 1); | 172 OpAppendExtent(&op, 3, 1); |
168 OpAppendExtent(&op, 7, 3); | 173 OpAppendExtent(&op, 7, 3); |
169 | 174 |
170 DeltaDiffGenerator::SubstituteBlocks(&op, remove_blocks, replace_blocks); | 175 DeltaDiffGenerator::SubstituteBlocks(&vertex, remove_blocks, replace_blocks); |
171 | 176 |
172 EXPECT_EQ(7, op.src_extents_size()); | 177 EXPECT_EQ(7, op.src_extents_size()); |
173 EXPECT_EQ(11, op.src_extents(0).start_block()); | 178 EXPECT_EQ(11, op.src_extents(0).start_block()); |
174 EXPECT_EQ(1, op.src_extents(0).num_blocks()); | 179 EXPECT_EQ(1, op.src_extents(0).num_blocks()); |
175 EXPECT_EQ(13, op.src_extents(1).start_block()); | 180 EXPECT_EQ(13, op.src_extents(1).start_block()); |
176 EXPECT_EQ(1, op.src_extents(1).num_blocks()); | 181 EXPECT_EQ(1, op.src_extents(1).num_blocks()); |
177 EXPECT_EQ(6, op.src_extents(2).start_block()); | 182 EXPECT_EQ(6, op.src_extents(2).start_block()); |
178 EXPECT_EQ(1, op.src_extents(2).num_blocks()); | 183 EXPECT_EQ(1, op.src_extents(2).num_blocks()); |
179 EXPECT_EQ(kSparseHole, op.src_extents(3).start_block()); | 184 EXPECT_EQ(kSparseHole, op.src_extents(3).start_block()); |
180 EXPECT_EQ(4, op.src_extents(3).num_blocks()); | 185 EXPECT_EQ(4, op.src_extents(3).num_blocks()); |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
247 | 252 |
248 // Find cycles | 253 // Find cycles |
249 CycleBreaker cycle_breaker; | 254 CycleBreaker cycle_breaker; |
250 set<Edge> cut_edges; | 255 set<Edge> cut_edges; |
251 cycle_breaker.BreakCycles(graph, &cut_edges); | 256 cycle_breaker.BreakCycles(graph, &cut_edges); |
252 | 257 |
253 EXPECT_EQ(1, cut_edges.size()); | 258 EXPECT_EQ(1, cut_edges.size()); |
254 EXPECT_TRUE(cut_edges.end() != cut_edges.find(make_pair<Vertex::Index>(1, | 259 EXPECT_TRUE(cut_edges.end() != cut_edges.find(make_pair<Vertex::Index>(1, |
255 0))); | 260 0))); |
256 | 261 |
257 EXPECT_TRUE(DeltaDiffGenerator::CutEdges(&graph, blocks, cut_edges)); | 262 vector<CutEdgeVertexes> cuts; |
| 263 EXPECT_TRUE(DeltaDiffGenerator::CutEdges(&graph, cut_edges, &cuts)); |
258 | 264 |
259 EXPECT_EQ(3, graph.size()); | 265 EXPECT_EQ(3, graph.size()); |
260 | 266 |
261 // Check new node in graph: | 267 // Check new node in graph: |
262 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_MOVE, | 268 EXPECT_EQ(DeltaArchiveManifest_InstallOperation_Type_MOVE, |
263 graph.back().op.type()); | 269 graph.back().op.type()); |
264 EXPECT_EQ(2, graph.back().op.src_extents_size()); | 270 EXPECT_EQ(2, graph.back().op.src_extents_size()); |
265 EXPECT_EQ(2, graph.back().op.dst_extents_size()); | 271 EXPECT_EQ(1, graph.back().op.dst_extents_size()); |
266 EXPECT_EQ(0, graph.back().op.dst_extents(0).start_block()); | 272 EXPECT_EQ(kTempBlockStart, graph.back().op.dst_extents(0).start_block()); |
267 EXPECT_EQ(1, graph.back().op.dst_extents(0).num_blocks()); | 273 EXPECT_EQ(2, graph.back().op.dst_extents(0).num_blocks()); |
268 EXPECT_EQ(8, graph.back().op.dst_extents(1).start_block()); | |
269 EXPECT_EQ(1, graph.back().op.dst_extents(1).num_blocks()); | |
270 EXPECT_TRUE(graph.back().out_edges.empty()); | 274 EXPECT_TRUE(graph.back().out_edges.empty()); |
271 | 275 |
272 // Check that old node reads from new blocks | 276 // Check that old node reads from new blocks |
273 EXPECT_EQ(3, graph[0].op.src_extents_size()); | 277 EXPECT_EQ(2, graph[0].op.src_extents_size()); |
274 EXPECT_EQ(0, graph[0].op.src_extents(0).start_block()); | 278 EXPECT_EQ(kTempBlockStart, graph[0].op.src_extents(0).start_block()); |
275 EXPECT_EQ(1, graph[0].op.src_extents(0).num_blocks()); | 279 EXPECT_EQ(2, graph[0].op.src_extents(0).num_blocks()); |
276 EXPECT_EQ(8, graph[0].op.src_extents(1).start_block()); | 280 EXPECT_EQ(7, graph[0].op.src_extents(1).start_block()); |
277 EXPECT_EQ(1, graph[0].op.src_extents(1).num_blocks()); | 281 EXPECT_EQ(1, graph[0].op.src_extents(1).num_blocks()); |
278 EXPECT_EQ(7, graph[0].op.src_extents(2).start_block()); | |
279 EXPECT_EQ(1, graph[0].op.src_extents(2).num_blocks()); | |
280 | 282 |
281 // And that the old dst extents haven't changed | 283 // And that the old dst extents haven't changed |
282 EXPECT_EQ(2, graph[0].op.dst_extents_size()); | 284 EXPECT_EQ(2, graph[0].op.dst_extents_size()); |
283 EXPECT_EQ(1, graph[0].op.dst_extents(0).start_block()); | 285 EXPECT_EQ(1, graph[0].op.dst_extents(0).start_block()); |
284 EXPECT_EQ(2, graph[0].op.dst_extents(0).num_blocks()); | 286 EXPECT_EQ(2, graph[0].op.dst_extents(0).num_blocks()); |
285 EXPECT_EQ(4, graph[0].op.dst_extents(1).start_block()); | 287 EXPECT_EQ(4, graph[0].op.dst_extents(1).start_block()); |
286 EXPECT_EQ(1, graph[0].op.dst_extents(1).num_blocks()); | 288 EXPECT_EQ(1, graph[0].op.dst_extents(1).num_blocks()); |
287 | 289 |
288 // Ensure it only depends on the next node and the new temp node | 290 // Ensure it only depends on the next node and the new temp node |
289 EXPECT_EQ(2, graph[0].out_edges.size()); | 291 EXPECT_EQ(2, graph[0].out_edges.size()); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
341 EXPECT_EQ(2, manifest.install_operations_size()); | 343 EXPECT_EQ(2, manifest.install_operations_size()); |
342 EXPECT_EQ(0, manifest.install_operations(0).data_offset()); | 344 EXPECT_EQ(0, manifest.install_operations(0).data_offset()); |
343 EXPECT_EQ(3, manifest.install_operations(0).data_length()); | 345 EXPECT_EQ(3, manifest.install_operations(0).data_length()); |
344 EXPECT_EQ(3, manifest.install_operations(1).data_offset()); | 346 EXPECT_EQ(3, manifest.install_operations(1).data_offset()); |
345 EXPECT_EQ(1, manifest.install_operations(1).data_length()); | 347 EXPECT_EQ(1, manifest.install_operations(1).data_length()); |
346 | 348 |
347 unlink(orig_blobs.c_str()); | 349 unlink(orig_blobs.c_str()); |
348 unlink(new_blobs.c_str()); | 350 unlink(new_blobs.c_str()); |
349 } | 351 } |
350 | 352 |
| 353 TEST_F(DeltaDiffGeneratorTest, MoveFullOpsToBackTest) { |
| 354 Graph graph(4); |
| 355 graph[0].file_name = "A"; |
| 356 graph[0].op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE); |
| 357 graph[1].file_name = "B"; |
| 358 graph[1].op.set_type(DeltaArchiveManifest_InstallOperation_Type_BSDIFF); |
| 359 graph[2].file_name = "C"; |
| 360 graph[2].op.set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ); |
| 361 graph[3].file_name = "D"; |
| 362 graph[3].op.set_type(DeltaArchiveManifest_InstallOperation_Type_MOVE); |
| 363 |
| 364 vector<Vertex::Index> vect(graph.size()); |
| 365 |
| 366 for (vector<Vertex::Index>::size_type i = 0; i < vect.size(); ++i) { |
| 367 vect[i] = i; |
| 368 } |
| 369 DeltaDiffGenerator::MoveFullOpsToBack(&graph, &vect); |
| 370 EXPECT_EQ(vect.size(), graph.size()); |
| 371 EXPECT_EQ(graph[vect[0]].file_name, "B"); |
| 372 EXPECT_EQ(graph[vect[1]].file_name, "D"); |
| 373 EXPECT_EQ(graph[vect[2]].file_name, "A"); |
| 374 EXPECT_EQ(graph[vect[3]].file_name, "C"); |
| 375 } |
| 376 |
| 377 namespace { |
| 378 |
| 379 #define OP_BSDIFF DeltaArchiveManifest_InstallOperation_Type_BSDIFF |
| 380 #define OP_MOVE DeltaArchiveManifest_InstallOperation_Type_MOVE |
| 381 #define OP_REPLACE DeltaArchiveManifest_InstallOperation_Type_REPLACE |
| 382 #define OP_REPLACE_BZ DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ |
| 383 |
| 384 void GenVertex(Vertex* out, |
| 385 const vector<Extent>& src_extents, |
| 386 const vector<Extent>& dst_extents, |
| 387 const string& path, |
| 388 DeltaArchiveManifest_InstallOperation_Type type) { |
| 389 out->op.set_type(type); |
| 390 out->file_name = path; |
| 391 DeltaDiffGenerator::StoreExtents(src_extents, out->op.mutable_src_extents()); |
| 392 DeltaDiffGenerator::StoreExtents(dst_extents, out->op.mutable_dst_extents()); |
| 393 } |
| 394 |
| 395 vector<Extent> VectOfExt(uint64_t start_block, uint64_t num_blocks) { |
| 396 return vector<Extent>(1, ExtentForRange(start_block, num_blocks)); |
| 397 } |
| 398 |
| 399 EdgeProperties EdgeWithReadDep(const vector<Extent>& extents) { |
| 400 EdgeProperties ret; |
| 401 ret.extents = extents; |
| 402 return ret; |
| 403 } |
| 404 |
| 405 EdgeProperties EdgeWithWriteDep(const vector<Extent>& extents) { |
| 406 EdgeProperties ret; |
| 407 ret.write_extents = extents; |
| 408 return ret; |
| 409 } |
| 410 |
| 411 template<typename T> |
| 412 void DumpVect(const vector<T>& vect) { |
| 413 std::stringstream ss(stringstream::out); |
| 414 for (typename vector<T>::const_iterator it = vect.begin(), e = vect.end(); |
| 415 it != e; ++it) { |
| 416 ss << *it << ", "; |
| 417 } |
| 418 LOG(INFO) << "{" << ss.str() << "}"; |
| 419 } |
| 420 |
| 421 } // namespace {} |
| 422 |
| 423 TEST_F(DeltaDiffGeneratorTest, RunAsRootAssignTempBlocksTest) { |
| 424 Graph graph(9); |
| 425 const vector<Extent> empt; // empty |
| 426 const string kFilename = "/foo"; |
| 427 |
| 428 // Some scratch space: |
| 429 GenVertex(&graph[0], empt, VectOfExt(200, 1), "", OP_REPLACE); |
| 430 GenVertex(&graph[1], empt, VectOfExt(210, 10), "", OP_REPLACE); |
| 431 GenVertex(&graph[2], empt, VectOfExt(220, 1), "", OP_REPLACE); |
| 432 |
| 433 // A cycle that requires 10 blocks to break: |
| 434 GenVertex(&graph[3], VectOfExt(10, 11), VectOfExt(0, 9), "", OP_BSDIFF); |
| 435 graph[3].out_edges[4] = EdgeWithReadDep(VectOfExt(0, 9)); |
| 436 GenVertex(&graph[4], VectOfExt(0, 9), VectOfExt(10, 11), "", OP_BSDIFF); |
| 437 graph[4].out_edges[3] = EdgeWithReadDep(VectOfExt(10, 11)); |
| 438 |
| 439 // A cycle that requires 9 blocks to break: |
| 440 GenVertex(&graph[5], VectOfExt(40, 11), VectOfExt(30, 10), "", OP_BSDIFF); |
| 441 graph[5].out_edges[6] = EdgeWithReadDep(VectOfExt(30, 10)); |
| 442 GenVertex(&graph[6], VectOfExt(30, 10), VectOfExt(40, 11), "", OP_BSDIFF); |
| 443 graph[6].out_edges[5] = EdgeWithReadDep(VectOfExt(40, 11)); |
| 444 |
| 445 // A cycle that requires 40 blocks to break (which is too many): |
| 446 GenVertex(&graph[7], |
| 447 VectOfExt(120, 50), |
| 448 VectOfExt(60, 40), |
| 449 "", |
| 450 OP_BSDIFF); |
| 451 graph[7].out_edges[8] = EdgeWithReadDep(VectOfExt(60, 40)); |
| 452 GenVertex(&graph[8], |
| 453 VectOfExt(60, 40), |
| 454 VectOfExt(120, 50), |
| 455 kFilename, |
| 456 OP_BSDIFF); |
| 457 graph[8].out_edges[7] = EdgeWithReadDep(VectOfExt(120, 50)); |
| 458 |
| 459 graph_utils::DumpGraph(graph); |
| 460 |
| 461 vector<Vertex::Index> final_order; |
| 462 |
| 463 |
| 464 // Prepare the filesystem with the minimum required for this to work |
| 465 string temp_dir; |
| 466 EXPECT_TRUE(utils::MakeTempDirectory("/tmp/AssignTempBlocksTest.XXXXXX", |
| 467 &temp_dir)); |
| 468 ScopedDirRemover temp_dir_remover(temp_dir); |
| 469 |
| 470 const size_t kBlockSize = 4096; |
| 471 vector<char> temp_data(kBlockSize * 50); |
| 472 FillWithData(&temp_data); |
| 473 EXPECT_TRUE(WriteFileVector(temp_dir + kFilename, temp_data)); |
| 474 ScopedPathUnlinker filename_unlinker(temp_dir + kFilename); |
| 475 |
| 476 int fd; |
| 477 EXPECT_TRUE(utils::MakeTempFile("/tmp/AssignTempBlocksTestData.XXXXXX", |
| 478 NULL, |
| 479 &fd)); |
| 480 ScopedFdCloser fd_closer(&fd); |
| 481 off_t data_file_size = 0; |
| 482 |
| 483 |
| 484 EXPECT_TRUE(DeltaDiffGenerator::ConvertGraphToDag(&graph, |
| 485 temp_dir, |
| 486 fd, |
| 487 &data_file_size, |
| 488 &final_order)); |
| 489 |
| 490 |
| 491 Graph expected_graph(12); |
| 492 GenVertex(&expected_graph[0], empt, VectOfExt(200, 1), "", OP_REPLACE); |
| 493 GenVertex(&expected_graph[1], empt, VectOfExt(210, 10), "", OP_REPLACE); |
| 494 GenVertex(&expected_graph[2], empt, VectOfExt(220, 1), "", OP_REPLACE); |
| 495 GenVertex(&expected_graph[3], |
| 496 VectOfExt(10, 11), |
| 497 VectOfExt(0, 9), |
| 498 "", |
| 499 OP_BSDIFF); |
| 500 expected_graph[3].out_edges[9] = EdgeWithReadDep(VectOfExt(0, 9)); |
| 501 GenVertex(&expected_graph[4], |
| 502 VectOfExt(60, 9), |
| 503 VectOfExt(10, 11), |
| 504 "", |
| 505 OP_BSDIFF); |
| 506 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 "", |
| 512 OP_BSDIFF); |
| 513 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 "", |
| 519 OP_BSDIFF); |
| 520 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 "", |
| 527 OP_BSDIFF); |
| 528 expected_graph[7].out_edges[6] = EdgeWithReadDep(VectOfExt(60, 10)); |
| 529 |
| 530 GenVertex(&expected_graph[8], empt, VectOfExt(0, 50), "/foo", OP_REPLACE_BZ); |
| 531 expected_graph[8].out_edges[7] = EdgeWithReadDep(VectOfExt(120, 50)); |
| 532 |
| 533 GenVertex(&expected_graph[9], |
| 534 VectOfExt(0, 9), |
| 535 VectOfExt(60, 9), |
| 536 "", |
| 537 OP_MOVE); |
| 538 |
| 539 GenVertex(&expected_graph[10], |
| 540 VectOfExt(30, 10), |
| 541 VectOfExt(60, 10), |
| 542 "", |
| 543 OP_MOVE); |
| 544 expected_graph[10].out_edges[4] = EdgeWithReadDep(VectOfExt(60, 9)); |
| 545 |
| 546 EXPECT_EQ(12, graph.size()); |
| 547 EXPECT_FALSE(graph.back().valid); |
| 548 for (Graph::size_type i = 0; i < graph.size() - 1; i++) { |
| 549 EXPECT_TRUE(graph[i].out_edges == expected_graph[i].out_edges); |
| 550 if (i == 8) { |
| 551 // special case |
| 552 } else { |
| 553 // EXPECT_TRUE(graph[i] == expected_graph[i]) << "i = " << i; |
| 554 } |
| 555 } |
| 556 } |
| 557 |
351 } // namespace chromeos_update_engine | 558 } // namespace chromeos_update_engine |
OLD | NEW |