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

Side by Side Diff: storage/browser/blob/blob_memory_controller.cc

Issue 2552153002: [BlobStorage] Enabling disk paging and direct storage. (Closed)
Patch Set: Added an early-exit clause so files don't get created unnecessarily Created 4 years 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
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698