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

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

Issue 2552153002: [BlobStorage] Enabling disk paging and direct storage. (Closed)
Patch Set: added comments to WebContentsImplTest Created 3 years, 11 months 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 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
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
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 // Note: The UMA metrics here intended to record state change between frozen,
705 // adjusted, and normal states.
706
707 if (avail_disk <= limits_.min_available_external_disk_space()) {
708 limits_.effective_max_disk_space = disk_used_;
709 if (curr_status != FROZEN &&
710 limits_.effective_max_disk_space != old_effective_max_disk_space) {
711 UMA_HISTOGRAM_ENUMERATION("Storage.Blob.MaxDiskSpaceAdjustment",
712 FREEZE_HIT_MIN_AVAILABLE, MAX_ADJUSTMENT_TYPE);
713 }
714 } else if (avail_disk_without_blobs <
715 limits_.min_available_external_disk_space() +
716 limits_.desired_max_disk_space) {
717 // |effective_max_disk_space| is guaranteed to be less than
718 // |desired_max_disk_space| by the if statement.
719 limits_.effective_max_disk_space =
720 avail_disk_without_blobs - limits_.min_available_external_disk_space();
721 if (curr_status != ADJUSTED &&
722 limits_.effective_max_disk_space != old_effective_max_disk_space) {
723 UMA_HISTOGRAM_ENUMERATION("Storage.Blob.MaxDiskSpaceAdjustment",
724 curr_status == NORMAL
725 ? LOWERED_NEAR_MIN_AVAILABLE
726 : RAISED_NEAR_MIN_AVAILABLE,
727 MAX_ADJUSTMENT_TYPE);
728 }
729 } else {
730 limits_.effective_max_disk_space = limits_.desired_max_disk_space;
731 if (curr_status != NORMAL &&
732 limits_.effective_max_disk_space != old_effective_max_disk_space) {
733 UMA_HISTOGRAM_ENUMERATION("Storage.Blob.MaxDiskSpaceAdjustment", RESTORED,
734 MAX_ADJUSTMENT_TYPE);
735 }
736 }
737 }
738
519 base::WeakPtr<QuotaAllocationTask> BlobMemoryController::AppendMemoryTask( 739 base::WeakPtr<QuotaAllocationTask> BlobMemoryController::AppendMemoryTask(
520 uint64_t total_bytes_needed, 740 uint64_t total_bytes_needed,
521 std::vector<scoped_refptr<ShareableBlobDataItem>> unreserved_memory_items, 741 std::vector<scoped_refptr<ShareableBlobDataItem>> unreserved_memory_items,
522 const MemoryQuotaRequestCallback& done_callback) { 742 const MemoryQuotaRequestCallback& done_callback) {
523 DCHECK(file_paging_enabled_) 743 DCHECK(file_paging_enabled_)
524 << "Caller tried to reserve memory when CanReserveQuota(" 744 << "Caller tried to reserve memory when CanReserveQuota("
525 << total_bytes_needed << ") would have returned false."; 745 << total_bytes_needed << ") would have returned false.";
526 746
527 pending_memory_quota_total_size_ += total_bytes_needed; 747 pending_memory_quota_total_size_ += total_bytes_needed;
528 pending_memory_quota_tasks_.push_back( 748 pending_memory_quota_tasks_.push_back(
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
567 return total_items_size.ValueOrDie(); 787 return total_items_size.ValueOrDie();
568 } 788 }
569 789
570 void BlobMemoryController::MaybeScheduleEvictionUntilSystemHealthy() { 790 void BlobMemoryController::MaybeScheduleEvictionUntilSystemHealthy() {
571 // Don't do eviction when others are happening, as we don't change our 791 // 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 792 // pending_memory_quota_total_size_ value until after the paging files have
573 // been written. 793 // been written.
574 if (pending_evictions_ != 0 || !file_paging_enabled_) 794 if (pending_evictions_ != 0 || !file_paging_enabled_)
575 return; 795 return;
576 796
797 uint64_t total_memory_usage =
798 static_cast<uint64_t>(pending_memory_quota_total_size_) +
799 blob_memory_used_;
800
577 // We try to page items to disk until our current system size + requested 801 // We try to page items to disk until our current system size + requested
578 // memory is below our size limit. 802 // memory is below our size limit.
579 while (pending_memory_quota_total_size_ + blob_memory_used_ > 803 // Size limit is a lower |memory_limit_before_paging()| if we have disk space.
580 limits_.memory_limit_before_paging()) { 804 while (total_memory_usage > limits_.effective_max_disk_space ||
805 (disk_used_ < limits_.effective_max_disk_space &&
806 total_memory_usage > limits_.memory_limit_before_paging())) {
581 // We only page when we have enough items to fill a whole page file. 807 // 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) 808 if (populated_memory_items_bytes_ < limits_.min_page_file_size)
583 break; 809 break;
584 DCHECK_LE(limits_.min_page_file_size, 810 DCHECK_LE(limits_.min_page_file_size,
585 static_cast<uint64_t>(blob_memory_used_)); 811 static_cast<uint64_t>(blob_memory_used_));
586 812
587 std::vector<scoped_refptr<ShareableBlobDataItem>> items_to_swap; 813 std::vector<scoped_refptr<ShareableBlobDataItem>> items_to_swap;
588 size_t total_items_size = CollectItemsForEviction(&items_to_swap); 814 size_t total_items_size = CollectItemsForEviction(&items_to_swap);
589 if (total_items_size == 0) 815 if (total_items_size == 0)
590 break; 816 break;
(...skipping 18 matching lines...) Expand all
609 file_runner_.get()); 835 file_runner_.get());
610 // Add the release callback so we decrement our disk usage on file deletion. 836 // Add the release callback so we decrement our disk usage on file deletion.
611 file_reference->AddFinalReleaseCallback( 837 file_reference->AddFinalReleaseCallback(
612 base::Bind(&BlobMemoryController::OnBlobFileDelete, 838 base::Bind(&BlobMemoryController::OnBlobFileDelete,
613 weak_factory_.GetWeakPtr(), total_items_size)); 839 weak_factory_.GetWeakPtr(), total_items_size));
614 840
615 // Post the file writing task. 841 // Post the file writing task.
616 base::PostTaskAndReplyWithResult( 842 base::PostTaskAndReplyWithResult(
617 file_runner_.get(), FROM_HERE, 843 file_runner_.get(), FROM_HERE,
618 base::Bind(&CreateFileAndWriteItems, blob_storage_dir_, 844 base::Bind(&CreateFileAndWriteItems, blob_storage_dir_,
619 base::Passed(&page_file_path), file_runner_, 845 disk_space_function_, base::Passed(&page_file_path),
620 base::Passed(&items_for_paging), total_items_size), 846 file_runner_, base::Passed(&items_for_paging),
847 total_items_size),
621 base::Bind(&BlobMemoryController::OnEvictionComplete, 848 base::Bind(&BlobMemoryController::OnEvictionComplete,
622 weak_factory_.GetWeakPtr(), base::Passed(&file_reference), 849 weak_factory_.GetWeakPtr(), base::Passed(&file_reference),
623 base::Passed(&items_to_swap), total_items_size)); 850 base::Passed(&items_to_swap), total_items_size));
624 } 851 }
625 RecordTracingCounters(); 852 RecordTracingCounters();
626 } 853 }
627 854
628 void BlobMemoryController::OnEvictionComplete( 855 void BlobMemoryController::OnEvictionComplete(
629 scoped_refptr<ShareableFileReference> file_reference, 856 scoped_refptr<ShareableFileReference> file_reference,
630 std::vector<scoped_refptr<ShareableBlobDataItem>> items, 857 std::vector<scoped_refptr<ShareableBlobDataItem>> items,
631 size_t total_items_size, 858 size_t total_items_size,
632 FileCreationInfo result) { 859 std::pair<FileCreationInfo, int64_t /* avail_disk */> result) {
633 if (!file_paging_enabled_) 860 if (!file_paging_enabled_)
634 return; 861 return;
635 862
636 if (result.error != File::FILE_OK) { 863 FileCreationInfo& file_info = std::get<0>(result);
637 DisableFilePaging(result.error); 864 int64_t avail_disk_space = std::get<1>(result);
865
866 if (file_info.error != File::FILE_OK) {
867 DisableFilePaging(file_info.error);
638 return; 868 return;
639 } 869 }
640 870
871 if (avail_disk_space != kUnknownDiskAvailability) {
872 AdjustDiskUsage(static_cast<uint64_t>(avail_disk_space));
873 }
874
641 DCHECK_LT(0, pending_evictions_); 875 DCHECK_LT(0, pending_evictions_);
642 pending_evictions_--; 876 pending_evictions_--;
643 877
644 // Switch item from memory to the new file. 878 // Switch item from memory to the new file.
645 uint64_t offset = 0; 879 uint64_t offset = 0;
646 for (const scoped_refptr<ShareableBlobDataItem>& shareable_item : items) { 880 for (const scoped_refptr<ShareableBlobDataItem>& shareable_item : items) {
647 scoped_refptr<BlobDataItem> new_item( 881 scoped_refptr<BlobDataItem> new_item(
648 new BlobDataItem(base::WrapUnique(new DataElement()), file_reference)); 882 new BlobDataItem(base::WrapUnique(new DataElement()), file_reference));
649 new_item->data_element_ptr()->SetToFilePathRange( 883 new_item->data_element_ptr()->SetToFilePathRange(
650 file_reference->path(), offset, shareable_item->item()->length(), 884 file_reference->path(), offset, shareable_item->item()->length(),
651 result.last_modified); 885 file_info.last_modified);
652 DCHECK(shareable_item->memory_allocation_); 886 DCHECK(shareable_item->memory_allocation_);
653 shareable_item->set_memory_allocation(nullptr); 887 shareable_item->set_memory_allocation(nullptr);
654 shareable_item->set_item(new_item); 888 shareable_item->set_item(new_item);
655 items_paging_to_file_.erase(shareable_item->item_id()); 889 items_paging_to_file_.erase(shareable_item->item_id());
656 offset += shareable_item->item()->length(); 890 offset += shareable_item->item()->length();
657 } 891 }
658 in_flight_memory_used_ -= total_items_size; 892 in_flight_memory_used_ -= total_items_size;
659 893
660 // We want callback on blobs up to the amount we've freed. 894 // We want callback on blobs up to the amount we've freed.
661 MaybeGrantPendingMemoryRequests(); 895 MaybeGrantPendingMemoryRequests();
(...skipping 27 matching lines...) Expand all
689 uint64_t BlobMemoryController::GetAvailableFileSpaceForBlobs() const { 923 uint64_t BlobMemoryController::GetAvailableFileSpaceForBlobs() const {
690 if (!file_paging_enabled_) 924 if (!file_paging_enabled_)
691 return 0; 925 return 0;
692 // Sometimes we're only paging part of what we need for the new blob, so add 926 // 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. 927 // the rest of the size we need into our disk usage if this is the case.
694 uint64_t total_disk_used = disk_used_; 928 uint64_t total_disk_used = disk_used_;
695 if (in_flight_memory_used_ < pending_memory_quota_total_size_) { 929 if (in_flight_memory_used_ < pending_memory_quota_total_size_) {
696 total_disk_used += 930 total_disk_used +=
697 pending_memory_quota_total_size_ - in_flight_memory_used_; 931 pending_memory_quota_total_size_ - in_flight_memory_used_;
698 } 932 }
699 if (limits_.max_blob_disk_space < total_disk_used) 933 if (limits_.effective_max_disk_space < total_disk_used)
700 return 0; 934 return 0;
701 return limits_.max_blob_disk_space - total_disk_used; 935 return limits_.effective_max_disk_space - total_disk_used;
702 } 936 }
703 937
704 void BlobMemoryController::GrantMemoryAllocations( 938 void BlobMemoryController::GrantMemoryAllocations(
705 std::vector<scoped_refptr<ShareableBlobDataItem>>* items, 939 std::vector<scoped_refptr<ShareableBlobDataItem>>* items,
706 size_t total_bytes) { 940 size_t total_bytes) {
707 // These metrics let us calculate the global distribution of blob storage by 941 // These metrics let us calculate the global distribution of blob storage by
708 // subtracting the histograms. 942 // subtracting the histograms.
709 UMA_HISTOGRAM_COUNTS("Storage.Blob.StorageSizeBeforeAppend", 943 UMA_HISTOGRAM_COUNTS("Storage.Blob.StorageSizeBeforeAppend",
710 blob_memory_used_ / 1024); 944 blob_memory_used_ / 1024);
711 blob_memory_used_ += total_bytes; 945 blob_memory_used_ += total_bytes;
(...skipping 29 matching lines...) Expand all
741 MaybeGrantPendingMemoryRequests(); 975 MaybeGrantPendingMemoryRequests();
742 } 976 }
743 977
744 void BlobMemoryController::OnBlobFileDelete(uint64_t size, 978 void BlobMemoryController::OnBlobFileDelete(uint64_t size,
745 const FilePath& path) { 979 const FilePath& path) {
746 DCHECK_LE(size, disk_used_); 980 DCHECK_LE(size, disk_used_);
747 disk_used_ -= size; 981 disk_used_ -= size;
748 } 982 }
749 983
750 } // namespace storage 984 } // namespace storage
OLDNEW
« no previous file with comments | « storage/browser/blob/blob_memory_controller.h ('k') | storage/browser/blob/blob_storage_context.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698