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 constexpr int64_t kUnknownDiskAvailability = -1ll; | |
43 constexpr uint64_t kMegabyte = 1024ull * 1024; | |
44 | |
40 using FileCreationInfo = BlobMemoryController::FileCreationInfo; | 45 using FileCreationInfo = BlobMemoryController::FileCreationInfo; |
41 using MemoryAllocation = BlobMemoryController::MemoryAllocation; | 46 using MemoryAllocation = BlobMemoryController::MemoryAllocation; |
42 using QuotaAllocationTask = BlobMemoryController::QuotaAllocationTask; | 47 using QuotaAllocationTask = BlobMemoryController::QuotaAllocationTask; |
48 using DiskSpaceFuncPtr = BlobMemoryController::DiskSpaceFuncPtr; | |
49 | |
50 // CrOS: | |
51 // * Ram - 20% | |
52 // * Disk - 50% | |
53 // Note: The disk is the user partition, so the operating system can still | |
54 // function if this is full. | |
55 // Android: | |
56 // * RAM - 20% | |
57 // * Disk - 5% | |
58 // Desktop: | |
59 // * Ram - 20%, or 2 GB if x64. | |
60 // * Disk - 10% | |
61 BlobStorageLimits CalculateBlobStorageLimitsImpl(const FilePath& storage_dir, | |
62 bool disk_enabled) { | |
63 int64_t disk_size = | |
64 disk_enabled ? base::SysInfo::AmountOfTotalDiskSpace(storage_dir) : 0ull; | |
65 int64_t memory_size = base::SysInfo::AmountOfPhysicalMemory(); | |
66 | |
67 BlobStorageLimits limits; | |
68 | |
69 // Don't do specialty configuration for error size (-1). | |
70 if (memory_size > 0) { | |
71 #if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && defined(ARCH_CPU_64_BITS) | |
72 constexpr size_t kTwoGigabytes = 2ull * 1024 * 1024 * 1024; | |
73 limits.max_blob_in_memory_space = kTwoGigabytes; | |
74 #else | |
75 limits.max_blob_in_memory_space = static_cast<size_t>(memory_size / 5ll); | |
76 #endif | |
77 } | |
78 | |
79 // Don't do specialty configuration for error size (-1). Allow no disk. | |
80 if (disk_size >= 0) { | |
81 #if defined(OS_CHROMEOS) | |
82 limits.desired_max_disk_space = static_cast<uint64_t>(disk_size / 2ll); | |
83 #elif defined(OS_ANDROID) | |
84 limits.desired_max_disk_space = static_cast<uint64_t>(disk_size / 20ll); | |
85 #else | |
86 limits.desired_max_disk_space = static_cast<uint64_t>(disk_size / 10ll); | |
87 #endif | |
88 } | |
89 UMA_HISTOGRAM_COUNTS_1M("Storage.Blob.MaxDiskSpace", | |
90 limits.desired_max_disk_space / kMegabyte); | |
91 limits.effective_max_disk_space = limits.desired_max_disk_space; | |
92 | |
93 return limits; | |
94 } | |
43 | 95 |
44 File::Error CreateBlobDirectory(const FilePath& blob_storage_dir) { | 96 File::Error CreateBlobDirectory(const FilePath& blob_storage_dir) { |
45 File::Error error = File::FILE_OK; | 97 File::Error error = File::FILE_OK; |
46 base::CreateDirectoryAndGetError(blob_storage_dir, &error); | 98 base::CreateDirectoryAndGetError(blob_storage_dir, &error); |
47 UMA_HISTOGRAM_ENUMERATION("Storage.Blob.CreateDirectoryResult", -error, | 99 UMA_HISTOGRAM_ENUMERATION("Storage.Blob.CreateDirectoryResult", -error, |
48 -File::FILE_ERROR_MAX); | 100 -File::FILE_ERROR_MAX); |
49 DLOG_IF(ERROR, error != File::FILE_OK) | 101 DLOG_IF(ERROR, error != File::FILE_OK) |
50 << "Error creating blob storage directory: " << error; | 102 << "Error creating blob storage directory: " << error; |
51 return error; | 103 return error; |
52 } | 104 } |
53 | 105 |
54 void DestructFile(File infos_without_references) {} | 106 void DestructFile(File infos_without_references) {} |
55 | 107 |
108 void DeleteFiles(std::vector<FileCreationInfo> files) { | |
109 for (FileCreationInfo& file_info : files) { | |
110 file_info.file.Close(); | |
111 base::DeleteFile(file_info.path, false); | |
112 } | |
113 } | |
114 | |
115 struct EmptyFilesResult { | |
116 EmptyFilesResult() {} | |
117 EmptyFilesResult(std::vector<FileCreationInfo> files, | |
118 File::Error file_error, | |
119 int64_t disk_availability) | |
120 : files(std::move(files)), | |
121 file_error(file_error), | |
122 disk_availability(disk_availability) {} | |
123 ~EmptyFilesResult() {} | |
124 EmptyFilesResult(EmptyFilesResult&& o) = default; | |
125 EmptyFilesResult& operator=(EmptyFilesResult&& other) = default; | |
126 | |
127 std::vector<FileCreationInfo> files; | |
128 File::Error file_error = File::FILE_ERROR_FAILED; | |
129 int64_t disk_availability = 0; | |
130 }; | |
131 | |
56 // Used for new unpopulated file items. Caller must populate file reference in | 132 // Used for new unpopulated file items. Caller must populate file reference in |
57 // returned FileCreationInfos. | 133 // returned FileCreationInfos. Also returns the currently available disk space |
58 std::pair<std::vector<FileCreationInfo>, File::Error> CreateEmptyFiles( | 134 // (without the future size of these files). |
135 EmptyFilesResult CreateEmptyFiles( | |
59 const FilePath& blob_storage_dir, | 136 const FilePath& blob_storage_dir, |
137 DiskSpaceFuncPtr disk_space_function, | |
60 scoped_refptr<base::TaskRunner> file_task_runner, | 138 scoped_refptr<base::TaskRunner> file_task_runner, |
61 std::vector<base::FilePath> file_paths) { | 139 std::vector<base::FilePath> file_paths) { |
62 base::ThreadRestrictions::AssertIOAllowed(); | 140 base::ThreadRestrictions::AssertIOAllowed(); |
63 | 141 |
64 File::Error dir_create_status = CreateBlobDirectory(blob_storage_dir); | 142 File::Error dir_create_status = CreateBlobDirectory(blob_storage_dir); |
65 if (dir_create_status != File::FILE_OK) | 143 if (dir_create_status != File::FILE_OK) { |
66 return std::make_pair(std::vector<FileCreationInfo>(), dir_create_status); | 144 return EmptyFilesResult(std::vector<FileCreationInfo>(), dir_create_status, |
145 kUnknownDiskAvailability); | |
146 } | |
147 | |
148 int64_t free_disk_space = disk_space_function(blob_storage_dir); | |
67 | 149 |
68 std::vector<FileCreationInfo> result; | 150 std::vector<FileCreationInfo> result; |
69 for (const base::FilePath& file_path : file_paths) { | 151 for (const base::FilePath& file_path : file_paths) { |
70 FileCreationInfo creation_info; | 152 FileCreationInfo creation_info; |
71 // Try to open our file. | 153 // Try to open our file. |
72 File file(file_path, File::FLAG_CREATE_ALWAYS | File::FLAG_WRITE); | 154 File file(file_path, File::FLAG_CREATE_ALWAYS | File::FLAG_WRITE); |
73 creation_info.path = std::move(file_path); | 155 creation_info.path = std::move(file_path); |
74 creation_info.file_deletion_runner = file_task_runner; | 156 creation_info.file_deletion_runner = file_task_runner; |
75 creation_info.error = file.error_details(); | 157 creation_info.error = file.error_details(); |
76 if (creation_info.error != File::FILE_OK) { | 158 if (creation_info.error != File::FILE_OK) { |
77 return std::make_pair(std::vector<FileCreationInfo>(), | 159 return EmptyFilesResult(std::vector<FileCreationInfo>(), |
78 creation_info.error); | 160 creation_info.error, free_disk_space); |
79 } | 161 } |
80 creation_info.file = std::move(file); | 162 creation_info.file = std::move(file); |
81 | 163 |
82 result.push_back(std::move(creation_info)); | 164 result.push_back(std::move(creation_info)); |
83 } | 165 } |
84 return std::make_pair(std::move(result), File::FILE_OK); | 166 return EmptyFilesResult(std::move(result), File::FILE_OK, free_disk_space); |
85 } | 167 } |
86 | 168 |
87 // Used to evict multiple memory items out to a single file. Caller must | 169 // Used to evict multiple memory items out to a single file. Caller must |
88 // populate file reference in returned FileCreationInfo. | 170 // populate file reference in returned FileCreationInfo. Also returns the free |
89 FileCreationInfo CreateFileAndWriteItems( | 171 // disk space AFTER creating this file. |
172 std::pair<FileCreationInfo, int64_t> CreateFileAndWriteItems( | |
90 const FilePath& blob_storage_dir, | 173 const FilePath& blob_storage_dir, |
174 DiskSpaceFuncPtr disk_space_function, | |
91 const FilePath& file_path, | 175 const FilePath& file_path, |
92 scoped_refptr<base::TaskRunner> file_task_runner, | 176 scoped_refptr<base::TaskRunner> file_task_runner, |
93 std::vector<DataElement*> items, | 177 std::vector<DataElement*> items, |
94 size_t total_size_bytes) { | 178 size_t total_size_bytes) { |
95 DCHECK_NE(0u, total_size_bytes); | 179 DCHECK_NE(0u, total_size_bytes); |
96 UMA_HISTOGRAM_MEMORY_KB("Storage.Blob.PageFileSize", total_size_bytes / 1024); | 180 UMA_HISTOGRAM_MEMORY_KB("Storage.Blob.PageFileSize", total_size_bytes / 1024); |
97 base::ThreadRestrictions::AssertIOAllowed(); | 181 base::ThreadRestrictions::AssertIOAllowed(); |
98 | 182 |
99 FileCreationInfo creation_info; | 183 FileCreationInfo creation_info; |
100 creation_info.file_deletion_runner = std::move(file_task_runner); | 184 creation_info.file_deletion_runner = std::move(file_task_runner); |
101 creation_info.error = CreateBlobDirectory(blob_storage_dir); | 185 creation_info.error = CreateBlobDirectory(blob_storage_dir); |
102 if (creation_info.error != File::FILE_OK) | 186 if (creation_info.error != File::FILE_OK) |
103 return creation_info; | 187 return std::make_pair(std::move(creation_info), kUnknownDiskAvailability); |
188 | |
189 int64_t free_disk_space = disk_space_function(blob_storage_dir); | |
190 | |
191 // Fail early instead of creating the files if we fill the disk. | |
192 if (free_disk_space != kUnknownDiskAvailability && | |
193 free_disk_space < static_cast<int64_t>(total_size_bytes)) { | |
194 creation_info.error = File::FILE_ERROR_NO_SPACE; | |
195 return std::make_pair(std::move(creation_info), free_disk_space); | |
196 } | |
197 int64_t disk_availability = | |
198 free_disk_space == kUnknownDiskAvailability | |
199 ? kUnknownDiskAvailability | |
200 : free_disk_space - static_cast<int64_t>(total_size_bytes); | |
104 | 201 |
105 // Create the page file. | 202 // Create the page file. |
106 File file(file_path, File::FLAG_CREATE_ALWAYS | File::FLAG_WRITE); | 203 File file(file_path, File::FLAG_CREATE_ALWAYS | File::FLAG_WRITE); |
107 creation_info.path = file_path; | 204 creation_info.path = file_path; |
108 creation_info.error = file.error_details(); | 205 creation_info.error = file.error_details(); |
109 if (creation_info.error != File::FILE_OK) | 206 if (creation_info.error != File::FILE_OK) |
110 return creation_info; | 207 return std::make_pair(std::move(creation_info), free_disk_space); |
111 | 208 |
112 // Write data. | 209 // Write data. |
113 file.SetLength(total_size_bytes); | 210 file.SetLength(total_size_bytes); |
114 int bytes_written = 0; | 211 int bytes_written = 0; |
115 for (DataElement* element : items) { | 212 for (DataElement* element : items) { |
116 DCHECK_EQ(DataElement::TYPE_BYTES, element->type()); | 213 DCHECK_EQ(DataElement::TYPE_BYTES, element->type()); |
117 size_t length = base::checked_cast<size_t>(element->length()); | 214 size_t length = base::checked_cast<size_t>(element->length()); |
118 size_t bytes_left = length; | 215 size_t bytes_left = length; |
119 while (bytes_left > 0) { | 216 while (bytes_left > 0) { |
120 bytes_written = | 217 bytes_written = |
121 file.WriteAtCurrentPos(element->bytes() + (length - bytes_left), | 218 file.WriteAtCurrentPos(element->bytes() + (length - bytes_left), |
122 base::saturated_cast<int>(bytes_left)); | 219 base::saturated_cast<int>(bytes_left)); |
123 if (bytes_written < 0) | 220 if (bytes_written < 0) |
124 break; | 221 break; |
125 DCHECK_LE(static_cast<size_t>(bytes_written), bytes_left); | 222 DCHECK_LE(static_cast<size_t>(bytes_written), bytes_left); |
126 bytes_left -= bytes_written; | 223 bytes_left -= bytes_written; |
127 } | 224 } |
128 if (bytes_written < 0) | 225 if (bytes_written < 0) |
129 break; | 226 break; |
130 } | 227 } |
131 if (!file.Flush()) { | 228 if (!file.Flush()) { |
229 file.Close(); | |
230 base::DeleteFile(file_path, false); | |
132 creation_info.error = File::FILE_ERROR_FAILED; | 231 creation_info.error = File::FILE_ERROR_FAILED; |
133 return creation_info; | 232 return std::make_pair(std::move(creation_info), free_disk_space); |
134 } | 233 } |
135 | 234 |
136 File::Info info; | 235 File::Info info; |
137 bool success = file.GetInfo(&info); | 236 bool success = file.GetInfo(&info); |
138 creation_info.error = | 237 creation_info.error = |
139 bytes_written < 0 || !success ? File::FILE_ERROR_FAILED : File::FILE_OK; | 238 bytes_written < 0 || !success ? File::FILE_ERROR_FAILED : File::FILE_OK; |
140 creation_info.last_modified = info.last_modified; | 239 creation_info.last_modified = info.last_modified; |
141 return creation_info; | 240 return std::make_pair(std::move(creation_info), disk_availability); |
142 } | 241 } |
143 | 242 |
144 uint64_t GetTotalSizeAndFileSizes( | 243 uint64_t GetTotalSizeAndFileSizes( |
145 const std::vector<scoped_refptr<ShareableBlobDataItem>>& | 244 const std::vector<scoped_refptr<ShareableBlobDataItem>>& |
146 unreserved_file_items, | 245 unreserved_file_items, |
147 std::vector<uint64_t>* file_sizes_output) { | 246 std::vector<uint64_t>* file_sizes_output) { |
148 uint64_t total_size_output = 0; | 247 uint64_t total_size_output = 0; |
149 base::SmallMap<std::map<uint64_t, uint64_t>> file_id_to_sizes; | 248 base::SmallMap<std::map<uint64_t, uint64_t>> file_id_to_sizes; |
150 for (const auto& item : unreserved_file_items) { | 249 for (const auto& item : unreserved_file_items) { |
151 const DataElement& element = item->item()->data_element(); | 250 const DataElement& element = item->item()->data_element(); |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
248 base::WeakPtrFactory<MemoryQuotaAllocationTask> weak_factory_; | 347 base::WeakPtrFactory<MemoryQuotaAllocationTask> weak_factory_; |
249 DISALLOW_COPY_AND_ASSIGN(MemoryQuotaAllocationTask); | 348 DISALLOW_COPY_AND_ASSIGN(MemoryQuotaAllocationTask); |
250 }; | 349 }; |
251 | 350 |
252 class BlobMemoryController::FileQuotaAllocationTask | 351 class BlobMemoryController::FileQuotaAllocationTask |
253 : public BlobMemoryController::QuotaAllocationTask { | 352 : public BlobMemoryController::QuotaAllocationTask { |
254 public: | 353 public: |
255 // We post a task to create the file for the items right away. | 354 // We post a task to create the file for the items right away. |
256 FileQuotaAllocationTask( | 355 FileQuotaAllocationTask( |
257 BlobMemoryController* memory_controller, | 356 BlobMemoryController* memory_controller, |
357 DiskSpaceFuncPtr disk_space_function, | |
258 std::vector<scoped_refptr<ShareableBlobDataItem>> unreserved_file_items, | 358 std::vector<scoped_refptr<ShareableBlobDataItem>> unreserved_file_items, |
259 const FileQuotaRequestCallback& done_callback) | 359 const FileQuotaRequestCallback& done_callback) |
260 : controller_(memory_controller), | 360 : controller_(memory_controller), |
261 done_callback_(done_callback), | 361 done_callback_(done_callback), |
262 weak_factory_(this) { | 362 weak_factory_(this) { |
263 // Get the file sizes and total size. | 363 // Get the file sizes and total size. |
264 std::vector<uint64_t> file_sizes; | |
265 uint64_t total_size = | 364 uint64_t total_size = |
266 GetTotalSizeAndFileSizes(unreserved_file_items, &file_sizes); | 365 GetTotalSizeAndFileSizes(unreserved_file_items, &file_sizes_); |
267 DCHECK_LE(total_size, controller_->GetAvailableFileSpaceForBlobs()); | 366 DCHECK_LE(total_size, controller_->GetAvailableFileSpaceForBlobs()); |
268 allocation_size_ = total_size; | 367 allocation_size_ = total_size; |
269 | 368 |
270 // Check & set our item states. | 369 // Check & set our item states. |
271 for (auto& shareable_item : unreserved_file_items) { | 370 for (auto& shareable_item : unreserved_file_items) { |
272 DCHECK_EQ(ShareableBlobDataItem::QUOTA_NEEDED, shareable_item->state()); | 371 DCHECK_EQ(ShareableBlobDataItem::QUOTA_NEEDED, shareable_item->state()); |
273 DCHECK_EQ(DataElement::TYPE_FILE, shareable_item->item()->type()); | 372 DCHECK_EQ(DataElement::TYPE_FILE, shareable_item->item()->type()); |
274 shareable_item->set_state(ShareableBlobDataItem::QUOTA_REQUESTED); | 373 shareable_item->set_state(ShareableBlobDataItem::QUOTA_REQUESTED); |
275 } | 374 } |
276 pending_items_ = std::move(unreserved_file_items); | 375 pending_items_ = std::move(unreserved_file_items); |
277 | 376 |
278 // Increment disk usage and create our file references. | 377 // Increment disk usage and create our file references. |
279 controller_->disk_used_ += allocation_size_; | 378 controller_->disk_used_ += allocation_size_; |
280 std::vector<base::FilePath> file_paths; | 379 std::vector<base::FilePath> file_paths; |
281 std::vector<scoped_refptr<ShareableFileReference>> references; | 380 std::vector<scoped_refptr<ShareableFileReference>> references; |
282 for (size_t i = 0; i < file_sizes.size(); i++) { | 381 for (size_t i = 0; i < file_sizes_.size(); i++) { |
283 file_paths.push_back(controller_->GenerateNextPageFileName()); | 382 file_paths.push_back(controller_->GenerateNextPageFileName()); |
284 references.push_back(ShareableFileReference::GetOrCreate( | 383 references.push_back(ShareableFileReference::GetOrCreate( |
285 file_paths.back(), ShareableFileReference::DELETE_ON_FINAL_RELEASE, | 384 file_paths.back(), ShareableFileReference::DELETE_ON_FINAL_RELEASE, |
286 controller_->file_runner_.get())); | 385 controller_->file_runner_.get())); |
287 references.back()->AddFinalReleaseCallback( | |
288 base::Bind(&BlobMemoryController::OnBlobFileDelete, | |
289 controller_->weak_factory_.GetWeakPtr(), file_sizes[i])); | |
290 } | 386 } |
291 | |
292 // Send file creation task to file thread. | 387 // Send file creation task to file thread. |
293 base::PostTaskAndReplyWithResult( | 388 base::PostTaskAndReplyWithResult( |
294 controller_->file_runner_.get(), FROM_HERE, | 389 controller_->file_runner_.get(), FROM_HERE, |
295 base::Bind(&CreateEmptyFiles, controller_->blob_storage_dir_, | 390 base::Bind(&CreateEmptyFiles, controller_->blob_storage_dir_, |
296 controller_->file_runner_, base::Passed(&file_paths)), | 391 disk_space_function, controller_->file_runner_, |
392 base::Passed(&file_paths)), | |
297 base::Bind(&FileQuotaAllocationTask::OnCreateEmptyFiles, | 393 base::Bind(&FileQuotaAllocationTask::OnCreateEmptyFiles, |
298 weak_factory_.GetWeakPtr(), base::Passed(&references))); | 394 weak_factory_.GetWeakPtr(), base::Passed(&references), |
395 allocation_size_)); | |
299 controller_->RecordTracingCounters(); | 396 controller_->RecordTracingCounters(); |
300 } | 397 } |
301 ~FileQuotaAllocationTask() override {} | 398 ~FileQuotaAllocationTask() override {} |
302 | 399 |
303 void RunDoneCallback(std::vector<FileCreationInfo> file_info, bool success) { | 400 void RunDoneCallback(std::vector<FileCreationInfo> file_info, bool success) { |
304 // Make sure we clear the weak pointers we gave to the caller beforehand. | 401 // Make sure we clear the weak pointers we gave to the caller beforehand. |
305 weak_factory_.InvalidateWeakPtrs(); | 402 weak_factory_.InvalidateWeakPtrs(); |
306 | 403 |
307 // We want to destroy this object on the exit of this method if we were | 404 // We want to destroy this object on the exit of this method if we were |
308 // successful. | 405 // successful. |
309 std::unique_ptr<FileQuotaAllocationTask> this_object; | 406 std::unique_ptr<FileQuotaAllocationTask> this_object; |
310 if (success) { | 407 if (success) { |
408 // Register the disk space accounting callback. | |
409 DCHECK_EQ(file_info.size(), file_sizes_.size()); | |
410 for (size_t i = 0; i < file_sizes_.size(); i++) { | |
411 file_info[i].file_reference->AddFinalReleaseCallback(base::Bind( | |
412 &BlobMemoryController::OnBlobFileDelete, | |
413 controller_->weak_factory_.GetWeakPtr(), file_sizes_[i])); | |
414 } | |
311 for (auto& item : pending_items_) { | 415 for (auto& item : pending_items_) { |
312 item->set_state(ShareableBlobDataItem::QUOTA_GRANTED); | 416 item->set_state(ShareableBlobDataItem::QUOTA_GRANTED); |
313 } | 417 } |
314 this_object = std::move(*my_list_position_); | 418 this_object = std::move(*my_list_position_); |
315 controller_->pending_file_quota_tasks_.erase(my_list_position_); | 419 controller_->pending_file_quota_tasks_.erase(my_list_position_); |
316 } | 420 } |
317 | 421 |
318 done_callback_.Run(std::move(file_info), success); | 422 done_callback_.Run(std::move(file_info), success); |
319 } | 423 } |
320 | 424 |
321 base::WeakPtr<QuotaAllocationTask> GetWeakPtr() { | 425 base::WeakPtr<QuotaAllocationTask> GetWeakPtr() { |
322 return weak_factory_.GetWeakPtr(); | 426 return weak_factory_.GetWeakPtr(); |
323 } | 427 } |
324 | 428 |
325 void Cancel() override { | 429 void Cancel() override { |
326 // This call destroys this object. We rely on ShareableFileReference's | 430 DCHECK_GE(controller_->disk_used_, allocation_size_); |
327 // final release callback for disk_usage_ accounting. | 431 controller_->disk_used_ -= allocation_size_; |
432 // This call destroys this object. | |
328 controller_->pending_file_quota_tasks_.erase(my_list_position_); | 433 controller_->pending_file_quota_tasks_.erase(my_list_position_); |
329 } | 434 } |
330 | 435 |
331 void OnCreateEmptyFiles( | 436 void OnCreateEmptyFiles( |
332 std::vector<scoped_refptr<ShareableFileReference>> references, | 437 std::vector<scoped_refptr<ShareableFileReference>> references, |
333 std::pair<std::vector<FileCreationInfo>, File::Error> files_and_error) { | 438 uint64_t new_files_total_size, |
334 auto& files = files_and_error.first; | 439 EmptyFilesResult result) { |
335 if (files.empty()) { | 440 int64_t avail_disk_space = result.disk_availability; |
441 if (result.files.empty()) { | |
442 DCHECK_NE(result.file_error, File::FILE_OK); | |
336 DCHECK_GE(controller_->disk_used_, allocation_size_); | 443 DCHECK_GE(controller_->disk_used_, allocation_size_); |
337 controller_->disk_used_ -= allocation_size_; | 444 controller_->disk_used_ -= allocation_size_; |
338 // This will call our callback and delete the object correctly. | 445 // This will call our callback and delete the object correctly. |
339 controller_->DisableFilePaging(files_and_error.second); | 446 controller_->DisableFilePaging(result.file_error); |
340 return; | 447 return; |
341 } | 448 } |
342 DCHECK_EQ(files.size(), references.size()); | 449 // The allocation won't fit at all. Cancel this request. The disk will be |
343 for (size_t i = 0; i < files.size(); i++) { | 450 // decremented when the file is deleted through AddFinalReleaseCallback. |
344 files[i].file_reference = std::move(references[i]); | 451 if (avail_disk_space != kUnknownDiskAvailability && |
452 base::checked_cast<uint64_t>(avail_disk_space) < new_files_total_size) { | |
453 DCHECK_GE(controller_->disk_used_, allocation_size_); | |
454 controller_->disk_used_ -= allocation_size_; | |
455 controller_->AdjustDiskUsage(static_cast<uint64_t>(avail_disk_space)); | |
456 controller_->file_runner_->PostTask( | |
457 FROM_HERE, base::Bind(&DeleteFiles, base::Passed(&result.files))); | |
458 std::unique_ptr<FileQuotaAllocationTask> this_object = | |
459 std::move(*my_list_position_); | |
460 controller_->pending_file_quota_tasks_.erase(my_list_position_); | |
461 RunDoneCallback(std::vector<FileCreationInfo>(), false); | |
462 return; | |
345 } | 463 } |
346 RunDoneCallback(std::move(files), true); | 464 if (avail_disk_space != kUnknownDiskAvailability) { |
465 controller_->AdjustDiskUsage(base::checked_cast<uint64_t>( | |
466 avail_disk_space - new_files_total_size)); | |
467 } | |
468 DCHECK_EQ(result.files.size(), references.size()); | |
469 for (size_t i = 0; i < result.files.size(); i++) { | |
470 result.files[i].file_reference = std::move(references[i]); | |
471 } | |
472 RunDoneCallback(std::move(result.files), true); | |
347 } | 473 } |
348 | 474 |
349 // The my_list_position_ iterator is stored so that we can remove ourself | 475 // The my_list_position_ iterator is stored so that we can remove ourself |
350 // from the task list when we are cancelled. | 476 // from the task list when we are cancelled. |
351 void set_my_list_position( | 477 void set_my_list_position( |
352 PendingFileQuotaTaskList::iterator my_list_position) { | 478 PendingFileQuotaTaskList::iterator my_list_position) { |
353 my_list_position_ = my_list_position; | 479 my_list_position_ = my_list_position; |
354 } | 480 } |
355 | 481 |
482 size_t allocation_size() const { return allocation_size_; } | |
483 | |
356 private: | 484 private: |
357 BlobMemoryController* controller_; | 485 BlobMemoryController* controller_; |
486 std::vector<uint64_t> file_sizes_; | |
358 std::vector<scoped_refptr<ShareableBlobDataItem>> pending_items_; | 487 std::vector<scoped_refptr<ShareableBlobDataItem>> pending_items_; |
359 scoped_refptr<base::TaskRunner> file_runner_; | |
360 FileQuotaRequestCallback done_callback_; | 488 FileQuotaRequestCallback done_callback_; |
361 | 489 |
362 uint64_t allocation_size_; | 490 uint64_t allocation_size_; |
363 PendingFileQuotaTaskList::iterator my_list_position_; | 491 PendingFileQuotaTaskList::iterator my_list_position_; |
364 | 492 |
365 base::WeakPtrFactory<FileQuotaAllocationTask> weak_factory_; | 493 base::WeakPtrFactory<FileQuotaAllocationTask> weak_factory_; |
366 DISALLOW_COPY_AND_ASSIGN(FileQuotaAllocationTask); | 494 DISALLOW_COPY_AND_ASSIGN(FileQuotaAllocationTask); |
367 }; | 495 }; |
368 | 496 |
369 BlobMemoryController::BlobMemoryController( | 497 BlobMemoryController::BlobMemoryController( |
370 const base::FilePath& storage_directory, | 498 const base::FilePath& storage_directory, |
371 scoped_refptr<base::TaskRunner> file_runner) | 499 scoped_refptr<base::TaskRunner> file_runner) |
372 : file_paging_enabled_(file_runner.get() != nullptr), | 500 : file_paging_enabled_(file_runner.get() != nullptr), |
373 blob_storage_dir_(storage_directory), | 501 blob_storage_dir_(storage_directory), |
374 file_runner_(std::move(file_runner)), | 502 file_runner_(std::move(file_runner)), |
503 disk_space_function_(&base::SysInfo::AmountOfFreeDiskSpace), | |
375 populated_memory_items_( | 504 populated_memory_items_( |
376 base::MRUCache<uint64_t, ShareableBlobDataItem*>::NO_AUTO_EVICT), | 505 base::MRUCache<uint64_t, ShareableBlobDataItem*>::NO_AUTO_EVICT), |
377 weak_factory_(this) {} | 506 weak_factory_(this) {} |
378 | 507 |
379 BlobMemoryController::~BlobMemoryController() {} | 508 BlobMemoryController::~BlobMemoryController() {} |
380 | 509 |
381 void BlobMemoryController::DisableFilePaging(base::File::Error reason) { | 510 void BlobMemoryController::DisableFilePaging(base::File::Error reason) { |
382 UMA_HISTOGRAM_ENUMERATION("Storage.Blob.PagingDisabled", -reason, | 511 UMA_HISTOGRAM_ENUMERATION("Storage.Blob.PagingDisabled", -reason, |
383 -File::FILE_ERROR_MAX); | 512 -File::FILE_ERROR_MAX); |
384 DLOG(ERROR) << "Blob storage paging disabled, reason: " << reason; | 513 DLOG(ERROR) << "Blob storage paging disabled, reason: " << reason; |
385 file_paging_enabled_ = false; | 514 file_paging_enabled_ = false; |
386 in_flight_memory_used_ = 0; | 515 in_flight_memory_used_ = 0; |
387 items_paging_to_file_.clear(); | 516 items_paging_to_file_.clear(); |
388 pending_evictions_ = 0; | 517 pending_evictions_ = 0; |
389 pending_memory_quota_total_size_ = 0; | 518 pending_memory_quota_total_size_ = 0; |
390 populated_memory_items_.Clear(); | 519 populated_memory_items_.Clear(); |
391 populated_memory_items_bytes_ = 0; | 520 populated_memory_items_bytes_ = 0; |
392 file_runner_ = nullptr; | 521 file_runner_ = nullptr; |
393 | 522 |
394 PendingMemoryQuotaTaskList old_memory_tasks; | 523 PendingMemoryQuotaTaskList old_memory_tasks; |
395 PendingFileQuotaTaskList old_file_tasks; | 524 PendingFileQuotaTaskList old_file_tasks; |
396 std::swap(old_memory_tasks, pending_memory_quota_tasks_); | 525 std::swap(old_memory_tasks, pending_memory_quota_tasks_); |
397 std::swap(old_file_tasks, pending_file_quota_tasks_); | 526 std::swap(old_file_tasks, pending_file_quota_tasks_); |
398 | 527 |
399 // Don't call the callbacks until we have a consistent state. | 528 // Don't call the callbacks until we have a consistent state. |
400 for (auto& memory_request : old_memory_tasks) { | 529 for (auto& memory_request : old_memory_tasks) { |
401 memory_request->RunDoneCallback(false); | 530 memory_request->RunDoneCallback(false); |
402 } | 531 } |
403 for (auto& file_request : old_file_tasks) { | 532 for (auto& file_request : old_file_tasks) { |
533 // OnBlobFileDelete is registered when RunDoneCallback is called with | |
534 // |true|, so manually do disk accounting. | |
535 disk_used_ -= file_request->allocation_size(); | |
404 file_request->RunDoneCallback(std::vector<FileCreationInfo>(), false); | 536 file_request->RunDoneCallback(std::vector<FileCreationInfo>(), false); |
405 } | 537 } |
406 } | 538 } |
407 | 539 |
408 BlobMemoryController::Strategy BlobMemoryController::DetermineStrategy( | 540 BlobMemoryController::Strategy BlobMemoryController::DetermineStrategy( |
409 size_t preemptive_transported_bytes, | 541 size_t preemptive_transported_bytes, |
410 uint64_t total_transportation_bytes) const { | 542 uint64_t total_transportation_bytes) const { |
411 if (total_transportation_bytes == 0) | 543 if (total_transportation_bytes == 0) |
412 return Strategy::NONE_NEEDED; | 544 return Strategy::NONE_NEEDED; |
413 if (!CanReserveQuota(total_transportation_bytes)) | 545 if (!CanReserveQuota(total_transportation_bytes)) |
414 return Strategy::TOO_LARGE; | 546 return Strategy::TOO_LARGE; |
415 | 547 |
416 // Handle the case where we have all the bytes preemptively transported, and | 548 // Handle the case where we have all the bytes preemptively transported, and |
417 // we can also fit them. | 549 // we can also fit them. |
418 if (preemptive_transported_bytes == total_transportation_bytes && | 550 if (preemptive_transported_bytes == total_transportation_bytes && |
419 pending_memory_quota_tasks_.empty() && | 551 pending_memory_quota_tasks_.empty() && |
420 preemptive_transported_bytes < GetAvailableMemoryForBlobs()) { | 552 preemptive_transported_bytes <= GetAvailableMemoryForBlobs()) { |
421 return Strategy::NONE_NEEDED; | 553 return Strategy::NONE_NEEDED; |
422 } | 554 } |
423 if (file_paging_enabled_ && | 555 if (file_paging_enabled_ && |
424 (total_transportation_bytes > limits_.memory_limit_before_paging())) { | 556 total_transportation_bytes <= GetAvailableFileSpaceForBlobs() && |
557 total_transportation_bytes > limits_.memory_limit_before_paging()) { | |
425 return Strategy::FILE; | 558 return Strategy::FILE; |
426 } | 559 } |
427 if (total_transportation_bytes > limits_.max_ipc_memory_size) | 560 if (total_transportation_bytes > limits_.max_ipc_memory_size) |
428 return Strategy::SHARED_MEMORY; | 561 return Strategy::SHARED_MEMORY; |
429 return Strategy::IPC; | 562 return Strategy::IPC; |
430 } | 563 } |
431 | 564 |
432 bool BlobMemoryController::CanReserveQuota(uint64_t size) const { | 565 bool BlobMemoryController::CanReserveQuota(uint64_t size) const { |
433 // We check each size independently as a blob can't be constructed in both | 566 // We check each size independently as a blob can't be constructed in both |
434 // disk and memory. | 567 // disk and memory. |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
481 auto weak_ptr = AppendMemoryTask( | 614 auto weak_ptr = AppendMemoryTask( |
482 total_bytes_needed, std::move(unreserved_memory_items), done_callback); | 615 total_bytes_needed, std::move(unreserved_memory_items), done_callback); |
483 MaybeScheduleEvictionUntilSystemHealthy(); | 616 MaybeScheduleEvictionUntilSystemHealthy(); |
484 return weak_ptr; | 617 return weak_ptr; |
485 } | 618 } |
486 | 619 |
487 base::WeakPtr<QuotaAllocationTask> BlobMemoryController::ReserveFileQuota( | 620 base::WeakPtr<QuotaAllocationTask> BlobMemoryController::ReserveFileQuota( |
488 std::vector<scoped_refptr<ShareableBlobDataItem>> unreserved_file_items, | 621 std::vector<scoped_refptr<ShareableBlobDataItem>> unreserved_file_items, |
489 const FileQuotaRequestCallback& done_callback) { | 622 const FileQuotaRequestCallback& done_callback) { |
490 pending_file_quota_tasks_.push_back(base::MakeUnique<FileQuotaAllocationTask>( | 623 pending_file_quota_tasks_.push_back(base::MakeUnique<FileQuotaAllocationTask>( |
491 this, std::move(unreserved_file_items), done_callback)); | 624 this, disk_space_function_, std::move(unreserved_file_items), |
625 done_callback)); | |
492 pending_file_quota_tasks_.back()->set_my_list_position( | 626 pending_file_quota_tasks_.back()->set_my_list_position( |
493 --pending_file_quota_tasks_.end()); | 627 --pending_file_quota_tasks_.end()); |
494 return pending_file_quota_tasks_.back()->GetWeakPtr(); | 628 return pending_file_quota_tasks_.back()->GetWeakPtr(); |
495 } | 629 } |
496 | 630 |
497 void BlobMemoryController::NotifyMemoryItemsUsed( | 631 void BlobMemoryController::NotifyMemoryItemsUsed( |
498 const std::vector<scoped_refptr<ShareableBlobDataItem>>& items) { | 632 const std::vector<scoped_refptr<ShareableBlobDataItem>>& items) { |
499 for (const auto& item : items) { | 633 for (const auto& item : items) { |
500 if (item->item()->type() != DataElement::TYPE_BYTES || | 634 if (item->item()->type() != DataElement::TYPE_BYTES || |
501 item->state() != ShareableBlobDataItem::POPULATED_WITH_QUOTA) { | 635 item->state() != ShareableBlobDataItem::POPULATED_WITH_QUOTA) { |
502 continue; | 636 continue; |
503 } | 637 } |
504 // We don't want to re-add the item if we're currently paging it to disk. | 638 // We don't want to re-add the item if we're currently paging it to disk. |
505 if (items_paging_to_file_.find(item->item_id()) != | 639 if (items_paging_to_file_.find(item->item_id()) != |
506 items_paging_to_file_.end()) { | 640 items_paging_to_file_.end()) { |
507 return; | 641 return; |
508 } | 642 } |
509 auto iterator = populated_memory_items_.Get(item->item_id()); | 643 auto iterator = populated_memory_items_.Get(item->item_id()); |
510 if (iterator == populated_memory_items_.end()) { | 644 if (iterator == populated_memory_items_.end()) { |
511 populated_memory_items_bytes_ += | 645 populated_memory_items_bytes_ += |
512 static_cast<size_t>(item->item()->length()); | 646 static_cast<size_t>(item->item()->length()); |
513 populated_memory_items_.Put(item->item_id(), item.get()); | 647 populated_memory_items_.Put(item->item_id(), item.get()); |
514 } | 648 } |
515 } | 649 } |
516 MaybeScheduleEvictionUntilSystemHealthy(); | 650 MaybeScheduleEvictionUntilSystemHealthy(); |
517 } | 651 } |
518 | 652 |
653 void BlobMemoryController::CalculateBlobStorageLimits() { | |
654 if (file_runner_) { | |
655 PostTaskAndReplyWithResult( | |
656 file_runner_.get(), FROM_HERE, | |
657 base::Bind(&CalculateBlobStorageLimitsImpl, blob_storage_dir_, true), | |
658 base::Bind(&BlobMemoryController::OnStorageLimitsCalculated, | |
659 weak_factory_.GetWeakPtr())); | |
660 } else { | |
661 OnStorageLimitsCalculated( | |
662 CalculateBlobStorageLimitsImpl(blob_storage_dir_, false)); | |
663 } | |
664 } | |
665 | |
666 base::WeakPtr<BlobMemoryController> BlobMemoryController::GetWeakPtr() { | |
667 return weak_factory_.GetWeakPtr(); | |
668 } | |
669 | |
670 void BlobMemoryController::OnStorageLimitsCalculated(BlobStorageLimits limits) { | |
671 if (!limits.IsValid() || manual_limits_set_) | |
672 return; | |
673 limits_ = limits; | |
674 } | |
675 | |
676 namespace { | |
677 // Used in UMA metrics, do not change values. | |
678 enum DiskSpaceAdjustmentType { | |
679 FREEZE_HIT_MIN_AVAILABLE = 0, | |
680 LOWERED_NEAR_MIN_AVAILABLE = 1, | |
681 RAISED_NEAR_MIN_AVAILABLE = 2, | |
682 RESTORED = 3, | |
683 MAX_ADJUSTMENT_TYPE | |
684 }; | |
685 | |
686 enum DiskSpaceAdjustmentStatus { FROZEN, ADJUSTED, NORMAL }; | |
687 } // namespace | |
688 | |
689 void BlobMemoryController::AdjustDiskUsage(uint64_t avail_disk) { | |
690 DCHECK_LE(disk_used_, limits_.desired_max_disk_space + | |
691 limits_.min_available_external_disk_space()); | |
692 | |
693 DiskSpaceAdjustmentStatus curr_status; | |
694 if (limits_.effective_max_disk_space == limits_.desired_max_disk_space) { | |
695 curr_status = NORMAL; | |
696 } else if (limits_.effective_max_disk_space == disk_used_) { | |
697 curr_status = FROZEN; | |
698 } else { | |
699 curr_status = ADJUSTED; | |
700 } | |
701 uint64_t old_effective_max_disk_space = limits_.effective_max_disk_space; | |
702 uint64_t avail_disk_without_blobs = avail_disk + disk_used_; | |
703 | |
704 if (avail_disk <= limits_.min_available_external_disk_space()) { | |
705 limits_.effective_max_disk_space = disk_used_; | |
706 if (curr_status != FROZEN && | |
Mark P
2017/01/11 17:49:14
optional nit: parens around binary operators in th
dmurph
2017/01/11 18:25:29
Acknowledged. I prefer w/o parens.
| |
707 limits_.effective_max_disk_space != old_effective_max_disk_space) { | |
708 UMA_HISTOGRAM_ENUMERATION("Storage.Blob.MaxDiskSpaceAdjustment", | |
709 FREEZE_HIT_MIN_AVAILABLE, MAX_ADJUSTMENT_TYPE); | |
710 } | |
711 } else if (avail_disk_without_blobs < | |
712 limits_.min_available_external_disk_space() + | |
713 limits_.desired_max_disk_space) { | |
714 // Subtraction is avoided the if statement to prevent overflows. | |
Mark P
2017/01/11 17:49:14
I cannot parse this sentence.
Also, it's usually *
dmurph
2017/01/11 18:25:29
Whoops, meant underflow. Since I moved the additio
| |
715 // |effective_max_disk_space| is guaranteed to be less than | |
716 // |desired_max_disk_space| by the if statement. | |
717 limits_.effective_max_disk_space = | |
718 avail_disk_without_blobs - limits_.min_available_external_disk_space(); | |
719 if (curr_status != ADJUSTED && | |
720 limits_.effective_max_disk_space != old_effective_max_disk_space) { | |
721 UMA_HISTOGRAM_ENUMERATION("Storage.Blob.MaxDiskSpaceAdjustment", | |
722 curr_status == NORMAL | |
723 ? LOWERED_NEAR_MIN_AVAILABLE | |
724 : RAISED_NEAR_MIN_AVAILABLE, | |
725 MAX_ADJUSTMENT_TYPE); | |
726 } | |
727 } else { | |
728 limits_.effective_max_disk_space = limits_.desired_max_disk_space; | |
729 if (curr_status != NORMAL) { | |
730 UMA_HISTOGRAM_ENUMERATION("Storage.Blob.MaxDiskSpaceAdjustment", RESTORED, | |
731 MAX_ADJUSTMENT_TYPE); | |
732 } | |
733 } | |
734 } | |
735 | |
519 base::WeakPtr<QuotaAllocationTask> BlobMemoryController::AppendMemoryTask( | 736 base::WeakPtr<QuotaAllocationTask> BlobMemoryController::AppendMemoryTask( |
520 uint64_t total_bytes_needed, | 737 uint64_t total_bytes_needed, |
521 std::vector<scoped_refptr<ShareableBlobDataItem>> unreserved_memory_items, | 738 std::vector<scoped_refptr<ShareableBlobDataItem>> unreserved_memory_items, |
522 const MemoryQuotaRequestCallback& done_callback) { | 739 const MemoryQuotaRequestCallback& done_callback) { |
523 DCHECK(file_paging_enabled_) | 740 DCHECK(file_paging_enabled_) |
524 << "Caller tried to reserve memory when CanReserveQuota(" | 741 << "Caller tried to reserve memory when CanReserveQuota(" |
525 << total_bytes_needed << ") would have returned false."; | 742 << total_bytes_needed << ") would have returned false."; |
526 | 743 |
527 pending_memory_quota_total_size_ += total_bytes_needed; | 744 pending_memory_quota_total_size_ += total_bytes_needed; |
528 pending_memory_quota_tasks_.push_back( | 745 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(); | 784 return total_items_size.ValueOrDie(); |
568 } | 785 } |
569 | 786 |
570 void BlobMemoryController::MaybeScheduleEvictionUntilSystemHealthy() { | 787 void BlobMemoryController::MaybeScheduleEvictionUntilSystemHealthy() { |
571 // Don't do eviction when others are happening, as we don't change our | 788 // 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 | 789 // pending_memory_quota_total_size_ value until after the paging files have |
573 // been written. | 790 // been written. |
574 if (pending_evictions_ != 0 || !file_paging_enabled_) | 791 if (pending_evictions_ != 0 || !file_paging_enabled_) |
575 return; | 792 return; |
576 | 793 |
794 uint64_t total_memory_usage = | |
795 static_cast<uint64_t>(pending_memory_quota_total_size_) + | |
796 blob_memory_used_; | |
797 | |
577 // We try to page items to disk until our current system size + requested | 798 // We try to page items to disk until our current system size + requested |
578 // memory is below our size limit. | 799 // memory is below our size limit. |
579 while (pending_memory_quota_total_size_ + blob_memory_used_ > | 800 // Size limit is a lower |memory_limit_before_paging()| if we have disk space. |
580 limits_.memory_limit_before_paging()) { | 801 while (total_memory_usage > limits_.effective_max_disk_space || |
802 (disk_used_ < limits_.effective_max_disk_space && | |
803 total_memory_usage > limits_.memory_limit_before_paging())) { | |
581 // We only page when we have enough items to fill a whole page file. | 804 // 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) | 805 if (populated_memory_items_bytes_ < limits_.min_page_file_size) |
583 break; | 806 break; |
584 DCHECK_LE(limits_.min_page_file_size, | 807 DCHECK_LE(limits_.min_page_file_size, |
585 static_cast<uint64_t>(blob_memory_used_)); | 808 static_cast<uint64_t>(blob_memory_used_)); |
586 | 809 |
587 std::vector<scoped_refptr<ShareableBlobDataItem>> items_to_swap; | 810 std::vector<scoped_refptr<ShareableBlobDataItem>> items_to_swap; |
588 size_t total_items_size = CollectItemsForEviction(&items_to_swap); | 811 size_t total_items_size = CollectItemsForEviction(&items_to_swap); |
589 if (total_items_size == 0) | 812 if (total_items_size == 0) |
590 break; | 813 break; |
(...skipping 18 matching lines...) Expand all Loading... | |
609 file_runner_.get()); | 832 file_runner_.get()); |
610 // Add the release callback so we decrement our disk usage on file deletion. | 833 // Add the release callback so we decrement our disk usage on file deletion. |
611 file_reference->AddFinalReleaseCallback( | 834 file_reference->AddFinalReleaseCallback( |
612 base::Bind(&BlobMemoryController::OnBlobFileDelete, | 835 base::Bind(&BlobMemoryController::OnBlobFileDelete, |
613 weak_factory_.GetWeakPtr(), total_items_size)); | 836 weak_factory_.GetWeakPtr(), total_items_size)); |
614 | 837 |
615 // Post the file writing task. | 838 // Post the file writing task. |
616 base::PostTaskAndReplyWithResult( | 839 base::PostTaskAndReplyWithResult( |
617 file_runner_.get(), FROM_HERE, | 840 file_runner_.get(), FROM_HERE, |
618 base::Bind(&CreateFileAndWriteItems, blob_storage_dir_, | 841 base::Bind(&CreateFileAndWriteItems, blob_storage_dir_, |
619 base::Passed(&page_file_path), file_runner_, | 842 disk_space_function_, base::Passed(&page_file_path), |
620 base::Passed(&items_for_paging), total_items_size), | 843 file_runner_, base::Passed(&items_for_paging), |
844 total_items_size), | |
621 base::Bind(&BlobMemoryController::OnEvictionComplete, | 845 base::Bind(&BlobMemoryController::OnEvictionComplete, |
622 weak_factory_.GetWeakPtr(), base::Passed(&file_reference), | 846 weak_factory_.GetWeakPtr(), base::Passed(&file_reference), |
623 base::Passed(&items_to_swap), total_items_size)); | 847 base::Passed(&items_to_swap), total_items_size)); |
624 } | 848 } |
625 RecordTracingCounters(); | 849 RecordTracingCounters(); |
626 } | 850 } |
627 | 851 |
628 void BlobMemoryController::OnEvictionComplete( | 852 void BlobMemoryController::OnEvictionComplete( |
629 scoped_refptr<ShareableFileReference> file_reference, | 853 scoped_refptr<ShareableFileReference> file_reference, |
630 std::vector<scoped_refptr<ShareableBlobDataItem>> items, | 854 std::vector<scoped_refptr<ShareableBlobDataItem>> items, |
631 size_t total_items_size, | 855 size_t total_items_size, |
632 FileCreationInfo result) { | 856 std::pair<FileCreationInfo, int64_t /* avail_disk */> result) { |
633 if (!file_paging_enabled_) | 857 if (!file_paging_enabled_) |
634 return; | 858 return; |
635 | 859 |
636 if (result.error != File::FILE_OK) { | 860 FileCreationInfo& file_info = std::get<0>(result); |
637 DisableFilePaging(result.error); | 861 int64_t avail_disk_space = std::get<1>(result); |
862 | |
863 if (file_info.error != File::FILE_OK) { | |
864 DisableFilePaging(file_info.error); | |
638 return; | 865 return; |
639 } | 866 } |
640 | 867 |
868 if (avail_disk_space != kUnknownDiskAvailability) { | |
869 AdjustDiskUsage(static_cast<uint64_t>(avail_disk_space)); | |
870 } | |
871 | |
641 DCHECK_LT(0, pending_evictions_); | 872 DCHECK_LT(0, pending_evictions_); |
642 pending_evictions_--; | 873 pending_evictions_--; |
643 | 874 |
644 // Switch item from memory to the new file. | 875 // Switch item from memory to the new file. |
645 uint64_t offset = 0; | 876 uint64_t offset = 0; |
646 for (const scoped_refptr<ShareableBlobDataItem>& shareable_item : items) { | 877 for (const scoped_refptr<ShareableBlobDataItem>& shareable_item : items) { |
647 scoped_refptr<BlobDataItem> new_item( | 878 scoped_refptr<BlobDataItem> new_item( |
648 new BlobDataItem(base::WrapUnique(new DataElement()), file_reference)); | 879 new BlobDataItem(base::WrapUnique(new DataElement()), file_reference)); |
649 new_item->data_element_ptr()->SetToFilePathRange( | 880 new_item->data_element_ptr()->SetToFilePathRange( |
650 file_reference->path(), offset, shareable_item->item()->length(), | 881 file_reference->path(), offset, shareable_item->item()->length(), |
651 result.last_modified); | 882 file_info.last_modified); |
652 DCHECK(shareable_item->memory_allocation_); | 883 DCHECK(shareable_item->memory_allocation_); |
653 shareable_item->set_memory_allocation(nullptr); | 884 shareable_item->set_memory_allocation(nullptr); |
654 shareable_item->set_item(new_item); | 885 shareable_item->set_item(new_item); |
655 items_paging_to_file_.erase(shareable_item->item_id()); | 886 items_paging_to_file_.erase(shareable_item->item_id()); |
656 offset += shareable_item->item()->length(); | 887 offset += shareable_item->item()->length(); |
657 } | 888 } |
658 in_flight_memory_used_ -= total_items_size; | 889 in_flight_memory_used_ -= total_items_size; |
659 | 890 |
660 // We want callback on blobs up to the amount we've freed. | 891 // We want callback on blobs up to the amount we've freed. |
661 MaybeGrantPendingMemoryRequests(); | 892 MaybeGrantPendingMemoryRequests(); |
(...skipping 27 matching lines...) Expand all Loading... | |
689 uint64_t BlobMemoryController::GetAvailableFileSpaceForBlobs() const { | 920 uint64_t BlobMemoryController::GetAvailableFileSpaceForBlobs() const { |
690 if (!file_paging_enabled_) | 921 if (!file_paging_enabled_) |
691 return 0; | 922 return 0; |
692 // Sometimes we're only paging part of what we need for the new blob, so add | 923 // Sometimes we're only paging part of what we need for the new blob, so add |
693 // the rest of the size we need into our disk usage if this is the case. | 924 // the rest of the size we need into our disk usage if this is the case. |
694 uint64_t total_disk_used = disk_used_; | 925 uint64_t total_disk_used = disk_used_; |
695 if (in_flight_memory_used_ < pending_memory_quota_total_size_) { | 926 if (in_flight_memory_used_ < pending_memory_quota_total_size_) { |
696 total_disk_used += | 927 total_disk_used += |
697 pending_memory_quota_total_size_ - in_flight_memory_used_; | 928 pending_memory_quota_total_size_ - in_flight_memory_used_; |
698 } | 929 } |
699 if (limits_.max_blob_disk_space < total_disk_used) | 930 if (limits_.effective_max_disk_space < total_disk_used) |
700 return 0; | 931 return 0; |
701 return limits_.max_blob_disk_space - total_disk_used; | 932 return limits_.effective_max_disk_space - total_disk_used; |
702 } | 933 } |
703 | 934 |
704 void BlobMemoryController::GrantMemoryAllocations( | 935 void BlobMemoryController::GrantMemoryAllocations( |
705 std::vector<scoped_refptr<ShareableBlobDataItem>>* items, | 936 std::vector<scoped_refptr<ShareableBlobDataItem>>* items, |
706 size_t total_bytes) { | 937 size_t total_bytes) { |
707 // These metrics let us calculate the global distribution of blob storage by | 938 // These metrics let us calculate the global distribution of blob storage by |
708 // subtracting the histograms. | 939 // subtracting the histograms. |
709 UMA_HISTOGRAM_COUNTS("Storage.Blob.StorageSizeBeforeAppend", | 940 UMA_HISTOGRAM_COUNTS("Storage.Blob.StorageSizeBeforeAppend", |
710 blob_memory_used_ / 1024); | 941 blob_memory_used_ / 1024); |
711 blob_memory_used_ += total_bytes; | 942 blob_memory_used_ += total_bytes; |
(...skipping 29 matching lines...) Expand all Loading... | |
741 MaybeGrantPendingMemoryRequests(); | 972 MaybeGrantPendingMemoryRequests(); |
742 } | 973 } |
743 | 974 |
744 void BlobMemoryController::OnBlobFileDelete(uint64_t size, | 975 void BlobMemoryController::OnBlobFileDelete(uint64_t size, |
745 const FilePath& path) { | 976 const FilePath& path) { |
746 DCHECK_LE(size, disk_used_); | 977 DCHECK_LE(size, disk_used_); |
747 disk_used_ -= size; | 978 disk_used_ -= size; |
748 } | 979 } |
749 | 980 |
750 } // namespace storage | 981 } // namespace storage |
OLD | NEW |