simple_index_unittest.cc 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  1. // Copyright (c) 2013 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. #include "net/disk_cache/simple/simple_index.h"
  5. #include <algorithm>
  6. #include <functional>
  7. #include <memory>
  8. #include <utility>
  9. #include "base/bind.h"
  10. #include "base/files/scoped_temp_dir.h"
  11. #include "base/hash/hash.h"
  12. #include "base/memory/raw_ptr.h"
  13. #include "base/pickle.h"
  14. #include "base/strings/stringprintf.h"
  15. #include "base/task/task_runner.h"
  16. #include "base/test/mock_entropy_provider.h"
  17. #include "base/threading/platform_thread.h"
  18. #include "base/time/time.h"
  19. #include "net/base/cache_type.h"
  20. #include "net/disk_cache/backend_cleanup_tracker.h"
  21. #include "net/disk_cache/disk_cache.h"
  22. #include "net/disk_cache/simple/simple_index_delegate.h"
  23. #include "net/disk_cache/simple/simple_index_file.h"
  24. #include "net/disk_cache/simple/simple_test_util.h"
  25. #include "net/disk_cache/simple/simple_util.h"
  26. #include "net/test/test_with_task_environment.h"
  27. #include "testing/gtest/include/gtest/gtest.h"
  28. namespace disk_cache {
  29. namespace {
  30. const base::Time kTestLastUsedTime = base::Time::UnixEpoch() + base::Days(20);
  31. const uint32_t kTestEntrySize = 789;
  32. const uint8_t kTestEntryMemoryData = 123;
  33. uint32_t RoundSize(uint32_t in) {
  34. return (in + 0xFFu) & 0xFFFFFF00u;
  35. }
  36. } // namespace
  37. class EntryMetadataTest : public testing::Test {
  38. public:
  39. EntryMetadata NewEntryMetadataWithValues() {
  40. EntryMetadata entry(kTestLastUsedTime, kTestEntrySize);
  41. entry.SetInMemoryData(kTestEntryMemoryData);
  42. return entry;
  43. }
  44. void CheckEntryMetadataValues(const EntryMetadata& entry_metadata) {
  45. EXPECT_LT(kTestLastUsedTime - base::Seconds(2),
  46. entry_metadata.GetLastUsedTime());
  47. EXPECT_GT(kTestLastUsedTime + base::Seconds(2),
  48. entry_metadata.GetLastUsedTime());
  49. EXPECT_EQ(RoundSize(kTestEntrySize), entry_metadata.GetEntrySize());
  50. EXPECT_EQ(kTestEntryMemoryData, entry_metadata.GetInMemoryData());
  51. }
  52. };
  53. class MockSimpleIndexFile : public SimpleIndexFile,
  54. public base::SupportsWeakPtr<MockSimpleIndexFile> {
  55. public:
  56. explicit MockSimpleIndexFile(net::CacheType cache_type)
  57. : SimpleIndexFile(nullptr,
  58. base::MakeRefCounted<TrivialFileOperationsFactory>(),
  59. cache_type,
  60. base::FilePath()) {}
  61. void LoadIndexEntries(base::Time cache_last_modified,
  62. base::OnceClosure callback,
  63. SimpleIndexLoadResult* out_load_result) override {
  64. load_callback_ = std::move(callback);
  65. load_result_ = out_load_result;
  66. ++load_index_entries_calls_;
  67. }
  68. void WriteToDisk(net::CacheType cache_type,
  69. SimpleIndex::IndexWriteToDiskReason reason,
  70. const SimpleIndex::EntrySet& entry_set,
  71. uint64_t cache_size,
  72. base::OnceClosure callback) override {
  73. disk_writes_++;
  74. disk_write_entry_set_ = entry_set;
  75. }
  76. void GetAndResetDiskWriteEntrySet(SimpleIndex::EntrySet* entry_set) {
  77. entry_set->swap(disk_write_entry_set_);
  78. }
  79. base::OnceClosure TakeLoadCallback() { return std::move(load_callback_); }
  80. SimpleIndexLoadResult* load_result() const { return load_result_; }
  81. int load_index_entries_calls() const { return load_index_entries_calls_; }
  82. int disk_writes() const { return disk_writes_; }
  83. private:
  84. base::OnceClosure load_callback_;
  85. raw_ptr<SimpleIndexLoadResult> load_result_ = nullptr;
  86. int load_index_entries_calls_ = 0;
  87. int disk_writes_ = 0;
  88. SimpleIndex::EntrySet disk_write_entry_set_;
  89. };
  90. class SimpleIndexTest : public net::TestWithTaskEnvironment,
  91. public SimpleIndexDelegate {
  92. protected:
  93. SimpleIndexTest() : hashes_(base::BindRepeating(&HashesInitializer)) {}
  94. static uint64_t HashesInitializer(size_t hash_index) {
  95. return disk_cache::simple_util::GetEntryHashKey(
  96. base::StringPrintf("key%d", static_cast<int>(hash_index)));
  97. }
  98. void SetUp() override {
  99. auto index_file = std::make_unique<MockSimpleIndexFile>(CacheType());
  100. index_file_ = index_file->AsWeakPtr();
  101. index_ =
  102. std::make_unique<SimpleIndex>(/* io_thread = */ nullptr,
  103. /* cleanup_tracker = */ nullptr, this,
  104. CacheType(), std::move(index_file));
  105. index_->Initialize(base::Time());
  106. }
  107. void WaitForTimeChange() {
  108. const base::Time initial_time = base::Time::Now();
  109. do {
  110. base::PlatformThread::YieldCurrentThread();
  111. } while (base::Time::Now() - initial_time < base::Seconds(1));
  112. }
  113. // From SimpleIndexDelegate:
  114. void DoomEntries(std::vector<uint64_t>* entry_hashes,
  115. net::CompletionOnceCallback callback) override {
  116. for (const uint64_t& entry_hash : *entry_hashes)
  117. index_->Remove(entry_hash);
  118. last_doom_entry_hashes_ = *entry_hashes;
  119. ++doom_entries_calls_;
  120. }
  121. // Redirect to allow single "friend" declaration in base class.
  122. bool GetEntryForTesting(uint64_t key, EntryMetadata* metadata) {
  123. auto it = index_->entries_set_.find(key);
  124. if (index_->entries_set_.end() == it)
  125. return false;
  126. *metadata = it->second;
  127. return true;
  128. }
  129. void InsertIntoIndexFileReturn(uint64_t hash_key,
  130. base::Time last_used_time,
  131. int entry_size) {
  132. index_file_->load_result()->entries.insert(std::make_pair(
  133. hash_key, EntryMetadata(last_used_time,
  134. base::checked_cast<uint32_t>(entry_size))));
  135. }
  136. void ReturnIndexFile() {
  137. index_file_->load_result()->did_load = true;
  138. index_file_->TakeLoadCallback().Run();
  139. }
  140. // Non-const for timer manipulation.
  141. SimpleIndex* index() { return index_.get(); }
  142. const MockSimpleIndexFile* index_file() const { return index_file_.get(); }
  143. const std::vector<uint64_t>& last_doom_entry_hashes() const {
  144. return last_doom_entry_hashes_;
  145. }
  146. int doom_entries_calls() const { return doom_entries_calls_; }
  147. virtual net::CacheType CacheType() const { return net::DISK_CACHE; }
  148. const simple_util::ImmutableArray<uint64_t, 16> hashes_;
  149. std::unique_ptr<SimpleIndex> index_;
  150. base::WeakPtr<MockSimpleIndexFile> index_file_;
  151. std::vector<uint64_t> last_doom_entry_hashes_;
  152. int doom_entries_calls_ = 0;
  153. };
  154. class SimpleIndexAppCacheTest : public SimpleIndexTest {
  155. protected:
  156. net::CacheType CacheType() const override { return net::APP_CACHE; }
  157. };
  158. class SimpleIndexCodeCacheTest : public SimpleIndexTest {
  159. protected:
  160. net::CacheType CacheType() const override {
  161. return net::GENERATED_BYTE_CODE_CACHE;
  162. }
  163. };
  164. TEST_F(EntryMetadataTest, Basics) {
  165. EntryMetadata entry_metadata;
  166. EXPECT_EQ(base::Time(), entry_metadata.GetLastUsedTime());
  167. EXPECT_EQ(0u, entry_metadata.GetEntrySize());
  168. EXPECT_EQ(0u, entry_metadata.GetInMemoryData());
  169. entry_metadata = NewEntryMetadataWithValues();
  170. CheckEntryMetadataValues(entry_metadata);
  171. const base::Time new_time = base::Time::Now();
  172. entry_metadata.SetLastUsedTime(new_time);
  173. EXPECT_LT(new_time - base::Seconds(2), entry_metadata.GetLastUsedTime());
  174. EXPECT_GT(new_time + base::Seconds(2), entry_metadata.GetLastUsedTime());
  175. }
  176. // Tests that setting an unusually small/large last used time results in
  177. // truncation (rather than crashing).
  178. TEST_F(EntryMetadataTest, SaturatedLastUsedTime) {
  179. EntryMetadata entry_metadata;
  180. // Set a time that is too large to be represented internally as 32-bit unix
  181. // timestamp. Will saturate to a large timestamp (in year 2106).
  182. entry_metadata.SetLastUsedTime(base::Time::Max());
  183. EXPECT_EQ(INT64_C(15939440895000000),
  184. entry_metadata.GetLastUsedTime().ToInternalValue());
  185. // Set a time that is too small to be represented by a unix timestamp (before
  186. // 1970).
  187. entry_metadata.SetLastUsedTime(
  188. base::Time::FromInternalValue(7u)); // This is a date in 1601.
  189. EXPECT_EQ(base::Time::UnixEpoch() + base::Seconds(1),
  190. entry_metadata.GetLastUsedTime());
  191. }
  192. TEST_F(EntryMetadataTest, Serialize) {
  193. EntryMetadata entry_metadata = NewEntryMetadataWithValues();
  194. base::Pickle pickle;
  195. entry_metadata.Serialize(net::DISK_CACHE, &pickle);
  196. base::PickleIterator it(pickle);
  197. EntryMetadata new_entry_metadata;
  198. new_entry_metadata.Deserialize(net::DISK_CACHE, &it, true, true);
  199. CheckEntryMetadataValues(new_entry_metadata);
  200. // Test reading of old format --- the modern serialization of above entry
  201. // corresponds, in older format, to an entry with size =
  202. // RoundSize(kTestEntrySize) | kTestEntryMemoryData, which then gets
  203. // rounded again when stored by EntryMetadata.
  204. base::PickleIterator it2(pickle);
  205. EntryMetadata new_entry_metadata2;
  206. new_entry_metadata2.Deserialize(net::DISK_CACHE, &it2, false, false);
  207. EXPECT_EQ(RoundSize(RoundSize(kTestEntrySize) | kTestEntryMemoryData),
  208. new_entry_metadata2.GetEntrySize());
  209. EXPECT_EQ(0, new_entry_metadata2.GetInMemoryData());
  210. }
  211. TEST_F(SimpleIndexTest, IndexSizeCorrectOnMerge) {
  212. const unsigned int kSizeResolution = 256u;
  213. index()->SetMaxSize(100 * kSizeResolution);
  214. index()->Insert(hashes_.at<2>());
  215. index()->UpdateEntrySize(hashes_.at<2>(), 2u * kSizeResolution);
  216. index()->Insert(hashes_.at<3>());
  217. index()->UpdateEntrySize(hashes_.at<3>(), 3u * kSizeResolution);
  218. index()->Insert(hashes_.at<4>());
  219. index()->UpdateEntrySize(hashes_.at<4>(), 4u * kSizeResolution);
  220. EXPECT_EQ(9u * kSizeResolution, index()->cache_size_);
  221. {
  222. auto result = std::make_unique<SimpleIndexLoadResult>();
  223. result->did_load = true;
  224. index()->MergeInitializingSet(std::move(result));
  225. }
  226. EXPECT_EQ(9u * kSizeResolution, index()->cache_size_);
  227. {
  228. auto result = std::make_unique<SimpleIndexLoadResult>();
  229. result->did_load = true;
  230. const uint64_t new_hash_key = hashes_.at<11>();
  231. result->entries.insert(std::make_pair(
  232. new_hash_key, EntryMetadata(base::Time::Now(), 11u * kSizeResolution)));
  233. const uint64_t redundant_hash_key = hashes_.at<4>();
  234. result->entries.insert(
  235. std::make_pair(redundant_hash_key,
  236. EntryMetadata(base::Time::Now(), 4u * kSizeResolution)));
  237. index()->MergeInitializingSet(std::move(result));
  238. }
  239. EXPECT_EQ((2u + 3u + 4u + 11u) * kSizeResolution, index()->cache_size_);
  240. }
  241. // State of index changes as expected with an insert and a remove.
  242. TEST_F(SimpleIndexTest, BasicInsertRemove) {
  243. // Confirm blank state.
  244. EntryMetadata metadata;
  245. EXPECT_EQ(base::Time(), metadata.GetLastUsedTime());
  246. EXPECT_EQ(0U, metadata.GetEntrySize());
  247. // Confirm state after insert.
  248. index()->Insert(hashes_.at<1>());
  249. ASSERT_TRUE(GetEntryForTesting(hashes_.at<1>(), &metadata));
  250. base::Time now(base::Time::Now());
  251. EXPECT_LT(now - base::Minutes(1), metadata.GetLastUsedTime());
  252. EXPECT_GT(now + base::Minutes(1), metadata.GetLastUsedTime());
  253. EXPECT_EQ(0U, metadata.GetEntrySize());
  254. // Confirm state after remove.
  255. metadata = EntryMetadata();
  256. index()->Remove(hashes_.at<1>());
  257. EXPECT_FALSE(GetEntryForTesting(hashes_.at<1>(), &metadata));
  258. EXPECT_EQ(base::Time(), metadata.GetLastUsedTime());
  259. EXPECT_EQ(0U, metadata.GetEntrySize());
  260. }
  261. TEST_F(SimpleIndexTest, Has) {
  262. // Confirm the base index has dispatched the request for index entries.
  263. EXPECT_TRUE(index_file_.get());
  264. EXPECT_EQ(1, index_file_->load_index_entries_calls());
  265. // Confirm "Has()" always returns true before the callback is called.
  266. const uint64_t kHash1 = hashes_.at<1>();
  267. EXPECT_TRUE(index()->Has(kHash1));
  268. index()->Insert(kHash1);
  269. EXPECT_TRUE(index()->Has(kHash1));
  270. index()->Remove(kHash1);
  271. // TODO(morlovich): Maybe return false on explicitly removed entries?
  272. EXPECT_TRUE(index()->Has(kHash1));
  273. ReturnIndexFile();
  274. // Confirm "Has() returns conditionally now.
  275. EXPECT_FALSE(index()->Has(kHash1));
  276. index()->Insert(kHash1);
  277. EXPECT_TRUE(index()->Has(kHash1));
  278. index()->Remove(kHash1);
  279. }
  280. TEST_F(SimpleIndexTest, UseIfExists) {
  281. // Confirm the base index has dispatched the request for index entries.
  282. EXPECT_TRUE(index_file_.get());
  283. EXPECT_EQ(1, index_file_->load_index_entries_calls());
  284. // Confirm "UseIfExists()" always returns true before the callback is called
  285. // and updates mod time if the entry was really there.
  286. const uint64_t kHash1 = hashes_.at<1>();
  287. EntryMetadata metadata1, metadata2;
  288. EXPECT_TRUE(index()->UseIfExists(kHash1));
  289. EXPECT_FALSE(GetEntryForTesting(kHash1, &metadata1));
  290. index()->Insert(kHash1);
  291. EXPECT_TRUE(index()->UseIfExists(kHash1));
  292. EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata1));
  293. WaitForTimeChange();
  294. EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata2));
  295. EXPECT_EQ(metadata1.GetLastUsedTime(), metadata2.GetLastUsedTime());
  296. EXPECT_TRUE(index()->UseIfExists(kHash1));
  297. EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata2));
  298. EXPECT_LT(metadata1.GetLastUsedTime(), metadata2.GetLastUsedTime());
  299. index()->Remove(kHash1);
  300. EXPECT_TRUE(index()->UseIfExists(kHash1));
  301. ReturnIndexFile();
  302. // Confirm "UseIfExists() returns conditionally now
  303. EXPECT_FALSE(index()->UseIfExists(kHash1));
  304. EXPECT_FALSE(GetEntryForTesting(kHash1, &metadata1));
  305. index()->Insert(kHash1);
  306. EXPECT_TRUE(index()->UseIfExists(kHash1));
  307. EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata1));
  308. WaitForTimeChange();
  309. EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata2));
  310. EXPECT_EQ(metadata1.GetLastUsedTime(), metadata2.GetLastUsedTime());
  311. EXPECT_TRUE(index()->UseIfExists(kHash1));
  312. EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata2));
  313. EXPECT_LT(metadata1.GetLastUsedTime(), metadata2.GetLastUsedTime());
  314. index()->Remove(kHash1);
  315. EXPECT_FALSE(index()->UseIfExists(kHash1));
  316. }
  317. TEST_F(SimpleIndexTest, UpdateEntrySize) {
  318. base::Time now(base::Time::Now());
  319. index()->SetMaxSize(1000);
  320. const uint64_t kHash1 = hashes_.at<1>();
  321. InsertIntoIndexFileReturn(kHash1, now - base::Days(2), 475);
  322. ReturnIndexFile();
  323. EntryMetadata metadata;
  324. EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata));
  325. EXPECT_LT(now - base::Days(2) - base::Seconds(1), metadata.GetLastUsedTime());
  326. EXPECT_GT(now - base::Days(2) + base::Seconds(1), metadata.GetLastUsedTime());
  327. EXPECT_EQ(RoundSize(475u), metadata.GetEntrySize());
  328. index()->UpdateEntrySize(kHash1, 600u);
  329. EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata));
  330. EXPECT_EQ(RoundSize(600u), metadata.GetEntrySize());
  331. EXPECT_EQ(1, index()->GetEntryCount());
  332. }
  333. TEST_F(SimpleIndexTest, GetEntryCount) {
  334. EXPECT_EQ(0, index()->GetEntryCount());
  335. index()->Insert(hashes_.at<1>());
  336. EXPECT_EQ(1, index()->GetEntryCount());
  337. index()->Insert(hashes_.at<2>());
  338. EXPECT_EQ(2, index()->GetEntryCount());
  339. index()->Insert(hashes_.at<3>());
  340. EXPECT_EQ(3, index()->GetEntryCount());
  341. index()->Insert(hashes_.at<3>());
  342. EXPECT_EQ(3, index()->GetEntryCount());
  343. index()->Remove(hashes_.at<2>());
  344. EXPECT_EQ(2, index()->GetEntryCount());
  345. index()->Insert(hashes_.at<4>());
  346. EXPECT_EQ(3, index()->GetEntryCount());
  347. index()->Remove(hashes_.at<3>());
  348. EXPECT_EQ(2, index()->GetEntryCount());
  349. index()->Remove(hashes_.at<3>());
  350. EXPECT_EQ(2, index()->GetEntryCount());
  351. index()->Remove(hashes_.at<1>());
  352. EXPECT_EQ(1, index()->GetEntryCount());
  353. index()->Remove(hashes_.at<4>());
  354. EXPECT_EQ(0, index()->GetEntryCount());
  355. }
  356. // Confirm that we get the results we expect from a simple init.
  357. TEST_F(SimpleIndexTest, BasicInit) {
  358. base::Time now(base::Time::Now());
  359. InsertIntoIndexFileReturn(hashes_.at<1>(), now - base::Days(2), 10u);
  360. InsertIntoIndexFileReturn(hashes_.at<2>(), now - base::Days(3), 1000u);
  361. ReturnIndexFile();
  362. EntryMetadata metadata;
  363. EXPECT_TRUE(GetEntryForTesting(hashes_.at<1>(), &metadata));
  364. EXPECT_EQ(metadata.GetLastUsedTime(),
  365. index()->GetLastUsedTime(hashes_.at<1>()));
  366. EXPECT_LT(now - base::Days(2) - base::Seconds(1), metadata.GetLastUsedTime());
  367. EXPECT_GT(now - base::Days(2) + base::Seconds(1), metadata.GetLastUsedTime());
  368. EXPECT_EQ(RoundSize(10u), metadata.GetEntrySize());
  369. EXPECT_TRUE(GetEntryForTesting(hashes_.at<2>(), &metadata));
  370. EXPECT_EQ(metadata.GetLastUsedTime(),
  371. index()->GetLastUsedTime(hashes_.at<2>()));
  372. EXPECT_LT(now - base::Days(3) - base::Seconds(1), metadata.GetLastUsedTime());
  373. EXPECT_GT(now - base::Days(3) + base::Seconds(1), metadata.GetLastUsedTime());
  374. EXPECT_EQ(RoundSize(1000u), metadata.GetEntrySize());
  375. EXPECT_EQ(base::Time(), index()->GetLastUsedTime(hashes_.at<3>()));
  376. }
  377. // Remove something that's going to come in from the loaded index.
  378. TEST_F(SimpleIndexTest, RemoveBeforeInit) {
  379. const uint64_t kHash1 = hashes_.at<1>();
  380. index()->Remove(kHash1);
  381. InsertIntoIndexFileReturn(kHash1, base::Time::Now() - base::Days(2), 10u);
  382. ReturnIndexFile();
  383. EXPECT_FALSE(index()->Has(kHash1));
  384. }
  385. // Insert something that's going to come in from the loaded index; correct
  386. // result?
  387. TEST_F(SimpleIndexTest, InsertBeforeInit) {
  388. const uint64_t kHash1 = hashes_.at<1>();
  389. index()->Insert(kHash1);
  390. InsertIntoIndexFileReturn(kHash1, base::Time::Now() - base::Days(2), 10u);
  391. ReturnIndexFile();
  392. EntryMetadata metadata;
  393. EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata));
  394. base::Time now(base::Time::Now());
  395. EXPECT_LT(now - base::Minutes(1), metadata.GetLastUsedTime());
  396. EXPECT_GT(now + base::Minutes(1), metadata.GetLastUsedTime());
  397. EXPECT_EQ(0U, metadata.GetEntrySize());
  398. }
  399. // Insert and Remove something that's going to come in from the loaded index.
  400. TEST_F(SimpleIndexTest, InsertRemoveBeforeInit) {
  401. const uint64_t kHash1 = hashes_.at<1>();
  402. index()->Insert(kHash1);
  403. index()->Remove(kHash1);
  404. InsertIntoIndexFileReturn(kHash1, base::Time::Now() - base::Days(2), 10u);
  405. ReturnIndexFile();
  406. EXPECT_FALSE(index()->Has(kHash1));
  407. }
  408. // Insert and Remove something that's going to come in from the loaded index.
  409. TEST_F(SimpleIndexTest, RemoveInsertBeforeInit) {
  410. const uint64_t kHash1 = hashes_.at<1>();
  411. index()->Remove(kHash1);
  412. index()->Insert(kHash1);
  413. InsertIntoIndexFileReturn(kHash1, base::Time::Now() - base::Days(2), 10u);
  414. ReturnIndexFile();
  415. EntryMetadata metadata;
  416. EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata));
  417. base::Time now(base::Time::Now());
  418. EXPECT_LT(now - base::Minutes(1), metadata.GetLastUsedTime());
  419. EXPECT_GT(now + base::Minutes(1), metadata.GetLastUsedTime());
  420. EXPECT_EQ(0U, metadata.GetEntrySize());
  421. }
  422. // Do all above tests at once + a non-conflict to test for cross-key
  423. // interactions.
  424. TEST_F(SimpleIndexTest, AllInitConflicts) {
  425. base::Time now(base::Time::Now());
  426. index()->Remove(hashes_.at<1>());
  427. InsertIntoIndexFileReturn(hashes_.at<1>(), now - base::Days(2), 10u);
  428. index()->Insert(hashes_.at<2>());
  429. InsertIntoIndexFileReturn(hashes_.at<2>(), now - base::Days(3), 100u);
  430. index()->Insert(hashes_.at<3>());
  431. index()->Remove(hashes_.at<3>());
  432. InsertIntoIndexFileReturn(hashes_.at<3>(), now - base::Days(4), 1000u);
  433. index()->Remove(hashes_.at<4>());
  434. index()->Insert(hashes_.at<4>());
  435. InsertIntoIndexFileReturn(hashes_.at<4>(), now - base::Days(5), 10000u);
  436. InsertIntoIndexFileReturn(hashes_.at<5>(), now - base::Days(6), 100000u);
  437. ReturnIndexFile();
  438. EXPECT_FALSE(index()->Has(hashes_.at<1>()));
  439. EntryMetadata metadata;
  440. EXPECT_TRUE(GetEntryForTesting(hashes_.at<2>(), &metadata));
  441. EXPECT_LT(now - base::Minutes(1), metadata.GetLastUsedTime());
  442. EXPECT_GT(now + base::Minutes(1), metadata.GetLastUsedTime());
  443. EXPECT_EQ(0U, metadata.GetEntrySize());
  444. EXPECT_FALSE(index()->Has(hashes_.at<3>()));
  445. EXPECT_TRUE(GetEntryForTesting(hashes_.at<4>(), &metadata));
  446. EXPECT_LT(now - base::Minutes(1), metadata.GetLastUsedTime());
  447. EXPECT_GT(now + base::Minutes(1), metadata.GetLastUsedTime());
  448. EXPECT_EQ(0U, metadata.GetEntrySize());
  449. EXPECT_TRUE(GetEntryForTesting(hashes_.at<5>(), &metadata));
  450. EXPECT_GT(now - base::Days(6) + base::Seconds(1), metadata.GetLastUsedTime());
  451. EXPECT_LT(now - base::Days(6) - base::Seconds(1), metadata.GetLastUsedTime());
  452. EXPECT_EQ(RoundSize(100000u), metadata.GetEntrySize());
  453. }
  454. TEST_F(SimpleIndexTest, BasicEviction) {
  455. base::Time now(base::Time::Now());
  456. index()->SetMaxSize(1000);
  457. InsertIntoIndexFileReturn(hashes_.at<1>(), now - base::Days(2), 475u);
  458. index()->Insert(hashes_.at<2>());
  459. index()->UpdateEntrySize(hashes_.at<2>(), 475u);
  460. ReturnIndexFile();
  461. WaitForTimeChange();
  462. index()->Insert(hashes_.at<3>());
  463. // Confirm index is as expected: No eviction, everything there.
  464. EXPECT_EQ(3, index()->GetEntryCount());
  465. EXPECT_EQ(0, doom_entries_calls());
  466. EXPECT_TRUE(index()->Has(hashes_.at<1>()));
  467. EXPECT_TRUE(index()->Has(hashes_.at<2>()));
  468. EXPECT_TRUE(index()->Has(hashes_.at<3>()));
  469. // Trigger an eviction, and make sure the right things are tossed.
  470. // TODO(morlovich): This is dependent on the innards of the implementation
  471. // as to at exactly what point we trigger eviction. Not sure how to fix
  472. // that.
  473. index()->UpdateEntrySize(hashes_.at<3>(), 475u);
  474. EXPECT_EQ(1, doom_entries_calls());
  475. EXPECT_EQ(1, index()->GetEntryCount());
  476. EXPECT_FALSE(index()->Has(hashes_.at<1>()));
  477. EXPECT_FALSE(index()->Has(hashes_.at<2>()));
  478. EXPECT_TRUE(index()->Has(hashes_.at<3>()));
  479. ASSERT_EQ(2u, last_doom_entry_hashes().size());
  480. }
  481. TEST_F(SimpleIndexTest, EvictBySize) {
  482. base::Time now(base::Time::Now());
  483. index()->SetMaxSize(50000);
  484. InsertIntoIndexFileReturn(hashes_.at<1>(), now - base::Days(2), 475u);
  485. InsertIntoIndexFileReturn(hashes_.at<2>(), now - base::Days(1), 40000u);
  486. ReturnIndexFile();
  487. WaitForTimeChange();
  488. index()->Insert(hashes_.at<3>());
  489. // Confirm index is as expected: No eviction, everything there.
  490. EXPECT_EQ(3, index()->GetEntryCount());
  491. EXPECT_EQ(0, doom_entries_calls());
  492. EXPECT_TRUE(index()->Has(hashes_.at<1>()));
  493. EXPECT_TRUE(index()->Has(hashes_.at<2>()));
  494. EXPECT_TRUE(index()->Has(hashes_.at<3>()));
  495. // Trigger an eviction, and make sure the right things are tossed.
  496. // TODO(morlovich): This is dependent on the innards of the implementation
  497. // as to at exactly what point we trigger eviction. Not sure how to fix
  498. // that.
  499. index()->UpdateEntrySize(hashes_.at<3>(), 40000u);
  500. EXPECT_EQ(1, doom_entries_calls());
  501. EXPECT_EQ(2, index()->GetEntryCount());
  502. EXPECT_TRUE(index()->Has(hashes_.at<1>()));
  503. EXPECT_FALSE(index()->Has(hashes_.at<2>()));
  504. EXPECT_TRUE(index()->Has(hashes_.at<3>()));
  505. ASSERT_EQ(1u, last_doom_entry_hashes().size());
  506. }
  507. TEST_F(SimpleIndexCodeCacheTest, DisableEvictBySize) {
  508. base::Time now(base::Time::Now());
  509. index()->SetMaxSize(50000);
  510. InsertIntoIndexFileReturn(hashes_.at<1>(), now - base::Days(2), 475u);
  511. InsertIntoIndexFileReturn(hashes_.at<2>(), now - base::Days(1), 40000u);
  512. ReturnIndexFile();
  513. WaitForTimeChange();
  514. index()->Insert(hashes_.at<3>());
  515. // Confirm index is as expected: No eviction, everything there.
  516. EXPECT_EQ(3, index()->GetEntryCount());
  517. EXPECT_EQ(0, doom_entries_calls());
  518. EXPECT_TRUE(index()->Has(hashes_.at<1>()));
  519. EXPECT_TRUE(index()->Has(hashes_.at<2>()));
  520. EXPECT_TRUE(index()->Has(hashes_.at<3>()));
  521. // Trigger an eviction, and make sure the right things are tossed.
  522. // Since evict by size is supposed to be disabled, it evicts in LRU order,
  523. // so entries 1 and 2 are both kicked out.
  524. index()->UpdateEntrySize(hashes_.at<3>(), 40000u);
  525. EXPECT_EQ(1, doom_entries_calls());
  526. EXPECT_EQ(1, index()->GetEntryCount());
  527. EXPECT_FALSE(index()->Has(hashes_.at<1>()));
  528. EXPECT_FALSE(index()->Has(hashes_.at<2>()));
  529. EXPECT_TRUE(index()->Has(hashes_.at<3>()));
  530. ASSERT_EQ(2u, last_doom_entry_hashes().size());
  531. }
  532. // Same as test above, but using much older entries to make sure that small
  533. // things eventually get evictied.
  534. TEST_F(SimpleIndexTest, EvictBySize2) {
  535. base::Time now(base::Time::Now());
  536. index()->SetMaxSize(50000);
  537. InsertIntoIndexFileReturn(hashes_.at<1>(), now - base::Days(200), 475u);
  538. InsertIntoIndexFileReturn(hashes_.at<2>(), now - base::Days(1), 40000u);
  539. ReturnIndexFile();
  540. WaitForTimeChange();
  541. index()->Insert(hashes_.at<3>());
  542. // Confirm index is as expected: No eviction, everything there.
  543. EXPECT_EQ(3, index()->GetEntryCount());
  544. EXPECT_EQ(0, doom_entries_calls());
  545. EXPECT_TRUE(index()->Has(hashes_.at<1>()));
  546. EXPECT_TRUE(index()->Has(hashes_.at<2>()));
  547. EXPECT_TRUE(index()->Has(hashes_.at<3>()));
  548. // Trigger an eviction, and make sure the right things are tossed.
  549. // TODO(morlovich): This is dependent on the innards of the implementation
  550. // as to at exactly what point we trigger eviction. Not sure how to fix
  551. // that.
  552. index()->UpdateEntrySize(hashes_.at<3>(), 40000u);
  553. EXPECT_EQ(1, doom_entries_calls());
  554. EXPECT_EQ(1, index()->GetEntryCount());
  555. EXPECT_FALSE(index()->Has(hashes_.at<1>()));
  556. EXPECT_FALSE(index()->Has(hashes_.at<2>()));
  557. EXPECT_TRUE(index()->Has(hashes_.at<3>()));
  558. ASSERT_EQ(2u, last_doom_entry_hashes().size());
  559. }
  560. // Confirm all the operations queue a disk write at some point in the
  561. // future.
  562. TEST_F(SimpleIndexTest, DiskWriteQueued) {
  563. index()->SetMaxSize(1000);
  564. ReturnIndexFile();
  565. EXPECT_FALSE(index()->HasPendingWrite());
  566. const uint64_t kHash1 = hashes_.at<1>();
  567. index()->Insert(kHash1);
  568. EXPECT_TRUE(index()->HasPendingWrite());
  569. index()->write_to_disk_timer_.Stop();
  570. EXPECT_FALSE(index()->HasPendingWrite());
  571. // Attempting to insert a hash that already exists should not queue the
  572. // write timer.
  573. index()->Insert(kHash1);
  574. EXPECT_FALSE(index()->HasPendingWrite());
  575. index()->UseIfExists(kHash1);
  576. EXPECT_TRUE(index()->HasPendingWrite());
  577. index()->write_to_disk_timer_.Stop();
  578. index()->UpdateEntrySize(kHash1, 20u);
  579. EXPECT_TRUE(index()->HasPendingWrite());
  580. index()->write_to_disk_timer_.Stop();
  581. // Updating to the same size should not queue the write timer.
  582. index()->UpdateEntrySize(kHash1, 20u);
  583. EXPECT_FALSE(index()->HasPendingWrite());
  584. index()->Remove(kHash1);
  585. EXPECT_TRUE(index()->HasPendingWrite());
  586. index()->write_to_disk_timer_.Stop();
  587. // Removing a non-existent hash should not queue the write timer.
  588. index()->Remove(kHash1);
  589. EXPECT_FALSE(index()->HasPendingWrite());
  590. }
  591. TEST_F(SimpleIndexTest, DiskWriteExecuted) {
  592. index()->SetMaxSize(1000);
  593. ReturnIndexFile();
  594. EXPECT_FALSE(index()->HasPendingWrite());
  595. const uint64_t kHash1 = hashes_.at<1>();
  596. index()->Insert(kHash1);
  597. index()->UpdateEntrySize(kHash1, 20u);
  598. EXPECT_TRUE(index()->HasPendingWrite());
  599. EXPECT_EQ(0, index_file_->disk_writes());
  600. index()->write_to_disk_timer_.FireNow();
  601. EXPECT_EQ(1, index_file_->disk_writes());
  602. SimpleIndex::EntrySet entry_set;
  603. index_file_->GetAndResetDiskWriteEntrySet(&entry_set);
  604. uint64_t hash_key = kHash1;
  605. base::Time now(base::Time::Now());
  606. ASSERT_EQ(1u, entry_set.size());
  607. EXPECT_EQ(hash_key, entry_set.begin()->first);
  608. const EntryMetadata& entry1(entry_set.begin()->second);
  609. EXPECT_LT(now - base::Minutes(1), entry1.GetLastUsedTime());
  610. EXPECT_GT(now + base::Minutes(1), entry1.GetLastUsedTime());
  611. EXPECT_EQ(RoundSize(20u), entry1.GetEntrySize());
  612. }
  613. TEST_F(SimpleIndexTest, DiskWritePostponed) {
  614. index()->SetMaxSize(1000);
  615. ReturnIndexFile();
  616. EXPECT_FALSE(index()->HasPendingWrite());
  617. index()->Insert(hashes_.at<1>());
  618. index()->UpdateEntrySize(hashes_.at<1>(), 20u);
  619. EXPECT_TRUE(index()->HasPendingWrite());
  620. base::TimeTicks expected_trigger(
  621. index()->write_to_disk_timer_.desired_run_time());
  622. WaitForTimeChange();
  623. EXPECT_EQ(expected_trigger, index()->write_to_disk_timer_.desired_run_time());
  624. index()->Insert(hashes_.at<2>());
  625. index()->UpdateEntrySize(hashes_.at<2>(), 40u);
  626. EXPECT_TRUE(index()->HasPendingWrite());
  627. EXPECT_LT(expected_trigger, index()->write_to_disk_timer_.desired_run_time());
  628. index()->write_to_disk_timer_.Stop();
  629. }
  630. // net::APP_CACHE mode should not need to queue disk writes in as many places
  631. // as the default net::DISK_CACHE mode.
  632. TEST_F(SimpleIndexAppCacheTest, DiskWriteQueued) {
  633. index()->SetMaxSize(1000);
  634. ReturnIndexFile();
  635. EXPECT_FALSE(index()->HasPendingWrite());
  636. const uint64_t kHash1 = hashes_.at<1>();
  637. index()->Insert(kHash1);
  638. EXPECT_TRUE(index()->HasPendingWrite());
  639. index()->write_to_disk_timer_.Stop();
  640. EXPECT_FALSE(index()->HasPendingWrite());
  641. // Attempting to insert a hash that already exists should not queue the
  642. // write timer.
  643. index()->Insert(kHash1);
  644. EXPECT_FALSE(index()->HasPendingWrite());
  645. // Since net::APP_CACHE does not evict or track access times using an
  646. // entry should not queue the write timer.
  647. index()->UseIfExists(kHash1);
  648. EXPECT_FALSE(index()->HasPendingWrite());
  649. index()->UpdateEntrySize(kHash1, 20u);
  650. EXPECT_TRUE(index()->HasPendingWrite());
  651. index()->write_to_disk_timer_.Stop();
  652. // Updating to the same size should not queue the write timer.
  653. index()->UpdateEntrySize(kHash1, 20u);
  654. EXPECT_FALSE(index()->HasPendingWrite());
  655. index()->Remove(kHash1);
  656. EXPECT_TRUE(index()->HasPendingWrite());
  657. index()->write_to_disk_timer_.Stop();
  658. // Removing a non-existent hash should not queue the write timer.
  659. index()->Remove(kHash1);
  660. EXPECT_FALSE(index()->HasPendingWrite());
  661. }
  662. } // namespace disk_cache