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

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

Issue 2552153002: [BlobStorage] Enabling disk paging and direct storage. (Closed)
Patch Set: Added an early-exit clause so files don't get created unnecessarily 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 "base/bind.h" 7 #include "base/bind.h"
8 #include "base/files/file_util.h" 8 #include "base/files/file_util.h"
9 #include "base/files/scoped_temp_dir.h" 9 #include "base/files/scoped_temp_dir.h"
10 #include "base/message_loop/message_loop.h" 10 #include "base/message_loop/message_loop.h"
(...skipping 16 matching lines...) Expand all
27 using QuotaAllocationTask = BlobMemoryController::QuotaAllocationTask; 27 using QuotaAllocationTask = BlobMemoryController::QuotaAllocationTask;
28 28
29 const std::string kBlobStorageDirectory = "blob_storage"; 29 const std::string kBlobStorageDirectory = "blob_storage";
30 const size_t kTestBlobStorageIPCThresholdBytes = 20; 30 const size_t kTestBlobStorageIPCThresholdBytes = 20;
31 const size_t kTestBlobStorageMaxSharedMemoryBytes = 50; 31 const size_t kTestBlobStorageMaxSharedMemoryBytes = 50;
32 const size_t kTestBlobStorageMaxBlobMemorySize = 500; 32 const size_t kTestBlobStorageMaxBlobMemorySize = 500;
33 const uint64_t kTestBlobStorageMaxDiskSpace = 1000; 33 const uint64_t kTestBlobStorageMaxDiskSpace = 1000;
34 const uint64_t kTestBlobStorageMinFileSizeBytes = 10; 34 const uint64_t kTestBlobStorageMinFileSizeBytes = 10;
35 const uint64_t kTestBlobStorageMaxFileSizeBytes = 100; 35 const uint64_t kTestBlobStorageMaxFileSizeBytes = 100;
36 36
37 const uint64_t kTestSmallBlobStorageMaxDiskSpace = 100;
38
37 class BlobMemoryControllerTest : public testing::Test { 39 class BlobMemoryControllerTest : public testing::Test {
38 protected: 40 protected:
39 BlobMemoryControllerTest() {} 41 BlobMemoryControllerTest() {}
40 42
41 void SetUp() override { 43 void SetUp() override {
42 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 44 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
43 base::ThreadRestrictions::SetIOAllowed(false); 45 base::ThreadRestrictions::SetIOAllowed(false);
44 }; 46 };
45 47
46 void TearDown() override { 48 void TearDown() override {
(...skipping 20 matching lines...) Expand all
67 BlobStorageLimits limits; 69 BlobStorageLimits limits;
68 limits.max_ipc_memory_size = kTestBlobStorageIPCThresholdBytes; 70 limits.max_ipc_memory_size = kTestBlobStorageIPCThresholdBytes;
69 limits.max_shared_memory_size = kTestBlobStorageMaxSharedMemoryBytes; 71 limits.max_shared_memory_size = kTestBlobStorageMaxSharedMemoryBytes;
70 limits.max_blob_in_memory_space = kTestBlobStorageMaxBlobMemorySize; 72 limits.max_blob_in_memory_space = kTestBlobStorageMaxBlobMemorySize;
71 limits.max_blob_disk_space = kTestBlobStorageMaxDiskSpace; 73 limits.max_blob_disk_space = kTestBlobStorageMaxDiskSpace;
72 limits.min_page_file_size = kTestBlobStorageMinFileSizeBytes; 74 limits.min_page_file_size = kTestBlobStorageMinFileSizeBytes;
73 limits.max_file_size = kTestBlobStorageMaxFileSizeBytes; 75 limits.max_file_size = kTestBlobStorageMaxFileSizeBytes;
74 controller->set_limits_for_testing(limits); 76 controller->set_limits_for_testing(limits);
75 } 77 }
76 78
79 void SetSmallDiskTestMemoryLimits(BlobMemoryController* controller) {
80 BlobStorageLimits limits;
81 limits.max_ipc_memory_size = kTestBlobStorageIPCThresholdBytes;
82 limits.max_shared_memory_size = kTestBlobStorageMaxSharedMemoryBytes;
83 limits.max_blob_in_memory_space = kTestBlobStorageMaxBlobMemorySize;
84 limits.max_blob_disk_space = kTestSmallBlobStorageMaxDiskSpace;
85 limits.min_page_file_size = kTestBlobStorageMinFileSizeBytes;
86 limits.max_file_size = kTestBlobStorageMaxFileSizeBytes;
87 controller->set_limits_for_testing(limits);
88 }
89
77 void SaveFileCreationInfo(std::vector<FileCreationInfo> info, bool success) { 90 void SaveFileCreationInfo(std::vector<FileCreationInfo> info, bool success) {
78 file_quota_result_ = success; 91 file_quota_result_ = success;
79 if (success) { 92 if (success) {
80 files_created_.swap(info); 93 files_created_.swap(info);
81 } 94 }
82 } 95 }
83 96
97 void SaveMemoryRequestToOutput(bool* output, bool success) {
98 ASSERT_TRUE(output);
99 *output = success;
100 }
84 void SaveMemoryRequest(bool success) { memory_quota_result_ = success; } 101 void SaveMemoryRequest(bool success) { memory_quota_result_ = success; }
85 102
86 BlobMemoryController::FileQuotaRequestCallback GetFileCreationCallback() { 103 BlobMemoryController::FileQuotaRequestCallback GetFileCreationCallback() {
87 return base::Bind(&BlobMemoryControllerTest::SaveFileCreationInfo, 104 return base::Bind(&BlobMemoryControllerTest::SaveFileCreationInfo,
88 base::Unretained(this)); 105 base::Unretained(this));
89 } 106 }
90 107
91 BlobMemoryController::MemoryQuotaRequestCallback GetMemoryRequestCallback() { 108 BlobMemoryController::MemoryQuotaRequestCallback GetMemoryRequestCallback() {
92 return base::Bind(&BlobMemoryControllerTest::SaveMemoryRequest, 109 return base::Bind(&BlobMemoryControllerTest::SaveMemoryRequest,
93 base::Unretained(this)); 110 base::Unretained(this));
94 } 111 }
95 112
113 BlobMemoryController::MemoryQuotaRequestCallback
114 GetMemoryRequestCallbackToOutput(bool* output) {
115 return base::Bind(&BlobMemoryControllerTest::SaveMemoryRequestToOutput,
116 base::Unretained(this), output);
117 }
118
96 void RunFileThreadTasks() { 119 void RunFileThreadTasks() {
97 base::ThreadRestrictions::SetIOAllowed(true); 120 base::ThreadRestrictions::SetIOAllowed(true);
98 file_runner_->RunPendingTasks(); 121 file_runner_->RunPendingTasks();
99 base::ThreadRestrictions::SetIOAllowed(false); 122 base::ThreadRestrictions::SetIOAllowed(false);
100 } 123 }
101 124
102 bool HasMemoryAllocation(ShareableBlobDataItem* item) { 125 bool HasMemoryAllocation(ShareableBlobDataItem* item) {
103 return static_cast<bool>(item->memory_allocation_); 126 return static_cast<bool>(item->memory_allocation_);
104 } 127 }
105 128
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
152 0, kTestBlobStorageMaxBlobMemorySize - 175 0, kTestBlobStorageMaxBlobMemorySize -
153 kTestBlobStorageMinFileSizeBytes + 1)); 176 kTestBlobStorageMinFileSizeBytes + 1));
154 177
155 EXPECT_EQ(Strategy::FILE, controller.DetermineStrategy( 178 EXPECT_EQ(Strategy::FILE, controller.DetermineStrategy(
156 0, kTestBlobStorageMaxBlobMemorySize)); 179 0, kTestBlobStorageMaxBlobMemorySize));
157 180
158 // Too large for disk. 181 // Too large for disk.
159 EXPECT_EQ(Strategy::TOO_LARGE, controller.DetermineStrategy( 182 EXPECT_EQ(Strategy::TOO_LARGE, controller.DetermineStrategy(
160 0, kTestBlobStorageMaxDiskSpace + 1)); 183 0, kTestBlobStorageMaxDiskSpace + 1));
161 } 184 }
185 {
186 BlobMemoryController controller(temp_dir_.GetPath(), file_runner_);
187 SetSmallDiskTestMemoryLimits(&controller);
188
189 EXPECT_TRUE(controller.CanReserveQuota(kTestBlobStorageMaxBlobMemorySize));
190 // Since our disk is too small, this should be sent with shared memory.
191 EXPECT_EQ(
192 Strategy::SHARED_MEMORY,
193 controller.DetermineStrategy(0, kTestBlobStorageMaxBlobMemorySize));
194 }
162 } 195 }
163 196
164 TEST_F(BlobMemoryControllerTest, GrantMemory) { 197 TEST_F(BlobMemoryControllerTest, GrantMemory) {
165 const std::string kId = "id"; 198 const std::string kId = "id";
166 BlobMemoryController controller(temp_dir_.GetPath(), file_runner_); 199 BlobMemoryController controller(temp_dir_.GetPath(), file_runner_);
167 SetTestMemoryLimits(&controller); 200 SetTestMemoryLimits(&controller);
168 201
169 BlobDataBuilder builder(kId); 202 BlobDataBuilder builder(kId);
170 builder.AppendFutureData(10); 203 builder.AppendFutureData(10);
171 builder.AppendFutureData(20); 204 builder.AppendFutureData(20);
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
274 items2.clear(); 307 items2.clear();
275 EXPECT_EQ(0u, controller.memory_usage()); 308 EXPECT_EQ(0u, controller.memory_usage());
276 items.clear(); 309 items.clear();
277 EXPECT_TRUE(file_runner_->HasPendingTask()); 310 EXPECT_TRUE(file_runner_->HasPendingTask());
278 RunFileThreadTasks(); 311 RunFileThreadTasks();
279 base::RunLoop().RunUntilIdle(); 312 base::RunLoop().RunUntilIdle();
280 EXPECT_EQ(0u, controller.disk_usage()); 313 EXPECT_EQ(0u, controller.disk_usage());
281 } 314 }
282 315
283 TEST_F(BlobMemoryControllerTest, NoDiskTooLarge) { 316 TEST_F(BlobMemoryControllerTest, NoDiskTooLarge) {
284 const std::string kId = "id";
285 BlobMemoryController controller(temp_dir_.GetPath(), nullptr); 317 BlobMemoryController controller(temp_dir_.GetPath(), nullptr);
286 SetTestMemoryLimits(&controller); 318 SetTestMemoryLimits(&controller);
287 319
288 EXPECT_FALSE(controller.CanReserveQuota(kTestBlobStorageMaxBlobMemorySize + 320 EXPECT_FALSE(controller.CanReserveQuota(kTestBlobStorageMaxBlobMemorySize +
289 kTestBlobStorageMinFileSizeBytes + 321 kTestBlobStorageMinFileSizeBytes +
290 1)); 322 1));
291 } 323 }
292 324
293 TEST_F(BlobMemoryControllerTest, TooLargeForDisk) { 325 TEST_F(BlobMemoryControllerTest, TooLargeForDisk) {
294 const std::string kId = "id";
295 BlobMemoryController controller(temp_dir_.GetPath(), file_runner_); 326 BlobMemoryController controller(temp_dir_.GetPath(), file_runner_);
296 SetTestMemoryLimits(&controller); 327 SetTestMemoryLimits(&controller);
297 328
298 EXPECT_FALSE(controller.CanReserveQuota(kTestBlobStorageMaxDiskSpace + 1)); 329 EXPECT_FALSE(controller.CanReserveQuota(kTestBlobStorageMaxDiskSpace + 1));
299 } 330 }
300 331
301 TEST_F(BlobMemoryControllerTest, CancelMemoryRequest) { 332 TEST_F(BlobMemoryControllerTest, CancelMemoryRequest) {
302 const std::string kId = "id"; 333 const std::string kId = "id";
303 const std::string kId2 = "id2"; 334 const std::string kId2 = "id2";
304 BlobMemoryController controller(temp_dir_.GetPath(), file_runner_); 335 BlobMemoryController controller(temp_dir_.GetPath(), file_runner_);
(...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after
587 EXPECT_EQ( 618 EXPECT_EQ(
588 kTestBlobStorageMaxBlobMemorySize - kTestBlobStorageMinFileSizeBytes, 619 kTestBlobStorageMaxBlobMemorySize - kTestBlobStorageMinFileSizeBytes,
589 controller.memory_usage()); 620 controller.memory_usage());
590 EXPECT_EQ( 621 EXPECT_EQ(
591 kTestBlobStorageMaxBlobMemorySize - kTestBlobStorageMinFileSizeBytes, 622 kTestBlobStorageMaxBlobMemorySize - kTestBlobStorageMinFileSizeBytes,
592 controller.disk_usage()); 623 controller.disk_usage());
593 624
594 EXPECT_TRUE(memory_quota_result_); 625 EXPECT_TRUE(memory_quota_result_);
595 } 626 }
596 627
628 TEST_F(BlobMemoryControllerTest, PagingStopsWhenFull) {
629 BlobMemoryController controller(temp_dir_.GetPath(), file_runner_);
630 SetTestMemoryLimits(&controller);
631 const size_t kTotalBlobStorageSize =
632 kTestBlobStorageMaxDiskSpace + kTestBlobStorageMaxBlobMemorySize;
633
634 const size_t kDataSize = 10u;
635 const size_t kBlobsThatCanFit = kTotalBlobStorageSize / kDataSize;
636 const size_t kNumFastBlobs = kTestBlobStorageMaxBlobMemorySize / kDataSize;
637 char kData[10];
638 memset(kData, 'e', kDataSize);
639
640 // Create all of our blobs.
641 std::vector<scoped_refptr<ShareableBlobDataItem>> all_items;
642 std::vector<base::WeakPtr<QuotaAllocationTask>> memory_tasks;
643 bool memory_requested[kBlobsThatCanFit] = {};
644 for (size_t i = 0; i < kBlobsThatCanFit; i++) {
645 BlobDataBuilder builder("fake");
646 builder.AppendData(kData, kDataSize);
647 std::vector<scoped_refptr<ShareableBlobDataItem>> items =
648 CreateSharedDataItems(builder);
649 EXPECT_TRUE(controller.CanReserveQuota(kDataSize));
650 EXPECT_EQ((i < kNumFastBlobs) ? Strategy::NONE_NEEDED : Strategy::IPC,
651 controller.DetermineStrategy(kDataSize, kDataSize))
652 << i;
653 base::WeakPtr<QuotaAllocationTask> memory_task =
654 controller.ReserveMemoryQuota(
655 items, GetMemoryRequestCallbackToOutput(memory_requested + i));
656 if (memory_task) {
657 memory_tasks.push_back(std::move(memory_task));
658 }
659 all_items.insert(all_items.end(), items.begin(), items.end());
660 }
661 // We should have stored all of our memory quota, and no disk yet.
662 EXPECT_EQ(500u, controller.memory_usage());
663 EXPECT_EQ(0ull, controller.disk_usage());
664
665 EXPECT_FALSE(controller.CanReserveQuota(1u));
666 EXPECT_EQ(Strategy::TOO_LARGE, controller.DetermineStrategy(1u, 1ull));
667 EXPECT_FALSE(file_runner_->HasPendingTask());
668
669 for (size_t i = 0; i < kBlobsThatCanFit; i++) {
670 // Note: this can fail if the bot's disk is almost full.
671 EXPECT_EQ(i < kBlobsThatCanFit / 3, memory_requested[i]) << i;
672 if (memory_requested[i] &&
673 all_items[i]->state() != ItemState::POPULATED_WITH_QUOTA) {
674 EXPECT_TRUE(memory_requested[i]);
675 all_items[i]->set_state(ItemState::POPULATED_WITH_QUOTA);
676 std::vector<scoped_refptr<ShareableBlobDataItem>> temp_vector;
677 temp_vector.push_back(all_items[i]);
678 controller.NotifyMemoryItemsUsed(temp_vector);
679 }
680 }
681 EXPECT_TRUE(file_runner_->HasPendingTask());
682
683 // This will schedule one task. Paging starts as soon as there is enough
684 // memory to page, and multiple pagings can't happen at the same time.
685 EXPECT_EQ(10ull, controller.disk_usage());
686 RunFileThreadTasks();
687 base::RunLoop().RunUntilIdle();
688 // The rest of the tasks should be scheduled.
689 EXPECT_TRUE(file_runner_->HasPendingTask());
690 RunFileThreadTasks();
691 base::RunLoop().RunUntilIdle();
692 // Everything in memory should be on disk, and next batch of memory items
693 // should be granted.
694 EXPECT_EQ(500u, controller.memory_usage());
695 EXPECT_EQ(500ull, controller.disk_usage());
696
697 // Still can't add anything.
698 EXPECT_FALSE(controller.CanReserveQuota(1u));
699 EXPECT_EQ(Strategy::TOO_LARGE, controller.DetermineStrategy(1u, 1ull));
700
701 // Flag next batch for saving to disk.
702 for (size_t i = 0; i < kBlobsThatCanFit; i++) {
703 // Note: this can fail if the bot's disk is almost full.
704 EXPECT_EQ(i < kBlobsThatCanFit * 2 / 3, memory_requested[i]) << i;
705 if (memory_requested[i] &&
706 all_items[i]->state() != ItemState::POPULATED_WITH_QUOTA) {
707 all_items[i]->set_state(ItemState::POPULATED_WITH_QUOTA);
708 std::vector<scoped_refptr<ShareableBlobDataItem>> temp_vector;
709 temp_vector.push_back(all_items[i]);
710 controller.NotifyMemoryItemsUsed(temp_vector);
711 }
712 }
713 EXPECT_TRUE(file_runner_->HasPendingTask());
714
715 // Same as before. One page task is scheduled, so run them twice.
716 EXPECT_EQ(510ull, controller.disk_usage());
717 RunFileThreadTasks();
718 base::RunLoop().RunUntilIdle();
719 // We page one time first, as it blocks paging once it starts.
720 RunFileThreadTasks();
721 base::RunLoop().RunUntilIdle();
722
723 // All quota should be allocated.
724 EXPECT_EQ(500u, controller.memory_usage());
725 EXPECT_EQ(1000ull, controller.disk_usage());
726
727 // Still can't add anything.
728 EXPECT_FALSE(controller.CanReserveQuota(1u));
729 EXPECT_EQ(Strategy::TOO_LARGE, controller.DetermineStrategy(1u, 1ull));
730
731 // Flag last batch as populated.
732 for (size_t i = 0; i < kBlobsThatCanFit; i++) {
733 // Note: this can fail if the bot's disk is almost full.
734 EXPECT_TRUE(memory_requested[i]);
735 if (memory_requested[i] &&
736 all_items[i]->state() != ItemState::POPULATED_WITH_QUOTA) {
737 all_items[i]->set_state(ItemState::POPULATED_WITH_QUOTA);
738 std::vector<scoped_refptr<ShareableBlobDataItem>> temp_vector;
739 temp_vector.push_back(all_items[i]);
740 controller.NotifyMemoryItemsUsed(temp_vector);
741 }
742 }
743
744 // There should be no more paging to disk, as we've reached the end.
745 EXPECT_FALSE(file_runner_->HasPendingTask());
746
747 // All quota should be allocated still.
748 EXPECT_EQ(500u, controller.memory_usage());
749 EXPECT_EQ(1000ull, controller.disk_usage());
750
751 // Still can't add anything.
752 EXPECT_FALSE(controller.CanReserveQuota(1u));
753 EXPECT_EQ(Strategy::TOO_LARGE, controller.DetermineStrategy(1u, 1ull));
754 EXPECT_FALSE(file_runner_->HasPendingTask());
755 }
756
597 TEST_F(BlobMemoryControllerTest, DisableDiskWithFileAndMemoryPending) { 757 TEST_F(BlobMemoryControllerTest, DisableDiskWithFileAndMemoryPending) {
598 const std::string kFirstMemoryId = "id"; 758 const std::string kFirstMemoryId = "id";
599 const uint64_t kFirstMemorySize = kTestBlobStorageMaxBlobMemorySize; 759 const uint64_t kFirstMemorySize = kTestBlobStorageMaxBlobMemorySize;
600 const std::string kSecondMemoryId = "id2"; 760 const std::string kSecondMemoryId = "id2";
601 const uint64_t kSecondMemorySize = 1; 761 const uint64_t kSecondMemorySize = 1;
602 const std::string kFileId = "id2"; 762 const std::string kFileId = "id2";
603 const uint64_t kFileBlobSize = kTestBlobStorageMaxBlobMemorySize; 763 const uint64_t kFileBlobSize = kTestBlobStorageMaxBlobMemorySize;
604 764
605 BlobMemoryController controller(temp_dir_.GetPath(), file_runner_); 765 BlobMemoryController controller(temp_dir_.GetPath(), file_runner_);
606 SetTestMemoryLimits(&controller); 766 SetTestMemoryLimits(&controller);
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
671 file_items.clear(); 831 file_items.clear();
672 items.clear(); 832 items.clear();
673 833
674 RunFileThreadTasks(); 834 RunFileThreadTasks();
675 base::RunLoop().RunUntilIdle(); 835 base::RunLoop().RunUntilIdle();
676 836
677 EXPECT_EQ(0ull, controller.disk_usage()); 837 EXPECT_EQ(0ull, controller.disk_usage());
678 EXPECT_EQ(0ull, controller.memory_usage()); 838 EXPECT_EQ(0ull, controller.memory_usage());
679 } 839 }
680 } // namespace storage 840 } // namespace storage
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698