Commit 4f2eab7c authored by rvargas's avatar rvargas Committed by Commit bot

Disk cache: Re-initialize stats counters if they are zero on-disk.

Stats are saved to disk every five minutes. If a client is initializing
the cache, and it crashes before saving the stats for the first time,
the next run will see an empty stats storage, and will discard the cache
because it may indicate that the storage address was invalid.

Now, we check the contents to see if the storage was empty and re-initialize
things as needed.

BUG=none
TEST=net_unittests

Review URL: https://codereview.chromium.org/980003002

Cr-Commit-Position: refs/heads/master@{#319204}
parent ea82a568
......@@ -107,8 +107,18 @@ bool Stats::Init(void* data, int num_bytes, Addr address) {
local_stats.size = sizeof(local_stats);
} else if (num_bytes >= static_cast<int>(sizeof(*stats))) {
stats = reinterpret_cast<OnDiskStats*>(data);
if (!VerifyStats(stats))
return false;
if (!VerifyStats(stats)) {
memset(&local_stats, 0, sizeof(local_stats));
if (memcmp(stats, &local_stats, sizeof(local_stats))) {
return false;
} else {
// The storage is empty which means that SerializeStats() was never
// called on the last run. Just re-initialize everything.
local_stats.signature = kDiskSignature;
local_stats.size = sizeof(local_stats);
stats = &local_stats;
}
}
} else {
return false;
}
......
......@@ -9,6 +9,7 @@
#include <vector>
#include "base/basictypes.h"
#include "net/base/net_export.h"
#include "net/disk_cache/blockfile/addr.h"
namespace base {
......@@ -20,7 +21,7 @@ namespace disk_cache {
typedef std::vector<std::pair<std::string, std::string> > StatsItems;
// This class stores cache-specific usage information, for tunning purposes.
class Stats {
class NET_EXPORT_PRIVATE Stats {
public:
static const int kDataSizesLength = 28;
enum Counters {
......
// Copyright 2015 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/blockfile/stats.h"
#include "base/memory/scoped_ptr.h"
#include "testing/gtest/include/gtest/gtest.h"
TEST(DiskCacheStatsTest, Init) {
disk_cache::Stats stats;
EXPECT_TRUE(stats.Init(nullptr, 0, disk_cache::Addr()));
EXPECT_EQ(0, stats.GetCounter(disk_cache::Stats::TRIM_ENTRY));
}
TEST(DiskCacheStatsTest, InitWithEmptyBuffer) {
disk_cache::Stats stats;
int required_len = stats.StorageSize();
scoped_ptr<char[]> storage(new char[required_len]);
memset(storage.get(), 0, required_len);
ASSERT_TRUE(stats.Init(storage.get(), required_len, disk_cache::Addr()));
EXPECT_EQ(0, stats.GetCounter(disk_cache::Stats::TRIM_ENTRY));
}
TEST(DiskCacheStatsTest, FailsInit) {
disk_cache::Stats stats;
int required_len = stats.StorageSize();
scoped_ptr<char[]> storage(new char[required_len]);
memset(storage.get(), 0, required_len);
// Try a small buffer.
EXPECT_LT(200, required_len);
disk_cache::Addr addr;
EXPECT_FALSE(stats.Init(storage.get(), 200, addr));
// Try a buffer with garbage.
memset(storage.get(), 'a', required_len);
EXPECT_FALSE(stats.Init(storage.get(), required_len, addr));
}
TEST(DiskCacheStatsTest, SaveRestore) {
scoped_ptr<disk_cache::Stats> stats(new disk_cache::Stats);
disk_cache::Addr addr(5);
ASSERT_TRUE(stats->Init(nullptr, 0, addr));
stats->SetCounter(disk_cache::Stats::CREATE_ERROR, 11);
stats->SetCounter(disk_cache::Stats::DOOM_ENTRY, 13);
stats->OnEvent(disk_cache::Stats::MIN_COUNTER);
stats->OnEvent(disk_cache::Stats::TRIM_ENTRY);
stats->OnEvent(disk_cache::Stats::DOOM_RECENT);
int required_len = stats->StorageSize();
scoped_ptr<char[]> storage(new char[required_len]);
disk_cache::Addr out_addr;
int real_len = stats->SerializeStats(storage.get(), required_len, &out_addr);
EXPECT_GE(required_len, real_len);
EXPECT_EQ(out_addr, addr);
stats.reset(new disk_cache::Stats);
ASSERT_TRUE(stats->Init(storage.get(), real_len, addr));
EXPECT_EQ(1, stats->GetCounter(disk_cache::Stats::MIN_COUNTER));
EXPECT_EQ(1, stats->GetCounter(disk_cache::Stats::TRIM_ENTRY));
EXPECT_EQ(1, stats->GetCounter(disk_cache::Stats::DOOM_RECENT));
EXPECT_EQ(0, stats->GetCounter(disk_cache::Stats::OPEN_HIT));
EXPECT_EQ(0, stats->GetCounter(disk_cache::Stats::READ_DATA));
EXPECT_EQ(0, stats->GetCounter(disk_cache::Stats::LAST_REPORT_TIMER));
EXPECT_EQ(11, stats->GetCounter(disk_cache::Stats::CREATE_ERROR));
EXPECT_EQ(13, stats->GetCounter(disk_cache::Stats::DOOM_ENTRY));
// Now pass the whole buffer. It shoulod not matter that there is unused
// space at the end.
stats.reset(new disk_cache::Stats);
ASSERT_TRUE(stats->Init(storage.get(), required_len, addr));
EXPECT_EQ(1, stats->GetCounter(disk_cache::Stats::MIN_COUNTER));
EXPECT_EQ(1, stats->GetCounter(disk_cache::Stats::TRIM_ENTRY));
EXPECT_EQ(1, stats->GetCounter(disk_cache::Stats::DOOM_RECENT));
EXPECT_EQ(0, stats->GetCounter(disk_cache::Stats::OPEN_HIT));
EXPECT_EQ(0, stats->GetCounter(disk_cache::Stats::READ_DATA));
EXPECT_EQ(0, stats->GetCounter(disk_cache::Stats::LAST_REPORT_TIMER));
EXPECT_EQ(11, stats->GetCounter(disk_cache::Stats::CREATE_ERROR));
EXPECT_EQ(13, stats->GetCounter(disk_cache::Stats::DOOM_ENTRY));
}
......@@ -1335,6 +1335,7 @@
'disk_cache/blockfile/block_files_unittest.cc',
'disk_cache/blockfile/index_table_v3_unittest.cc',
'disk_cache/blockfile/mapped_file_unittest.cc',
'disk_cache/blockfile/stats_unittest.cc',
'disk_cache/blockfile/storage_block_unittest.cc',
'disk_cache/cache_util_unittest.cc',
'disk_cache/entry_unittest.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment