123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789 |
- // Copyright (c) 2013 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "net/disk_cache/simple/simple_index.h"
- #include <algorithm>
- #include <functional>
- #include <memory>
- #include <utility>
- #include "base/bind.h"
- #include "base/files/scoped_temp_dir.h"
- #include "base/hash/hash.h"
- #include "base/memory/raw_ptr.h"
- #include "base/pickle.h"
- #include "base/strings/stringprintf.h"
- #include "base/task/task_runner.h"
- #include "base/test/mock_entropy_provider.h"
- #include "base/threading/platform_thread.h"
- #include "base/time/time.h"
- #include "net/base/cache_type.h"
- #include "net/disk_cache/backend_cleanup_tracker.h"
- #include "net/disk_cache/disk_cache.h"
- #include "net/disk_cache/simple/simple_index_delegate.h"
- #include "net/disk_cache/simple/simple_index_file.h"
- #include "net/disk_cache/simple/simple_test_util.h"
- #include "net/disk_cache/simple/simple_util.h"
- #include "net/test/test_with_task_environment.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace disk_cache {
- namespace {
- const base::Time kTestLastUsedTime = base::Time::UnixEpoch() + base::Days(20);
- const uint32_t kTestEntrySize = 789;
- const uint8_t kTestEntryMemoryData = 123;
- uint32_t RoundSize(uint32_t in) {
- return (in + 0xFFu) & 0xFFFFFF00u;
- }
- } // namespace
- class EntryMetadataTest : public testing::Test {
- public:
- EntryMetadata NewEntryMetadataWithValues() {
- EntryMetadata entry(kTestLastUsedTime, kTestEntrySize);
- entry.SetInMemoryData(kTestEntryMemoryData);
- return entry;
- }
- void CheckEntryMetadataValues(const EntryMetadata& entry_metadata) {
- EXPECT_LT(kTestLastUsedTime - base::Seconds(2),
- entry_metadata.GetLastUsedTime());
- EXPECT_GT(kTestLastUsedTime + base::Seconds(2),
- entry_metadata.GetLastUsedTime());
- EXPECT_EQ(RoundSize(kTestEntrySize), entry_metadata.GetEntrySize());
- EXPECT_EQ(kTestEntryMemoryData, entry_metadata.GetInMemoryData());
- }
- };
- class MockSimpleIndexFile : public SimpleIndexFile,
- public base::SupportsWeakPtr<MockSimpleIndexFile> {
- public:
- explicit MockSimpleIndexFile(net::CacheType cache_type)
- : SimpleIndexFile(nullptr,
- base::MakeRefCounted<TrivialFileOperationsFactory>(),
- cache_type,
- base::FilePath()) {}
- void LoadIndexEntries(base::Time cache_last_modified,
- base::OnceClosure callback,
- SimpleIndexLoadResult* out_load_result) override {
- load_callback_ = std::move(callback);
- load_result_ = out_load_result;
- ++load_index_entries_calls_;
- }
- void WriteToDisk(net::CacheType cache_type,
- SimpleIndex::IndexWriteToDiskReason reason,
- const SimpleIndex::EntrySet& entry_set,
- uint64_t cache_size,
- base::OnceClosure callback) override {
- disk_writes_++;
- disk_write_entry_set_ = entry_set;
- }
- void GetAndResetDiskWriteEntrySet(SimpleIndex::EntrySet* entry_set) {
- entry_set->swap(disk_write_entry_set_);
- }
- base::OnceClosure TakeLoadCallback() { return std::move(load_callback_); }
- SimpleIndexLoadResult* load_result() const { return load_result_; }
- int load_index_entries_calls() const { return load_index_entries_calls_; }
- int disk_writes() const { return disk_writes_; }
- private:
- base::OnceClosure load_callback_;
- raw_ptr<SimpleIndexLoadResult> load_result_ = nullptr;
- int load_index_entries_calls_ = 0;
- int disk_writes_ = 0;
- SimpleIndex::EntrySet disk_write_entry_set_;
- };
- class SimpleIndexTest : public net::TestWithTaskEnvironment,
- public SimpleIndexDelegate {
- protected:
- SimpleIndexTest() : hashes_(base::BindRepeating(&HashesInitializer)) {}
- static uint64_t HashesInitializer(size_t hash_index) {
- return disk_cache::simple_util::GetEntryHashKey(
- base::StringPrintf("key%d", static_cast<int>(hash_index)));
- }
- void SetUp() override {
- auto index_file = std::make_unique<MockSimpleIndexFile>(CacheType());
- index_file_ = index_file->AsWeakPtr();
- index_ =
- std::make_unique<SimpleIndex>(/* io_thread = */ nullptr,
- /* cleanup_tracker = */ nullptr, this,
- CacheType(), std::move(index_file));
- index_->Initialize(base::Time());
- }
- void WaitForTimeChange() {
- const base::Time initial_time = base::Time::Now();
- do {
- base::PlatformThread::YieldCurrentThread();
- } while (base::Time::Now() - initial_time < base::Seconds(1));
- }
- // From SimpleIndexDelegate:
- void DoomEntries(std::vector<uint64_t>* entry_hashes,
- net::CompletionOnceCallback callback) override {
- for (const uint64_t& entry_hash : *entry_hashes)
- index_->Remove(entry_hash);
- last_doom_entry_hashes_ = *entry_hashes;
- ++doom_entries_calls_;
- }
- // Redirect to allow single "friend" declaration in base class.
- bool GetEntryForTesting(uint64_t key, EntryMetadata* metadata) {
- auto it = index_->entries_set_.find(key);
- if (index_->entries_set_.end() == it)
- return false;
- *metadata = it->second;
- return true;
- }
- void InsertIntoIndexFileReturn(uint64_t hash_key,
- base::Time last_used_time,
- int entry_size) {
- index_file_->load_result()->entries.insert(std::make_pair(
- hash_key, EntryMetadata(last_used_time,
- base::checked_cast<uint32_t>(entry_size))));
- }
- void ReturnIndexFile() {
- index_file_->load_result()->did_load = true;
- index_file_->TakeLoadCallback().Run();
- }
- // Non-const for timer manipulation.
- SimpleIndex* index() { return index_.get(); }
- const MockSimpleIndexFile* index_file() const { return index_file_.get(); }
- const std::vector<uint64_t>& last_doom_entry_hashes() const {
- return last_doom_entry_hashes_;
- }
- int doom_entries_calls() const { return doom_entries_calls_; }
- virtual net::CacheType CacheType() const { return net::DISK_CACHE; }
- const simple_util::ImmutableArray<uint64_t, 16> hashes_;
- std::unique_ptr<SimpleIndex> index_;
- base::WeakPtr<MockSimpleIndexFile> index_file_;
- std::vector<uint64_t> last_doom_entry_hashes_;
- int doom_entries_calls_ = 0;
- };
- class SimpleIndexAppCacheTest : public SimpleIndexTest {
- protected:
- net::CacheType CacheType() const override { return net::APP_CACHE; }
- };
- class SimpleIndexCodeCacheTest : public SimpleIndexTest {
- protected:
- net::CacheType CacheType() const override {
- return net::GENERATED_BYTE_CODE_CACHE;
- }
- };
- TEST_F(EntryMetadataTest, Basics) {
- EntryMetadata entry_metadata;
- EXPECT_EQ(base::Time(), entry_metadata.GetLastUsedTime());
- EXPECT_EQ(0u, entry_metadata.GetEntrySize());
- EXPECT_EQ(0u, entry_metadata.GetInMemoryData());
- entry_metadata = NewEntryMetadataWithValues();
- CheckEntryMetadataValues(entry_metadata);
- const base::Time new_time = base::Time::Now();
- entry_metadata.SetLastUsedTime(new_time);
- EXPECT_LT(new_time - base::Seconds(2), entry_metadata.GetLastUsedTime());
- EXPECT_GT(new_time + base::Seconds(2), entry_metadata.GetLastUsedTime());
- }
- // Tests that setting an unusually small/large last used time results in
- // truncation (rather than crashing).
- TEST_F(EntryMetadataTest, SaturatedLastUsedTime) {
- EntryMetadata entry_metadata;
- // Set a time that is too large to be represented internally as 32-bit unix
- // timestamp. Will saturate to a large timestamp (in year 2106).
- entry_metadata.SetLastUsedTime(base::Time::Max());
- EXPECT_EQ(INT64_C(15939440895000000),
- entry_metadata.GetLastUsedTime().ToInternalValue());
- // Set a time that is too small to be represented by a unix timestamp (before
- // 1970).
- entry_metadata.SetLastUsedTime(
- base::Time::FromInternalValue(7u)); // This is a date in 1601.
- EXPECT_EQ(base::Time::UnixEpoch() + base::Seconds(1),
- entry_metadata.GetLastUsedTime());
- }
- TEST_F(EntryMetadataTest, Serialize) {
- EntryMetadata entry_metadata = NewEntryMetadataWithValues();
- base::Pickle pickle;
- entry_metadata.Serialize(net::DISK_CACHE, &pickle);
- base::PickleIterator it(pickle);
- EntryMetadata new_entry_metadata;
- new_entry_metadata.Deserialize(net::DISK_CACHE, &it, true, true);
- CheckEntryMetadataValues(new_entry_metadata);
- // Test reading of old format --- the modern serialization of above entry
- // corresponds, in older format, to an entry with size =
- // RoundSize(kTestEntrySize) | kTestEntryMemoryData, which then gets
- // rounded again when stored by EntryMetadata.
- base::PickleIterator it2(pickle);
- EntryMetadata new_entry_metadata2;
- new_entry_metadata2.Deserialize(net::DISK_CACHE, &it2, false, false);
- EXPECT_EQ(RoundSize(RoundSize(kTestEntrySize) | kTestEntryMemoryData),
- new_entry_metadata2.GetEntrySize());
- EXPECT_EQ(0, new_entry_metadata2.GetInMemoryData());
- }
- TEST_F(SimpleIndexTest, IndexSizeCorrectOnMerge) {
- const unsigned int kSizeResolution = 256u;
- index()->SetMaxSize(100 * kSizeResolution);
- index()->Insert(hashes_.at<2>());
- index()->UpdateEntrySize(hashes_.at<2>(), 2u * kSizeResolution);
- index()->Insert(hashes_.at<3>());
- index()->UpdateEntrySize(hashes_.at<3>(), 3u * kSizeResolution);
- index()->Insert(hashes_.at<4>());
- index()->UpdateEntrySize(hashes_.at<4>(), 4u * kSizeResolution);
- EXPECT_EQ(9u * kSizeResolution, index()->cache_size_);
- {
- auto result = std::make_unique<SimpleIndexLoadResult>();
- result->did_load = true;
- index()->MergeInitializingSet(std::move(result));
- }
- EXPECT_EQ(9u * kSizeResolution, index()->cache_size_);
- {
- auto result = std::make_unique<SimpleIndexLoadResult>();
- result->did_load = true;
- const uint64_t new_hash_key = hashes_.at<11>();
- result->entries.insert(std::make_pair(
- new_hash_key, EntryMetadata(base::Time::Now(), 11u * kSizeResolution)));
- const uint64_t redundant_hash_key = hashes_.at<4>();
- result->entries.insert(
- std::make_pair(redundant_hash_key,
- EntryMetadata(base::Time::Now(), 4u * kSizeResolution)));
- index()->MergeInitializingSet(std::move(result));
- }
- EXPECT_EQ((2u + 3u + 4u + 11u) * kSizeResolution, index()->cache_size_);
- }
- // State of index changes as expected with an insert and a remove.
- TEST_F(SimpleIndexTest, BasicInsertRemove) {
- // Confirm blank state.
- EntryMetadata metadata;
- EXPECT_EQ(base::Time(), metadata.GetLastUsedTime());
- EXPECT_EQ(0U, metadata.GetEntrySize());
- // Confirm state after insert.
- index()->Insert(hashes_.at<1>());
- ASSERT_TRUE(GetEntryForTesting(hashes_.at<1>(), &metadata));
- base::Time now(base::Time::Now());
- EXPECT_LT(now - base::Minutes(1), metadata.GetLastUsedTime());
- EXPECT_GT(now + base::Minutes(1), metadata.GetLastUsedTime());
- EXPECT_EQ(0U, metadata.GetEntrySize());
- // Confirm state after remove.
- metadata = EntryMetadata();
- index()->Remove(hashes_.at<1>());
- EXPECT_FALSE(GetEntryForTesting(hashes_.at<1>(), &metadata));
- EXPECT_EQ(base::Time(), metadata.GetLastUsedTime());
- EXPECT_EQ(0U, metadata.GetEntrySize());
- }
- TEST_F(SimpleIndexTest, Has) {
- // Confirm the base index has dispatched the request for index entries.
- EXPECT_TRUE(index_file_.get());
- EXPECT_EQ(1, index_file_->load_index_entries_calls());
- // Confirm "Has()" always returns true before the callback is called.
- const uint64_t kHash1 = hashes_.at<1>();
- EXPECT_TRUE(index()->Has(kHash1));
- index()->Insert(kHash1);
- EXPECT_TRUE(index()->Has(kHash1));
- index()->Remove(kHash1);
- // TODO(morlovich): Maybe return false on explicitly removed entries?
- EXPECT_TRUE(index()->Has(kHash1));
- ReturnIndexFile();
- // Confirm "Has() returns conditionally now.
- EXPECT_FALSE(index()->Has(kHash1));
- index()->Insert(kHash1);
- EXPECT_TRUE(index()->Has(kHash1));
- index()->Remove(kHash1);
- }
- TEST_F(SimpleIndexTest, UseIfExists) {
- // Confirm the base index has dispatched the request for index entries.
- EXPECT_TRUE(index_file_.get());
- EXPECT_EQ(1, index_file_->load_index_entries_calls());
- // Confirm "UseIfExists()" always returns true before the callback is called
- // and updates mod time if the entry was really there.
- const uint64_t kHash1 = hashes_.at<1>();
- EntryMetadata metadata1, metadata2;
- EXPECT_TRUE(index()->UseIfExists(kHash1));
- EXPECT_FALSE(GetEntryForTesting(kHash1, &metadata1));
- index()->Insert(kHash1);
- EXPECT_TRUE(index()->UseIfExists(kHash1));
- EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata1));
- WaitForTimeChange();
- EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata2));
- EXPECT_EQ(metadata1.GetLastUsedTime(), metadata2.GetLastUsedTime());
- EXPECT_TRUE(index()->UseIfExists(kHash1));
- EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata2));
- EXPECT_LT(metadata1.GetLastUsedTime(), metadata2.GetLastUsedTime());
- index()->Remove(kHash1);
- EXPECT_TRUE(index()->UseIfExists(kHash1));
- ReturnIndexFile();
- // Confirm "UseIfExists() returns conditionally now
- EXPECT_FALSE(index()->UseIfExists(kHash1));
- EXPECT_FALSE(GetEntryForTesting(kHash1, &metadata1));
- index()->Insert(kHash1);
- EXPECT_TRUE(index()->UseIfExists(kHash1));
- EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata1));
- WaitForTimeChange();
- EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata2));
- EXPECT_EQ(metadata1.GetLastUsedTime(), metadata2.GetLastUsedTime());
- EXPECT_TRUE(index()->UseIfExists(kHash1));
- EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata2));
- EXPECT_LT(metadata1.GetLastUsedTime(), metadata2.GetLastUsedTime());
- index()->Remove(kHash1);
- EXPECT_FALSE(index()->UseIfExists(kHash1));
- }
- TEST_F(SimpleIndexTest, UpdateEntrySize) {
- base::Time now(base::Time::Now());
- index()->SetMaxSize(1000);
- const uint64_t kHash1 = hashes_.at<1>();
- InsertIntoIndexFileReturn(kHash1, now - base::Days(2), 475);
- ReturnIndexFile();
- EntryMetadata metadata;
- EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata));
- EXPECT_LT(now - base::Days(2) - base::Seconds(1), metadata.GetLastUsedTime());
- EXPECT_GT(now - base::Days(2) + base::Seconds(1), metadata.GetLastUsedTime());
- EXPECT_EQ(RoundSize(475u), metadata.GetEntrySize());
- index()->UpdateEntrySize(kHash1, 600u);
- EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata));
- EXPECT_EQ(RoundSize(600u), metadata.GetEntrySize());
- EXPECT_EQ(1, index()->GetEntryCount());
- }
- TEST_F(SimpleIndexTest, GetEntryCount) {
- EXPECT_EQ(0, index()->GetEntryCount());
- index()->Insert(hashes_.at<1>());
- EXPECT_EQ(1, index()->GetEntryCount());
- index()->Insert(hashes_.at<2>());
- EXPECT_EQ(2, index()->GetEntryCount());
- index()->Insert(hashes_.at<3>());
- EXPECT_EQ(3, index()->GetEntryCount());
- index()->Insert(hashes_.at<3>());
- EXPECT_EQ(3, index()->GetEntryCount());
- index()->Remove(hashes_.at<2>());
- EXPECT_EQ(2, index()->GetEntryCount());
- index()->Insert(hashes_.at<4>());
- EXPECT_EQ(3, index()->GetEntryCount());
- index()->Remove(hashes_.at<3>());
- EXPECT_EQ(2, index()->GetEntryCount());
- index()->Remove(hashes_.at<3>());
- EXPECT_EQ(2, index()->GetEntryCount());
- index()->Remove(hashes_.at<1>());
- EXPECT_EQ(1, index()->GetEntryCount());
- index()->Remove(hashes_.at<4>());
- EXPECT_EQ(0, index()->GetEntryCount());
- }
- // Confirm that we get the results we expect from a simple init.
- TEST_F(SimpleIndexTest, BasicInit) {
- base::Time now(base::Time::Now());
- InsertIntoIndexFileReturn(hashes_.at<1>(), now - base::Days(2), 10u);
- InsertIntoIndexFileReturn(hashes_.at<2>(), now - base::Days(3), 1000u);
- ReturnIndexFile();
- EntryMetadata metadata;
- EXPECT_TRUE(GetEntryForTesting(hashes_.at<1>(), &metadata));
- EXPECT_EQ(metadata.GetLastUsedTime(),
- index()->GetLastUsedTime(hashes_.at<1>()));
- EXPECT_LT(now - base::Days(2) - base::Seconds(1), metadata.GetLastUsedTime());
- EXPECT_GT(now - base::Days(2) + base::Seconds(1), metadata.GetLastUsedTime());
- EXPECT_EQ(RoundSize(10u), metadata.GetEntrySize());
- EXPECT_TRUE(GetEntryForTesting(hashes_.at<2>(), &metadata));
- EXPECT_EQ(metadata.GetLastUsedTime(),
- index()->GetLastUsedTime(hashes_.at<2>()));
- EXPECT_LT(now - base::Days(3) - base::Seconds(1), metadata.GetLastUsedTime());
- EXPECT_GT(now - base::Days(3) + base::Seconds(1), metadata.GetLastUsedTime());
- EXPECT_EQ(RoundSize(1000u), metadata.GetEntrySize());
- EXPECT_EQ(base::Time(), index()->GetLastUsedTime(hashes_.at<3>()));
- }
- // Remove something that's going to come in from the loaded index.
- TEST_F(SimpleIndexTest, RemoveBeforeInit) {
- const uint64_t kHash1 = hashes_.at<1>();
- index()->Remove(kHash1);
- InsertIntoIndexFileReturn(kHash1, base::Time::Now() - base::Days(2), 10u);
- ReturnIndexFile();
- EXPECT_FALSE(index()->Has(kHash1));
- }
- // Insert something that's going to come in from the loaded index; correct
- // result?
- TEST_F(SimpleIndexTest, InsertBeforeInit) {
- const uint64_t kHash1 = hashes_.at<1>();
- index()->Insert(kHash1);
- InsertIntoIndexFileReturn(kHash1, base::Time::Now() - base::Days(2), 10u);
- ReturnIndexFile();
- EntryMetadata metadata;
- EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata));
- base::Time now(base::Time::Now());
- EXPECT_LT(now - base::Minutes(1), metadata.GetLastUsedTime());
- EXPECT_GT(now + base::Minutes(1), metadata.GetLastUsedTime());
- EXPECT_EQ(0U, metadata.GetEntrySize());
- }
- // Insert and Remove something that's going to come in from the loaded index.
- TEST_F(SimpleIndexTest, InsertRemoveBeforeInit) {
- const uint64_t kHash1 = hashes_.at<1>();
- index()->Insert(kHash1);
- index()->Remove(kHash1);
- InsertIntoIndexFileReturn(kHash1, base::Time::Now() - base::Days(2), 10u);
- ReturnIndexFile();
- EXPECT_FALSE(index()->Has(kHash1));
- }
- // Insert and Remove something that's going to come in from the loaded index.
- TEST_F(SimpleIndexTest, RemoveInsertBeforeInit) {
- const uint64_t kHash1 = hashes_.at<1>();
- index()->Remove(kHash1);
- index()->Insert(kHash1);
- InsertIntoIndexFileReturn(kHash1, base::Time::Now() - base::Days(2), 10u);
- ReturnIndexFile();
- EntryMetadata metadata;
- EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata));
- base::Time now(base::Time::Now());
- EXPECT_LT(now - base::Minutes(1), metadata.GetLastUsedTime());
- EXPECT_GT(now + base::Minutes(1), metadata.GetLastUsedTime());
- EXPECT_EQ(0U, metadata.GetEntrySize());
- }
- // Do all above tests at once + a non-conflict to test for cross-key
- // interactions.
- TEST_F(SimpleIndexTest, AllInitConflicts) {
- base::Time now(base::Time::Now());
- index()->Remove(hashes_.at<1>());
- InsertIntoIndexFileReturn(hashes_.at<1>(), now - base::Days(2), 10u);
- index()->Insert(hashes_.at<2>());
- InsertIntoIndexFileReturn(hashes_.at<2>(), now - base::Days(3), 100u);
- index()->Insert(hashes_.at<3>());
- index()->Remove(hashes_.at<3>());
- InsertIntoIndexFileReturn(hashes_.at<3>(), now - base::Days(4), 1000u);
- index()->Remove(hashes_.at<4>());
- index()->Insert(hashes_.at<4>());
- InsertIntoIndexFileReturn(hashes_.at<4>(), now - base::Days(5), 10000u);
- InsertIntoIndexFileReturn(hashes_.at<5>(), now - base::Days(6), 100000u);
- ReturnIndexFile();
- EXPECT_FALSE(index()->Has(hashes_.at<1>()));
- EntryMetadata metadata;
- EXPECT_TRUE(GetEntryForTesting(hashes_.at<2>(), &metadata));
- EXPECT_LT(now - base::Minutes(1), metadata.GetLastUsedTime());
- EXPECT_GT(now + base::Minutes(1), metadata.GetLastUsedTime());
- EXPECT_EQ(0U, metadata.GetEntrySize());
- EXPECT_FALSE(index()->Has(hashes_.at<3>()));
- EXPECT_TRUE(GetEntryForTesting(hashes_.at<4>(), &metadata));
- EXPECT_LT(now - base::Minutes(1), metadata.GetLastUsedTime());
- EXPECT_GT(now + base::Minutes(1), metadata.GetLastUsedTime());
- EXPECT_EQ(0U, metadata.GetEntrySize());
- EXPECT_TRUE(GetEntryForTesting(hashes_.at<5>(), &metadata));
- EXPECT_GT(now - base::Days(6) + base::Seconds(1), metadata.GetLastUsedTime());
- EXPECT_LT(now - base::Days(6) - base::Seconds(1), metadata.GetLastUsedTime());
- EXPECT_EQ(RoundSize(100000u), metadata.GetEntrySize());
- }
- TEST_F(SimpleIndexTest, BasicEviction) {
- base::Time now(base::Time::Now());
- index()->SetMaxSize(1000);
- InsertIntoIndexFileReturn(hashes_.at<1>(), now - base::Days(2), 475u);
- index()->Insert(hashes_.at<2>());
- index()->UpdateEntrySize(hashes_.at<2>(), 475u);
- ReturnIndexFile();
- WaitForTimeChange();
- index()->Insert(hashes_.at<3>());
- // Confirm index is as expected: No eviction, everything there.
- EXPECT_EQ(3, index()->GetEntryCount());
- EXPECT_EQ(0, doom_entries_calls());
- EXPECT_TRUE(index()->Has(hashes_.at<1>()));
- EXPECT_TRUE(index()->Has(hashes_.at<2>()));
- EXPECT_TRUE(index()->Has(hashes_.at<3>()));
- // Trigger an eviction, and make sure the right things are tossed.
- // TODO(morlovich): This is dependent on the innards of the implementation
- // as to at exactly what point we trigger eviction. Not sure how to fix
- // that.
- index()->UpdateEntrySize(hashes_.at<3>(), 475u);
- EXPECT_EQ(1, doom_entries_calls());
- EXPECT_EQ(1, index()->GetEntryCount());
- EXPECT_FALSE(index()->Has(hashes_.at<1>()));
- EXPECT_FALSE(index()->Has(hashes_.at<2>()));
- EXPECT_TRUE(index()->Has(hashes_.at<3>()));
- ASSERT_EQ(2u, last_doom_entry_hashes().size());
- }
- TEST_F(SimpleIndexTest, EvictBySize) {
- base::Time now(base::Time::Now());
- index()->SetMaxSize(50000);
- InsertIntoIndexFileReturn(hashes_.at<1>(), now - base::Days(2), 475u);
- InsertIntoIndexFileReturn(hashes_.at<2>(), now - base::Days(1), 40000u);
- ReturnIndexFile();
- WaitForTimeChange();
- index()->Insert(hashes_.at<3>());
- // Confirm index is as expected: No eviction, everything there.
- EXPECT_EQ(3, index()->GetEntryCount());
- EXPECT_EQ(0, doom_entries_calls());
- EXPECT_TRUE(index()->Has(hashes_.at<1>()));
- EXPECT_TRUE(index()->Has(hashes_.at<2>()));
- EXPECT_TRUE(index()->Has(hashes_.at<3>()));
- // Trigger an eviction, and make sure the right things are tossed.
- // TODO(morlovich): This is dependent on the innards of the implementation
- // as to at exactly what point we trigger eviction. Not sure how to fix
- // that.
- index()->UpdateEntrySize(hashes_.at<3>(), 40000u);
- EXPECT_EQ(1, doom_entries_calls());
- EXPECT_EQ(2, index()->GetEntryCount());
- EXPECT_TRUE(index()->Has(hashes_.at<1>()));
- EXPECT_FALSE(index()->Has(hashes_.at<2>()));
- EXPECT_TRUE(index()->Has(hashes_.at<3>()));
- ASSERT_EQ(1u, last_doom_entry_hashes().size());
- }
- TEST_F(SimpleIndexCodeCacheTest, DisableEvictBySize) {
- base::Time now(base::Time::Now());
- index()->SetMaxSize(50000);
- InsertIntoIndexFileReturn(hashes_.at<1>(), now - base::Days(2), 475u);
- InsertIntoIndexFileReturn(hashes_.at<2>(), now - base::Days(1), 40000u);
- ReturnIndexFile();
- WaitForTimeChange();
- index()->Insert(hashes_.at<3>());
- // Confirm index is as expected: No eviction, everything there.
- EXPECT_EQ(3, index()->GetEntryCount());
- EXPECT_EQ(0, doom_entries_calls());
- EXPECT_TRUE(index()->Has(hashes_.at<1>()));
- EXPECT_TRUE(index()->Has(hashes_.at<2>()));
- EXPECT_TRUE(index()->Has(hashes_.at<3>()));
- // Trigger an eviction, and make sure the right things are tossed.
- // Since evict by size is supposed to be disabled, it evicts in LRU order,
- // so entries 1 and 2 are both kicked out.
- index()->UpdateEntrySize(hashes_.at<3>(), 40000u);
- EXPECT_EQ(1, doom_entries_calls());
- EXPECT_EQ(1, index()->GetEntryCount());
- EXPECT_FALSE(index()->Has(hashes_.at<1>()));
- EXPECT_FALSE(index()->Has(hashes_.at<2>()));
- EXPECT_TRUE(index()->Has(hashes_.at<3>()));
- ASSERT_EQ(2u, last_doom_entry_hashes().size());
- }
- // Same as test above, but using much older entries to make sure that small
- // things eventually get evictied.
- TEST_F(SimpleIndexTest, EvictBySize2) {
- base::Time now(base::Time::Now());
- index()->SetMaxSize(50000);
- InsertIntoIndexFileReturn(hashes_.at<1>(), now - base::Days(200), 475u);
- InsertIntoIndexFileReturn(hashes_.at<2>(), now - base::Days(1), 40000u);
- ReturnIndexFile();
- WaitForTimeChange();
- index()->Insert(hashes_.at<3>());
- // Confirm index is as expected: No eviction, everything there.
- EXPECT_EQ(3, index()->GetEntryCount());
- EXPECT_EQ(0, doom_entries_calls());
- EXPECT_TRUE(index()->Has(hashes_.at<1>()));
- EXPECT_TRUE(index()->Has(hashes_.at<2>()));
- EXPECT_TRUE(index()->Has(hashes_.at<3>()));
- // Trigger an eviction, and make sure the right things are tossed.
- // TODO(morlovich): This is dependent on the innards of the implementation
- // as to at exactly what point we trigger eviction. Not sure how to fix
- // that.
- index()->UpdateEntrySize(hashes_.at<3>(), 40000u);
- EXPECT_EQ(1, doom_entries_calls());
- EXPECT_EQ(1, index()->GetEntryCount());
- EXPECT_FALSE(index()->Has(hashes_.at<1>()));
- EXPECT_FALSE(index()->Has(hashes_.at<2>()));
- EXPECT_TRUE(index()->Has(hashes_.at<3>()));
- ASSERT_EQ(2u, last_doom_entry_hashes().size());
- }
- // Confirm all the operations queue a disk write at some point in the
- // future.
- TEST_F(SimpleIndexTest, DiskWriteQueued) {
- index()->SetMaxSize(1000);
- ReturnIndexFile();
- EXPECT_FALSE(index()->HasPendingWrite());
- const uint64_t kHash1 = hashes_.at<1>();
- index()->Insert(kHash1);
- EXPECT_TRUE(index()->HasPendingWrite());
- index()->write_to_disk_timer_.Stop();
- EXPECT_FALSE(index()->HasPendingWrite());
- // Attempting to insert a hash that already exists should not queue the
- // write timer.
- index()->Insert(kHash1);
- EXPECT_FALSE(index()->HasPendingWrite());
- index()->UseIfExists(kHash1);
- EXPECT_TRUE(index()->HasPendingWrite());
- index()->write_to_disk_timer_.Stop();
- index()->UpdateEntrySize(kHash1, 20u);
- EXPECT_TRUE(index()->HasPendingWrite());
- index()->write_to_disk_timer_.Stop();
- // Updating to the same size should not queue the write timer.
- index()->UpdateEntrySize(kHash1, 20u);
- EXPECT_FALSE(index()->HasPendingWrite());
- index()->Remove(kHash1);
- EXPECT_TRUE(index()->HasPendingWrite());
- index()->write_to_disk_timer_.Stop();
- // Removing a non-existent hash should not queue the write timer.
- index()->Remove(kHash1);
- EXPECT_FALSE(index()->HasPendingWrite());
- }
- TEST_F(SimpleIndexTest, DiskWriteExecuted) {
- index()->SetMaxSize(1000);
- ReturnIndexFile();
- EXPECT_FALSE(index()->HasPendingWrite());
- const uint64_t kHash1 = hashes_.at<1>();
- index()->Insert(kHash1);
- index()->UpdateEntrySize(kHash1, 20u);
- EXPECT_TRUE(index()->HasPendingWrite());
- EXPECT_EQ(0, index_file_->disk_writes());
- index()->write_to_disk_timer_.FireNow();
- EXPECT_EQ(1, index_file_->disk_writes());
- SimpleIndex::EntrySet entry_set;
- index_file_->GetAndResetDiskWriteEntrySet(&entry_set);
- uint64_t hash_key = kHash1;
- base::Time now(base::Time::Now());
- ASSERT_EQ(1u, entry_set.size());
- EXPECT_EQ(hash_key, entry_set.begin()->first);
- const EntryMetadata& entry1(entry_set.begin()->second);
- EXPECT_LT(now - base::Minutes(1), entry1.GetLastUsedTime());
- EXPECT_GT(now + base::Minutes(1), entry1.GetLastUsedTime());
- EXPECT_EQ(RoundSize(20u), entry1.GetEntrySize());
- }
- TEST_F(SimpleIndexTest, DiskWritePostponed) {
- index()->SetMaxSize(1000);
- ReturnIndexFile();
- EXPECT_FALSE(index()->HasPendingWrite());
- index()->Insert(hashes_.at<1>());
- index()->UpdateEntrySize(hashes_.at<1>(), 20u);
- EXPECT_TRUE(index()->HasPendingWrite());
- base::TimeTicks expected_trigger(
- index()->write_to_disk_timer_.desired_run_time());
- WaitForTimeChange();
- EXPECT_EQ(expected_trigger, index()->write_to_disk_timer_.desired_run_time());
- index()->Insert(hashes_.at<2>());
- index()->UpdateEntrySize(hashes_.at<2>(), 40u);
- EXPECT_TRUE(index()->HasPendingWrite());
- EXPECT_LT(expected_trigger, index()->write_to_disk_timer_.desired_run_time());
- index()->write_to_disk_timer_.Stop();
- }
- // net::APP_CACHE mode should not need to queue disk writes in as many places
- // as the default net::DISK_CACHE mode.
- TEST_F(SimpleIndexAppCacheTest, DiskWriteQueued) {
- index()->SetMaxSize(1000);
- ReturnIndexFile();
- EXPECT_FALSE(index()->HasPendingWrite());
- const uint64_t kHash1 = hashes_.at<1>();
- index()->Insert(kHash1);
- EXPECT_TRUE(index()->HasPendingWrite());
- index()->write_to_disk_timer_.Stop();
- EXPECT_FALSE(index()->HasPendingWrite());
- // Attempting to insert a hash that already exists should not queue the
- // write timer.
- index()->Insert(kHash1);
- EXPECT_FALSE(index()->HasPendingWrite());
- // Since net::APP_CACHE does not evict or track access times using an
- // entry should not queue the write timer.
- index()->UseIfExists(kHash1);
- EXPECT_FALSE(index()->HasPendingWrite());
- index()->UpdateEntrySize(kHash1, 20u);
- EXPECT_TRUE(index()->HasPendingWrite());
- index()->write_to_disk_timer_.Stop();
- // Updating to the same size should not queue the write timer.
- index()->UpdateEntrySize(kHash1, 20u);
- EXPECT_FALSE(index()->HasPendingWrite());
- index()->Remove(kHash1);
- EXPECT_TRUE(index()->HasPendingWrite());
- index()->write_to_disk_timer_.Stop();
- // Removing a non-existent hash should not queue the write timer.
- index()->Remove(kHash1);
- EXPECT_FALSE(index()->HasPendingWrite());
- }
- } // namespace disk_cache
|