OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #ifndef STORAGE_BROWSER_BLOB_BLOB_MEMORY_CONTROLLER_H_ |
| 6 #define STORAGE_BROWSER_BLOB_BLOB_MEMORY_CONTROLLER_H_ |
| 7 |
| 8 #include <stdint.h> |
| 9 |
| 10 #include <list> |
| 11 #include <map> |
| 12 #include <memory> |
| 13 #include <string> |
| 14 #include <unordered_map> |
| 15 #include <unordered_set> |
| 16 #include <utility> |
| 17 #include <vector> |
| 18 |
| 19 #include "base/callback.h" |
| 20 #include "base/containers/mru_cache.h" |
| 21 #include "base/files/file.h" |
| 22 #include "base/files/file_path.h" |
| 23 #include "base/macros.h" |
| 24 #include "base/memory/ref_counted.h" |
| 25 #include "base/memory/weak_ptr.h" |
| 26 #include "base/optional.h" |
| 27 #include "base/time/time.h" |
| 28 #include "storage/browser/storage_browser_export.h" |
| 29 #include "storage/common/blob_storage/blob_storage_constants.h" |
| 30 |
| 31 namespace base { |
| 32 class TaskRunner; |
| 33 } |
| 34 |
| 35 namespace storage { |
| 36 class DataElement; |
| 37 class ShareableBlobDataItem; |
| 38 class ShareableFileReference; |
| 39 |
| 40 // This class is responsible for file & memory quota bookkeeping, creating files |
| 41 // and paging old blob items to disk, and keeping track of an LRU of blob items. |
| 42 // |
| 43 // See ReserveMemoryQuotaForItems and ReserveFileQuotaForItems for reserving |
| 44 // memory and file quota respectively, and use MaybeFreeQuotaForItems to free |
| 45 // quota. |
| 46 // |
| 47 // Use UpdateBlobItemInRecents & RemoveBlobItemInRecents for modifying the LRU |
| 48 // of blob items. |
| 49 class STORAGE_EXPORT BlobMemoryController { |
| 50 public: |
| 51 enum class Strategy { |
| 52 // We don't have enough memory for this blob. |
| 53 TOO_LARGE, |
| 54 // There isn't any memory that needs transporting. |
| 55 NONE_NEEDED, |
| 56 // Transportation strategies. |
| 57 IPC, |
| 58 SHARED_MEMORY, |
| 59 FILE |
| 60 }; |
| 61 |
| 62 struct FileCreationInfo { |
| 63 FileCreationInfo(); |
| 64 ~FileCreationInfo(); |
| 65 FileCreationInfo(FileCreationInfo&& other); |
| 66 FileCreationInfo& operator=(FileCreationInfo&&); |
| 67 |
| 68 base::File::Error error = base::File::FILE_ERROR_FAILED; |
| 69 scoped_refptr<ShareableFileReference> file_reference; |
| 70 base::File file; |
| 71 base::Time last_modified; |
| 72 }; |
| 73 |
| 74 // The bool argument is if we were able to successfuly receive quota. |
| 75 using FileQuotaRequestCallback = |
| 76 base::Callback<void(bool, std::vector<FileCreationInfo>)>; |
| 77 using PendingFileQuotaRequest = uint64_t; |
| 78 static const uint64_t kInvalidFileQuotaRequest = 0; |
| 79 |
| 80 // The bool argument is if we were able to successfuly receive quota. |
| 81 using MemoryQuotaRequestCallback = base::Callback<void(bool)>; |
| 82 using PendingBlobConstructionList = |
| 83 std::list<std::pair<size_t, MemoryQuotaRequestCallback>>; |
| 84 using PendingMemoryQuotaRequest = PendingBlobConstructionList::iterator; |
| 85 PendingMemoryQuotaRequest GetInvalidMemoryQuotaRequest(); |
| 86 |
| 87 BlobMemoryController(); |
| 88 virtual ~BlobMemoryController(); |
| 89 |
| 90 void EnableDisk(const base::FilePath& storage_directory, |
| 91 scoped_refptr<base::TaskRunner> file_runner); |
| 92 |
| 93 // Disables the disk. This cancels all pending file creations and paging |
| 94 // operations. |
| 95 void DisableDisk(); |
| 96 |
| 97 bool disk_enabled() const { return disk_enabled_; } |
| 98 |
| 99 // Returns the strategy the transportation layer should use to transport the |
| 100 // given memory. |shortcut_bytes| are the number of transport bytes that are |
| 101 // already populated for us, so we don't haved to request them from the |
| 102 // renderer. |
| 103 Strategy DetermineStrategy(size_t shortcut_bytes, |
| 104 uint64_t total_transportation_bytes) const; |
| 105 |
| 106 // Checks to see if we can reserve quota (disk or memory) for the given size. |
| 107 bool CanReserveQuota(uint64_t size) const; |
| 108 |
| 109 // This reserves quota for the given |unreserved_memory_items|. We expect |
| 110 // the item states to start QUOTA_NEEDED, which we change to QUOTA_REQUESTED. |
| 111 // After we reserve memory quota we change their state to QUOTA_GRANTED and |
| 112 // call |success_callback|. This can happen synchronously. |
| 113 // NOTE: We don't inspect quota limits and assume the user checked |
| 114 // CanReserveQuota before calling this. |
| 115 // Returns a value if we're async for use with CancelMemoryQuotaReservation. |
| 116 PendingMemoryQuotaRequest ReserveMemoryQuota( |
| 117 std::vector<ShareableBlobDataItem*> unreserved_memory_items, |
| 118 const MemoryQuotaRequestCallback& success_callback); |
| 119 |
| 120 void CancelMemoryQuotaReservation(const PendingMemoryQuotaRequest& entry); |
| 121 |
| 122 // This reserves quota for the given |unreserved_file_items|. We expect |
| 123 // the item states to start QUOTA_NEEDED, which we change to QUOTA_REQUESTED. |
| 124 // After we reserve memory quota we change their state to QUOTA_GRANTED and |
| 125 // call |success_callback|. All items should be temporary file items |
| 126 // (BlobDataBuilder::IsTemporaryFileItem returns true). |
| 127 // NOTE: We don't inspect quota limits and assume the user checked |
| 128 // CanReserveQuota before calling this. |
| 129 // The return value can be used with CancelFileQuotaReservation to cancel. |
| 130 PendingFileQuotaRequest ReserveFileQuota( |
| 131 std::vector<ShareableBlobDataItem*> unreserved_file_items, |
| 132 const FileQuotaRequestCallback& success_callback); |
| 133 |
| 134 void CancelFileQuotaReservation(const PendingFileQuotaRequest& entry); |
| 135 |
| 136 // This frees quota for items that don't have any blob references. |
| 137 void MaybeFreeQuotaForItems( |
| 138 const std::vector<scoped_refptr<ShareableBlobDataItem>>& items); |
| 139 |
| 140 // This is used to release quota for an item that was supposed to be filled |
| 141 // with a data copy from an item in another blob, but by the time the copy |
| 142 // was meant to be performed the original item had been paged to file. This |
| 143 // functionally just decrements the memory by the item length, but we do |
| 144 // extra checks to make sure our state is correct. |
| 145 void FreeQuotaForPagedItemReference( |
| 146 const scoped_refptr<ShareableBlobDataItem>& item); |
| 147 |
| 148 // This adds or updates a bytes item in our LRU table used for paging items |
| 149 // to disk. The item must have state POPULATED_WITH_QUOTA. |
| 150 void UpdateBlobItemInRecents(ShareableBlobDataItem* item); |
| 151 void RemoveBlobItemInRecents(const ShareableBlobDataItem& item); |
| 152 |
| 153 size_t memory_usage() const { |
| 154 return blob_memory_used_ + in_flight_memory_used_; |
| 155 } |
| 156 uint64_t disk_usage() const { return disk_used_; } |
| 157 |
| 158 const BlobStorageQuotas& quotas() const { return quotas_; } |
| 159 void SetQuotasForTesting(BlobStorageQuotas quotas) { quotas_ = quotas; } |
| 160 |
| 161 private: |
| 162 // Must be class method because state_ is private in ShareableBlobDataItem. |
| 163 void SetStateQuotaGrantedAndCallback( |
| 164 std::vector<scoped_refptr<ShareableBlobDataItem>> items, |
| 165 const BlobMemoryController::MemoryQuotaRequestCallback& final_callback, |
| 166 bool success); |
| 167 |
| 168 // Called when we've finished creating files for ReserveQuotaForItems when the |
| 169 // items are pending file items. We handle error cases, the case where the |
| 170 // cancels the quota reservation, and the success case where we add a delete |
| 171 // callback to the file reference to decrement our disk usage before fowarding |
| 172 // the files and result to the |file_callback|. |
| 173 void OnCreateFiles( |
| 174 std::vector<uint64_t> file_sizes, |
| 175 std::vector<scoped_refptr<ShareableBlobDataItem>> pending_items, |
| 176 uint64_t disk_quota_entry, |
| 177 const FileQuotaRequestCallback& file_callback, |
| 178 std::vector<FileCreationInfo> result); |
| 179 |
| 180 void MaybeGrantPendingQuotaRequests(); |
| 181 |
| 182 // We schedule paging until our memory usage is below our memory limit. We use |
| 183 // the lru table to find old items, and we combine them until we reach the |
| 184 // min_page_file_size(), and don't schedule paging until we have at least that |
| 185 // amount of memory to save to disk. |
| 186 void MaybeSchedulePagingUntilSystemHealthy(); |
| 187 |
| 188 // Called when we've completed paging a list of items to disk. This is where |
| 189 // we swap the bytes items for file items, and and update our bookkeeping. |
| 190 void OnPagingComplete( |
| 191 std::unique_ptr<std::vector<scoped_refptr<ShareableBlobDataItem>>> items, |
| 192 size_t total_items_size, |
| 193 FileCreationInfo result); |
| 194 |
| 195 void RecordTracingCounters(); |
| 196 |
| 197 size_t GetAvailableMemoryForBlobs() const; |
| 198 uint64_t GetAvailableDiskSpaceForBlobs() const; |
| 199 |
| 200 // This is registered as a callback for file deletions on the file reference |
| 201 // of our paging files. We decrement the disk space used. |
| 202 void OnBlobFileDelete(uint64_t size, const base::FilePath& path); |
| 203 |
| 204 BlobStorageQuotas quotas_; |
| 205 |
| 206 // Memory bookkeeping. These numbers are all disjoint. |
| 207 // This is the amount of memory we're using for blobs in RAM. |
| 208 size_t blob_memory_used_ = 0; |
| 209 // This is memory we're temporarily using while we try to write blob items to |
| 210 // disk. |
| 211 size_t in_flight_memory_used_ = 0; |
| 212 // This is the amount of memory we're using on disk. |
| 213 uint64_t disk_used_ = 0; |
| 214 |
| 215 size_t pending_pagings_ = 0; |
| 216 PendingBlobConstructionList blobs_waiting_for_paging_; |
| 217 size_t blobs_waiting_for_paging_size_ = 0; |
| 218 |
| 219 // We use the same data storage as above to keep the PendingEntry API |
| 220 // consistent. |
| 221 uint64_t curr_disk_save_entry_ = 0; |
| 222 std::unordered_map<uint64_t, uint64_t> pending_file_request_sizes_; |
| 223 |
| 224 scoped_refptr<base::TaskRunner> file_runner_; |
| 225 |
| 226 bool disk_enabled_ = false; |
| 227 base::FilePath blob_storage_dir_; |
| 228 uint64_t current_file_num_ = 0; |
| 229 |
| 230 // Lifetime of the ShareableBlobDataItem objects is handled externally in the |
| 231 // BlobStorageContext class. |
| 232 base::MRUCache<uint64_t, ShareableBlobDataItem*> recent_item_cache_; |
| 233 size_t recent_item_cache_bytes_ = 0; |
| 234 // We need to keep track of items currently being paged to disk so that if |
| 235 // another blob successfully grabs a ref, we can prevent it from adding the |
| 236 // item to the recent_item_cache_ above. |
| 237 std::unordered_set<uint64_t> items_saving_to_disk_; |
| 238 |
| 239 base::WeakPtrFactory<BlobMemoryController> ptr_factory_; |
| 240 |
| 241 DISALLOW_COPY_AND_ASSIGN(BlobMemoryController); |
| 242 }; |
| 243 } // namespace storage |
| 244 #endif // STORAGE_BROWSER_BLOB_BLOB_MEMORY_CONTROLLER_H_ |
OLD | NEW |