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: | |
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. |
58 std::pair<std::vector<FileCreationInfo>, File::Error> CreateEmptyFiles( | 110 std::tuple<std::vector<FileCreationInfo>, File::Error, int64_t> |
59 const FilePath& blob_storage_dir, | 111 CreateEmptyFiles(const FilePath& blob_storage_dir, |
60 scoped_refptr<base::TaskRunner> file_task_runner, | 112 scoped_refptr<base::TaskRunner> file_task_runner, |
61 std::vector<base::FilePath> file_paths) { | 113 std::vector<base::FilePath> file_paths) { |
62 base::ThreadRestrictions::AssertIOAllowed(); | 114 base::ThreadRestrictions::AssertIOAllowed(); |
63 | 115 |
64 File::Error dir_create_status = CreateBlobDirectory(blob_storage_dir); | 116 File::Error dir_create_status = CreateBlobDirectory(blob_storage_dir); |
65 if (dir_create_status != File::FILE_OK) | 117 if (dir_create_status != File::FILE_OK) { |
66 return std::make_pair(std::vector<FileCreationInfo>(), dir_create_status); | 118 return std::make_tuple(std::vector<FileCreationInfo>(), dir_create_status, |
119 kUnknownDiskAvailability); | |
120 } | |
121 | |
122 int64_t free_disk_space = | |
123 base::SysInfo::AmountOfFreeDiskSpace(blob_storage_dir); | |
67 | 124 |
68 std::vector<FileCreationInfo> result; | 125 std::vector<FileCreationInfo> result; |
69 for (const base::FilePath& file_path : file_paths) { | 126 for (const base::FilePath& file_path : file_paths) { |
70 FileCreationInfo creation_info; | 127 FileCreationInfo creation_info; |
71 // Try to open our file. | 128 // Try to open our file. |
72 File file(file_path, File::FLAG_CREATE_ALWAYS | File::FLAG_WRITE); | 129 File file(file_path, File::FLAG_CREATE_ALWAYS | File::FLAG_WRITE); |
73 creation_info.path = std::move(file_path); | 130 creation_info.path = std::move(file_path); |
74 creation_info.file_deletion_runner = file_task_runner; | 131 creation_info.file_deletion_runner = file_task_runner; |
75 creation_info.error = file.error_details(); | 132 creation_info.error = file.error_details(); |
76 if (creation_info.error != File::FILE_OK) { | 133 if (creation_info.error != File::FILE_OK) { |
77 return std::make_pair(std::vector<FileCreationInfo>(), | 134 return std::make_tuple(std::vector<FileCreationInfo>(), |
78 creation_info.error); | 135 creation_info.error, free_disk_space); |
79 } | 136 } |
80 creation_info.file = std::move(file); | 137 creation_info.file = std::move(file); |
81 | 138 |
82 result.push_back(std::move(creation_info)); | 139 result.push_back(std::move(creation_info)); |
83 } | 140 } |
84 return std::make_pair(std::move(result), File::FILE_OK); | 141 return std::make_tuple(std::move(result), File::FILE_OK, free_disk_space); |
85 } | 142 } |
86 | 143 |
87 // Used to evict multiple memory items out to a single file. Caller must | 144 // Used to evict multiple memory items out to a single file. Caller must |
88 // populate file reference in returned FileCreationInfo. | 145 // populate file reference in returned FileCreationInfo. Also returns the disk |
89 FileCreationInfo CreateFileAndWriteItems( | 146 // space AFTER creating this file. |
147 std::pair<FileCreationInfo, int64_t> CreateFileAndWriteItems( | |
90 const FilePath& blob_storage_dir, | 148 const FilePath& blob_storage_dir, |
91 const FilePath& file_path, | 149 const FilePath& file_path, |
92 scoped_refptr<base::TaskRunner> file_task_runner, | 150 scoped_refptr<base::TaskRunner> file_task_runner, |
93 std::vector<DataElement*> items, | 151 std::vector<DataElement*> items, |
94 size_t total_size_bytes) { | 152 size_t total_size_bytes) { |
95 DCHECK_NE(0u, total_size_bytes); | 153 DCHECK_NE(0u, total_size_bytes); |
96 UMA_HISTOGRAM_MEMORY_KB("Storage.Blob.PageFileSize", total_size_bytes / 1024); | 154 UMA_HISTOGRAM_MEMORY_KB("Storage.Blob.PageFileSize", total_size_bytes / 1024); |
97 base::ThreadRestrictions::AssertIOAllowed(); | 155 base::ThreadRestrictions::AssertIOAllowed(); |
98 | 156 |
99 FileCreationInfo creation_info; | 157 FileCreationInfo creation_info; |
100 creation_info.file_deletion_runner = std::move(file_task_runner); | 158 creation_info.file_deletion_runner = std::move(file_task_runner); |
101 creation_info.error = CreateBlobDirectory(blob_storage_dir); | 159 creation_info.error = CreateBlobDirectory(blob_storage_dir); |
102 if (creation_info.error != File::FILE_OK) | 160 if (creation_info.error != File::FILE_OK) |
103 return creation_info; | 161 return std::make_pair(std::move(creation_info), kUnknownDiskAvailability); |
162 | |
163 int64_t free_disk_space = | |
164 base::SysInfo::AmountOfFreeDiskSpace(blob_storage_dir); | |
165 int64_t disk_availability = | |
166 free_disk_space == kUnknownDiskAvailability | |
167 ? kUnknownDiskAvailability | |
168 : free_disk_space - static_cast<int64_t>(total_size_bytes); | |
104 | 169 |
105 // Create the page file. | 170 // Create the page file. |
106 File file(file_path, File::FLAG_CREATE_ALWAYS | File::FLAG_WRITE); | 171 File file(file_path, File::FLAG_CREATE_ALWAYS | File::FLAG_WRITE); |
107 creation_info.path = file_path; | 172 creation_info.path = file_path; |
108 creation_info.error = file.error_details(); | 173 creation_info.error = file.error_details(); |
109 if (creation_info.error != File::FILE_OK) | 174 if (creation_info.error != File::FILE_OK) |
110 return creation_info; | 175 return std::make_pair(std::move(creation_info), disk_availability); |
111 | 176 |
112 // Write data. | 177 // Write data. |
113 file.SetLength(total_size_bytes); | 178 file.SetLength(total_size_bytes); |
114 int bytes_written = 0; | 179 int bytes_written = 0; |
115 for (DataElement* element : items) { | 180 for (DataElement* element : items) { |
116 DCHECK_EQ(DataElement::TYPE_BYTES, element->type()); | 181 DCHECK_EQ(DataElement::TYPE_BYTES, element->type()); |
117 size_t length = base::checked_cast<size_t>(element->length()); | 182 size_t length = base::checked_cast<size_t>(element->length()); |
118 size_t bytes_left = length; | 183 size_t bytes_left = length; |
119 while (bytes_left > 0) { | 184 while (bytes_left > 0) { |
120 bytes_written = | 185 bytes_written = |
121 file.WriteAtCurrentPos(element->bytes() + (length - bytes_left), | 186 file.WriteAtCurrentPos(element->bytes() + (length - bytes_left), |
122 base::saturated_cast<int>(bytes_left)); | 187 base::saturated_cast<int>(bytes_left)); |
123 if (bytes_written < 0) | 188 if (bytes_written < 0) |
124 break; | 189 break; |
125 DCHECK_LE(static_cast<size_t>(bytes_written), bytes_left); | 190 DCHECK_LE(static_cast<size_t>(bytes_written), bytes_left); |
126 bytes_left -= bytes_written; | 191 bytes_left -= bytes_written; |
127 } | 192 } |
128 if (bytes_written < 0) | 193 if (bytes_written < 0) |
129 break; | 194 break; |
130 } | 195 } |
131 if (!file.Flush()) { | 196 if (!file.Flush()) { |
132 creation_info.error = File::FILE_ERROR_FAILED; | 197 creation_info.error = File::FILE_ERROR_FAILED; |
133 return creation_info; | 198 return std::make_pair(std::move(creation_info), disk_availability); |
134 } | 199 } |
135 | 200 |
136 File::Info info; | 201 File::Info info; |
137 bool success = file.GetInfo(&info); | 202 bool success = file.GetInfo(&info); |
138 creation_info.error = | 203 creation_info.error = |
139 bytes_written < 0 || !success ? File::FILE_ERROR_FAILED : File::FILE_OK; | 204 bytes_written < 0 || !success ? File::FILE_ERROR_FAILED : File::FILE_OK; |
140 creation_info.last_modified = info.last_modified; | 205 creation_info.last_modified = info.last_modified; |
141 return creation_info; | 206 return std::make_pair(std::move(creation_info), disk_availability); |
142 } | 207 } |
143 | 208 |
144 uint64_t GetTotalSizeAndFileSizes( | 209 uint64_t GetTotalSizeAndFileSizes( |
145 const std::vector<scoped_refptr<ShareableBlobDataItem>>& | 210 const std::vector<scoped_refptr<ShareableBlobDataItem>>& |
146 unreserved_file_items, | 211 unreserved_file_items, |
147 std::vector<uint64_t>* file_sizes_output) { | 212 std::vector<uint64_t>* file_sizes_output) { |
148 uint64_t total_size_output = 0; | 213 uint64_t total_size_output = 0; |
149 base::SmallMap<std::map<uint64_t, uint64_t>> file_id_to_sizes; | 214 base::SmallMap<std::map<uint64_t, uint64_t>> file_id_to_sizes; |
150 for (const auto& item : unreserved_file_items) { | 215 for (const auto& item : unreserved_file_items) { |
151 const DataElement& element = item->item()->data_element(); | 216 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, | 353 base::Bind(&BlobMemoryController::OnBlobFileDelete, |
289 controller_->weak_factory_.GetWeakPtr(), file_sizes[i])); | 354 controller_->weak_factory_.GetWeakPtr(), file_sizes[i])); |
290 } | 355 } |
291 | 356 |
292 // Send file creation task to file thread. | 357 // Send file creation task to file thread. |
293 base::PostTaskAndReplyWithResult( | 358 base::PostTaskAndReplyWithResult( |
294 controller_->file_runner_.get(), FROM_HERE, | 359 controller_->file_runner_.get(), FROM_HERE, |
295 base::Bind(&CreateEmptyFiles, controller_->blob_storage_dir_, | 360 base::Bind(&CreateEmptyFiles, controller_->blob_storage_dir_, |
296 controller_->file_runner_, base::Passed(&file_paths)), | 361 controller_->file_runner_, base::Passed(&file_paths)), |
297 base::Bind(&FileQuotaAllocationTask::OnCreateEmptyFiles, | 362 base::Bind(&FileQuotaAllocationTask::OnCreateEmptyFiles, |
298 weak_factory_.GetWeakPtr(), base::Passed(&references))); | 363 weak_factory_.GetWeakPtr(), base::Passed(&references), |
364 allocation_size_)); | |
299 controller_->RecordTracingCounters(); | 365 controller_->RecordTracingCounters(); |
300 } | 366 } |
301 ~FileQuotaAllocationTask() override {} | 367 ~FileQuotaAllocationTask() override {} |
302 | 368 |
303 void RunDoneCallback(std::vector<FileCreationInfo> file_info, bool success) { | 369 void RunDoneCallback(std::vector<FileCreationInfo> file_info, bool success) { |
304 // Make sure we clear the weak pointers we gave to the caller beforehand. | 370 // Make sure we clear the weak pointers we gave to the caller beforehand. |
305 weak_factory_.InvalidateWeakPtrs(); | 371 weak_factory_.InvalidateWeakPtrs(); |
306 | 372 |
307 // We want to destroy this object on the exit of this method if we were | 373 // We want to destroy this object on the exit of this method if we were |
308 // successful. | 374 // successful. |
(...skipping 14 matching lines...) Expand all Loading... | |
323 } | 389 } |
324 | 390 |
325 void Cancel() override { | 391 void Cancel() override { |
326 // This call destroys this object. We rely on ShareableFileReference's | 392 // This call destroys this object. We rely on ShareableFileReference's |
327 // final release callback for disk_usage_ accounting. | 393 // final release callback for disk_usage_ accounting. |
328 controller_->pending_file_quota_tasks_.erase(my_list_position_); | 394 controller_->pending_file_quota_tasks_.erase(my_list_position_); |
329 } | 395 } |
330 | 396 |
331 void OnCreateEmptyFiles( | 397 void OnCreateEmptyFiles( |
332 std::vector<scoped_refptr<ShareableFileReference>> references, | 398 std::vector<scoped_refptr<ShareableFileReference>> references, |
333 std::pair<std::vector<FileCreationInfo>, File::Error> files_and_error) { | 399 uint64_t new_files_total_size, |
334 auto& files = files_and_error.first; | 400 std::tuple<std::vector<FileCreationInfo>, File::Error, int64_t> result) { |
401 std::vector<FileCreationInfo> files = std::move(std::get<0>(result)); | |
402 File::Error error = std::get<1>(result); | |
403 int64_t avail_disk_space = std::get<2>(result); | |
335 if (files.empty()) { | 404 if (files.empty()) { |
405 DCHECK_NE(error, File::FILE_OK); | |
336 DCHECK_GE(controller_->disk_used_, allocation_size_); | 406 DCHECK_GE(controller_->disk_used_, allocation_size_); |
337 controller_->disk_used_ -= allocation_size_; | 407 controller_->disk_used_ -= allocation_size_; |
338 // This will call our callback and delete the object correctly. | 408 // This will call our callback and delete the object correctly. |
339 controller_->DisableFilePaging(files_and_error.second); | 409 controller_->DisableFilePaging(error); |
340 return; | 410 return; |
341 } | 411 } |
412 // The allocation won't fit at all. Freeze the disk and cancel this request. | |
413 if (avail_disk_space != kUnknownDiskAvailability && | |
414 base::checked_cast<uint64_t>(avail_disk_space) < new_files_total_size) { | |
415 DCHECK_GE(controller_->disk_used_, allocation_size_); | |
416 controller_->disk_used_ -= allocation_size_; | |
417 controller_->FreezeDiskUsage(static_cast<uint64_t>(avail_disk_space)); | |
418 file_runner_->PostTask(FROM_HERE, | |
419 base::Bind(&DeleteFiles, base::Passed(&files))); | |
420 std::unique_ptr<FileQuotaAllocationTask> this_object = | |
421 std::move(*my_list_position_); | |
422 controller_->pending_file_quota_tasks_.erase(my_list_position_); | |
423 RunDoneCallback(std::vector<FileCreationInfo>(), false); | |
424 return; | |
425 } | |
426 // Freeze disk if we're getting close. | |
427 if (avail_disk_space != kUnknownDiskAvailability && | |
428 avail_disk_space - new_files_total_size <= | |
429 controller_->limits().min_available_disk_space()) { | |
430 controller_->FreezeDiskUsage(base::checked_cast<uint64_t>( | |
431 avail_disk_space - new_files_total_size)); | |
432 } | |
342 DCHECK_EQ(files.size(), references.size()); | 433 DCHECK_EQ(files.size(), references.size()); |
343 for (size_t i = 0; i < files.size(); i++) { | 434 for (size_t i = 0; i < files.size(); i++) { |
344 files[i].file_reference = std::move(references[i]); | 435 files[i].file_reference = std::move(references[i]); |
345 } | 436 } |
346 RunDoneCallback(std::move(files), true); | 437 RunDoneCallback(std::move(files), true); |
347 } | 438 } |
348 | 439 |
349 // The my_list_position_ iterator is stored so that we can remove ourself | 440 // The my_list_position_ iterator is stored so that we can remove ourself |
350 // from the task list when we are cancelled. | 441 // from the task list when we are cancelled. |
351 void set_my_list_position( | 442 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 { | 501 uint64_t total_transportation_bytes) const { |
411 if (total_transportation_bytes == 0) | 502 if (total_transportation_bytes == 0) |
412 return Strategy::NONE_NEEDED; | 503 return Strategy::NONE_NEEDED; |
413 if (!CanReserveQuota(total_transportation_bytes)) | 504 if (!CanReserveQuota(total_transportation_bytes)) |
414 return Strategy::TOO_LARGE; | 505 return Strategy::TOO_LARGE; |
415 | 506 |
416 // Handle the case where we have all the bytes preemptively transported, and | 507 // Handle the case where we have all the bytes preemptively transported, and |
417 // we can also fit them. | 508 // we can also fit them. |
418 if (preemptive_transported_bytes == total_transportation_bytes && | 509 if (preemptive_transported_bytes == total_transportation_bytes && |
419 pending_memory_quota_tasks_.empty() && | 510 pending_memory_quota_tasks_.empty() && |
420 preemptive_transported_bytes < GetAvailableMemoryForBlobs()) { | 511 preemptive_transported_bytes <= GetAvailableMemoryForBlobs()) { |
421 return Strategy::NONE_NEEDED; | 512 return Strategy::NONE_NEEDED; |
422 } | 513 } |
423 if (file_paging_enabled_ && | 514 if (file_paging_enabled_ && |
424 (total_transportation_bytes > limits_.memory_limit_before_paging())) { | 515 total_transportation_bytes <= GetAvailableFileSpaceForBlobs() && |
516 total_transportation_bytes > limits_.memory_limit_before_paging()) { | |
425 return Strategy::FILE; | 517 return Strategy::FILE; |
426 } | 518 } |
427 if (total_transportation_bytes > limits_.max_ipc_memory_size) | 519 if (total_transportation_bytes > limits_.max_ipc_memory_size) |
428 return Strategy::SHARED_MEMORY; | 520 return Strategy::SHARED_MEMORY; |
429 return Strategy::IPC; | 521 return Strategy::IPC; |
430 } | 522 } |
431 | 523 |
432 bool BlobMemoryController::CanReserveQuota(uint64_t size) const { | 524 bool BlobMemoryController::CanReserveQuota(uint64_t size) const { |
433 // We check each size independently as a blob can't be constructed in both | 525 // We check each size independently as a blob can't be constructed in both |
434 // disk and memory. | 526 // 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()); | 601 auto iterator = populated_memory_items_.Get(item->item_id()); |
510 if (iterator == populated_memory_items_.end()) { | 602 if (iterator == populated_memory_items_.end()) { |
511 populated_memory_items_bytes_ += | 603 populated_memory_items_bytes_ += |
512 static_cast<size_t>(item->item()->length()); | 604 static_cast<size_t>(item->item()->length()); |
513 populated_memory_items_.Put(item->item_id(), item.get()); | 605 populated_memory_items_.Put(item->item_id(), item.get()); |
514 } | 606 } |
515 } | 607 } |
516 MaybeScheduleEvictionUntilSystemHealthy(); | 608 MaybeScheduleEvictionUntilSystemHealthy(); |
517 } | 609 } |
518 | 610 |
611 void BlobMemoryController::CalculateBlobStorageLimits() { | |
612 if (file_runner_) { | |
613 PostTaskAndReplyWithResult( | |
614 file_runner_.get(), FROM_HERE, | |
615 base::Bind(&CalculateBlobStorageLimitsImpl, blob_storage_dir_, true), | |
616 base::Bind(&BlobMemoryController::OnStorageLimitsCalculated, | |
617 weak_factory_.GetWeakPtr())); | |
618 } else { | |
michaeln
2016/12/08 21:17:33
it'd be nice if this branch wasn't needed, i guess
dmurph
2016/12/20 02:21:36
Chatted about. This is to differentiate between in
| |
619 OnStorageLimitsCalculated( | |
620 CalculateBlobStorageLimitsImpl(blob_storage_dir_, false)); | |
621 } | |
622 } | |
623 | |
624 base::WeakPtr<BlobMemoryController> BlobMemoryController::GetWeakPtr() { | |
625 return weak_factory_.GetWeakPtr(); | |
626 } | |
627 | |
628 void BlobMemoryController::OnStorageLimitsCalculated(BlobStorageLimits limits) { | |
629 if (!limits.IsValid() || manual_limits_set_) | |
630 return; | |
631 limits_ = limits; | |
632 } | |
633 | |
634 void BlobMemoryController::FreezeDiskUsage(uint64_t avail_disk) { | |
635 limits_.max_blob_disk_space = disk_used_; | |
636 if (avail_disk > limits_.min_available_disk_space()) { | |
637 limits_.max_blob_disk_space += | |
638 avail_disk - limits_.min_available_disk_space(); | |
639 } | |
640 } | |
641 | |
519 base::WeakPtr<QuotaAllocationTask> BlobMemoryController::AppendMemoryTask( | 642 base::WeakPtr<QuotaAllocationTask> BlobMemoryController::AppendMemoryTask( |
520 uint64_t total_bytes_needed, | 643 uint64_t total_bytes_needed, |
521 std::vector<scoped_refptr<ShareableBlobDataItem>> unreserved_memory_items, | 644 std::vector<scoped_refptr<ShareableBlobDataItem>> unreserved_memory_items, |
522 const MemoryQuotaRequestCallback& done_callback) { | 645 const MemoryQuotaRequestCallback& done_callback) { |
523 DCHECK(file_paging_enabled_) | 646 DCHECK(file_paging_enabled_) |
524 << "Caller tried to reserve memory when CanReserveQuota(" | 647 << "Caller tried to reserve memory when CanReserveQuota(" |
525 << total_bytes_needed << ") would have returned false."; | 648 << total_bytes_needed << ") would have returned false."; |
526 | 649 |
527 pending_memory_quota_total_size_ += total_bytes_needed; | 650 pending_memory_quota_total_size_ += total_bytes_needed; |
528 pending_memory_quota_tasks_.push_back( | 651 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(); | 690 return total_items_size.ValueOrDie(); |
568 } | 691 } |
569 | 692 |
570 void BlobMemoryController::MaybeScheduleEvictionUntilSystemHealthy() { | 693 void BlobMemoryController::MaybeScheduleEvictionUntilSystemHealthy() { |
571 // Don't do eviction when others are happening, as we don't change our | 694 // 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 | 695 // pending_memory_quota_total_size_ value until after the paging files have |
573 // been written. | 696 // been written. |
574 if (pending_evictions_ != 0 || !file_paging_enabled_) | 697 if (pending_evictions_ != 0 || !file_paging_enabled_) |
575 return; | 698 return; |
576 | 699 |
700 uint64_t total_memory_usage = | |
701 static_cast<uint64_t>(pending_memory_quota_total_size_) + | |
702 blob_memory_used_; | |
703 | |
577 // We try to page items to disk until our current system size + requested | 704 // We try to page items to disk until our current system size + requested |
578 // memory is below our size limit. | 705 // memory is below our size limit. |
579 while (pending_memory_quota_total_size_ + blob_memory_used_ > | 706 // Size limit is a lower |memory_limit_before_paging()| if we have disk space. |
580 limits_.memory_limit_before_paging()) { | 707 while (total_memory_usage > limits_.max_blob_disk_space || |
708 (disk_used_ < limits_.max_blob_disk_space && | |
709 total_memory_usage > limits_.memory_limit_before_paging())) { | |
581 // We only page when we have enough items to fill a whole page file. | 710 // 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) | 711 if (populated_memory_items_bytes_ < limits_.min_page_file_size) |
583 break; | 712 break; |
584 DCHECK_LE(limits_.min_page_file_size, | 713 DCHECK_LE(limits_.min_page_file_size, |
585 static_cast<uint64_t>(blob_memory_used_)); | 714 static_cast<uint64_t>(blob_memory_used_)); |
586 | 715 |
587 std::vector<scoped_refptr<ShareableBlobDataItem>> items_to_swap; | 716 std::vector<scoped_refptr<ShareableBlobDataItem>> items_to_swap; |
588 size_t total_items_size = CollectItemsForEviction(&items_to_swap); | 717 size_t total_items_size = CollectItemsForEviction(&items_to_swap); |
589 if (total_items_size == 0) | 718 if (total_items_size == 0) |
590 break; | 719 break; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
622 weak_factory_.GetWeakPtr(), base::Passed(&file_reference), | 751 weak_factory_.GetWeakPtr(), base::Passed(&file_reference), |
623 base::Passed(&items_to_swap), total_items_size)); | 752 base::Passed(&items_to_swap), total_items_size)); |
624 } | 753 } |
625 RecordTracingCounters(); | 754 RecordTracingCounters(); |
626 } | 755 } |
627 | 756 |
628 void BlobMemoryController::OnEvictionComplete( | 757 void BlobMemoryController::OnEvictionComplete( |
629 scoped_refptr<ShareableFileReference> file_reference, | 758 scoped_refptr<ShareableFileReference> file_reference, |
630 std::vector<scoped_refptr<ShareableBlobDataItem>> items, | 759 std::vector<scoped_refptr<ShareableBlobDataItem>> items, |
631 size_t total_items_size, | 760 size_t total_items_size, |
632 FileCreationInfo result) { | 761 std::pair<FileCreationInfo, int64_t> result) { |
633 if (!file_paging_enabled_) | 762 if (!file_paging_enabled_) |
634 return; | 763 return; |
635 | 764 |
636 if (result.error != File::FILE_OK) { | 765 FileCreationInfo& file_info = std::get<0>(result); |
637 DisableFilePaging(result.error); | 766 int64_t avail_disk_space = std::get<1>(result); |
767 | |
768 if (file_info.error != File::FILE_OK) { | |
769 DisableFilePaging(file_info.error); | |
638 return; | 770 return; |
639 } | 771 } |
640 | 772 |
773 if (avail_disk_space != kUnknownDiskAvailability && | |
774 base::checked_cast<uint64_t>(avail_disk_space) <= | |
775 limits_.min_available_disk_space()) { | |
776 FreezeDiskUsage(static_cast<uint64_t>(avail_disk_space)); | |
777 } | |
778 | |
641 DCHECK_LT(0, pending_evictions_); | 779 DCHECK_LT(0, pending_evictions_); |
642 pending_evictions_--; | 780 pending_evictions_--; |
643 | 781 |
644 // Switch item from memory to the new file. | 782 // Switch item from memory to the new file. |
645 uint64_t offset = 0; | 783 uint64_t offset = 0; |
646 for (const scoped_refptr<ShareableBlobDataItem>& shareable_item : items) { | 784 for (const scoped_refptr<ShareableBlobDataItem>& shareable_item : items) { |
647 scoped_refptr<BlobDataItem> new_item( | 785 scoped_refptr<BlobDataItem> new_item( |
648 new BlobDataItem(base::WrapUnique(new DataElement()), file_reference)); | 786 new BlobDataItem(base::WrapUnique(new DataElement()), file_reference)); |
649 new_item->data_element_ptr()->SetToFilePathRange( | 787 new_item->data_element_ptr()->SetToFilePathRange( |
650 file_reference->path(), offset, shareable_item->item()->length(), | 788 file_reference->path(), offset, shareable_item->item()->length(), |
651 result.last_modified); | 789 file_info.last_modified); |
652 DCHECK(shareable_item->memory_allocation_); | 790 DCHECK(shareable_item->memory_allocation_); |
653 shareable_item->set_memory_allocation(nullptr); | 791 shareable_item->set_memory_allocation(nullptr); |
654 shareable_item->set_item(new_item); | 792 shareable_item->set_item(new_item); |
655 items_paging_to_file_.erase(shareable_item->item_id()); | 793 items_paging_to_file_.erase(shareable_item->item_id()); |
656 offset += shareable_item->item()->length(); | 794 offset += shareable_item->item()->length(); |
657 } | 795 } |
658 in_flight_memory_used_ -= total_items_size; | 796 in_flight_memory_used_ -= total_items_size; |
659 | 797 |
660 // We want callback on blobs up to the amount we've freed. | 798 // We want callback on blobs up to the amount we've freed. |
661 MaybeGrantPendingMemoryRequests(); | 799 MaybeGrantPendingMemoryRequests(); |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
741 MaybeGrantPendingMemoryRequests(); | 879 MaybeGrantPendingMemoryRequests(); |
742 } | 880 } |
743 | 881 |
744 void BlobMemoryController::OnBlobFileDelete(uint64_t size, | 882 void BlobMemoryController::OnBlobFileDelete(uint64_t size, |
745 const FilePath& path) { | 883 const FilePath& path) { |
746 DCHECK_LE(size, disk_used_); | 884 DCHECK_LE(size, disk_used_); |
747 disk_used_ -= size; | 885 disk_used_ -= size; |
748 } | 886 } |
749 | 887 |
750 } // namespace storage | 888 } // namespace storage |
OLD | NEW |