Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(25)

Side by Side Diff: delta_diff_generator.cc

Issue 3785008: AU: Don't send no-op operations in the delta payload. (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/update_engine.git
Patch Set: fix comment Created 10 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « delta_diff_generator.h ('k') | delta_diff_generator_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium OS 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 "update_engine/delta_diff_generator.h" 5 #include "update_engine/delta_diff_generator.h"
6 6
7 #include <errno.h> 7 #include <errno.h>
8 #include <fcntl.h> 8 #include <fcntl.h>
9 #include <inttypes.h> 9 #include <inttypes.h>
10 #include <sys/stat.h> 10 #include <sys/stat.h>
(...skipping 29 matching lines...) Expand all
40 using std::map; 40 using std::map;
41 using std::max; 41 using std::max;
42 using std::min; 42 using std::min;
43 using std::set; 43 using std::set;
44 using std::string; 44 using std::string;
45 using std::vector; 45 using std::vector;
46 46
47 namespace chromeos_update_engine { 47 namespace chromeos_update_engine {
48 48
49 typedef DeltaDiffGenerator::Block Block; 49 typedef DeltaDiffGenerator::Block Block;
50 typedef map<const DeltaArchiveManifest_InstallOperation*,
51 const string*> OperationNameMap;
50 52
51 namespace { 53 namespace {
52 const size_t kBlockSize = 4096; // bytes 54 const size_t kBlockSize = 4096; // bytes
53 const size_t kRootFSPartitionSize = 1 * 1024 * 1024 * 1024; // bytes 55 const size_t kRootFSPartitionSize = 1 * 1024 * 1024 * 1024; // bytes
54 const uint64_t kVersionNumber = 1; 56 const uint64_t kVersionNumber = 1;
55 const uint64_t kFullUpdateChunkSize = 1024 * 1024; // bytes 57 const uint64_t kFullUpdateChunkSize = 1024 * 1024; // bytes
56 58
57 static const char* kInstallOperationTypes[] = { 59 static const char* kInstallOperationTypes[] = {
58 "REPLACE", 60 "REPLACE",
59 "REPLACE_BZ", 61 "REPLACE_BZ",
(...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after
369 371
370 // Writes the uint64_t passed in in host-endian to the file as big-endian. 372 // Writes the uint64_t passed in in host-endian to the file as big-endian.
371 // Returns true on success. 373 // Returns true on success.
372 bool WriteUint64AsBigEndian(FileWriter* writer, const uint64_t value) { 374 bool WriteUint64AsBigEndian(FileWriter* writer, const uint64_t value) {
373 uint64_t value_be = htobe64(value); 375 uint64_t value_be = htobe64(value);
374 TEST_AND_RETURN_FALSE(writer->Write(&value_be, sizeof(value_be)) == 376 TEST_AND_RETURN_FALSE(writer->Write(&value_be, sizeof(value_be)) ==
375 sizeof(value_be)); 377 sizeof(value_be));
376 return true; 378 return true;
377 } 379 }
378 380
379 // Adds each operation from the graph to the manifest in the order 381 // Adds each operation from |graph| to |out_manifest| in the order specified by
380 // specified by 'order'. 382 // |order| while building |out_op_name_map| with operation to name
383 // mappings. Adds all |kernel_ops| to |out_manifest|. Filters out no-op
384 // operations.
381 void InstallOperationsToManifest( 385 void InstallOperationsToManifest(
382 const Graph& graph, 386 const Graph& graph,
383 const vector<Vertex::Index>& order, 387 const vector<Vertex::Index>& order,
384 const vector<DeltaArchiveManifest_InstallOperation>& kernel_ops, 388 const vector<DeltaArchiveManifest_InstallOperation>& kernel_ops,
385 DeltaArchiveManifest* out_manifest) { 389 DeltaArchiveManifest* out_manifest,
390 OperationNameMap* out_op_name_map) {
386 for (vector<Vertex::Index>::const_iterator it = order.begin(); 391 for (vector<Vertex::Index>::const_iterator it = order.begin();
387 it != order.end(); ++it) { 392 it != order.end(); ++it) {
393 const Vertex& vertex = graph[*it];
394 const DeltaArchiveManifest_InstallOperation& add_op = vertex.op;
395 if (DeltaDiffGenerator::IsNoopOperation(add_op)) {
396 continue;
397 }
388 DeltaArchiveManifest_InstallOperation* op = 398 DeltaArchiveManifest_InstallOperation* op =
389 out_manifest->add_install_operations(); 399 out_manifest->add_install_operations();
390 *op = graph[*it].op; 400 *op = add_op;
401 (*out_op_name_map)[op] = &vertex.file_name;
391 } 402 }
392 for (vector<DeltaArchiveManifest_InstallOperation>::const_iterator it = 403 for (vector<DeltaArchiveManifest_InstallOperation>::const_iterator it =
393 kernel_ops.begin(); it != kernel_ops.end(); ++it) { 404 kernel_ops.begin(); it != kernel_ops.end(); ++it) {
405 const DeltaArchiveManifest_InstallOperation& add_op = *it;
406 if (DeltaDiffGenerator::IsNoopOperation(add_op)) {
407 continue;
408 }
394 DeltaArchiveManifest_InstallOperation* op = 409 DeltaArchiveManifest_InstallOperation* op =
395 out_manifest->add_kernel_install_operations(); 410 out_manifest->add_kernel_install_operations();
396 *op = *it; 411 *op = add_op;
397 } 412 }
398 } 413 }
399 414
400 void CheckGraph(const Graph& graph) { 415 void CheckGraph(const Graph& graph) {
401 for (Graph::const_iterator it = graph.begin(); it != graph.end(); ++it) { 416 for (Graph::const_iterator it = graph.begin(); it != graph.end(); ++it) {
402 CHECK(it->op.has_type()); 417 CHECK(it->op.has_type());
403 } 418 }
404 } 419 }
405 420
406 // Delta compresses a kernel partition |new_kernel_part| with knowledge of the 421 // Delta compresses a kernel partition |new_kernel_part| with knowledge of the
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
446 type(in_type), 461 type(in_type),
447 size(in_size) {} 462 size(in_size) {}
448 bool operator <(const DeltaObject& object) const { 463 bool operator <(const DeltaObject& object) const {
449 return (size != object.size) ? (size < object.size) : (name < object.name); 464 return (size != object.size) ? (size < object.size) : (name < object.name);
450 } 465 }
451 string name; 466 string name;
452 int type; 467 int type;
453 off_t size; 468 off_t size;
454 }; 469 };
455 470
456 void ReportPayloadUsage(const Graph& graph, 471 void ReportPayloadUsage(const DeltaArchiveManifest& manifest,
457 const DeltaArchiveManifest& manifest, 472 const int64_t manifest_metadata_size,
458 const int64_t manifest_metadata_size) { 473 const OperationNameMap& op_name_map) {
459 vector<DeltaObject> objects; 474 vector<DeltaObject> objects;
460 off_t total_size = 0; 475 off_t total_size = 0;
461 476
462 // Graph nodes with information about file names. 477 // Rootfs install operations.
463 for (Vertex::Index node = 0; node < graph.size(); node++) { 478 for (int i = 0; i < manifest.install_operations_size(); ++i) {
464 const Vertex& vertex = graph[node]; 479 const DeltaArchiveManifest_InstallOperation& op =
465 if (!vertex.valid) { 480 manifest.install_operations(i);
466 continue; 481 objects.push_back(DeltaObject(*op_name_map.find(&op)->second,
467 } 482 op.type(),
468 objects.push_back(DeltaObject(vertex.file_name, 483 op.data_length()));
469 vertex.op.type(), 484 total_size += op.data_length();
470 vertex.op.data_length()));
471 total_size += vertex.op.data_length();
472 } 485 }
473 486
474 // Kernel install operations. 487 // Kernel install operations.
475 for (int i = 0; i < manifest.kernel_install_operations_size(); ++i) { 488 for (int i = 0; i < manifest.kernel_install_operations_size(); ++i) {
476 const DeltaArchiveManifest_InstallOperation& op = 489 const DeltaArchiveManifest_InstallOperation& op =
477 manifest.kernel_install_operations(i); 490 manifest.kernel_install_operations(i);
478 objects.push_back(DeltaObject(StringPrintf("<kernel-operation-%d>", i), 491 objects.push_back(DeltaObject(StringPrintf("<kernel-operation-%d>", i),
479 op.type(), 492 op.type(),
480 op.data_length())); 493 op.data_length()));
481 total_size += op.data_length(); 494 total_size += op.data_length();
(...skipping 423 matching lines...) Expand 10 before | Expand all | Expand 10 after
905 return true; 918 return true;
906 } 919 }
907 // check for wrap-around, which would be a bug: 920 // check for wrap-around, which would be a bug:
908 CHECK(start <= (start + num)); 921 CHECK(start <= (start + num));
909 } 922 }
910 return false; 923 return false;
911 } 924 }
912 925
913 } // namespace {} 926 } // namespace {}
914 927
928 // Returns true if |op| is a no-op operation that doesn't do any useful work
929 // (e.g., a move operation that copies blocks onto themselves).
930 bool DeltaDiffGenerator::IsNoopOperation(
931 const DeltaArchiveManifest_InstallOperation& op) {
932 return (op.type() == DeltaArchiveManifest_InstallOperation_Type_MOVE &&
933 ExpandExtents(op.src_extents()) == ExpandExtents(op.dst_extents()));
934 }
935
915 bool DeltaDiffGenerator::AssignTempBlocks( 936 bool DeltaDiffGenerator::AssignTempBlocks(
916 Graph* graph, 937 Graph* graph,
917 const string& new_root, 938 const string& new_root,
918 int data_fd, 939 int data_fd,
919 off_t* data_file_size, 940 off_t* data_file_size,
920 vector<Vertex::Index>* op_indexes, 941 vector<Vertex::Index>* op_indexes,
921 vector<vector<Vertex::Index>::size_type>* reverse_op_indexes, 942 vector<vector<Vertex::Index>::size_type>* reverse_op_indexes,
922 vector<CutEdgeVertexes>& cuts) { 943 vector<CutEdgeVertexes>& cuts) {
923 CHECK(!cuts.empty()); 944 CHECK(!cuts.empty());
924 for (vector<CutEdgeVertexes>::size_type i = cuts.size() - 1, e = 0; 945 for (vector<CutEdgeVertexes>::size_type i = cuts.size() - 1, e = 0;
(...skipping 438 matching lines...) Expand 10 before | Expand all | Expand 10 after
1363 fd, 1384 fd,
1364 &data_file_size, 1385 &data_file_size,
1365 kFullUpdateChunkSize, 1386 kFullUpdateChunkSize,
1366 &kernel_ops, 1387 &kernel_ops,
1367 &final_order)); 1388 &final_order));
1368 } 1389 }
1369 } 1390 }
1370 1391
1371 // Convert to protobuf Manifest object 1392 // Convert to protobuf Manifest object
1372 DeltaArchiveManifest manifest; 1393 DeltaArchiveManifest manifest;
1394 OperationNameMap op_name_map;
1373 CheckGraph(graph); 1395 CheckGraph(graph);
1374 InstallOperationsToManifest(graph, final_order, kernel_ops, &manifest); 1396 InstallOperationsToManifest(graph,
1375 1397 final_order,
1398 kernel_ops,
1399 &manifest,
1400 &op_name_map);
1376 CheckGraph(graph); 1401 CheckGraph(graph);
1377 manifest.set_block_size(kBlockSize); 1402 manifest.set_block_size(kBlockSize);
1378 1403
1379 // Reorder the data blobs with the newly ordered manifest 1404 // Reorder the data blobs with the newly ordered manifest
1380 string ordered_blobs_path; 1405 string ordered_blobs_path;
1381 TEST_AND_RETURN_FALSE(utils::MakeTempFile( 1406 TEST_AND_RETURN_FALSE(utils::MakeTempFile(
1382 "/tmp/CrAU_temp_data.ordered.XXXXXX", 1407 "/tmp/CrAU_temp_data.ordered.XXXXXX",
1383 &ordered_blobs_path, 1408 &ordered_blobs_path,
1384 false)); 1409 false));
1385 TEST_AND_RETURN_FALSE(ReorderDataBlobs(&manifest, 1410 TEST_AND_RETURN_FALSE(ReorderDataBlobs(&manifest,
1386 temp_file_path, 1411 temp_file_path,
1387 ordered_blobs_path)); 1412 ordered_blobs_path));
1388 1413
1389 // Check that install op blobs are in order and that all blocks are written. 1414 // Check that install op blobs are in order.
1390 uint64_t next_blob_offset = 0; 1415 uint64_t next_blob_offset = 0;
1391 { 1416 {
1392 vector<uint32_t> written_count(blocks.size(), 0);
1393 for (int i = 0; i < (manifest.install_operations_size() + 1417 for (int i = 0; i < (manifest.install_operations_size() +
1394 manifest.kernel_install_operations_size()); i++) { 1418 manifest.kernel_install_operations_size()); i++) {
1395 DeltaArchiveManifest_InstallOperation* op = 1419 DeltaArchiveManifest_InstallOperation* op =
1396 i < manifest.install_operations_size() ? 1420 i < manifest.install_operations_size() ?
1397 manifest.mutable_install_operations(i) : 1421 manifest.mutable_install_operations(i) :
1398 manifest.mutable_kernel_install_operations( 1422 manifest.mutable_kernel_install_operations(
1399 i - manifest.install_operations_size()); 1423 i - manifest.install_operations_size());
1400 for (int j = 0; j < op->dst_extents_size(); j++) {
1401 const Extent& extent = op->dst_extents(j);
1402 for (uint64_t block = extent.start_block();
1403 block < (extent.start_block() + extent.num_blocks()); block++) {
1404 if (block < blocks.size())
1405 written_count[block]++;
1406 }
1407 }
1408 if (op->has_data_offset()) { 1424 if (op->has_data_offset()) {
1409 if (op->data_offset() != next_blob_offset) { 1425 if (op->data_offset() != next_blob_offset) {
1410 LOG(FATAL) << "bad blob offset! " << op->data_offset() << " != " 1426 LOG(FATAL) << "bad blob offset! " << op->data_offset() << " != "
1411 << next_blob_offset; 1427 << next_blob_offset;
1412 } 1428 }
1413 next_blob_offset += op->data_length(); 1429 next_blob_offset += op->data_length();
1414 } 1430 }
1415 } 1431 }
1416 // check all blocks written to
1417 for (vector<uint32_t>::size_type i = 0; i < written_count.size(); i++) {
1418 if (written_count[i] == 0) {
1419 LOG(FATAL) << "block " << i << " not written!";
1420 }
1421 }
1422 } 1432 }
1423 1433
1424 // Signatures appear at the end of the blobs. Note the offset in the 1434 // Signatures appear at the end of the blobs. Note the offset in the
1425 // manifest 1435 // manifest
1426 if (!private_key_path.empty()) { 1436 if (!private_key_path.empty()) {
1427 LOG(INFO) << "Making room for signature in file"; 1437 LOG(INFO) << "Making room for signature in file";
1428 manifest.set_signatures_offset(next_blob_offset); 1438 manifest.set_signatures_offset(next_blob_offset);
1429 LOG(INFO) << "set? " << manifest.has_signatures_offset(); 1439 LOG(INFO) << "set? " << manifest.has_signatures_offset();
1430 // Add a dummy op at the end to appease older clients 1440 // Add a dummy op at the end to appease older clients
1431 DeltaArchiveManifest_InstallOperation* dummy_op = 1441 DeltaArchiveManifest_InstallOperation* dummy_op =
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
1507 TEST_AND_RETURN_FALSE(PayloadSigner::SignPayload(output_path, 1517 TEST_AND_RETURN_FALSE(PayloadSigner::SignPayload(output_path,
1508 private_key_path, 1518 private_key_path,
1509 &signature_blob)); 1519 &signature_blob));
1510 TEST_AND_RETURN_FALSE(writer.Write(&signature_blob[0], 1520 TEST_AND_RETURN_FALSE(writer.Write(&signature_blob[0],
1511 signature_blob.size()) == 1521 signature_blob.size()) ==
1512 static_cast<ssize_t>(signature_blob.size())); 1522 static_cast<ssize_t>(signature_blob.size()));
1513 } 1523 }
1514 1524
1515 int64_t manifest_metadata_size = 1525 int64_t manifest_metadata_size =
1516 strlen(kDeltaMagic) + 2 * sizeof(uint64_t) + serialized_manifest.size(); 1526 strlen(kDeltaMagic) + 2 * sizeof(uint64_t) + serialized_manifest.size();
1517 ReportPayloadUsage(graph, manifest, manifest_metadata_size); 1527 ReportPayloadUsage(manifest, manifest_metadata_size, op_name_map);
1518 1528
1519 LOG(INFO) << "All done. Successfully created delta file."; 1529 LOG(INFO) << "All done. Successfully created delta file.";
1520 return true; 1530 return true;
1521 } 1531 }
1522 1532
1523 const char* const kBsdiffPath = "/usr/bin/bsdiff"; 1533 const char* const kBsdiffPath = "/usr/bin/bsdiff";
1524 const char* const kBspatchPath = "/usr/bin/bspatch"; 1534 const char* const kBspatchPath = "/usr/bin/bspatch";
1525 const char* const kDeltaMagic = "CrAU"; 1535 const char* const kDeltaMagic = "CrAU";
1526 1536
1527 }; // namespace chromeos_update_engine 1537 }; // namespace chromeos_update_engine
OLDNEW
« no previous file with comments | « delta_diff_generator.h ('k') | delta_diff_generator_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698