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

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

Issue 2339933004: [BlobStorage] BlobMemoryController & tests (Closed)
Patch Set: rebase Created 4 years, 3 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
(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
pwnall 2016/09/21 22:56:58 It might be easier to reason about what's in this
dmurph 2016/09/23 20:15:14 MAkes sense. I tried to fix my language, let me kn
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.
pwnall 2016/09/21 22:56:59 is if -> is true if? Please feel free to discard
dmurph 2016/09/23 20:15:14 Fixed.
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 EnableFilePaging(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 DisableFilePaging();
96
97 bool file_paging_enabled() const { return file_paging_enabled_; }
98
99 // Returns the strategy the transportation layer should use to transport the
100 // given memory. |preemptive_transported_bytes| are the number of transport
101 // bytes that are already populated for us, so we don't haved to request them
102 // from the renderer.
103 Strategy DetermineStrategy(size_t preemptive_transported_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|. The items must
pwnall 2016/09/21 22:56:59 "This" seems unnecessary here, and diverges from t
dmurph 2016/09/23 20:15:14 Done.
110 // be bytes items in QUOTA_NEEDED state, 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.
pwnall 2016/09/21 22:56:58 Would it make sense to have a stronger requirement
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|. The items must
123 // be temporary file items (BlobDataBuilder::IsTemporaryFileItem returns true)
124 // in QUOTA_NEEDED state, which we change to QUOTA_REQUESTED. After we reserve
125 // file quota we change their state to QUOTA_GRANTED and call
126 // |success_callback|.
127 // NOTE: We don't inspect quota limits and assume the user checked
pwnall 2016/09/21 22:56:59 nit: not sure if "user" is common, but I think "ca
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
pwnall 2016/09/21 22:56:58 Who is responsible for updating the LRU cache/list
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 BlobStorageLimits& limits() const { return limits_; }
159 void SetLimitsForTesting(BlobStorageLimits limits) { limits_ = limits; }
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 ReserveFileQuota. We make
pwnall 2016/09/21 22:56:59 Everything after the first sentence seems like an
dmurph 2016/09/23 20:15:14 removed.
169 // sure to handle the case where the user had cancelled the operation, and if
pwnall 2016/09/21 22:56:58 I find "user" mildly confusing here. I'm guessing
170 // successful we add the callback to the file reference to decrement our disk
171 // usage on destruction. Then we foward the files and result to the
172 // |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
pwnall 2016/09/21 22:56:58 "We" seems redundant. The first sentence seems to
dmurph 2016/09/23 20:15:14 Done.
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 GetAvailableFileSpaceForBlobs() 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 BlobStorageLimits limits_;
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 file_paging_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_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698