Chromium Code Reviews| 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 #include <numeric> | 8 #include <numeric> |
| 9 | 9 |
| 10 #include "base/bind.h" | |
| 11 #include "base/bind_helpers.h" | |
| 10 #include "base/callback.h" | 12 #include "base/callback.h" |
| 11 #include "base/callback_helpers.h" | 13 #include "base/callback_helpers.h" |
| 12 #include "base/containers/small_map.h" | 14 #include "base/containers/small_map.h" |
| 13 #include "base/files/file_util.h" | 15 #include "base/files/file_util.h" |
| 14 #include "base/guid.h" | 16 #include "base/guid.h" |
| 15 #include "base/location.h" | 17 #include "base/location.h" |
| 16 #include "base/memory/ptr_util.h" | 18 #include "base/memory/ptr_util.h" |
| 17 #include "base/metrics/histogram_macros.h" | 19 #include "base/metrics/histogram_macros.h" |
| 18 #include "base/numerics/safe_conversions.h" | 20 #include "base/numerics/safe_conversions.h" |
| 19 #include "base/numerics/safe_math.h" | 21 #include "base/numerics/safe_math.h" |
| 20 #include "base/single_thread_task_runner.h" | 22 #include "base/single_thread_task_runner.h" |
| 21 #include "base/stl_util.h" | 23 #include "base/stl_util.h" |
| 22 #include "base/strings/string_number_conversions.h" | 24 #include "base/strings/string_number_conversions.h" |
| 25 #include "base/sys_info.h" | |
| 23 #include "base/task_runner.h" | 26 #include "base/task_runner.h" |
| 24 #include "base/task_runner_util.h" | 27 #include "base/task_runner_util.h" |
| 25 #include "base/threading/thread_restrictions.h" | 28 #include "base/threading/thread_restrictions.h" |
| 26 #include "base/time/time.h" | 29 #include "base/time/time.h" |
| 27 #include "base/trace_event/trace_event.h" | 30 #include "base/trace_event/trace_event.h" |
| 28 #include "base/tuple.h" | |
| 29 #include "storage/browser/blob/blob_data_builder.h" | 31 #include "storage/browser/blob/blob_data_builder.h" |
| 30 #include "storage/browser/blob/blob_data_item.h" | 32 #include "storage/browser/blob/blob_data_item.h" |
| 31 #include "storage/browser/blob/shareable_blob_data_item.h" | 33 #include "storage/browser/blob/shareable_blob_data_item.h" |
| 32 #include "storage/browser/blob/shareable_file_reference.h" | 34 #include "storage/browser/blob/shareable_file_reference.h" |
| 33 #include "storage/common/data_element.h" | 35 #include "storage/common/data_element.h" |
| 34 | 36 |
| 35 using base::File; | 37 using base::File; |
| 36 using base::FilePath; | 38 using base::FilePath; |
| 37 | 39 |
| 38 namespace storage { | 40 namespace storage { |
| 39 namespace { | 41 namespace { |
| 42 const int64_t kUnknownDiskAvailability = -1ll; | |
| 43 | |
| 40 using FileCreationInfo = BlobMemoryController::FileCreationInfo; | 44 using FileCreationInfo = BlobMemoryController::FileCreationInfo; |
| 41 using MemoryAllocation = BlobMemoryController::MemoryAllocation; | 45 using MemoryAllocation = BlobMemoryController::MemoryAllocation; |
| 42 using QuotaAllocationTask = BlobMemoryController::QuotaAllocationTask; | 46 using QuotaAllocationTask = BlobMemoryController::QuotaAllocationTask; |
| 43 | 47 |
| 48 // CrOS: | |
|
pwnall
2016/12/08 21:59:24
Can you please add explanations of where (which me
dmurph
2016/12/20 02:21:36
Done.
| |
| 49 // * Ram - 20% | |
| 50 // * Disk - 50% | |
| 51 // Android: | |
| 52 // * RAM - 20% | |
| 53 // * Disk - 5% | |
| 54 // Desktop: | |
| 55 // * Ram - 20%, or 2 gigs if x64. | |
| 56 // * Disk - 10% | |
| 57 BlobStorageLimits CalculateBlobStorageLimitsImpl(const FilePath& storage_dir, | |
| 58 bool disk_enabled) { | |
| 59 BlobStorageLimits output; | |
| 60 | |
| 61 int64_t disk_size = | |
| 62 disk_enabled ? base::SysInfo::AmountOfTotalDiskSpace(storage_dir) : 0ull; | |
| 63 int64_t memory_size = base::SysInfo::AmountOfPhysicalMemory(); | |
| 64 | |
| 65 BlobStorageLimits limits; | |
| 66 | |
| 67 if (memory_size > 0) { | |
| 68 #if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && defined(ARCH_CPU_64_BITS) | |
| 69 static const size_t kTwoGigabytes = 2ull * 1024 * 1024 * 1024; | |
| 70 limits.max_blob_in_memory_space = kTwoGigabytes; | |
| 71 #else | |
| 72 limits.max_blob_in_memory_space = static_cast<size_t>(memory_size / 5ll); | |
| 73 #endif | |
| 74 } | |
| 75 | |
| 76 if (disk_size > 0) { | |
| 77 #if defined(OS_CHROMEOS) | |
| 78 limits.max_blob_disk_space = static_cast<size_t>(disk_size / 2ll); | |
| 79 #elif defined(OS_ANDROID) | |
| 80 limits.max_blob_disk_space = static_cast<size_t>(disk_size / 20ll); | |
| 81 #else | |
| 82 limits.max_blob_disk_space = static_cast<size_t>(disk_size / 10ll); | |
| 83 #endif | |
| 84 } | |
| 85 | |
| 86 return limits; | |
| 87 } | |
| 88 | |
| 44 File::Error CreateBlobDirectory(const FilePath& blob_storage_dir) { | 89 File::Error CreateBlobDirectory(const FilePath& blob_storage_dir) { |
| 45 File::Error error = File::FILE_OK; | 90 File::Error error = File::FILE_OK; |
| 46 base::CreateDirectoryAndGetError(blob_storage_dir, &error); | 91 base::CreateDirectoryAndGetError(blob_storage_dir, &error); |
| 47 UMA_HISTOGRAM_ENUMERATION("Storage.Blob.CreateDirectoryResult", -error, | 92 UMA_HISTOGRAM_ENUMERATION("Storage.Blob.CreateDirectoryResult", -error, |
| 48 -File::FILE_ERROR_MAX); | 93 -File::FILE_ERROR_MAX); |
| 49 DLOG_IF(ERROR, error != File::FILE_OK) | 94 DLOG_IF(ERROR, error != File::FILE_OK) |
| 50 << "Error creating blob storage directory: " << error; | 95 << "Error creating blob storage directory: " << error; |
| 51 return error; | 96 return error; |
| 52 } | 97 } |
| 53 | 98 |
| 54 void DestructFile(File infos_without_references) {} | 99 void DestructFile(File infos_without_references) {} |
| 55 | 100 |
| 101 void DeleteFiles(std::vector<FileCreationInfo> files) { | |
| 102 for (FileCreationInfo& file_info : files) { | |
| 103 file_info.file.Close(); | |
| 104 base::DeleteFile(file_info.path, false); | |
| 105 } | |
| 106 } | |
| 107 | |
| 56 // Used for new unpopulated file items. Caller must populate file reference in | 108 // Used for new unpopulated file items. Caller must populate file reference in |
| 57 // returned FileCreationInfos. | 109 // returned FileCreationInfos. Also returns the current available disk space |
| 58 std::pair<std::vector<FileCreationInfo>, File::Error> CreateEmptyFiles( | 110 // (without the future size of these files). |
| 59 const FilePath& blob_storage_dir, | 111 std::tuple<std::vector<FileCreationInfo>, File::Error, int64_t> |
| 60 scoped_refptr<base::TaskRunner> file_task_runner, | 112 CreateEmptyFiles(const FilePath& blob_storage_dir, |
| 61 std::vector<base::FilePath> file_paths) { | 113 scoped_refptr<base::TaskRunner> file_task_runner, |
| 114 std::vector<base::FilePath> file_paths) { | |
| 62 base::ThreadRestrictions::AssertIOAllowed(); | 115 base::ThreadRestrictions::AssertIOAllowed(); |
| 63 | 116 |
| 64 File::Error dir_create_status = CreateBlobDirectory(blob_storage_dir); | 117 File::Error dir_create_status = CreateBlobDirectory(blob_storage_dir); |
| 65 if (dir_create_status != File::FILE_OK) | 118 if (dir_create_status != File::FILE_OK) { |
| 66 return std::make_pair(std::vector<FileCreationInfo>(), dir_create_status); | 119 return std::make_tuple(std::vector<FileCreationInfo>(), dir_create_status, |
| 120 kUnknownDiskAvailability); | |
| 121 } | |
| 122 | |
| 123 int64_t free_disk_space = | |
| 124 base::SysInfo::AmountOfFreeDiskSpace(blob_storage_dir); | |
| 67 | 125 |
| 68 std::vector<FileCreationInfo> result; | 126 std::vector<FileCreationInfo> result; |
| 69 for (const base::FilePath& file_path : file_paths) { | 127 for (const base::FilePath& file_path : file_paths) { |
| 70 FileCreationInfo creation_info; | 128 FileCreationInfo creation_info; |
| 71 // Try to open our file. | 129 // Try to open our file. |
| 72 File file(file_path, File::FLAG_CREATE_ALWAYS | File::FLAG_WRITE); | 130 File file(file_path, File::FLAG_CREATE_ALWAYS | File::FLAG_WRITE); |
| 73 creation_info.path = std::move(file_path); | 131 creation_info.path = std::move(file_path); |
| 74 creation_info.file_deletion_runner = file_task_runner; | 132 creation_info.file_deletion_runner = file_task_runner; |
| 75 creation_info.error = file.error_details(); | 133 creation_info.error = file.error_details(); |
| 76 if (creation_info.error != File::FILE_OK) { | 134 if (creation_info.error != File::FILE_OK) { |
| 77 return std::make_pair(std::vector<FileCreationInfo>(), | 135 return std::make_tuple(std::vector<FileCreationInfo>(), |
| 78 creation_info.error); | 136 creation_info.error, free_disk_space); |
| 79 } | 137 } |
| 80 creation_info.file = std::move(file); | 138 creation_info.file = std::move(file); |
| 81 | 139 |
| 82 result.push_back(std::move(creation_info)); | 140 result.push_back(std::move(creation_info)); |
| 83 } | 141 } |
| 84 return std::make_pair(std::move(result), File::FILE_OK); | 142 return std::make_tuple(std::move(result), File::FILE_OK, free_disk_space); |
| 85 } | 143 } |
| 86 | 144 |
| 87 // Used to evict multiple memory items out to a single file. Caller must | 145 // Used to evict multiple memory items out to a single file. Caller must |
| 88 // populate file reference in returned FileCreationInfo. | 146 // populate file reference in returned FileCreationInfo. Also returns the disk |
| 89 FileCreationInfo CreateFileAndWriteItems( | 147 // space AFTER creating this file. |
| 148 std::pair<FileCreationInfo, int64_t> CreateFileAndWriteItems( | |
| 90 const FilePath& blob_storage_dir, | 149 const FilePath& blob_storage_dir, |
| 91 const FilePath& file_path, | 150 const FilePath& file_path, |
| 92 scoped_refptr<base::TaskRunner> file_task_runner, | 151 scoped_refptr<base::TaskRunner> file_task_runner, |
| 93 std::vector<DataElement*> items, | 152 std::vector<DataElement*> items, |
| 94 size_t total_size_bytes) { | 153 size_t total_size_bytes) { |
| 95 DCHECK_NE(0u, total_size_bytes); | 154 DCHECK_NE(0u, total_size_bytes); |
| 96 UMA_HISTOGRAM_MEMORY_KB("Storage.Blob.PageFileSize", total_size_bytes / 1024); | 155 UMA_HISTOGRAM_MEMORY_KB("Storage.Blob.PageFileSize", total_size_bytes / 1024); |
| 97 base::ThreadRestrictions::AssertIOAllowed(); | 156 base::ThreadRestrictions::AssertIOAllowed(); |
| 98 | 157 |
| 99 FileCreationInfo creation_info; | 158 FileCreationInfo creation_info; |
| 100 creation_info.file_deletion_runner = std::move(file_task_runner); | 159 creation_info.file_deletion_runner = std::move(file_task_runner); |
| 101 creation_info.error = CreateBlobDirectory(blob_storage_dir); | 160 creation_info.error = CreateBlobDirectory(blob_storage_dir); |
| 102 if (creation_info.error != File::FILE_OK) | 161 if (creation_info.error != File::FILE_OK) |
| 103 return creation_info; | 162 return std::make_pair(std::move(creation_info), kUnknownDiskAvailability); |
| 163 | |
| 164 int64_t free_disk_space = | |
| 165 base::SysInfo::AmountOfFreeDiskSpace(blob_storage_dir); | |
| 166 | |
| 167 // Fail early instead of creating the files if we fill the disk. | |
| 168 if (free_disk_space != kUnknownDiskAvailability && | |
| 169 free_disk_space < static_cast<int64_t>(total_size_bytes)) { | |
| 170 creation_info.error = File::FILE_ERROR_NO_SPACE; | |
| 171 return std::make_pair(std::move(creation_info), kUnknownDiskAvailability); | |
|
michaeln
2016/12/08 21:17:33
why say 'unkwonwavail' here, we know what it is, w
dmurph
2016/12/20 02:21:36
Done.
| |
| 172 } | |
| 173 int64_t disk_availability = | |
| 174 free_disk_space == kUnknownDiskAvailability | |
| 175 ? kUnknownDiskAvailability | |
| 176 : free_disk_space - static_cast<int64_t>(total_size_bytes); | |
| 104 | 177 |
| 105 // Create the page file. | 178 // Create the page file. |
| 106 File file(file_path, File::FLAG_CREATE_ALWAYS | File::FLAG_WRITE); | 179 File file(file_path, File::FLAG_CREATE_ALWAYS | File::FLAG_WRITE); |
| 107 creation_info.path = file_path; | 180 creation_info.path = file_path; |
| 108 creation_info.error = file.error_details(); | 181 creation_info.error = file.error_details(); |
| 109 if (creation_info.error != File::FILE_OK) | 182 if (creation_info.error != File::FILE_OK) |
| 110 return creation_info; | 183 return std::make_pair(std::move(creation_info), disk_availability); |
|
michaeln
2016/12/08 21:17:33
since we failed to create the file and won't be wr
dmurph
2016/12/20 02:21:36
Done.
| |
| 111 | 184 |
| 112 // Write data. | 185 // Write data. |
| 113 file.SetLength(total_size_bytes); | 186 file.SetLength(total_size_bytes); |
| 114 int bytes_written = 0; | 187 int bytes_written = 0; |
| 115 for (DataElement* element : items) { | 188 for (DataElement* element : items) { |
| 116 DCHECK_EQ(DataElement::TYPE_BYTES, element->type()); | 189 DCHECK_EQ(DataElement::TYPE_BYTES, element->type()); |
| 117 size_t length = base::checked_cast<size_t>(element->length()); | 190 size_t length = base::checked_cast<size_t>(element->length()); |
| 118 size_t bytes_left = length; | 191 size_t bytes_left = length; |
| 119 while (bytes_left > 0) { | 192 while (bytes_left > 0) { |
| 120 bytes_written = | 193 bytes_written = |
| 121 file.WriteAtCurrentPos(element->bytes() + (length - bytes_left), | 194 file.WriteAtCurrentPos(element->bytes() + (length - bytes_left), |
| 122 base::saturated_cast<int>(bytes_left)); | 195 base::saturated_cast<int>(bytes_left)); |
| 123 if (bytes_written < 0) | 196 if (bytes_written < 0) |
| 124 break; | 197 break; |
| 125 DCHECK_LE(static_cast<size_t>(bytes_written), bytes_left); | 198 DCHECK_LE(static_cast<size_t>(bytes_written), bytes_left); |
| 126 bytes_left -= bytes_written; | 199 bytes_left -= bytes_written; |
| 127 } | 200 } |
| 128 if (bytes_written < 0) | 201 if (bytes_written < 0) |
| 129 break; | 202 break; |
| 130 } | 203 } |
| 131 if (!file.Flush()) { | 204 if (!file.Flush()) { |
| 132 creation_info.error = File::FILE_ERROR_FAILED; | 205 creation_info.error = File::FILE_ERROR_FAILED; |
| 133 return creation_info; | 206 return std::make_pair(std::move(creation_info), disk_availability); |
|
michaeln
2016/12/08 21:17:33
similar question about |free_disk| vs the locally
dmurph
2016/12/20 02:21:36
Done.
| |
| 134 } | 207 } |
| 135 | 208 |
| 136 File::Info info; | 209 File::Info info; |
| 137 bool success = file.GetInfo(&info); | 210 bool success = file.GetInfo(&info); |
| 138 creation_info.error = | 211 creation_info.error = |
| 139 bytes_written < 0 || !success ? File::FILE_ERROR_FAILED : File::FILE_OK; | 212 bytes_written < 0 || !success ? File::FILE_ERROR_FAILED : File::FILE_OK; |
| 140 creation_info.last_modified = info.last_modified; | 213 creation_info.last_modified = info.last_modified; |
| 141 return creation_info; | 214 return std::make_pair(std::move(creation_info), disk_availability); |
| 142 } | 215 } |
| 143 | 216 |
| 144 uint64_t GetTotalSizeAndFileSizes( | 217 uint64_t GetTotalSizeAndFileSizes( |
| 145 const std::vector<scoped_refptr<ShareableBlobDataItem>>& | 218 const std::vector<scoped_refptr<ShareableBlobDataItem>>& |
| 146 unreserved_file_items, | 219 unreserved_file_items, |
| 147 std::vector<uint64_t>* file_sizes_output) { | 220 std::vector<uint64_t>* file_sizes_output) { |
| 148 uint64_t total_size_output = 0; | 221 uint64_t total_size_output = 0; |
| 149 base::SmallMap<std::map<uint64_t, uint64_t>> file_id_to_sizes; | 222 base::SmallMap<std::map<uint64_t, uint64_t>> file_id_to_sizes; |
| 150 for (const auto& item : unreserved_file_items) { | 223 for (const auto& item : unreserved_file_items) { |
| 151 const DataElement& element = item->item()->data_element(); | 224 const DataElement& element = item->item()->data_element(); |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 288 base::Bind(&BlobMemoryController::OnBlobFileDelete, | 361 base::Bind(&BlobMemoryController::OnBlobFileDelete, |
| 289 controller_->weak_factory_.GetWeakPtr(), file_sizes[i])); | 362 controller_->weak_factory_.GetWeakPtr(), file_sizes[i])); |
| 290 } | 363 } |
| 291 | 364 |
| 292 // Send file creation task to file thread. | 365 // Send file creation task to file thread. |
| 293 base::PostTaskAndReplyWithResult( | 366 base::PostTaskAndReplyWithResult( |
| 294 controller_->file_runner_.get(), FROM_HERE, | 367 controller_->file_runner_.get(), FROM_HERE, |
| 295 base::Bind(&CreateEmptyFiles, controller_->blob_storage_dir_, | 368 base::Bind(&CreateEmptyFiles, controller_->blob_storage_dir_, |
| 296 controller_->file_runner_, base::Passed(&file_paths)), | 369 controller_->file_runner_, base::Passed(&file_paths)), |
| 297 base::Bind(&FileQuotaAllocationTask::OnCreateEmptyFiles, | 370 base::Bind(&FileQuotaAllocationTask::OnCreateEmptyFiles, |
| 298 weak_factory_.GetWeakPtr(), base::Passed(&references))); | 371 weak_factory_.GetWeakPtr(), base::Passed(&references), |
| 372 allocation_size_)); | |
| 299 controller_->RecordTracingCounters(); | 373 controller_->RecordTracingCounters(); |
| 300 } | 374 } |
| 301 ~FileQuotaAllocationTask() override {} | 375 ~FileQuotaAllocationTask() override {} |
| 302 | 376 |
| 303 void RunDoneCallback(std::vector<FileCreationInfo> file_info, bool success) { | 377 void RunDoneCallback(std::vector<FileCreationInfo> file_info, bool success) { |
| 304 // Make sure we clear the weak pointers we gave to the caller beforehand. | 378 // Make sure we clear the weak pointers we gave to the caller beforehand. |
| 305 weak_factory_.InvalidateWeakPtrs(); | 379 weak_factory_.InvalidateWeakPtrs(); |
| 306 | 380 |
| 307 // We want to destroy this object on the exit of this method if we were | 381 // We want to destroy this object on the exit of this method if we were |
| 308 // successful. | 382 // successful. |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 323 } | 397 } |
| 324 | 398 |
| 325 void Cancel() override { | 399 void Cancel() override { |
| 326 // This call destroys this object. We rely on ShareableFileReference's | 400 // This call destroys this object. We rely on ShareableFileReference's |
| 327 // final release callback for disk_usage_ accounting. | 401 // final release callback for disk_usage_ accounting. |
| 328 controller_->pending_file_quota_tasks_.erase(my_list_position_); | 402 controller_->pending_file_quota_tasks_.erase(my_list_position_); |
| 329 } | 403 } |
| 330 | 404 |
| 331 void OnCreateEmptyFiles( | 405 void OnCreateEmptyFiles( |
| 332 std::vector<scoped_refptr<ShareableFileReference>> references, | 406 std::vector<scoped_refptr<ShareableFileReference>> references, |
| 333 std::pair<std::vector<FileCreationInfo>, File::Error> files_and_error) { | 407 uint64_t new_files_total_size, |
| 334 auto& files = files_and_error.first; | 408 std::tuple<std::vector<FileCreationInfo>, File::Error, int64_t> result) { |
| 409 std::vector<FileCreationInfo> files = std::move(std::get<0>(result)); | |
| 410 File::Error error = std::get<1>(result); | |
| 411 int64_t avail_disk_space = std::get<2>(result); | |
| 335 if (files.empty()) { | 412 if (files.empty()) { |
| 413 DCHECK_NE(error, File::FILE_OK); | |
| 336 DCHECK_GE(controller_->disk_used_, allocation_size_); | 414 DCHECK_GE(controller_->disk_used_, allocation_size_); |
| 337 controller_->disk_used_ -= allocation_size_; | 415 controller_->disk_used_ -= allocation_size_; |
| 338 // This will call our callback and delete the object correctly. | 416 // This will call our callback and delete the object correctly. |
| 339 controller_->DisableFilePaging(files_and_error.second); | 417 controller_->DisableFilePaging(error); |
| 340 return; | 418 return; |
| 341 } | 419 } |
| 420 // The allocation won't fit at all. Freeze the disk and cancel this request. | |
| 421 if (avail_disk_space != kUnknownDiskAvailability && | |
| 422 base::checked_cast<uint64_t>(avail_disk_space) < new_files_total_size) { | |
| 423 DCHECK_GE(controller_->disk_used_, allocation_size_); | |
| 424 controller_->disk_used_ -= allocation_size_; | |
| 425 controller_->FreezeDiskUsage(static_cast<uint64_t>(avail_disk_space)); | |
| 426 file_runner_->PostTask(FROM_HERE, | |
| 427 base::Bind(&DeleteFiles, base::Passed(&files))); | |
| 428 std::unique_ptr<FileQuotaAllocationTask> this_object = | |
| 429 std::move(*my_list_position_); | |
| 430 controller_->pending_file_quota_tasks_.erase(my_list_position_); | |
| 431 RunDoneCallback(std::vector<FileCreationInfo>(), false); | |
| 432 return; | |
| 433 } | |
| 434 // Freeze disk if we're getting close. | |
| 435 if (avail_disk_space != kUnknownDiskAvailability && | |
| 436 avail_disk_space - new_files_total_size <= | |
| 437 controller_->limits().min_available_disk_space()) { | |
| 438 controller_->FreezeDiskUsage(base::checked_cast<uint64_t>( | |
| 439 avail_disk_space - new_files_total_size)); | |
| 440 } | |
| 342 DCHECK_EQ(files.size(), references.size()); | 441 DCHECK_EQ(files.size(), references.size()); |
| 343 for (size_t i = 0; i < files.size(); i++) { | 442 for (size_t i = 0; i < files.size(); i++) { |
| 344 files[i].file_reference = std::move(references[i]); | 443 files[i].file_reference = std::move(references[i]); |
| 345 } | 444 } |
| 346 RunDoneCallback(std::move(files), true); | 445 RunDoneCallback(std::move(files), true); |
| 347 } | 446 } |
| 348 | 447 |
| 349 // The my_list_position_ iterator is stored so that we can remove ourself | 448 // The my_list_position_ iterator is stored so that we can remove ourself |
| 350 // from the task list when we are cancelled. | 449 // from the task list when we are cancelled. |
| 351 void set_my_list_position( | 450 void set_my_list_position( |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 410 uint64_t total_transportation_bytes) const { | 509 uint64_t total_transportation_bytes) const { |
| 411 if (total_transportation_bytes == 0) | 510 if (total_transportation_bytes == 0) |
| 412 return Strategy::NONE_NEEDED; | 511 return Strategy::NONE_NEEDED; |
| 413 if (!CanReserveQuota(total_transportation_bytes)) | 512 if (!CanReserveQuota(total_transportation_bytes)) |
| 414 return Strategy::TOO_LARGE; | 513 return Strategy::TOO_LARGE; |
| 415 | 514 |
| 416 // Handle the case where we have all the bytes preemptively transported, and | 515 // Handle the case where we have all the bytes preemptively transported, and |
| 417 // we can also fit them. | 516 // we can also fit them. |
| 418 if (preemptive_transported_bytes == total_transportation_bytes && | 517 if (preemptive_transported_bytes == total_transportation_bytes && |
| 419 pending_memory_quota_tasks_.empty() && | 518 pending_memory_quota_tasks_.empty() && |
| 420 preemptive_transported_bytes < GetAvailableMemoryForBlobs()) { | 519 preemptive_transported_bytes <= GetAvailableMemoryForBlobs()) { |
| 421 return Strategy::NONE_NEEDED; | 520 return Strategy::NONE_NEEDED; |
| 422 } | 521 } |
| 423 if (file_paging_enabled_ && | 522 if (file_paging_enabled_ && |
| 424 (total_transportation_bytes > limits_.memory_limit_before_paging())) { | 523 total_transportation_bytes <= GetAvailableFileSpaceForBlobs() && |
| 524 total_transportation_bytes > limits_.memory_limit_before_paging()) { | |
| 425 return Strategy::FILE; | 525 return Strategy::FILE; |
| 426 } | 526 } |
| 427 if (total_transportation_bytes > limits_.max_ipc_memory_size) | 527 if (total_transportation_bytes > limits_.max_ipc_memory_size) |
| 428 return Strategy::SHARED_MEMORY; | 528 return Strategy::SHARED_MEMORY; |
| 429 return Strategy::IPC; | 529 return Strategy::IPC; |
| 430 } | 530 } |
| 431 | 531 |
| 432 bool BlobMemoryController::CanReserveQuota(uint64_t size) const { | 532 bool BlobMemoryController::CanReserveQuota(uint64_t size) const { |
| 433 // We check each size independently as a blob can't be constructed in both | 533 // We check each size independently as a blob can't be constructed in both |
| 434 // disk and memory. | 534 // disk and memory. |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 509 auto iterator = populated_memory_items_.Get(item->item_id()); | 609 auto iterator = populated_memory_items_.Get(item->item_id()); |
| 510 if (iterator == populated_memory_items_.end()) { | 610 if (iterator == populated_memory_items_.end()) { |
| 511 populated_memory_items_bytes_ += | 611 populated_memory_items_bytes_ += |
| 512 static_cast<size_t>(item->item()->length()); | 612 static_cast<size_t>(item->item()->length()); |
| 513 populated_memory_items_.Put(item->item_id(), item.get()); | 613 populated_memory_items_.Put(item->item_id(), item.get()); |
| 514 } | 614 } |
| 515 } | 615 } |
| 516 MaybeScheduleEvictionUntilSystemHealthy(); | 616 MaybeScheduleEvictionUntilSystemHealthy(); |
| 517 } | 617 } |
| 518 | 618 |
| 619 void BlobMemoryController::CalculateBlobStorageLimits() { | |
| 620 if (file_runner_) { | |
| 621 PostTaskAndReplyWithResult( | |
| 622 file_runner_.get(), FROM_HERE, | |
| 623 base::Bind(&CalculateBlobStorageLimitsImpl, blob_storage_dir_, true), | |
| 624 base::Bind(&BlobMemoryController::OnStorageLimitsCalculated, | |
| 625 weak_factory_.GetWeakPtr())); | |
| 626 } else { | |
| 627 OnStorageLimitsCalculated( | |
| 628 CalculateBlobStorageLimitsImpl(blob_storage_dir_, false)); | |
| 629 } | |
| 630 } | |
| 631 | |
| 632 base::WeakPtr<BlobMemoryController> BlobMemoryController::GetWeakPtr() { | |
| 633 return weak_factory_.GetWeakPtr(); | |
| 634 } | |
| 635 | |
| 636 void BlobMemoryController::OnStorageLimitsCalculated(BlobStorageLimits limits) { | |
| 637 if (!limits.IsValid() || manual_limits_set_) | |
| 638 return; | |
| 639 limits_ = limits; | |
| 640 } | |
| 641 | |
| 642 void BlobMemoryController::FreezeDiskUsage(uint64_t avail_disk) { | |
|
michaeln
2016/12/08 21:17:33
Is "Freeze" a misnomer? If i'm understanding the C
dmurph
2016/12/20 02:21:36
As per our offline discussion, this is a great ide
| |
| 643 limits_.max_blob_disk_space = disk_used_; | |
| 644 if (avail_disk > limits_.min_available_disk_space()) { | |
| 645 limits_.max_blob_disk_space += | |
| 646 avail_disk - limits_.min_available_disk_space(); | |
| 647 } | |
| 648 } | |
| 649 | |
| 519 base::WeakPtr<QuotaAllocationTask> BlobMemoryController::AppendMemoryTask( | 650 base::WeakPtr<QuotaAllocationTask> BlobMemoryController::AppendMemoryTask( |
| 520 uint64_t total_bytes_needed, | 651 uint64_t total_bytes_needed, |
| 521 std::vector<scoped_refptr<ShareableBlobDataItem>> unreserved_memory_items, | 652 std::vector<scoped_refptr<ShareableBlobDataItem>> unreserved_memory_items, |
| 522 const MemoryQuotaRequestCallback& done_callback) { | 653 const MemoryQuotaRequestCallback& done_callback) { |
| 523 DCHECK(file_paging_enabled_) | 654 DCHECK(file_paging_enabled_) |
| 524 << "Caller tried to reserve memory when CanReserveQuota(" | 655 << "Caller tried to reserve memory when CanReserveQuota(" |
| 525 << total_bytes_needed << ") would have returned false."; | 656 << total_bytes_needed << ") would have returned false."; |
| 526 | 657 |
| 527 pending_memory_quota_total_size_ += total_bytes_needed; | 658 pending_memory_quota_total_size_ += total_bytes_needed; |
| 528 pending_memory_quota_tasks_.push_back( | 659 pending_memory_quota_tasks_.push_back( |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 567 return total_items_size.ValueOrDie(); | 698 return total_items_size.ValueOrDie(); |
| 568 } | 699 } |
| 569 | 700 |
| 570 void BlobMemoryController::MaybeScheduleEvictionUntilSystemHealthy() { | 701 void BlobMemoryController::MaybeScheduleEvictionUntilSystemHealthy() { |
| 571 // Don't do eviction when others are happening, as we don't change our | 702 // Don't do eviction when others are happening, as we don't change our |
| 572 // pending_memory_quota_total_size_ value until after the paging files have | 703 // pending_memory_quota_total_size_ value until after the paging files have |
| 573 // been written. | 704 // been written. |
| 574 if (pending_evictions_ != 0 || !file_paging_enabled_) | 705 if (pending_evictions_ != 0 || !file_paging_enabled_) |
| 575 return; | 706 return; |
| 576 | 707 |
| 708 uint64_t total_memory_usage = | |
| 709 static_cast<uint64_t>(pending_memory_quota_total_size_) + | |
| 710 blob_memory_used_; | |
| 711 | |
| 577 // We try to page items to disk until our current system size + requested | 712 // We try to page items to disk until our current system size + requested |
| 578 // memory is below our size limit. | 713 // memory is below our size limit. |
| 579 while (pending_memory_quota_total_size_ + blob_memory_used_ > | 714 // Size limit is a lower |memory_limit_before_paging()| if we have disk space. |
| 580 limits_.memory_limit_before_paging()) { | 715 while (total_memory_usage > limits_.max_blob_disk_space || |
| 716 (disk_used_ < limits_.max_blob_disk_space && | |
| 717 total_memory_usage > limits_.memory_limit_before_paging())) { | |
| 581 // We only page when we have enough items to fill a whole page file. | 718 // We only page when we have enough items to fill a whole page file. |
| 582 if (populated_memory_items_bytes_ < limits_.min_page_file_size) | 719 if (populated_memory_items_bytes_ < limits_.min_page_file_size) |
| 583 break; | 720 break; |
| 584 DCHECK_LE(limits_.min_page_file_size, | 721 DCHECK_LE(limits_.min_page_file_size, |
| 585 static_cast<uint64_t>(blob_memory_used_)); | 722 static_cast<uint64_t>(blob_memory_used_)); |
| 586 | 723 |
| 587 std::vector<scoped_refptr<ShareableBlobDataItem>> items_to_swap; | 724 std::vector<scoped_refptr<ShareableBlobDataItem>> items_to_swap; |
| 588 size_t total_items_size = CollectItemsForEviction(&items_to_swap); | 725 size_t total_items_size = CollectItemsForEviction(&items_to_swap); |
| 589 if (total_items_size == 0) | 726 if (total_items_size == 0) |
| 590 break; | 727 break; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 622 weak_factory_.GetWeakPtr(), base::Passed(&file_reference), | 759 weak_factory_.GetWeakPtr(), base::Passed(&file_reference), |
| 623 base::Passed(&items_to_swap), total_items_size)); | 760 base::Passed(&items_to_swap), total_items_size)); |
| 624 } | 761 } |
| 625 RecordTracingCounters(); | 762 RecordTracingCounters(); |
| 626 } | 763 } |
| 627 | 764 |
| 628 void BlobMemoryController::OnEvictionComplete( | 765 void BlobMemoryController::OnEvictionComplete( |
| 629 scoped_refptr<ShareableFileReference> file_reference, | 766 scoped_refptr<ShareableFileReference> file_reference, |
| 630 std::vector<scoped_refptr<ShareableBlobDataItem>> items, | 767 std::vector<scoped_refptr<ShareableBlobDataItem>> items, |
| 631 size_t total_items_size, | 768 size_t total_items_size, |
| 632 FileCreationInfo result) { | 769 std::pair<FileCreationInfo, int64_t> result) { |
| 633 if (!file_paging_enabled_) | 770 if (!file_paging_enabled_) |
| 634 return; | 771 return; |
| 635 | 772 |
| 636 if (result.error != File::FILE_OK) { | 773 FileCreationInfo& file_info = std::get<0>(result); |
| 637 DisableFilePaging(result.error); | 774 int64_t avail_disk_space = std::get<1>(result); |
| 775 | |
| 776 if (file_info.error != File::FILE_OK) { | |
| 777 DisableFilePaging(file_info.error); | |
| 638 return; | 778 return; |
| 639 } | 779 } |
| 640 | 780 |
| 781 if (avail_disk_space != kUnknownDiskAvailability && | |
| 782 base::checked_cast<uint64_t>(avail_disk_space) <= | |
| 783 limits_.min_available_disk_space()) { | |
| 784 FreezeDiskUsage(static_cast<uint64_t>(avail_disk_space)); | |
| 785 } | |
| 786 | |
| 641 DCHECK_LT(0, pending_evictions_); | 787 DCHECK_LT(0, pending_evictions_); |
| 642 pending_evictions_--; | 788 pending_evictions_--; |
| 643 | 789 |
| 644 // Switch item from memory to the new file. | 790 // Switch item from memory to the new file. |
| 645 uint64_t offset = 0; | 791 uint64_t offset = 0; |
| 646 for (const scoped_refptr<ShareableBlobDataItem>& shareable_item : items) { | 792 for (const scoped_refptr<ShareableBlobDataItem>& shareable_item : items) { |
| 647 scoped_refptr<BlobDataItem> new_item( | 793 scoped_refptr<BlobDataItem> new_item( |
| 648 new BlobDataItem(base::WrapUnique(new DataElement()), file_reference)); | 794 new BlobDataItem(base::WrapUnique(new DataElement()), file_reference)); |
| 649 new_item->data_element_ptr()->SetToFilePathRange( | 795 new_item->data_element_ptr()->SetToFilePathRange( |
| 650 file_reference->path(), offset, shareable_item->item()->length(), | 796 file_reference->path(), offset, shareable_item->item()->length(), |
| 651 result.last_modified); | 797 file_info.last_modified); |
| 652 DCHECK(shareable_item->memory_allocation_); | 798 DCHECK(shareable_item->memory_allocation_); |
| 653 shareable_item->set_memory_allocation(nullptr); | 799 shareable_item->set_memory_allocation(nullptr); |
| 654 shareable_item->set_item(new_item); | 800 shareable_item->set_item(new_item); |
| 655 items_paging_to_file_.erase(shareable_item->item_id()); | 801 items_paging_to_file_.erase(shareable_item->item_id()); |
| 656 offset += shareable_item->item()->length(); | 802 offset += shareable_item->item()->length(); |
| 657 } | 803 } |
| 658 in_flight_memory_used_ -= total_items_size; | 804 in_flight_memory_used_ -= total_items_size; |
| 659 | 805 |
| 660 // We want callback on blobs up to the amount we've freed. | 806 // We want callback on blobs up to the amount we've freed. |
| 661 MaybeGrantPendingMemoryRequests(); | 807 MaybeGrantPendingMemoryRequests(); |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 741 MaybeGrantPendingMemoryRequests(); | 887 MaybeGrantPendingMemoryRequests(); |
| 742 } | 888 } |
| 743 | 889 |
| 744 void BlobMemoryController::OnBlobFileDelete(uint64_t size, | 890 void BlobMemoryController::OnBlobFileDelete(uint64_t size, |
| 745 const FilePath& path) { | 891 const FilePath& path) { |
| 746 DCHECK_LE(size, disk_used_); | 892 DCHECK_LE(size, disk_used_); |
| 747 disk_used_ -= size; | 893 disk_used_ -= size; |
| 748 } | 894 } |
| 749 | 895 |
| 750 } // namespace storage | 896 } // namespace storage |
| OLD | NEW |