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

Side by Side Diff: content/browser/blob_storage/blob_memory_controller_unittest.cc

Issue 2339933004: [BlobStorage] BlobMemoryController & tests (Closed)
Patch Set: comments and in_flight limit simplification (using min_page_file_size) Created 4 years, 2 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 #include "storage/browser/blob/blob_memory_controller.h"
6
7 #include "base/bind.h"
8 #include "base/files/file_util.h"
9 #include "base/files/scoped_temp_dir.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/run_loop.h"
12 #include "base/test/test_simple_task_runner.h"
13 #include "base/threading/thread_restrictions.h"
14 #include "base/threading/thread_task_runner_handle.h"
15 #include "storage/browser/blob/blob_data_builder.h"
16 #include "storage/browser/blob/blob_data_item.h"
17 #include "storage/browser/blob/shareable_blob_data_item.h"
18 #include "storage/common/data_element.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20
21 namespace storage {
22
23 using Strategy = BlobMemoryController::Strategy;
24 using FileCreationInfo = BlobMemoryController::FileCreationInfo;
25 using base::TestSimpleTaskRunner;
26 using ItemState = ShareableBlobDataItem::State;
27 using QuotaAllocationTask = BlobMemoryController::QuotaAllocationTask;
28
29 const std::string kBlobStorageDirectory = "blob_storage";
30 const size_t kTestBlobStorageIPCThresholdBytes = 20;
31 const size_t kTestBlobStorageMaxSharedMemoryBytes = 50;
32 const size_t kTestBlobStorageMaxBlobMemorySize = 500;
33 const uint64_t kTestBlobStorageMaxDiskSpace = 1000;
34 const uint64_t kTestBlobStorageMinFileSizeBytes = 10;
35 const uint64_t kTestBlobStorageMaxFileSizeBytes = 100;
36
37 class BlobMemoryControllerTest : public testing::Test {
38 protected:
39 BlobMemoryControllerTest() {}
40
41 void SetUp() override {
42 ASSERT_EQ(true, temp_dir_.CreateUniqueTempDir());
kinuko 2016/10/20 16:15:34 nit: ASSERT_TRUE? (For all similar lines, unless
dmurph 2016/10/20 21:05:22 Done.
43 base::ThreadRestrictions::SetIOAllowed(false);
44 };
45
46 void TearDown() override {
47 files_created_.clear();
48 // Make sure we clean up the files.
49 base::RunLoop().RunUntilIdle();
50 RunFileThreadTasks();
51 base::RunLoop().RunUntilIdle();
52 base::ThreadRestrictions::SetIOAllowed(true);
53 ASSERT_EQ(true, temp_dir_.Delete());
54 }
55
56 std::vector<scoped_refptr<ShareableBlobDataItem>> CreateSharedDataItems(
57 const BlobDataBuilder& builder) {
58 std::vector<scoped_refptr<ShareableBlobDataItem>> result;
59 for (size_t i = 0; i < builder.items_.size(); ++i) {
60 result.push_back(make_scoped_refptr(
61 new ShareableBlobDataItem(builder.uuid(), builder.items_[i],
62 ShareableBlobDataItem::QUOTA_NEEDED)));
63 }
64 return result;
65 }
66
67 void SetTestMemoryLimits(BlobMemoryController* controller) {
68 BlobStorageLimits limits;
69 limits.max_ipc_memory_size = kTestBlobStorageIPCThresholdBytes;
70 limits.max_shared_memory_size = kTestBlobStorageMaxSharedMemoryBytes;
71 limits.max_blob_in_memory_space = kTestBlobStorageMaxBlobMemorySize;
72 limits.max_blob_disk_space = kTestBlobStorageMaxDiskSpace;
73 limits.min_page_file_size = kTestBlobStorageMinFileSizeBytes;
74 limits.max_file_size = kTestBlobStorageMaxFileSizeBytes;
75 controller->set_limits_for_testing(limits);
76 }
77
78 void SaveFileCreationInfo(bool success, std::vector<FileCreationInfo> info) {
79 file_quota_result_ = success;
80 if (success)
81 files_created_.swap(info);
kinuko 2016/10/20 16:15:34 nit: { } for consistency
dmurph 2016/10/20 21:05:22 Done.
82 }
83
84 void SaveMemoryRequest(bool success) { memory_quota_result_ = success; }
85
86 BlobMemoryController::FileQuotaRequestCallback GetFileCreationCallback() {
87 return base::Bind(&BlobMemoryControllerTest::SaveFileCreationInfo,
88 base::Unretained(this));
89 }
90
91 BlobMemoryController::MemoryQuotaRequestCallback GetMemoryRequestCallback() {
92 return base::Bind(&BlobMemoryControllerTest::SaveMemoryRequest,
93 base::Unretained(this));
94 }
95
96 void CleanUpFileItemsFromController(
97 BlobMemoryController* controller,
98 std::vector<scoped_refptr<ShareableBlobDataItem>> items,
99 const std::string& blob_id) {
100 // Make items free from blob references
101 for (const auto& item : items) {
102 item->referencing_blobs_mutable()->erase(blob_id);
103 }
104
105 // We need the shareable file reference to go away, which schedules tasks
106 // that
107 // eventually calls back to our system and decrements our disk usage.
kinuko 2016/10/20 16:15:34 nit: line wraps look a bit off
dmurph 2016/10/20 21:05:22 Done.
108 items.clear();
109 base::RunLoop().RunUntilIdle();
110 EXPECT_TRUE(file_runner_->HasPendingTask());
111 RunFileThreadTasks();
112 base::RunLoop().RunUntilIdle();
113 }
114
115 void RunFileThreadTasks() {
116 base::ThreadRestrictions::SetIOAllowed(true);
117 file_runner_->RunPendingTasks();
118 base::ThreadRestrictions::SetIOAllowed(false);
119 }
120
121 bool HasMemoryAllocation(ShareableBlobDataItem* item) {
122 return static_cast<bool>(item->memory_allocation_);
123 }
124
125 bool file_quota_result_ = false;
126 base::ScopedTempDir temp_dir_;
127 std::vector<FileCreationInfo> files_created_;
128 bool memory_quota_result_ = false;
129
130 scoped_refptr<TestSimpleTaskRunner> file_runner_ = new TestSimpleTaskRunner();
131
132 base::MessageLoop fake_io_message_loop_;
133 };
134
135 TEST_F(BlobMemoryControllerTest, Strategy) {
136 {
137 BlobMemoryController controller(temp_dir_.GetPath(), nullptr);
138 SetTestMemoryLimits(&controller);
139
140 // No transportation needed.
141 EXPECT_EQ(Strategy::NONE_NEEDED, controller.DetermineStrategy(0, 0));
142
143 // IPC.
144 EXPECT_EQ(Strategy::IPC, controller.DetermineStrategy(
145 0, kTestBlobStorageIPCThresholdBytes));
146
147 // Shared Memory.
148 EXPECT_EQ(
149 Strategy::SHARED_MEMORY,
150 controller.DetermineStrategy(kTestBlobStorageIPCThresholdBytes,
151 kTestBlobStorageMaxSharedMemoryBytes));
152 EXPECT_EQ(
153 Strategy::SHARED_MEMORY,
154 controller.DetermineStrategy(0, kTestBlobStorageMaxBlobMemorySize));
155
156 // Too large.
157 EXPECT_EQ(
158 Strategy::TOO_LARGE,
159 controller.DetermineStrategy(0, kTestBlobStorageMaxBlobMemorySize + 1));
160 }
161 {
162 // Enable disk, and check file strategies.
163 BlobMemoryController controller(temp_dir_.GetPath(), file_runner_);
164 SetTestMemoryLimits(&controller);
165
166 EXPECT_EQ(
167 Strategy::SHARED_MEMORY,
168 controller.DetermineStrategy(0, kTestBlobStorageMaxBlobMemorySize -
169 kTestBlobStorageMinFileSizeBytes));
170 EXPECT_EQ(Strategy::FILE, controller.DetermineStrategy(
171 0, kTestBlobStorageMaxBlobMemorySize -
172 kTestBlobStorageMinFileSizeBytes + 1));
173
174 EXPECT_EQ(Strategy::FILE, controller.DetermineStrategy(
175 0, kTestBlobStorageMaxBlobMemorySize));
176
177 // Too large for disk.
178 EXPECT_EQ(Strategy::TOO_LARGE, controller.DetermineStrategy(
179 0, kTestBlobStorageMaxDiskSpace + 1));
180 }
181 }
182
183 TEST_F(BlobMemoryControllerTest, GrantMemory) {
184 const std::string kId = "id";
185 BlobMemoryController controller(temp_dir_.GetPath(), file_runner_);
186 SetTestMemoryLimits(&controller);
187
188 BlobDataBuilder builder(kId);
189 builder.AppendFutureData(10);
190 builder.AppendFutureData(20);
191 builder.AppendFutureData(30);
192
193 std::vector<scoped_refptr<ShareableBlobDataItem>> items =
194 CreateSharedDataItems(builder);
195
196 controller.ReserveMemoryQuota(items, GetMemoryRequestCallback());
197 EXPECT_TRUE(memory_quota_result_);
198 EXPECT_EQ(ItemState::QUOTA_GRANTED, items[0]->state());
199 EXPECT_TRUE(HasMemoryAllocation(items[0].get()));
200 EXPECT_EQ(ItemState::QUOTA_GRANTED, items[1]->state());
201 EXPECT_TRUE(HasMemoryAllocation(items[0].get()));
202 EXPECT_EQ(ItemState::QUOTA_GRANTED, items[2]->state());
203 EXPECT_TRUE(HasMemoryAllocation(items[0].get()));
204 }
205
206 TEST_F(BlobMemoryControllerTest, SimpleMemoryRequest) {
207 const std::string kId = "id";
208 BlobMemoryController controller(temp_dir_.GetPath(), file_runner_);
209 SetTestMemoryLimits(&controller);
210
211 // Add memory item that is the memory quota.
212 BlobDataBuilder builder(kId);
213 builder.AppendFutureData(kTestBlobStorageMaxBlobMemorySize);
214
215 std::vector<scoped_refptr<ShareableBlobDataItem>> items =
216 CreateSharedDataItems(builder);
217
218 base::WeakPtr<QuotaAllocationTask> task =
219 controller.ReserveMemoryQuota(items, GetMemoryRequestCallback());
220 EXPECT_EQ(nullptr, task);
221 EXPECT_TRUE(memory_quota_result_);
222 memory_quota_result_ = false;
223 EXPECT_EQ(ItemState::QUOTA_GRANTED, items[0]->state());
224 EXPECT_FALSE(file_runner_->HasPendingTask());
225 EXPECT_EQ(kTestBlobStorageMaxBlobMemorySize, controller.memory_usage());
226 EXPECT_EQ(0u, controller.disk_usage());
227
228 items.clear();
229 EXPECT_EQ(0u, controller.memory_usage());
230 }
231
232 TEST_F(BlobMemoryControllerTest, PageToDisk) {
233 const std::string kId = "id";
234 const std::string kId2 = "id2";
235 BlobMemoryController controller(temp_dir_.GetPath(), file_runner_);
236 SetTestMemoryLimits(&controller);
237
238 char kData[kTestBlobStorageMaxBlobMemorySize];
239 std::memset(kData, kTestBlobStorageMaxBlobMemorySize, 'e');
240
241 // Add memory item that is the memory quota.
242 BlobDataBuilder builder(kId);
243 builder.AppendFutureData(kTestBlobStorageMaxBlobMemorySize);
244
245 std::vector<scoped_refptr<ShareableBlobDataItem>> items =
246 CreateSharedDataItems(builder);
247
248 controller.ReserveMemoryQuota(items, GetMemoryRequestCallback());
249 EXPECT_TRUE(memory_quota_result_);
250 memory_quota_result_ = false;
251 EXPECT_EQ(ItemState::QUOTA_GRANTED, items[0]->state());
252 EXPECT_FALSE(file_runner_->HasPendingTask());
253 EXPECT_EQ(kTestBlobStorageMaxBlobMemorySize, controller.memory_usage());
254 EXPECT_EQ(0u, controller.disk_usage());
255
256 // Create an item that is just a little too big.
257 BlobDataBuilder builder2(kId2);
258 builder2.AppendFutureData(kTestBlobStorageMinFileSizeBytes + 1);
259
260 // Reserve memory, which should request successfuly but we can't fit it yet
261 // (no callback).
262 std::vector<scoped_refptr<ShareableBlobDataItem>> items2 =
263 CreateSharedDataItems(builder2);
264 base::WeakPtr<QuotaAllocationTask> task =
265 controller.ReserveMemoryQuota(items2, GetMemoryRequestCallback());
266 EXPECT_NE(nullptr, task);
267 // We don't count the usage yet.
268 EXPECT_EQ(kTestBlobStorageMaxBlobMemorySize, controller.memory_usage());
269 EXPECT_EQ(0u, controller.disk_usage());
270
271 EXPECT_FALSE(memory_quota_result_);
272 EXPECT_EQ(ItemState::QUOTA_REQUESTED, items2[0]->state());
273 EXPECT_FALSE(file_runner_->HasPendingTask());
274
275 // Add our original item as populated so it's paged to disk.
276 items[0]->item()->data_element_ptr()->SetToBytes(
277 kData, kTestBlobStorageMaxBlobMemorySize);
278 items[0]->set_state(ItemState::POPULATED_WITH_QUOTA);
279 controller.NotifyMemoryItemsUsed(items);
280
281 EXPECT_TRUE(file_runner_->HasPendingTask());
282 RunFileThreadTasks();
283 base::RunLoop().RunUntilIdle();
284 // items2 are successfuly allocated.
285 EXPECT_EQ(nullptr, task);
286 EXPECT_EQ(ItemState::QUOTA_GRANTED, items2[0]->state());
287 EXPECT_EQ(DataElement::TYPE_FILE, items[0]->item()->type());
288 EXPECT_EQ(kTestBlobStorageMinFileSizeBytes + 1, controller.memory_usage());
289 EXPECT_EQ(kTestBlobStorageMaxBlobMemorySize, controller.disk_usage());
290
291 EXPECT_FALSE(controller.CanReserveQuota(kTestBlobStorageMaxDiskSpace));
292
293 items2.clear();
294 EXPECT_EQ(0u, controller.memory_usage());
295 items.clear();
296 EXPECT_TRUE(file_runner_->HasPendingTask());
297 RunFileThreadTasks();
298 base::RunLoop().RunUntilIdle();
299 EXPECT_EQ(0u, controller.disk_usage());
300 }
301
302 TEST_F(BlobMemoryControllerTest, NoDiskTooLarge) {
303 const std::string kId = "id";
304 BlobMemoryController controller(temp_dir_.GetPath(), nullptr);
305 SetTestMemoryLimits(&controller);
306
307 EXPECT_FALSE(controller.CanReserveQuota(kTestBlobStorageMaxBlobMemorySize +
308 kTestBlobStorageMinFileSizeBytes +
309 1));
310 }
311
312 TEST_F(BlobMemoryControllerTest, TooLargeForDisk) {
313 const std::string kId = "id";
314 BlobMemoryController controller(temp_dir_.GetPath(), file_runner_);
315 SetTestMemoryLimits(&controller);
316
317 EXPECT_FALSE(controller.CanReserveQuota(kTestBlobStorageMaxDiskSpace + 1));
318 }
319
320 TEST_F(BlobMemoryControllerTest, CancelMemoryRequest) {
321 const std::string kId = "id";
322 const std::string kId2 = "id2";
323 BlobMemoryController controller(temp_dir_.GetPath(), file_runner_);
324 SetTestMemoryLimits(&controller);
325
326 char kData[kTestBlobStorageMaxBlobMemorySize];
327 std::memset(kData, kTestBlobStorageMaxBlobMemorySize, 'e');
328
329 // Add memory item that is the memory quota.
330 BlobDataBuilder builder(kId);
331 builder.AppendFutureData(kTestBlobStorageMaxBlobMemorySize);
332
333 std::vector<scoped_refptr<ShareableBlobDataItem>> items =
334 CreateSharedDataItems(builder);
335
336 controller.ReserveMemoryQuota(items, GetMemoryRequestCallback());
337
338 // Create an item that is just a little too big.
339 BlobDataBuilder builder2(kId2);
340 builder2.AppendFutureData(kTestBlobStorageMinFileSizeBytes + 1);
341
342 // Reserve memory, which should request successfuly but we can't fit it yet
343 // (no callback).
344 std::vector<scoped_refptr<ShareableBlobDataItem>> items2 =
345 CreateSharedDataItems(builder2);
346 base::WeakPtr<QuotaAllocationTask> task =
347 controller.ReserveMemoryQuota(items2, GetMemoryRequestCallback());
348 // We don't count the usage yet.
349 EXPECT_EQ(kTestBlobStorageMaxBlobMemorySize, controller.memory_usage());
350 EXPECT_EQ(0u, controller.disk_usage());
351
352 // Add our original item as populated so we start paging to disk.
353 items[0]->item()->data_element_ptr()->SetToBytes(
354 kData, kTestBlobStorageMaxBlobMemorySize);
355 items[0]->set_state(ItemState::POPULATED_WITH_QUOTA);
356 controller.NotifyMemoryItemsUsed(items);
357
358 EXPECT_TRUE(file_runner_->HasPendingTask());
359 EXPECT_TRUE(task);
360
361 task->Cancel();
362 EXPECT_FALSE(task);
363 RunFileThreadTasks();
364 base::RunLoop().RunUntilIdle();
365 EXPECT_EQ(ItemState::QUOTA_REQUESTED, items2[0]->state());
366 EXPECT_EQ(DataElement::TYPE_FILE, items[0]->item()->type());
367 EXPECT_EQ(0u, controller.memory_usage());
368 EXPECT_EQ(kTestBlobStorageMaxBlobMemorySize, controller.disk_usage());
369
370 CleanUpFileItemsFromController(&controller, std::move(items), kId);
371 EXPECT_EQ(0u, controller.disk_usage());
372 }
373
374 TEST_F(BlobMemoryControllerTest, FileRequest) {
375 const std::string kId = "id";
376 const size_t kBlobSize = kTestBlobStorageMaxBlobMemorySize + 1;
377
378 BlobMemoryController controller(temp_dir_.GetPath(), file_runner_);
379 SetTestMemoryLimits(&controller);
380
381 char kData[kBlobSize];
382 std::memset(kData, kBlobSize, 'e');
383
384 // Add item that is the file quota.
385 BlobDataBuilder builder(kId);
386 builder.AppendFutureFile(0, kBlobSize, 0);
387
388 std::vector<scoped_refptr<ShareableBlobDataItem>> items =
389 CreateSharedDataItems(builder);
390
391 file_quota_result_ = false;
392 base::WeakPtr<QuotaAllocationTask> task =
393 controller.ReserveFileQuota(items, GetFileCreationCallback());
394 EXPECT_TRUE(task);
395 EXPECT_FALSE(file_quota_result_);
396 EXPECT_EQ(ItemState::QUOTA_REQUESTED, items[0]->state());
397 EXPECT_TRUE(file_runner_->HasPendingTask());
398 EXPECT_EQ(0u, controller.memory_usage());
399 EXPECT_EQ(kBlobSize, controller.disk_usage());
400
401 EXPECT_FALSE(controller.CanReserveQuota(kTestBlobStorageMaxDiskSpace));
402
403 RunFileThreadTasks();
404 base::RunLoop().RunUntilIdle();
405 EXPECT_TRUE(file_quota_result_);
406 EXPECT_FALSE(file_runner_->HasPendingTask());
407 EXPECT_FALSE(task);
408
409 // Do the work to populate the file.
410 EXPECT_EQ(1u, files_created_.size());
411 EXPECT_TRUE(
412 builder.PopulateFutureFile(0, std::move(files_created_[0].file_reference),
413 files_created_[0].last_modified));
414 base::ThreadRestrictions::SetIOAllowed(true);
415 files_created_.clear();
416 base::ThreadRestrictions::SetIOAllowed(false);
417 EXPECT_EQ(DataElement::TYPE_FILE, items[0]->item()->type());
418 EXPECT_FALSE(
419 BlobDataBuilder::IsFutureFileItem(items[0]->item()->data_element()));
420
421 builder.Clear();
422 CleanUpFileItemsFromController(&controller, std::move(items), kId);
423 EXPECT_EQ(0u, controller.disk_usage());
424 }
425
426 TEST_F(BlobMemoryControllerTest, CancelFileRequest) {
427 const std::string kId = "id";
428 const size_t kBlobSize = kTestBlobStorageMaxBlobMemorySize + 1;
429
430 BlobMemoryController controller(temp_dir_.GetPath(), file_runner_);
431 SetTestMemoryLimits(&controller);
432
433 char kData[kBlobSize];
434 std::memset(kData, kBlobSize, 'e');
435
436 // Add memory item that is the memory quota.
437 BlobDataBuilder builder(kId);
438 builder.AppendFutureFile(0, kBlobSize, 0);
439
440 std::vector<scoped_refptr<ShareableBlobDataItem>> items =
441 CreateSharedDataItems(builder);
442
443 base::WeakPtr<QuotaAllocationTask> task =
444 controller.ReserveFileQuota(items, GetFileCreationCallback());
445 EXPECT_TRUE(task);
446 EXPECT_EQ(ItemState::QUOTA_REQUESTED, items[0]->state());
447 EXPECT_TRUE(file_runner_->HasPendingTask());
448 EXPECT_EQ(0u, controller.memory_usage());
449 EXPECT_EQ(kBlobSize, controller.disk_usage());
450
451 task->Cancel();
452 EXPECT_FALSE(task);
453 EXPECT_EQ(kBlobSize, controller.disk_usage());
454 EXPECT_TRUE(file_runner_->HasPendingTask());
455 RunFileThreadTasks();
456 base::RunLoop().RunUntilIdle();
457 EXPECT_EQ(0u, controller.disk_usage());
458 }
459
460 TEST_F(BlobMemoryControllerTest, MultipleFilesPaged) {
461 const std::string kId1 = "id";
462 const size_t kSize1 = kTestBlobStorageMaxFileSizeBytes;
463 char kData1[kSize1];
464 std::memset(kData1, 'e', kSize1);
465
466 const std::string kId2 = "id2";
467 const size_t kSize2 = kTestBlobStorageMaxFileSizeBytes;
468 char kData2[kSize2];
469 std::memset(kData2, 'f', kSize2);
470
471 const std::string kId3 = "id3";
472 const size_t kSize3 = kTestBlobStorageMaxBlobMemorySize - 1;
473
474 // Assert we shouldn't trigger paging preemptively.
475 ASSERT_LE(kSize1 + kSize2, kTestBlobStorageMaxBlobMemorySize);
476
477 BlobMemoryController controller(temp_dir_.GetPath(), file_runner_);
478 SetTestMemoryLimits(&controller);
479
480 // We add two items that should be their own files when we page to disk, and
481 // then add the last item to trigger the paging.
482
483 BlobDataBuilder builder1(kId1);
484 builder1.AppendFutureData(kSize1);
485 BlobDataBuilder builder2(kId2);
486 builder2.AppendFutureData(kSize2);
487
488 std::vector<scoped_refptr<ShareableBlobDataItem>> items1 =
489 CreateSharedDataItems(builder1);
490 std::vector<scoped_refptr<ShareableBlobDataItem>> items2 =
491 CreateSharedDataItems(builder2);
492
493 memory_quota_result_ = false;
494 controller.ReserveMemoryQuota(items1, GetMemoryRequestCallback());
495 EXPECT_TRUE(memory_quota_result_);
496 memory_quota_result_ = false;
497 controller.ReserveMemoryQuota(items2, GetMemoryRequestCallback());
498 EXPECT_TRUE(memory_quota_result_);
499 EXPECT_EQ(ItemState::QUOTA_GRANTED, items1[0]->state());
500 EXPECT_EQ(ItemState::QUOTA_GRANTED, items2[0]->state());
501 EXPECT_FALSE(file_runner_->HasPendingTask());
502 EXPECT_EQ(kSize1 + kSize2, controller.memory_usage());
503 EXPECT_EQ(0u, controller.disk_usage());
504
505 // Create an item that is too big.
506 BlobDataBuilder builder3(kId3);
507 builder3.AppendFutureData(kSize3);
508
509 std::vector<scoped_refptr<ShareableBlobDataItem>> items3 =
510 CreateSharedDataItems(builder3);
511 memory_quota_result_ = false;
512 controller.ReserveMemoryQuota(items3, GetMemoryRequestCallback());
513 EXPECT_FALSE(memory_quota_result_);
514
515 EXPECT_EQ(ItemState::QUOTA_REQUESTED, items3[0]->state());
516 EXPECT_FALSE(file_runner_->HasPendingTask());
517
518 // Add our original item as populated so it's paged to disk.
519 items1[0]->item()->data_element_ptr()->SetToBytes(kData1, kSize1);
520 items1[0]->set_state(ItemState::POPULATED_WITH_QUOTA);
521 items2[0]->item()->data_element_ptr()->SetToBytes(kData2, kSize2);
522 items2[0]->set_state(ItemState::POPULATED_WITH_QUOTA);
523
524 std::vector<scoped_refptr<ShareableBlobDataItem>> both_items = {items1[0],
525 items2[0]};
526 controller.NotifyMemoryItemsUsed(both_items);
527 both_items.clear();
528
529 EXPECT_TRUE(file_runner_->HasPendingTask());
530 RunFileThreadTasks();
531 base::RunLoop().RunUntilIdle();
532 EXPECT_TRUE(memory_quota_result_);
533 EXPECT_EQ(ItemState::QUOTA_GRANTED, items3[0]->state());
534 EXPECT_EQ(DataElement::TYPE_FILE, items1[0]->item()->type());
535 EXPECT_EQ(DataElement::TYPE_FILE, items2[0]->item()->type());
536 EXPECT_NE(items1[0]->item()->path(), items2[0]->item()->path());
537 EXPECT_EQ(kSize3, controller.memory_usage());
538 EXPECT_EQ(kSize1 + kSize2, controller.disk_usage());
539
540 items1.clear();
541 items2.clear();
542 items3.clear();
543
544 EXPECT_EQ(0u, controller.memory_usage());
545 base::RunLoop().RunUntilIdle();
546 EXPECT_TRUE(file_runner_->HasPendingTask());
547 RunFileThreadTasks();
548 base::RunLoop().RunUntilIdle();
549 EXPECT_EQ(0u, controller.disk_usage());
550 }
551
552 TEST_F(BlobMemoryControllerTest, FullEviction) {
553 BlobMemoryController controller(temp_dir_.GetPath(), file_runner_);
554 SetTestMemoryLimits(&controller);
555
556 char kData[1];
557 kData[0] = 'e';
558
559 // Create a bunch of small stuff.
560 std::vector<scoped_refptr<ShareableBlobDataItem>> small_items;
561 for (size_t i = 0;
562 i < kTestBlobStorageMaxBlobMemorySize - kTestBlobStorageMinFileSizeBytes;
563 i++) {
564 BlobDataBuilder builder("fake");
565 builder.AppendData(kData, 1);
566 std::vector<scoped_refptr<ShareableBlobDataItem>> items =
567 CreateSharedDataItems(builder);
568 base::WeakPtr<QuotaAllocationTask> memory_task =
569 controller.ReserveMemoryQuota(items, GetMemoryRequestCallback());
570 EXPECT_FALSE(memory_task);
571 items[0]->set_state(ItemState::POPULATED_WITH_QUOTA);
572 small_items.insert(small_items.end(), items.begin(), items.end());
573 }
574 controller.NotifyMemoryItemsUsed(small_items);
575 EXPECT_FALSE(file_runner_->HasPendingTask());
576 EXPECT_EQ(
577 kTestBlobStorageMaxBlobMemorySize - kTestBlobStorageMinFileSizeBytes,
578 controller.memory_usage());
579
580 // Create maximum size blob to evict ALL small stuff.
581 BlobDataBuilder builder("fake");
582 builder.AppendFutureData(kTestBlobStorageMaxBlobMemorySize -
583 kTestBlobStorageMinFileSizeBytes);
584 std::vector<scoped_refptr<ShareableBlobDataItem>> items =
585 CreateSharedDataItems(builder);
586
587 memory_quota_result_ = false;
588 base::WeakPtr<QuotaAllocationTask> memory_task =
589 controller.ReserveMemoryQuota(items, GetMemoryRequestCallback());
590 EXPECT_TRUE(memory_task);
591 EXPECT_TRUE(file_runner_->HasPendingTask());
592
593 RunFileThreadTasks();
594 base::RunLoop().RunUntilIdle();
595
596 EXPECT_EQ(
597 kTestBlobStorageMaxBlobMemorySize - kTestBlobStorageMinFileSizeBytes,
598 controller.memory_usage());
599 EXPECT_EQ(
600 kTestBlobStorageMaxBlobMemorySize - kTestBlobStorageMinFileSizeBytes,
601 controller.disk_usage());
602
603 EXPECT_TRUE(memory_quota_result_);
604 }
605
606 TEST_F(BlobMemoryControllerTest, DisableDiskWithFileAndMemoryPending) {
607 const std::string kFirstMemoryId = "id";
608 const uint64_t kFirstMemorySize = kTestBlobStorageMaxBlobMemorySize;
609 const std::string kSecondMemoryId = "id2";
610 const uint64_t kSecondMemorySize = 1;
611 const std::string kFileId = "id2";
612 const uint64_t kFileBlobSize = kTestBlobStorageMaxBlobMemorySize;
613
614 BlobMemoryController controller(temp_dir_.GetPath(), file_runner_);
615 SetTestMemoryLimits(&controller);
616
617 char kDataMemoryData[kFirstMemorySize];
618 std::memset(kDataMemoryData, kFirstMemorySize, 'e');
619
620 // Add first memory item to fill up some memory quota.
621 BlobDataBuilder builder(kFirstMemoryId);
622 builder.AppendFutureData(kTestBlobStorageMaxBlobMemorySize);
623
624 std::vector<scoped_refptr<ShareableBlobDataItem>> items =
625 CreateSharedDataItems(builder);
626
627 controller.ReserveMemoryQuota(items, GetMemoryRequestCallback());
628
629 // Create a second memory item that is just a little too big.
630 BlobDataBuilder builder2(kSecondMemoryId);
631 builder2.AppendFutureData(kSecondMemorySize);
632
633 // Reserve memory, which should request successfuly but we can't fit it yet.
634 std::vector<scoped_refptr<ShareableBlobDataItem>> items2 =
635 CreateSharedDataItems(builder2);
636 base::WeakPtr<QuotaAllocationTask> memory_task =
637 controller.ReserveMemoryQuota(items2, GetMemoryRequestCallback());
638 // We don't count the usage yet.
639 EXPECT_EQ(kTestBlobStorageMaxBlobMemorySize, controller.memory_usage());
640 EXPECT_EQ(0u, controller.disk_usage());
641
642 // Add our original item as populated so we start paging it to disk.
643 items[0]->item()->data_element_ptr()->SetToBytes(kDataMemoryData,
644 kFirstMemorySize);
645 items[0]->set_state(ItemState::POPULATED_WITH_QUOTA);
646 controller.NotifyMemoryItemsUsed(items);
647
648 EXPECT_TRUE(file_runner_->HasPendingTask());
649 EXPECT_TRUE(memory_task);
650 EXPECT_EQ(kFirstMemorySize, controller.disk_usage());
651
652 // Add our file item now.
653 BlobDataBuilder file_builder(kFileId);
654 file_builder.AppendFutureFile(0, kFileBlobSize, 0);
655
656 std::vector<scoped_refptr<ShareableBlobDataItem>> file_items =
657 CreateSharedDataItems(file_builder);
658
659 base::WeakPtr<QuotaAllocationTask> file_task =
660 controller.ReserveFileQuota(file_items, GetFileCreationCallback());
661 EXPECT_TRUE(file_task);
662 EXPECT_TRUE(file_runner_->HasPendingTask());
663
664 // We should have both memory paging tasks and file paging tasks.
665 EXPECT_EQ(kFirstMemorySize, controller.memory_usage());
666 EXPECT_EQ(kFirstMemorySize + kFileBlobSize, controller.disk_usage());
667 file_quota_result_ = true;
668 memory_quota_result_ = true;
669
670 files_created_.clear();
671
672 // Disable paging! This should cancel all file-related tasks and leave us with
673 // only the first memory item.
674 controller.DisableFilePaging(base::File::FILE_ERROR_FAILED);
675 EXPECT_FALSE(file_quota_result_);
676 EXPECT_FALSE(memory_quota_result_);
677 EXPECT_FALSE(file_task);
678 EXPECT_FALSE(memory_task);
679
680 file_items.clear();
681 items.clear();
682
683 RunFileThreadTasks();
684 base::RunLoop().RunUntilIdle();
685
686 EXPECT_EQ(0ull, controller.disk_usage());
687 EXPECT_EQ(0ull, controller.memory_usage());
688 }
689 } // namespace storage
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698