full_update_generator.cc 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. //
  2. // Copyright (C) 2012 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. #include "update_engine/payload_generator/full_update_generator.h"
  17. #include <fcntl.h>
  18. #include <inttypes.h>
  19. #include <algorithm>
  20. #include <deque>
  21. #include <memory>
  22. #include <base/format_macros.h>
  23. #include <base/strings/string_util.h>
  24. #include <base/strings/stringprintf.h>
  25. #include <base/synchronization/lock.h>
  26. #include <base/threading/simple_thread.h>
  27. #include <brillo/secure_blob.h>
  28. #include "update_engine/common/utils.h"
  29. #include "update_engine/payload_generator/delta_diff_utils.h"
  30. using std::vector;
  31. namespace chromeos_update_engine {
  32. namespace {
  33. const size_t kDefaultFullChunkSize = 1024 * 1024; // 1 MiB
  34. // This class encapsulates a full update chunk processing thread work. The
  35. // processor reads a chunk of data from the input file descriptor and compresses
  36. // it. The processor will destroy itself when the work is done.
  37. class ChunkProcessor : public base::DelegateSimpleThread::Delegate {
  38. public:
  39. // Read a chunk of |size| bytes from |fd| starting at offset |offset|.
  40. ChunkProcessor(const PayloadVersion& version,
  41. int fd,
  42. off_t offset,
  43. size_t size,
  44. BlobFileWriter* blob_file,
  45. AnnotatedOperation* aop)
  46. : version_(version),
  47. fd_(fd),
  48. offset_(offset),
  49. size_(size),
  50. blob_file_(blob_file),
  51. aop_(aop) {}
  52. // We use a default move constructor since all the data members are POD types.
  53. ChunkProcessor(ChunkProcessor&&) = default;
  54. ~ChunkProcessor() override = default;
  55. // Overrides DelegateSimpleThread::Delegate.
  56. // Run() handles the read from |fd| in a thread-safe way, and stores the
  57. // new operation to generate the region starting at |offset| of size |size|
  58. // in the output operation |aop|. The associated blob data is stored in
  59. // |blob_fd| and |blob_file_size| is updated.
  60. void Run() override;
  61. private:
  62. bool ProcessChunk();
  63. // Work parameters.
  64. const PayloadVersion& version_;
  65. int fd_;
  66. off_t offset_;
  67. size_t size_;
  68. BlobFileWriter* blob_file_;
  69. AnnotatedOperation* aop_;
  70. DISALLOW_COPY_AND_ASSIGN(ChunkProcessor);
  71. };
  72. void ChunkProcessor::Run() {
  73. if (!ProcessChunk()) {
  74. LOG(ERROR) << "Error processing region at " << offset_ << " of size "
  75. << size_;
  76. }
  77. }
  78. bool ChunkProcessor::ProcessChunk() {
  79. brillo::Blob buffer_in_(size_);
  80. brillo::Blob op_blob;
  81. ssize_t bytes_read = -1;
  82. TEST_AND_RETURN_FALSE(utils::PReadAll(
  83. fd_, buffer_in_.data(), buffer_in_.size(), offset_, &bytes_read));
  84. TEST_AND_RETURN_FALSE(bytes_read == static_cast<ssize_t>(size_));
  85. InstallOperation::Type op_type;
  86. TEST_AND_RETURN_FALSE(diff_utils::GenerateBestFullOperation(
  87. buffer_in_, version_, &op_blob, &op_type));
  88. aop_->op.set_type(op_type);
  89. TEST_AND_RETURN_FALSE(aop_->SetOperationBlob(op_blob, blob_file_));
  90. return true;
  91. }
  92. } // namespace
  93. bool FullUpdateGenerator::GenerateOperations(
  94. const PayloadGenerationConfig& config,
  95. const PartitionConfig& old_part,
  96. const PartitionConfig& new_part,
  97. BlobFileWriter* blob_file,
  98. vector<AnnotatedOperation>* aops) {
  99. TEST_AND_RETURN_FALSE(new_part.ValidateExists());
  100. // FullUpdateGenerator requires a positive chunk_size, otherwise there will
  101. // be only one operation with the whole partition which should not be allowed.
  102. // For performance reasons, we force a small default hard limit of 1 MiB. This
  103. // limit can be changed in the config, and we will use the smaller of the two
  104. // soft/hard limits.
  105. size_t full_chunk_size;
  106. if (config.hard_chunk_size >= 0) {
  107. full_chunk_size = std::min(static_cast<size_t>(config.hard_chunk_size),
  108. config.soft_chunk_size);
  109. } else {
  110. full_chunk_size = std::min(kDefaultFullChunkSize, config.soft_chunk_size);
  111. LOG(INFO) << "No chunk_size provided, using the default chunk_size for the "
  112. << "full operations: " << full_chunk_size << " bytes.";
  113. }
  114. TEST_AND_RETURN_FALSE(full_chunk_size > 0);
  115. TEST_AND_RETURN_FALSE(full_chunk_size % config.block_size == 0);
  116. size_t chunk_blocks = full_chunk_size / config.block_size;
  117. size_t max_threads = diff_utils::GetMaxThreads();
  118. LOG(INFO) << "Compressing partition " << new_part.name << " from "
  119. << new_part.path << " splitting in chunks of " << chunk_blocks
  120. << " blocks (" << config.block_size << " bytes each) using "
  121. << max_threads << " threads";
  122. int in_fd = open(new_part.path.c_str(), O_RDONLY, 0);
  123. TEST_AND_RETURN_FALSE(in_fd >= 0);
  124. ScopedFdCloser in_fd_closer(&in_fd);
  125. // We potentially have all the ChunkProcessors in memory but only
  126. // |max_threads| will actually hold a block in memory while we process.
  127. size_t partition_blocks = new_part.size / config.block_size;
  128. size_t num_chunks = utils::DivRoundUp(partition_blocks, chunk_blocks);
  129. aops->resize(num_chunks);
  130. vector<ChunkProcessor> chunk_processors;
  131. chunk_processors.reserve(num_chunks);
  132. blob_file->SetTotalBlobs(num_chunks);
  133. for (size_t i = 0; i < num_chunks; ++i) {
  134. size_t start_block = i * chunk_blocks;
  135. // The last chunk could be smaller.
  136. size_t num_blocks =
  137. std::min(chunk_blocks, partition_blocks - i * chunk_blocks);
  138. // Preset all the static information about the operations. The
  139. // ChunkProcessor will set the rest.
  140. AnnotatedOperation* aop = aops->data() + i;
  141. aop->name = base::StringPrintf(
  142. "<%s-operation-%" PRIuS ">", new_part.name.c_str(), i);
  143. Extent* dst_extent = aop->op.add_dst_extents();
  144. dst_extent->set_start_block(start_block);
  145. dst_extent->set_num_blocks(num_blocks);
  146. chunk_processors.emplace_back(
  147. config.version,
  148. in_fd,
  149. static_cast<off_t>(start_block) * config.block_size,
  150. num_blocks * config.block_size,
  151. blob_file,
  152. aop);
  153. }
  154. // Thread pool used for worker threads.
  155. base::DelegateSimpleThreadPool thread_pool("full-update-generator",
  156. max_threads);
  157. thread_pool.Start();
  158. for (ChunkProcessor& processor : chunk_processors)
  159. thread_pool.AddWork(&processor);
  160. thread_pool.JoinAll();
  161. // All the work done, disable logging.
  162. blob_file->SetTotalBlobs(0);
  163. // All the operations must have a type set at this point. Otherwise, a
  164. // ChunkProcessor failed to complete.
  165. for (const AnnotatedOperation& aop : *aops) {
  166. if (!aop.op.has_type())
  167. return false;
  168. }
  169. return true;
  170. }
  171. } // namespace chromeos_update_engine