| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "storage/browser/blob/blob_memory_controller.h" | 5 #include "storage/browser/blob/blob_memory_controller.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/callback.h" | 9 #include "base/callback.h" |
| 10 #include "base/callback_helpers.h" | 10 #include "base/callback_helpers.h" |
| (...skipping 27 matching lines...) Expand all Loading... |
| 38 namespace { | 38 namespace { |
| 39 using FileCreationInfo = BlobMemoryController::FileCreationInfo; | 39 using FileCreationInfo = BlobMemoryController::FileCreationInfo; |
| 40 using MemoryAllocation = BlobMemoryController::MemoryAllocation; | 40 using MemoryAllocation = BlobMemoryController::MemoryAllocation; |
| 41 using QuotaAllocationTask = BlobMemoryController::QuotaAllocationTask; | 41 using QuotaAllocationTask = BlobMemoryController::QuotaAllocationTask; |
| 42 | 42 |
| 43 File::Error CreateBlobDirectory(const FilePath& blob_storage_dir) { | 43 File::Error CreateBlobDirectory(const FilePath& blob_storage_dir) { |
| 44 File::Error error = File::FILE_OK; | 44 File::Error error = File::FILE_OK; |
| 45 base::CreateDirectoryAndGetError(blob_storage_dir, &error); | 45 base::CreateDirectoryAndGetError(blob_storage_dir, &error); |
| 46 UMA_HISTOGRAM_ENUMERATION("Storage.Blob.CreateDirectoryResult", -error, | 46 UMA_HISTOGRAM_ENUMERATION("Storage.Blob.CreateDirectoryResult", -error, |
| 47 -File::FILE_ERROR_MAX); | 47 -File::FILE_ERROR_MAX); |
| 48 if (error != File::FILE_OK) |
| 49 LOG(ERROR) << "Error creating blob storage directory: " << error; |
| 48 return error; | 50 return error; |
| 49 } | 51 } |
| 50 | 52 |
| 51 void DestructFile(File infos_without_references) {} | 53 void DestructFile(File infos_without_references) {} |
| 52 | 54 |
| 53 // Used for new unpopulated file items. Caller must populate file reference in | 55 // Used for new unpopulated file items. Caller must populate file reference in |
| 54 // returned FileCreationInfos. | 56 // returned FileCreationInfos. |
| 55 std::pair<std::vector<FileCreationInfo>, File::Error> CreateEmptyFiles( | 57 std::pair<std::vector<FileCreationInfo>, File::Error> CreateEmptyFiles( |
| 56 const FilePath& blob_storage_dir, | 58 const FilePath& blob_storage_dir, |
| 57 scoped_refptr<base::TaskRunner> file_task_runner, | 59 scoped_refptr<base::TaskRunner> file_task_runner, |
| 58 std::vector<base::FilePath> file_paths) { | 60 std::vector<base::FilePath> file_paths) { |
| 59 base::ThreadRestrictions::AssertIOAllowed(); | 61 base::ThreadRestrictions::AssertIOAllowed(); |
| 60 | 62 |
| 61 File::Error dir_create_status = CreateBlobDirectory(blob_storage_dir); | 63 File::Error dir_create_status = CreateBlobDirectory(blob_storage_dir); |
| 62 if (dir_create_status != File::FILE_OK) | 64 if (dir_create_status != File::FILE_OK) |
| 63 return std::make_pair(std::vector<FileCreationInfo>(), dir_create_status); | 65 return std::make_pair(std::vector<FileCreationInfo>(), dir_create_status); |
| 64 | 66 |
| 65 std::vector<FileCreationInfo> result; | 67 std::vector<FileCreationInfo> result; |
| 66 for (const base::FilePath& file_path : file_paths) { | 68 for (const base::FilePath& file_path : file_paths) { |
| 67 FileCreationInfo creation_info; | 69 FileCreationInfo creation_info; |
| 68 // Try to open our file. | 70 // Try to open our file. |
| 69 File file(file_path, File::FLAG_CREATE_ALWAYS | File::FLAG_WRITE); | 71 File file(file_path, File::FLAG_CREATE_ALWAYS | File::FLAG_WRITE); |
| 70 creation_info.path = std::move(file_path); | 72 creation_info.path = std::move(file_path); |
| 71 creation_info.file_deletion_runner = file_task_runner; | 73 creation_info.file_deletion_runner = file_task_runner; |
| 72 creation_info.error = file.error_details(); | 74 creation_info.error = file.error_details(); |
| 73 if (creation_info.error != File::FILE_OK) { | 75 if (creation_info.error != File::FILE_OK) { |
| 74 return std::make_pair(std::vector<FileCreationInfo>(), | 76 return std::make_pair(std::vector<FileCreationInfo>(), |
| 75 creation_info.error); | 77 creation_info.error); |
| 76 } | 78 } |
| 77 | |
| 78 // Grab the file info to get the "last modified" time and store the file. | |
| 79 File::Info file_info; | |
| 80 bool success = file.GetInfo(&file_info); | |
| 81 creation_info.error = success ? File::FILE_OK : File::FILE_ERROR_FAILED; | |
| 82 if (!success) { | |
| 83 return std::make_pair(std::vector<FileCreationInfo>(), | |
| 84 creation_info.error); | |
| 85 } | |
| 86 creation_info.file = std::move(file); | 79 creation_info.file = std::move(file); |
| 87 | 80 |
| 88 result.push_back(std::move(creation_info)); | 81 result.push_back(std::move(creation_info)); |
| 89 } | 82 } |
| 90 return std::make_pair(std::move(result), File::FILE_OK); | 83 return std::make_pair(std::move(result), File::FILE_OK); |
| 91 } | 84 } |
| 92 | 85 |
| 93 // Used to evict multiple memory items out to a single file. Caller must | 86 // Used to evict multiple memory items out to a single file. Caller must |
| 94 // populate file reference in returned FileCreationInfo. | 87 // populate file reference in returned FileCreationInfo. |
| 95 FileCreationInfo CreateFileAndWriteItems( | 88 FileCreationInfo CreateFileAndWriteItems( |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 127 file.WriteAtCurrentPos(element->bytes() + (length - bytes_left), | 120 file.WriteAtCurrentPos(element->bytes() + (length - bytes_left), |
| 128 base::saturated_cast<int>(bytes_left)); | 121 base::saturated_cast<int>(bytes_left)); |
| 129 if (bytes_written < 0) | 122 if (bytes_written < 0) |
| 130 break; | 123 break; |
| 131 DCHECK_LE(static_cast<size_t>(bytes_written), bytes_left); | 124 DCHECK_LE(static_cast<size_t>(bytes_written), bytes_left); |
| 132 bytes_left -= bytes_written; | 125 bytes_left -= bytes_written; |
| 133 } | 126 } |
| 134 if (bytes_written < 0) | 127 if (bytes_written < 0) |
| 135 break; | 128 break; |
| 136 } | 129 } |
| 130 if (!file.Flush()) { |
| 131 creation_info.error = File::FILE_ERROR_FAILED; |
| 132 return creation_info; |
| 133 } |
| 137 | 134 |
| 138 File::Info info; | 135 File::Info info; |
| 139 bool success = file.GetInfo(&info); | 136 bool success = file.GetInfo(&info); |
| 140 creation_info.error = | 137 creation_info.error = |
| 141 bytes_written < 0 || !success ? File::FILE_ERROR_FAILED : File::FILE_OK; | 138 bytes_written < 0 || !success ? File::FILE_ERROR_FAILED : File::FILE_OK; |
| 142 creation_info.last_modified = info.last_modified; | 139 creation_info.last_modified = info.last_modified; |
| 143 return creation_info; | 140 return creation_info; |
| 144 } | 141 } |
| 145 | 142 |
| 146 uint64_t GetTotalSizeAndFileSizes( | 143 uint64_t GetTotalSizeAndFileSizes( |
| 147 const std::vector<scoped_refptr<ShareableBlobDataItem>>& | 144 const std::vector<scoped_refptr<ShareableBlobDataItem>>& |
| 148 unreserved_file_items, | 145 unreserved_file_items, |
| 149 std::vector<uint64_t>* file_sizes_output) { | 146 std::vector<uint64_t>* file_sizes_output) { |
| 150 uint64_t total_size_output = 0; | 147 uint64_t total_size_output = 0; |
| 151 base::SmallMap<std::map<uint64_t, uint64_t>> file_id_to_sizes; | 148 base::SmallMap<std::map<uint64_t, uint64_t>> file_id_to_sizes; |
| 152 for (const auto& item : unreserved_file_items) { | 149 for (const auto& item : unreserved_file_items) { |
| 153 const DataElement& element = item->item()->data_element(); | 150 const DataElement& element = item->item()->data_element(); |
| 154 uint64_t file_id = BlobDataBuilder::GetFutureFileID(element); | 151 uint64_t file_id = BlobDataBuilder::GetFutureFileID(element); |
| 155 auto it = file_id_to_sizes.find(file_id); | 152 auto it = file_id_to_sizes.find(file_id); |
| 156 if (it != file_id_to_sizes.end()) | 153 if (it != file_id_to_sizes.end()) |
| 157 it->second = std::max(it->second, element.offset() + element.length()); | 154 it->second = std::max(it->second, element.offset() + element.length()); |
| 158 else | 155 else |
| 159 file_id_to_sizes[file_id] = element.offset() + element.length(); | 156 file_id_to_sizes[file_id] = element.offset() + element.length(); |
| 160 total_size_output += element.length(); | 157 total_size_output += element.length(); |
| 161 } | 158 } |
| 159 uint64_t sizes_from_files = 0; |
| 162 for (const auto& size_pair : file_id_to_sizes) { | 160 for (const auto& size_pair : file_id_to_sizes) { |
| 163 file_sizes_output->push_back(size_pair.second); | 161 file_sizes_output->push_back(size_pair.second); |
| 162 sizes_from_files += size_pair.second; |
| 164 } | 163 } |
| 164 DCHECK_EQ(sizes_from_files, total_size_output) |
| 165 << "Illegal builder configuration, temporary files must be totally used."; |
| 165 return total_size_output; | 166 return total_size_output; |
| 166 } | 167 } |
| 167 | 168 |
| 168 } // namespace | 169 } // namespace |
| 169 | 170 |
| 170 FileCreationInfo::FileCreationInfo() {} | 171 FileCreationInfo::FileCreationInfo() {} |
| 171 FileCreationInfo::~FileCreationInfo() { | 172 FileCreationInfo::~FileCreationInfo() { |
| 172 if (file.IsValid()) { | 173 if (file.IsValid()) { |
| 173 DCHECK(file_deletion_runner); | 174 DCHECK(file_deletion_runner); |
| 174 file_deletion_runner->PostTask( | 175 file_deletion_runner->PostTask( |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 291 base::PostTaskAndReplyWithResult( | 292 base::PostTaskAndReplyWithResult( |
| 292 controller_->file_runner_.get(), FROM_HERE, | 293 controller_->file_runner_.get(), FROM_HERE, |
| 293 base::Bind(&CreateEmptyFiles, controller_->blob_storage_dir_, | 294 base::Bind(&CreateEmptyFiles, controller_->blob_storage_dir_, |
| 294 controller_->file_runner_, base::Passed(&file_paths)), | 295 controller_->file_runner_, base::Passed(&file_paths)), |
| 295 base::Bind(&FileQuotaAllocationTask::OnCreateEmptyFiles, | 296 base::Bind(&FileQuotaAllocationTask::OnCreateEmptyFiles, |
| 296 weak_factory_.GetWeakPtr(), base::Passed(&references))); | 297 weak_factory_.GetWeakPtr(), base::Passed(&references))); |
| 297 controller_->RecordTracingCounters(); | 298 controller_->RecordTracingCounters(); |
| 298 } | 299 } |
| 299 ~FileQuotaAllocationTask() override {} | 300 ~FileQuotaAllocationTask() override {} |
| 300 | 301 |
| 301 void RunDoneCallback(bool success, std::vector<FileCreationInfo> file_info) { | 302 void RunDoneCallback(std::vector<FileCreationInfo> file_info, bool success) { |
| 302 // Make sure we clear the weak pointers we gave to the caller beforehand. | 303 // Make sure we clear the weak pointers we gave to the caller beforehand. |
| 303 weak_factory_.InvalidateWeakPtrs(); | 304 weak_factory_.InvalidateWeakPtrs(); |
| 304 | 305 |
| 305 // We want to destroy this object on the exit of this method if we were | 306 // We want to destroy this object on the exit of this method if we were |
| 306 // successful. | 307 // successful. |
| 307 std::unique_ptr<FileQuotaAllocationTask> this_object; | 308 std::unique_ptr<FileQuotaAllocationTask> this_object; |
| 308 if (success) { | 309 if (success) { |
| 309 for (auto& item : pending_items_) { | 310 for (auto& item : pending_items_) { |
| 310 item->set_state(ShareableBlobDataItem::QUOTA_GRANTED); | 311 item->set_state(ShareableBlobDataItem::QUOTA_GRANTED); |
| 311 } | 312 } |
| 312 this_object = std::move(*my_list_position_); | 313 this_object = std::move(*my_list_position_); |
| 313 controller_->pending_file_quota_tasks_.erase(my_list_position_); | 314 controller_->pending_file_quota_tasks_.erase(my_list_position_); |
| 314 } | 315 } |
| 315 | 316 |
| 316 done_callback_.Run(success, std::move(file_info)); | 317 done_callback_.Run(std::move(file_info), success); |
| 317 } | 318 } |
| 318 | 319 |
| 319 base::WeakPtr<QuotaAllocationTask> GetWeakPtr() { | 320 base::WeakPtr<QuotaAllocationTask> GetWeakPtr() { |
| 320 return weak_factory_.GetWeakPtr(); | 321 return weak_factory_.GetWeakPtr(); |
| 321 } | 322 } |
| 322 | 323 |
| 323 void Cancel() override { | 324 void Cancel() override { |
| 324 // This call destroys this object. We rely on ShareableFileReference's | 325 // This call destroys this object. We rely on ShareableFileReference's |
| 325 // final release callback for disk_usage_ accounting. | 326 // final release callback for disk_usage_ accounting. |
| 326 controller_->pending_file_quota_tasks_.erase(my_list_position_); | 327 controller_->pending_file_quota_tasks_.erase(my_list_position_); |
| 327 } | 328 } |
| 328 | 329 |
| 329 void OnCreateEmptyFiles( | 330 void OnCreateEmptyFiles( |
| 330 std::vector<scoped_refptr<ShareableFileReference>> references, | 331 std::vector<scoped_refptr<ShareableFileReference>> references, |
| 331 std::pair<std::vector<FileCreationInfo>, File::Error> files_and_error) { | 332 std::pair<std::vector<FileCreationInfo>, File::Error> files_and_error) { |
| 332 auto& files = files_and_error.first; | 333 auto& files = files_and_error.first; |
| 333 if (files.empty()) { | 334 if (files.empty()) { |
| 334 DCHECK_GE(controller_->disk_used_, allocation_size_); | 335 DCHECK_GE(controller_->disk_used_, allocation_size_); |
| 335 controller_->disk_used_ -= allocation_size_; | 336 controller_->disk_used_ -= allocation_size_; |
| 336 // This will call our callback and delete the object correctly. | 337 // This will call our callback and delete the object correctly. |
| 337 controller_->DisableFilePaging(files_and_error.second); | 338 controller_->DisableFilePaging(files_and_error.second); |
| 338 return; | 339 return; |
| 339 } | 340 } |
| 340 DCHECK_EQ(files.size(), references.size()); | 341 DCHECK_EQ(files.size(), references.size()); |
| 341 for (size_t i = 0; i < files.size(); i++) { | 342 for (size_t i = 0; i < files.size(); i++) { |
| 342 files[i].file_reference = std::move(references[i]); | 343 files[i].file_reference = std::move(references[i]); |
| 343 } | 344 } |
| 344 RunDoneCallback(true, std::move(files)); | 345 RunDoneCallback(std::move(files), true); |
| 345 } | 346 } |
| 346 | 347 |
| 347 // The my_list_position_ iterator is stored so that we can remove ourself | 348 // The my_list_position_ iterator is stored so that we can remove ourself |
| 348 // from the task list when we are cancelled. | 349 // from the task list when we are cancelled. |
| 349 void set_my_list_position( | 350 void set_my_list_position( |
| 350 PendingFileQuotaTaskList::iterator my_list_position) { | 351 PendingFileQuotaTaskList::iterator my_list_position) { |
| 351 my_list_position_ = my_list_position; | 352 my_list_position_ = my_list_position; |
| 352 } | 353 } |
| 353 | 354 |
| 354 private: | 355 private: |
| (...skipping 17 matching lines...) Expand all Loading... |
| 372 file_runner_(std::move(file_runner)), | 373 file_runner_(std::move(file_runner)), |
| 373 populated_memory_items_( | 374 populated_memory_items_( |
| 374 base::MRUCache<uint64_t, ShareableBlobDataItem*>::NO_AUTO_EVICT), | 375 base::MRUCache<uint64_t, ShareableBlobDataItem*>::NO_AUTO_EVICT), |
| 375 weak_factory_(this) {} | 376 weak_factory_(this) {} |
| 376 | 377 |
| 377 BlobMemoryController::~BlobMemoryController() {} | 378 BlobMemoryController::~BlobMemoryController() {} |
| 378 | 379 |
| 379 void BlobMemoryController::DisableFilePaging(base::File::Error reason) { | 380 void BlobMemoryController::DisableFilePaging(base::File::Error reason) { |
| 380 UMA_HISTOGRAM_ENUMERATION("Storage.Blob.PagingDisabled", -reason, | 381 UMA_HISTOGRAM_ENUMERATION("Storage.Blob.PagingDisabled", -reason, |
| 381 -File::FILE_ERROR_MAX); | 382 -File::FILE_ERROR_MAX); |
| 383 LOG(ERROR) << "Blob storage paging disabled due to: " << reason; |
| 382 file_paging_enabled_ = false; | 384 file_paging_enabled_ = false; |
| 383 in_flight_memory_used_ = 0; | 385 in_flight_memory_used_ = 0; |
| 384 items_paging_to_file_.clear(); | 386 items_paging_to_file_.clear(); |
| 385 pending_evictions_ = 0; | 387 pending_evictions_ = 0; |
| 386 pending_memory_quota_total_size_ = 0; | 388 pending_memory_quota_total_size_ = 0; |
| 387 populated_memory_items_.Clear(); | 389 populated_memory_items_.Clear(); |
| 388 populated_memory_items_bytes_ = 0; | 390 populated_memory_items_bytes_ = 0; |
| 389 file_runner_ = nullptr; | 391 file_runner_ = nullptr; |
| 390 | 392 |
| 391 PendingMemoryQuotaTaskList old_memory_tasks; | 393 PendingMemoryQuotaTaskList old_memory_tasks; |
| 392 PendingFileQuotaTaskList old_file_tasks; | 394 PendingFileQuotaTaskList old_file_tasks; |
| 393 std::swap(old_memory_tasks, pending_memory_quota_tasks_); | 395 std::swap(old_memory_tasks, pending_memory_quota_tasks_); |
| 394 std::swap(old_file_tasks, pending_file_quota_tasks_); | 396 std::swap(old_file_tasks, pending_file_quota_tasks_); |
| 395 | 397 |
| 396 // Don't call the callbacks until we have a consistent state. | 398 // Don't call the callbacks until we have a consistent state. |
| 397 for (auto& memory_request : old_memory_tasks) { | 399 for (auto& memory_request : old_memory_tasks) { |
| 398 memory_request->RunDoneCallback(false); | 400 memory_request->RunDoneCallback(false); |
| 399 } | 401 } |
| 400 for (auto& file_request : old_file_tasks) { | 402 for (auto& file_request : old_file_tasks) { |
| 401 file_request->RunDoneCallback(false, std::vector<FileCreationInfo>()); | 403 file_request->RunDoneCallback(std::vector<FileCreationInfo>(), false); |
| 402 } | 404 } |
| 403 } | 405 } |
| 404 | 406 |
| 405 BlobMemoryController::Strategy BlobMemoryController::DetermineStrategy( | 407 BlobMemoryController::Strategy BlobMemoryController::DetermineStrategy( |
| 406 size_t preemptive_transported_bytes, | 408 size_t preemptive_transported_bytes, |
| 407 uint64_t total_transportation_bytes) const { | 409 uint64_t total_transportation_bytes) const { |
| 408 if (total_transportation_bytes == 0) | 410 if (total_transportation_bytes == 0) |
| 409 return Strategy::NONE_NEEDED; | 411 return Strategy::NONE_NEEDED; |
| 410 if (!CanReserveQuota(total_transportation_bytes)) | 412 if (!CanReserveQuota(total_transportation_bytes)) |
| 411 return Strategy::TOO_LARGE; | 413 return Strategy::TOO_LARGE; |
| (...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 738 MaybeGrantPendingMemoryRequests(); | 740 MaybeGrantPendingMemoryRequests(); |
| 739 } | 741 } |
| 740 | 742 |
| 741 void BlobMemoryController::OnBlobFileDelete(uint64_t size, | 743 void BlobMemoryController::OnBlobFileDelete(uint64_t size, |
| 742 const FilePath& path) { | 744 const FilePath& path) { |
| 743 DCHECK_LE(size, disk_used_); | 745 DCHECK_LE(size, disk_used_); |
| 744 disk_used_ -= size; | 746 disk_used_ -= size; |
| 745 } | 747 } |
| 746 | 748 |
| 747 } // namespace storage | 749 } // namespace storage |
| OLD | NEW |