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

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

Issue 2516713002: [BlobStorage] Implementing disk. (Closed)
Patch Set: flush maybe worked? Adding it in paging spot. Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "storage/browser/blob/blob_memory_controller.h" 5 #include "storage/browser/blob/blob_memory_controller.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/callback.h" 9 #include "base/callback.h"
10 #include "base/callback_helpers.h" 10 #include "base/callback_helpers.h"
(...skipping 27 matching lines...) Expand all
38 namespace { 38 namespace {
39 using FileCreationInfo = BlobMemoryController::FileCreationInfo; 39 using FileCreationInfo = BlobMemoryController::FileCreationInfo;
40 using MemoryAllocation = BlobMemoryController::MemoryAllocation; 40 using MemoryAllocation = BlobMemoryController::MemoryAllocation;
41 using QuotaAllocationTask = BlobMemoryController::QuotaAllocationTask; 41 using QuotaAllocationTask = BlobMemoryController::QuotaAllocationTask;
42 42
43 File::Error CreateBlobDirectory(const FilePath& blob_storage_dir) { 43 File::Error CreateBlobDirectory(const FilePath& blob_storage_dir) {
44 File::Error error = File::FILE_OK; 44 File::Error error = File::FILE_OK;
45 base::CreateDirectoryAndGetError(blob_storage_dir, &error); 45 base::CreateDirectoryAndGetError(blob_storage_dir, &error);
46 UMA_HISTOGRAM_ENUMERATION("Storage.Blob.CreateDirectoryResult", -error, 46 UMA_HISTOGRAM_ENUMERATION("Storage.Blob.CreateDirectoryResult", -error,
47 -File::FILE_ERROR_MAX); 47 -File::FILE_ERROR_MAX);
48 if (error != File::FILE_OK)
49 LOG(ERROR) << "Error creating blob storage directory: " << error;
48 return error; 50 return error;
49 } 51 }
50 52
51 void DestructFile(File infos_without_references) {} 53 void DestructFile(File infos_without_references) {}
52 54
53 // Used for new unpopulated file items. Caller must populate file reference in 55 // Used for new unpopulated file items. Caller must populate file reference in
54 // returned FileCreationInfos. 56 // returned FileCreationInfos.
55 std::pair<std::vector<FileCreationInfo>, File::Error> CreateEmptyFiles( 57 std::pair<std::vector<FileCreationInfo>, File::Error> CreateEmptyFiles(
56 const FilePath& blob_storage_dir, 58 const FilePath& blob_storage_dir,
57 scoped_refptr<base::TaskRunner> file_task_runner, 59 scoped_refptr<base::TaskRunner> file_task_runner,
58 std::vector<base::FilePath> file_paths) { 60 std::vector<base::FilePath> file_paths) {
59 base::ThreadRestrictions::AssertIOAllowed(); 61 base::ThreadRestrictions::AssertIOAllowed();
60 62
61 File::Error dir_create_status = CreateBlobDirectory(blob_storage_dir); 63 File::Error dir_create_status = CreateBlobDirectory(blob_storage_dir);
62 if (dir_create_status != File::FILE_OK) 64 if (dir_create_status != File::FILE_OK)
63 return std::make_pair(std::vector<FileCreationInfo>(), dir_create_status); 65 return std::make_pair(std::vector<FileCreationInfo>(), dir_create_status);
64 66
65 std::vector<FileCreationInfo> result; 67 std::vector<FileCreationInfo> result;
66 for (const base::FilePath& file_path : file_paths) { 68 for (const base::FilePath& file_path : file_paths) {
67 FileCreationInfo creation_info; 69 FileCreationInfo creation_info;
68 // Try to open our file. 70 // Try to open our file.
69 File file(file_path, File::FLAG_CREATE_ALWAYS | File::FLAG_WRITE); 71 File file(file_path, File::FLAG_CREATE_ALWAYS | File::FLAG_WRITE);
70 creation_info.path = std::move(file_path); 72 creation_info.path = std::move(file_path);
71 creation_info.file_deletion_runner = file_task_runner; 73 creation_info.file_deletion_runner = file_task_runner;
72 creation_info.error = file.error_details(); 74 creation_info.error = file.error_details();
73 if (creation_info.error != File::FILE_OK) { 75 if (creation_info.error != File::FILE_OK) {
74 return std::make_pair(std::vector<FileCreationInfo>(), 76 return std::make_pair(std::vector<FileCreationInfo>(),
75 creation_info.error); 77 creation_info.error);
76 } 78 }
77
78 // Grab the file info to get the "last modified" time and store the file.
79 File::Info file_info;
80 bool success = file.GetInfo(&file_info);
81 creation_info.error = success ? File::FILE_OK : File::FILE_ERROR_FAILED;
82 if (!success) {
83 return std::make_pair(std::vector<FileCreationInfo>(),
84 creation_info.error);
85 }
86 creation_info.file = std::move(file); 79 creation_info.file = std::move(file);
87 80
88 result.push_back(std::move(creation_info)); 81 result.push_back(std::move(creation_info));
89 } 82 }
90 return std::make_pair(std::move(result), File::FILE_OK); 83 return std::make_pair(std::move(result), File::FILE_OK);
91 } 84 }
92 85
93 // Used to evict multiple memory items out to a single file. Caller must 86 // Used to evict multiple memory items out to a single file. Caller must
94 // populate file reference in returned FileCreationInfo. 87 // populate file reference in returned FileCreationInfo.
95 FileCreationInfo CreateFileAndWriteItems( 88 FileCreationInfo CreateFileAndWriteItems(
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
127 file.WriteAtCurrentPos(element->bytes() + (length - bytes_left), 120 file.WriteAtCurrentPos(element->bytes() + (length - bytes_left),
128 base::saturated_cast<int>(bytes_left)); 121 base::saturated_cast<int>(bytes_left));
129 if (bytes_written < 0) 122 if (bytes_written < 0)
130 break; 123 break;
131 DCHECK_LE(static_cast<size_t>(bytes_written), bytes_left); 124 DCHECK_LE(static_cast<size_t>(bytes_written), bytes_left);
132 bytes_left -= bytes_written; 125 bytes_left -= bytes_written;
133 } 126 }
134 if (bytes_written < 0) 127 if (bytes_written < 0)
135 break; 128 break;
136 } 129 }
130 if (!file.Flush()) {
131 creation_info.error = File::FILE_ERROR_FAILED;
132 return creation_info;
133 }
137 134
138 File::Info info; 135 File::Info info;
139 bool success = file.GetInfo(&info); 136 bool success = file.GetInfo(&info);
140 creation_info.error = 137 creation_info.error =
141 bytes_written < 0 || !success ? File::FILE_ERROR_FAILED : File::FILE_OK; 138 bytes_written < 0 || !success ? File::FILE_ERROR_FAILED : File::FILE_OK;
142 creation_info.last_modified = info.last_modified; 139 creation_info.last_modified = info.last_modified;
143 return creation_info; 140 return creation_info;
144 } 141 }
145 142
146 uint64_t GetTotalSizeAndFileSizes( 143 uint64_t GetTotalSizeAndFileSizes(
147 const std::vector<scoped_refptr<ShareableBlobDataItem>>& 144 const std::vector<scoped_refptr<ShareableBlobDataItem>>&
148 unreserved_file_items, 145 unreserved_file_items,
149 std::vector<uint64_t>* file_sizes_output) { 146 std::vector<uint64_t>* file_sizes_output) {
150 uint64_t total_size_output = 0; 147 uint64_t total_size_output = 0;
151 base::SmallMap<std::map<uint64_t, uint64_t>> file_id_to_sizes; 148 base::SmallMap<std::map<uint64_t, uint64_t>> file_id_to_sizes;
152 for (const auto& item : unreserved_file_items) { 149 for (const auto& item : unreserved_file_items) {
153 const DataElement& element = item->item()->data_element(); 150 const DataElement& element = item->item()->data_element();
154 uint64_t file_id = BlobDataBuilder::GetFutureFileID(element); 151 uint64_t file_id = BlobDataBuilder::GetFutureFileID(element);
155 auto it = file_id_to_sizes.find(file_id); 152 auto it = file_id_to_sizes.find(file_id);
156 if (it != file_id_to_sizes.end()) 153 if (it != file_id_to_sizes.end())
157 it->second = std::max(it->second, element.offset() + element.length()); 154 it->second = std::max(it->second, element.offset() + element.length());
158 else 155 else
159 file_id_to_sizes[file_id] = element.offset() + element.length(); 156 file_id_to_sizes[file_id] = element.offset() + element.length();
160 total_size_output += element.length(); 157 total_size_output += element.length();
161 } 158 }
159 uint64_t sizes_from_files = 0;
162 for (const auto& size_pair : file_id_to_sizes) { 160 for (const auto& size_pair : file_id_to_sizes) {
163 file_sizes_output->push_back(size_pair.second); 161 file_sizes_output->push_back(size_pair.second);
162 sizes_from_files += size_pair.second;
164 } 163 }
164 DCHECK_EQ(sizes_from_files, total_size_output)
165 << "Illegal builder configuration, temporary files must be totally used.";
165 return total_size_output; 166 return total_size_output;
166 } 167 }
167 168
168 } // namespace 169 } // namespace
169 170
170 FileCreationInfo::FileCreationInfo() {} 171 FileCreationInfo::FileCreationInfo() {}
171 FileCreationInfo::~FileCreationInfo() { 172 FileCreationInfo::~FileCreationInfo() {
172 if (file.IsValid()) { 173 if (file.IsValid()) {
173 DCHECK(file_deletion_runner); 174 DCHECK(file_deletion_runner);
174 file_deletion_runner->PostTask( 175 file_deletion_runner->PostTask(
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
291 base::PostTaskAndReplyWithResult( 292 base::PostTaskAndReplyWithResult(
292 controller_->file_runner_.get(), FROM_HERE, 293 controller_->file_runner_.get(), FROM_HERE,
293 base::Bind(&CreateEmptyFiles, controller_->blob_storage_dir_, 294 base::Bind(&CreateEmptyFiles, controller_->blob_storage_dir_,
294 controller_->file_runner_, base::Passed(&file_paths)), 295 controller_->file_runner_, base::Passed(&file_paths)),
295 base::Bind(&FileQuotaAllocationTask::OnCreateEmptyFiles, 296 base::Bind(&FileQuotaAllocationTask::OnCreateEmptyFiles,
296 weak_factory_.GetWeakPtr(), base::Passed(&references))); 297 weak_factory_.GetWeakPtr(), base::Passed(&references)));
297 controller_->RecordTracingCounters(); 298 controller_->RecordTracingCounters();
298 } 299 }
299 ~FileQuotaAllocationTask() override {} 300 ~FileQuotaAllocationTask() override {}
300 301
301 void RunDoneCallback(bool success, std::vector<FileCreationInfo> file_info) { 302 void RunDoneCallback(std::vector<FileCreationInfo> file_info, bool success) {
302 // Make sure we clear the weak pointers we gave to the caller beforehand. 303 // Make sure we clear the weak pointers we gave to the caller beforehand.
303 weak_factory_.InvalidateWeakPtrs(); 304 weak_factory_.InvalidateWeakPtrs();
304 305
305 // We want to destroy this object on the exit of this method if we were 306 // We want to destroy this object on the exit of this method if we were
306 // successful. 307 // successful.
307 std::unique_ptr<FileQuotaAllocationTask> this_object; 308 std::unique_ptr<FileQuotaAllocationTask> this_object;
308 if (success) { 309 if (success) {
309 for (auto& item : pending_items_) { 310 for (auto& item : pending_items_) {
310 item->set_state(ShareableBlobDataItem::QUOTA_GRANTED); 311 item->set_state(ShareableBlobDataItem::QUOTA_GRANTED);
311 } 312 }
312 this_object = std::move(*my_list_position_); 313 this_object = std::move(*my_list_position_);
313 controller_->pending_file_quota_tasks_.erase(my_list_position_); 314 controller_->pending_file_quota_tasks_.erase(my_list_position_);
314 } 315 }
315 316
316 done_callback_.Run(success, std::move(file_info)); 317 done_callback_.Run(std::move(file_info), success);
317 } 318 }
318 319
319 base::WeakPtr<QuotaAllocationTask> GetWeakPtr() { 320 base::WeakPtr<QuotaAllocationTask> GetWeakPtr() {
320 return weak_factory_.GetWeakPtr(); 321 return weak_factory_.GetWeakPtr();
321 } 322 }
322 323
323 void Cancel() override { 324 void Cancel() override {
324 // This call destroys this object. We rely on ShareableFileReference's 325 // This call destroys this object. We rely on ShareableFileReference's
325 // final release callback for disk_usage_ accounting. 326 // final release callback for disk_usage_ accounting.
326 controller_->pending_file_quota_tasks_.erase(my_list_position_); 327 controller_->pending_file_quota_tasks_.erase(my_list_position_);
327 } 328 }
328 329
329 void OnCreateEmptyFiles( 330 void OnCreateEmptyFiles(
330 std::vector<scoped_refptr<ShareableFileReference>> references, 331 std::vector<scoped_refptr<ShareableFileReference>> references,
331 std::pair<std::vector<FileCreationInfo>, File::Error> files_and_error) { 332 std::pair<std::vector<FileCreationInfo>, File::Error> files_and_error) {
332 auto& files = files_and_error.first; 333 auto& files = files_and_error.first;
333 if (files.empty()) { 334 if (files.empty()) {
334 DCHECK_GE(controller_->disk_used_, allocation_size_); 335 DCHECK_GE(controller_->disk_used_, allocation_size_);
335 controller_->disk_used_ -= allocation_size_; 336 controller_->disk_used_ -= allocation_size_;
336 // This will call our callback and delete the object correctly. 337 // This will call our callback and delete the object correctly.
337 controller_->DisableFilePaging(files_and_error.second); 338 controller_->DisableFilePaging(files_and_error.second);
338 return; 339 return;
339 } 340 }
340 DCHECK_EQ(files.size(), references.size()); 341 DCHECK_EQ(files.size(), references.size());
341 for (size_t i = 0; i < files.size(); i++) { 342 for (size_t i = 0; i < files.size(); i++) {
342 files[i].file_reference = std::move(references[i]); 343 files[i].file_reference = std::move(references[i]);
343 } 344 }
344 RunDoneCallback(true, std::move(files)); 345 RunDoneCallback(std::move(files), true);
345 } 346 }
346 347
347 // The my_list_position_ iterator is stored so that we can remove ourself 348 // The my_list_position_ iterator is stored so that we can remove ourself
348 // from the task list when we are cancelled. 349 // from the task list when we are cancelled.
349 void set_my_list_position( 350 void set_my_list_position(
350 PendingFileQuotaTaskList::iterator my_list_position) { 351 PendingFileQuotaTaskList::iterator my_list_position) {
351 my_list_position_ = my_list_position; 352 my_list_position_ = my_list_position;
352 } 353 }
353 354
354 private: 355 private:
(...skipping 17 matching lines...) Expand all
372 file_runner_(std::move(file_runner)), 373 file_runner_(std::move(file_runner)),
373 populated_memory_items_( 374 populated_memory_items_(
374 base::MRUCache<uint64_t, ShareableBlobDataItem*>::NO_AUTO_EVICT), 375 base::MRUCache<uint64_t, ShareableBlobDataItem*>::NO_AUTO_EVICT),
375 weak_factory_(this) {} 376 weak_factory_(this) {}
376 377
377 BlobMemoryController::~BlobMemoryController() {} 378 BlobMemoryController::~BlobMemoryController() {}
378 379
379 void BlobMemoryController::DisableFilePaging(base::File::Error reason) { 380 void BlobMemoryController::DisableFilePaging(base::File::Error reason) {
380 UMA_HISTOGRAM_ENUMERATION("Storage.Blob.PagingDisabled", -reason, 381 UMA_HISTOGRAM_ENUMERATION("Storage.Blob.PagingDisabled", -reason,
381 -File::FILE_ERROR_MAX); 382 -File::FILE_ERROR_MAX);
383 LOG(ERROR) << "Blob storage paging disabled due to: " << reason;
382 file_paging_enabled_ = false; 384 file_paging_enabled_ = false;
383 in_flight_memory_used_ = 0; 385 in_flight_memory_used_ = 0;
384 items_paging_to_file_.clear(); 386 items_paging_to_file_.clear();
385 pending_evictions_ = 0; 387 pending_evictions_ = 0;
386 pending_memory_quota_total_size_ = 0; 388 pending_memory_quota_total_size_ = 0;
387 populated_memory_items_.Clear(); 389 populated_memory_items_.Clear();
388 populated_memory_items_bytes_ = 0; 390 populated_memory_items_bytes_ = 0;
389 file_runner_ = nullptr; 391 file_runner_ = nullptr;
390 392
391 PendingMemoryQuotaTaskList old_memory_tasks; 393 PendingMemoryQuotaTaskList old_memory_tasks;
392 PendingFileQuotaTaskList old_file_tasks; 394 PendingFileQuotaTaskList old_file_tasks;
393 std::swap(old_memory_tasks, pending_memory_quota_tasks_); 395 std::swap(old_memory_tasks, pending_memory_quota_tasks_);
394 std::swap(old_file_tasks, pending_file_quota_tasks_); 396 std::swap(old_file_tasks, pending_file_quota_tasks_);
395 397
396 // Don't call the callbacks until we have a consistent state. 398 // Don't call the callbacks until we have a consistent state.
397 for (auto& memory_request : old_memory_tasks) { 399 for (auto& memory_request : old_memory_tasks) {
398 memory_request->RunDoneCallback(false); 400 memory_request->RunDoneCallback(false);
399 } 401 }
400 for (auto& file_request : old_file_tasks) { 402 for (auto& file_request : old_file_tasks) {
401 file_request->RunDoneCallback(false, std::vector<FileCreationInfo>()); 403 file_request->RunDoneCallback(std::vector<FileCreationInfo>(), false);
402 } 404 }
403 } 405 }
404 406
405 BlobMemoryController::Strategy BlobMemoryController::DetermineStrategy( 407 BlobMemoryController::Strategy BlobMemoryController::DetermineStrategy(
406 size_t preemptive_transported_bytes, 408 size_t preemptive_transported_bytes,
407 uint64_t total_transportation_bytes) const { 409 uint64_t total_transportation_bytes) const {
408 if (total_transportation_bytes == 0) 410 if (total_transportation_bytes == 0)
409 return Strategy::NONE_NEEDED; 411 return Strategy::NONE_NEEDED;
410 if (!CanReserveQuota(total_transportation_bytes)) 412 if (!CanReserveQuota(total_transportation_bytes))
411 return Strategy::TOO_LARGE; 413 return Strategy::TOO_LARGE;
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after
738 MaybeGrantPendingMemoryRequests(); 740 MaybeGrantPendingMemoryRequests();
739 } 741 }
740 742
741 void BlobMemoryController::OnBlobFileDelete(uint64_t size, 743 void BlobMemoryController::OnBlobFileDelete(uint64_t size,
742 const FilePath& path) { 744 const FilePath& path) {
743 DCHECK_LE(size, disk_used_); 745 DCHECK_LE(size, disk_used_);
744 disk_used_ -= size; 746 disk_used_ -= size;
745 } 747 }
746 748
747 } // namespace storage 749 } // namespace storage
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698