summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-20 19:12:25 +0000
committerrvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-20 19:12:25 +0000
commitea9080b5665d0ac2007a6521d075ad73e9ad10b2 (patch)
tree4564eebf016a0ae0d1ebd1629493d8b2c1c52aa5
parent794d83cda5183b25665e99296ab6f5e6c1dbf2dc (diff)
downloadchromium_src-ea9080b5665d0ac2007a6521d075ad73e9ad10b2.zip
chromium_src-ea9080b5665d0ac2007a6521d075ad73e9ad10b2.tar.gz
chromium_src-ea9080b5665d0ac2007a6521d075ad73e9ad10b2.tar.bz2
Disk cache: Update stress_cache to perform deeper testsing.
BUG=none TEST=none Review URL: http://codereview.chromium.org/8352013 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@106538 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--net/disk_cache/backend_impl.cc83
-rw-r--r--net/disk_cache/backend_impl.h9
-rw-r--r--net/disk_cache/backend_unittest.cc8
-rw-r--r--net/disk_cache/disk_cache_test_base.cc4
-rw-r--r--net/disk_cache/disk_cache_test_util.cc4
-rw-r--r--net/disk_cache/disk_cache_test_util.h2
-rw-r--r--net/disk_cache/entry_impl.cc9
-rw-r--r--net/disk_cache/rankings.cc8
-rw-r--r--net/disk_cache/stress_cache.cc89
-rw-r--r--net/disk_cache/stress_support.h40
-rw-r--r--net/disk_cache/trace.cc24
-rw-r--r--net/disk_cache/trace.h1
12 files changed, 242 insertions, 39 deletions
diff --git a/net/disk_cache/backend_impl.cc b/net/disk_cache/backend_impl.cc
index c1cdad7..0d9c7e3 100644
--- a/net/disk_cache/backend_impl.cc
+++ b/net/disk_cache/backend_impl.cc
@@ -453,6 +453,10 @@ int BackendImpl::Init(OldCompletionCallback* callback) {
}
int BackendImpl::SyncInit() {
+#if defined(NET_BUILD_STRESS_CACHE)
+ // Start evictions right away.
+ up_ticks_ = kTrimDelay * 2;
+#endif
DCHECK(!init_);
if (init_)
return net::ERR_FAILED;
@@ -476,6 +480,7 @@ int BackendImpl::SyncInit() {
}
init_ = true;
+ Trace("Init");
if (data_->header.experiment != NO_EXPERIMENT &&
cache_type_ != net::DISK_CACHE) {
@@ -531,6 +536,14 @@ int BackendImpl::SyncInit() {
disabled_ = !rankings_.Init(this, new_eviction_);
+#if defined(STRESS_CACHE_EXTENDED_VALIDATION)
+ trace_object_->EnableTracing(false);
+ int sc = SelfCheck();
+ if (sc < 0 && sc != ERR_NUM_ENTRIES_MISMATCH)
+ NOTREACHED();
+ trace_object_->EnableTracing(true);
+#endif
+
return disabled_ ? net::ERR_FAILED : net::OK;
}
@@ -931,8 +944,10 @@ void BackendImpl::UpdateRank(EntryImpl* entry, bool modified) {
void BackendImpl::RecoveredEntry(CacheRankingsBlock* rankings) {
Addr address(rankings->Data()->contents);
EntryImpl* cache_entry = NULL;
- if (NewEntry(address, &cache_entry))
+ if (NewEntry(address, &cache_entry)) {
+ STRESS_NOTREACHED();
return;
+}
uint32 hash = cache_entry->GetHash();
cache_entry->Release();
@@ -972,9 +987,44 @@ void BackendImpl::InternalDoomEntry(EntryImpl* entry) {
}
}
+#if defined(NET_BUILD_STRESS_CACHE)
+
+CacheAddr BackendImpl::GetNextAddr(Addr address) {
+ EntriesMap::iterator it = open_entries_.find(address.value());
+ if (it != open_entries_.end()) {
+ EntryImpl* this_entry = it->second;
+ return this_entry->GetNextAddress();
+ }
+ DCHECK(block_files_.IsValid(address));
+ DCHECK(!address.is_separate_file() && address.file_type() == BLOCK_256);
+
+ CacheEntryBlock entry(File(address), address);
+ CHECK(entry.Load());
+ return entry.Data()->next;
+}
+
+void BackendImpl::NotLinked(EntryImpl* entry) {
+ Addr entry_addr = entry->entry()->address();
+ uint32 i = entry->GetHash() & mask_;
+ Addr address(data_->table[i]);
+ if (!address.is_initialized())
+ return;
+
+ for (;;) {
+ DCHECK(entry_addr.value() != address.value());
+ address.set_value(GetNextAddr(address));
+ if (!address.is_initialized())
+ break;
+ }
+}
+#endif // NET_BUILD_STRESS_CACHE
+
// An entry may be linked on the DELETED list for a while after being doomed.
// This function is called when we want to remove it.
void BackendImpl::RemoveEntry(EntryImpl* entry) {
+#if defined(NET_BUILD_STRESS_CACHE)
+ NotLinked(entry);
+#endif
if (!new_eviction_)
return;
@@ -1147,6 +1197,7 @@ void BackendImpl::FirstEviction() {
}
void BackendImpl::CriticalError(int error) {
+ STRESS_NOTREACHED();
LOG(ERROR) << "Critical error found " << error;
if (disabled_)
return;
@@ -1166,6 +1217,8 @@ void BackendImpl::CriticalError(int error) {
}
void BackendImpl::ReportError(int error) {
+ STRESS_DCHECK(!error || error == ERR_PREVIOUS_CRASH);
+
// We transmit positive numbers, instead of direct error codes.
DCHECK_LE(error, 0);
CACHE_UMA(CACHE_ERROR, "Error", 0, error * -1);
@@ -1284,12 +1337,16 @@ int BackendImpl::SelfCheck() {
int num_entries = rankings_.SelfCheck();
if (num_entries < 0) {
LOG(ERROR) << "Invalid rankings list, error " << num_entries;
+#if !defined(NET_BUILD_STRESS_CACHE)
return num_entries;
+#endif
}
if (num_entries != data_->header.num_entries) {
LOG(ERROR) << "Number of entries mismatch";
+#if !defined(NET_BUILD_STRESS_CACHE)
return ERR_NUM_ENTRIES_MISMATCH;
+#endif
}
return CheckAllEntries();
@@ -1547,9 +1604,12 @@ int BackendImpl::NewEntry(Addr address, EntryImpl** entry) {
return 0;
}
+ STRESS_DCHECK(block_files_.IsValid(address));
+
if (!address.is_initialized() || address.is_separate_file() ||
address.file_type() != BLOCK_256) {
LOG(WARNING) << "Wrong entry address.";
+ STRESS_NOTREACHED();
return ERR_INVALID_ADDRESS;
}
@@ -1568,9 +1628,13 @@ int BackendImpl::NewEntry(Addr address, EntryImpl** entry) {
if (!cache_entry->SanityCheck()) {
LOG(WARNING) << "Messed up entry found.";
+ STRESS_NOTREACHED();
return ERR_INVALID_ENTRY;
}
+ STRESS_DCHECK(block_files_.IsValid(
+ Addr(cache_entry->entry()->Data()->rankings_node)));
+
if (!cache_entry->LoadNodeAddress())
return ERR_READ_FAILURE;
@@ -1578,12 +1642,14 @@ int BackendImpl::NewEntry(Addr address, EntryImpl** entry) {
cache_entry->SetDirtyFlag(GetCurrentEntryId());
if (!rankings_.SanityCheck(cache_entry->rankings(), false)) {
+ STRESS_NOTREACHED();
cache_entry->SetDirtyFlag(0);
// Don't remove this from the list (it is not linked properly). Instead,
// break the link back to the entry because it is going away, and leave the
// rankings node to be deleted if we find it through a list.
rankings_.SetContents(cache_entry->rankings(), 0);
} else if (!rankings_.DataSanityCheck(cache_entry->rankings(), false)) {
+ STRESS_NOTREACHED();
cache_entry->SetDirtyFlag(0);
rankings_.SetContents(cache_entry->rankings(), address.value());
}
@@ -1816,6 +1882,7 @@ EntryImpl* BackendImpl::GetEnumeratedEntry(CacheRankingsBlock* next,
EntryImpl* entry;
int rv = NewEntry(Addr(next->Data()->contents), &entry);
if (rv) {
+ STRESS_NOTREACHED();
rankings_.Remove(next, list, false);
if (rv == ERR_INVALID_ADDRESS) {
// There is nothing linked from the index. Delete the rankings node.
@@ -1832,6 +1899,7 @@ EntryImpl* BackendImpl::GetEnumeratedEntry(CacheRankingsBlock* next,
}
if (!entry->Update()) {
+ STRESS_NOTREACHED();
entry->Release();
return NULL;
}
@@ -2069,12 +2137,14 @@ bool BackendImpl::CheckIndex() {
AdjustMaxCacheSize(data_->header.table_len);
+#if !defined(NET_BUILD_STRESS_CACHE)
if (data_->header.num_bytes < 0 ||
(max_size_ < kint32max - kDefaultCacheSize &&
data_->header.num_bytes > max_size_ + kDefaultCacheSize)) {
LOG(ERROR) << "Invalid cache (current) size";
return false;
}
+#endif
if (data_->header.num_entries < 0) {
LOG(ERROR) << "Invalid number of entries";
@@ -2093,15 +2163,17 @@ int BackendImpl::CheckAllEntries() {
int num_dirty = 0;
int num_entries = 0;
DCHECK(mask_ < kuint32max);
- for (int i = 0; i <= static_cast<int>(mask_); i++) {
+ for (unsigned int i = 0; i <= mask_; i++) {
Addr address(data_->table[i]);
if (!address.is_initialized())
continue;
for (;;) {
EntryImpl* tmp;
int ret = NewEntry(address, &tmp);
- if (ret)
+ if (ret) {
+ STRESS_NOTREACHED();
return ret;
+ }
scoped_refptr<EntryImpl> cache_entry;
cache_entry.swap(&tmp);
@@ -2112,6 +2184,7 @@ int BackendImpl::CheckAllEntries() {
else
return ERR_INVALID_ENTRY;
+ DCHECK_EQ(i, cache_entry->entry()->Data()->hash & mask_);
address.set_value(cache_entry->GetNextAddress());
if (!address.is_initialized())
break;
@@ -2120,7 +2193,9 @@ int BackendImpl::CheckAllEntries() {
Trace("CheckAllEntries End");
if (num_entries + num_dirty != data_->header.num_entries) {
- LOG(ERROR) << "Number of entries mismatch";
+ LOG(ERROR) << "Number of entries " << num_entries << " " << num_dirty <<
+ " " << data_->header.num_entries;
+ DCHECK_LT(num_entries, data_->header.num_entries);
return ERR_NUM_ENTRIES_MISMATCH;
}
diff --git a/net/disk_cache/backend_impl.h b/net/disk_cache/backend_impl.h
index 8d529d3..c637791 100644
--- a/net/disk_cache/backend_impl.h
+++ b/net/disk_cache/backend_impl.h
@@ -17,6 +17,7 @@
#include "net/disk_cache/in_flight_backend_io.h"
#include "net/disk_cache/rankings.h"
#include "net/disk_cache/stats.h"
+#include "net/disk_cache/stress_support.h"
#include "net/disk_cache/trace.h"
namespace net {
@@ -127,6 +128,14 @@ class NET_EXPORT_PRIVATE BackendImpl : public Backend {
// Permanently deletes an entry, but still keeps track of it.
void InternalDoomEntry(EntryImpl* entry);
+#if defined(NET_BUILD_STRESS_CACHE)
+ // Returns the address of the entry linked to the entry at a given |address|.
+ CacheAddr GetNextAddr(Addr address);
+
+ // Verifies that |entry| is not currently reachable through the index.
+ void NotLinked(EntryImpl* entry);
+#endif
+
// Removes all references to this entry.
void RemoveEntry(EntryImpl* entry);
diff --git a/net/disk_cache/backend_unittest.cc b/net/disk_cache/backend_unittest.cc
index bae4649..8188894 100644
--- a/net/disk_cache/backend_unittest.cc
+++ b/net/disk_cache/backend_unittest.cc
@@ -1199,14 +1199,16 @@ void DiskCacheBackendTest::BackendTransaction(const std::string& name,
ASSERT_TRUE(CopyTestCache(name));
DisableFirstCleanup();
+ uint32 mask;
if (load) {
- SetMask(0xf);
+ mask = 0xf;
SetMaxSize(0x100000);
} else {
// Clear the settings from the previous run.
- SetMask(0);
+ mask = 0;
SetMaxSize(0);
}
+ SetMask(mask);
InitCache();
ASSERT_EQ(num_entries + 1, cache_->GetEntryCount());
@@ -1227,7 +1229,7 @@ void DiskCacheBackendTest::BackendTransaction(const std::string& name,
cache_ = NULL;
cache_impl_ = NULL;
- ASSERT_TRUE(CheckCacheIntegrity(GetCacheFilePath(), new_eviction_));
+ ASSERT_TRUE(CheckCacheIntegrity(GetCacheFilePath(), new_eviction_, mask));
success_ = true;
}
diff --git a/net/disk_cache/disk_cache_test_base.cc b/net/disk_cache/disk_cache_test_base.cc
index c200328..28c1233 100644
--- a/net/disk_cache/disk_cache_test_base.cc
+++ b/net/disk_cache/disk_cache_test_base.cc
@@ -58,7 +58,7 @@ void DiskCacheTestWithCache::SimulateCrash() {
delete cache_impl_;
FilePath path = GetCacheFilePath();
- EXPECT_TRUE(CheckCacheIntegrity(path, new_eviction_));
+ EXPECT_TRUE(CheckCacheIntegrity(path, new_eviction_, mask_));
InitDiskCacheImpl(path);
}
@@ -213,7 +213,7 @@ void DiskCacheTestWithCache::TearDown() {
if (!memory_only_ && integrity_) {
FilePath path = GetCacheFilePath();
- EXPECT_TRUE(CheckCacheIntegrity(path, new_eviction_));
+ EXPECT_TRUE(CheckCacheIntegrity(path, new_eviction_, mask_));
}
PlatformTest::TearDown();
diff --git a/net/disk_cache/disk_cache_test_util.cc b/net/disk_cache/disk_cache_test_util.cc
index b68e3eb..1a348cf 100644
--- a/net/disk_cache/disk_cache_test_util.cc
+++ b/net/disk_cache/disk_cache_test_util.cc
@@ -92,9 +92,9 @@ bool CopyTestCache(const std::string& name) {
return file_util::CopyDirectory(path, dest, false);
}
-bool CheckCacheIntegrity(const FilePath& path, bool new_eviction) {
+bool CheckCacheIntegrity(const FilePath& path, bool new_eviction, uint32 mask) {
scoped_ptr<disk_cache::BackendImpl> cache(new disk_cache::BackendImpl(
- path, base::MessageLoopProxy::current(), NULL));
+ path, mask, base::MessageLoopProxy::current(), NULL));
if (!cache.get())
return false;
if (new_eviction)
diff --git a/net/disk_cache/disk_cache_test_util.h b/net/disk_cache/disk_cache_test_util.h
index 0bd937c..6469761 100644
--- a/net/disk_cache/disk_cache_test_util.h
+++ b/net/disk_cache/disk_cache_test_util.h
@@ -34,7 +34,7 @@ void CacheTestFillBuffer(char* buffer, size_t len, bool no_nulls);
std::string GenerateKey(bool same_length);
// Returns true if the cache is not corrupt.
-bool CheckCacheIntegrity(const FilePath& path, bool new_eviction);
+bool CheckCacheIntegrity(const FilePath& path, bool new_eviction, uint32 mask);
// Helper class which ensures that the cache dir returned by GetCacheFilePath
// exists and is clear in ctor and that the directory gets deleted in dtor.
diff --git a/net/disk_cache/entry_impl.cc b/net/disk_cache/entry_impl.cc
index e830fa0..920600d 100644
--- a/net/disk_cache/entry_impl.cc
+++ b/net/disk_cache/entry_impl.cc
@@ -585,8 +585,11 @@ bool EntryImpl::SanityCheck() {
Addr next_addr(stored->next);
if (next_addr.is_initialized() &&
- (next_addr.is_separate_file() || next_addr.file_type() != BLOCK_256))
+ (next_addr.is_separate_file() || next_addr.file_type() != BLOCK_256)) {
+ STRESS_NOTREACHED();
return false;
+ }
+ STRESS_DCHECK(next_addr.value() != entry_.address().value());
if (!rankings_addr.SanityCheck() || !next_addr.SanityCheck())
return false;
@@ -658,6 +661,7 @@ void EntryImpl::FixForDelete() {
if ((data_size <= kMaxBlockSize && data_addr.is_separate_file()) ||
(data_size > kMaxBlockSize && data_addr.is_block_file()) ||
!data_addr.SanityCheck()) {
+ STRESS_NOTREACHED();
// The address is weird so don't attempt to delete it.
stored->data_addr[i] = 0;
// In general, trust the stored size as it should be in sync with the
@@ -896,6 +900,9 @@ EntryImpl::~EntryImpl() {
if (doomed_) {
DeleteEntryData(true);
} else {
+#if defined(NET_BUILD_STRESS_CACHE)
+ SanityCheck();
+#endif
net_log_.AddEvent(net::NetLog::TYPE_ENTRY_CLOSE, NULL);
bool ret = true;
for (int index = 0; index < kNumStreams; index++) {
diff --git a/net/disk_cache/rankings.cc b/net/disk_cache/rankings.cc
index 9f183f5..8b31088 100644
--- a/net/disk_cache/rankings.cc
+++ b/net/disk_cache/rankings.cc
@@ -9,6 +9,7 @@
#include "net/disk_cache/entry_impl.h"
#include "net/disk_cache/errors.h"
#include "net/disk_cache/histogram_macros.h"
+#include "net/disk_cache/stress_support.h"
using base::Time;
using base::TimeTicks;
@@ -313,14 +314,17 @@ void Rankings::Remove(CacheRankingsBlock* node, List list, bool strict) {
!prev_addr.is_initialized() || prev_addr.is_separate_file()) {
if (next_addr.is_initialized() || prev_addr.is_initialized()) {
LOG(ERROR) << "Invalid rankings info.";
+ STRESS_NOTREACHED();
}
return;
}
CacheRankingsBlock next(backend_->File(next_addr), next_addr);
CacheRankingsBlock prev(backend_->File(prev_addr), prev_addr);
- if (!GetRanking(&next) || !GetRanking(&prev))
+ if (!GetRanking(&next) || !GetRanking(&prev)) {
+ STRESS_NOTREACHED();
return;
+ }
if (!CheckLinks(node, &prev, &next, &list))
return;
@@ -758,6 +762,8 @@ bool Rankings::CheckLinks(CacheRankingsBlock* node, CacheRankingsBlock* prev,
}
LOG(ERROR) << "Inconsistent LRU.";
+ STRESS_NOTREACHED();
+
backend_->CriticalError(ERR_INVALID_LINKS);
return false;
}
diff --git a/net/disk_cache/stress_cache.cc b/net/disk_cache/stress_cache.cc
index 7fad2ef..a18df2a 100644
--- a/net/disk_cache/stress_cache.cc
+++ b/net/disk_cache/stress_cache.cc
@@ -12,15 +12,7 @@
// A regular build should never crash.
// To test that the disk cache doesn't generate critical errors with regular
-// application level crashes, add the following code and re-compile:
-//
-// void BackendImpl::CriticalError(int error) {
-// NOTREACHED();
-//
-// void BackendImpl::ReportError(int error) {
-// if (error && error != ERR_PREVIOUS_CRASH) {
-// NOTREACHED();
-// }
+// application level crashes, edit stress_support.h.
#include <string>
#include <vector>
@@ -44,6 +36,12 @@
#include "net/disk_cache/backend_impl.h"
#include "net/disk_cache/disk_cache.h"
#include "net/disk_cache/disk_cache_test_util.h"
+#include "net/disk_cache/stress_support.h"
+#include "net/disk_cache/trace.h"
+
+#if defined(OS_WIN)
+#include "base/logging_win.h"
+#endif
using base::Time;
@@ -87,11 +85,21 @@ int MasterCode() {
// -----------------------------------------------------------------------
+std::string GenerateStressKey() {
+ char key[20 * 1024];
+ size_t size = 50 + rand() % 20000;
+ CacheTestFillBuffer(key, size, true);
+
+ key[size - 1] = '\0';
+ return std::string(key);
+}
+
// This thread will loop forever, adding and removing entries from the cache.
// iteration is the current crash cycle, so the entries on the cache are marked
// to know which instance of the application wrote them.
void StressTheCache(int iteration) {
- int cache_size = 0x800000; // 8MB
+ int cache_size = 0x2000000; // 32MB.
+ uint32 mask = 0xfff; // 4096 entries.
FilePath path = GetCacheFilePath().InsertBeforeExtensionASCII("_stress");
base::Thread cache_thread("CacheThread");
@@ -99,12 +107,14 @@ void StressTheCache(int iteration) {
base::Thread::Options(MessageLoop::TYPE_IO, 0)))
return;
+ disk_cache::BackendImpl* cache =
+ new disk_cache::BackendImpl(path, mask, cache_thread.message_loop_proxy(),
+ NULL);
+ cache->SetMaxSize(cache_size);
+ cache->SetFlags(disk_cache::kNoLoadProtection);
+
TestOldCompletionCallback cb;
- disk_cache::Backend* cache;
- int rv = disk_cache::BackendImpl::CreateBackend(
- path, false, cache_size, net::DISK_CACHE,
- disk_cache::kNoLoadProtection | disk_cache::kNoRandom,
- cache_thread.message_loop_proxy(), NULL, &cache, &cb);
+ int rv = cache->Init(&cb);
if (cb.GetResult(rv) != net::OK) {
printf("Unable to initialize cache.\n");
@@ -116,20 +126,22 @@ void StressTheCache(int iteration) {
int seed = static_cast<int>(Time::Now().ToInternalValue());
srand(seed);
+ // kNumKeys is meant to be enough to have about 3x or 4x iterations before
+ // the process crashes.
#ifdef NDEBUG
- const int kNumKeys = 5000;
+ const int kNumKeys = 4000;
#else
- const int kNumKeys = 1700;
+ const int kNumKeys = 1200;
#endif
const int kNumEntries = 30;
std::string keys[kNumKeys];
disk_cache::Entry* entries[kNumEntries] = {0};
for (int i = 0; i < kNumKeys; i++) {
- keys[i] = GenerateKey(true);
+ keys[i] = GenerateStressKey();
}
- const int kSize = 4000;
+ const int kSize = 20000;
scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize));
memset(buffer->data(), 'k', kSize);
@@ -137,7 +149,7 @@ void StressTheCache(int iteration) {
int slot = rand() % kNumEntries;
int key = rand() % kNumKeys;
bool truncate = rand() % 2 ? false : true;
- int size = kSize - (rand() % 4) * kSize / 4;
+ int size = kSize - (rand() % 20) * kSize / 20;
if (entries[slot])
entries[slot]->Close();
@@ -149,8 +161,8 @@ void StressTheCache(int iteration) {
}
base::snprintf(buffer->data(), kSize,
- "i: %d iter: %d, size: %d, truncate: %d", i, iteration, size,
- truncate ? 1 : 0);
+ "i: %d iter: %d, size: %d, truncate: %d ", i, iteration,
+ size, truncate ? 1 : 0);
rv = entries[slot]->WriteData(0, 0, buffer, size, &cb, truncate);
CHECK_EQ(size, cb.GetResult(rv));
@@ -181,7 +193,7 @@ class CrashTask : public Task {
if (g_crashing)
return;
- if (rand() % 100 > 1) {
+ if (rand() % 100 > 30) {
printf("sweet death...\n");
#if defined(OS_WIN)
// Windows does more work on _exit() that we would like, so we use Kill.
@@ -216,8 +228,29 @@ void CrashHandler(const std::string& str) {
base::debug::BreakDebugger();
}
+bool MessageHandler(int severity, const char* file, int line,
+ size_t message_start, const std::string& str) {
+ const size_t kMaxMessageLen = 48;
+ char message[kMaxMessageLen];
+ size_t len = std::min(str.length() - message_start, kMaxMessageLen - 1);
+
+ memcpy(message, str.c_str() + message_start, len);
+ message[len] = '\0';
+#if !defined(DISK_CACHE_TRACE_TO_LOG)
+ disk_cache::Trace("%s", message);
+#endif
+ return false;
+}
+
// -----------------------------------------------------------------------
+#if defined(OS_WIN)
+// {B9A153D4-31C3-48e4-9ABF-D54383F14A0D}
+const GUID kStressCacheTraceProviderName = {
+ 0xb9a153d4, 0x31c3, 0x48e4,
+ { 0x9a, 0xbf, 0xd5, 0x43, 0x83, 0xf1, 0x4a, 0xd } };
+#endif
+
int main(int argc, const char* argv[]) {
// Setup an AtExitManager so Singleton objects will be destructed.
base::AtExitManager at_exit_manager;
@@ -226,6 +259,16 @@ int main(int argc, const char* argv[]) {
return MasterCode();
logging::SetLogAssertHandler(CrashHandler);
+ logging::SetLogMessageHandler(MessageHandler);
+
+#if defined(OS_WIN)
+ logging::LogEventProvider::Initialize(kStressCacheTraceProviderName);
+#else
+ CommandLine::Init(argc, argv);
+ logging::InitLogging(NULL, logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
+ logging::LOCK_LOG_FILE, logging::DELETE_OLD_LOG_FILE,
+ logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS);
+#endif
// Some time for the memory manager to flush stuff.
base::PlatformThread::Sleep(3000);
diff --git a/net/disk_cache/stress_support.h b/net/disk_cache/stress_support.h
new file mode 100644
index 0000000..68457fb0
--- /dev/null
+++ b/net/disk_cache/stress_support.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2011 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.
+
+#ifndef NET_DISK_CACHE_STRESS_SUPPORT_H_
+#define NET_DISK_CACHE_STRESS_SUPPORT_H_
+#pragma once
+
+#include "base/logging.h"
+
+namespace disk_cache {
+
+// Uncomment this line to generate a debug build of stress_cache with checks
+// to ensure that we are not producing corrupt entries.
+// #define NET_BUILD_STRESS_CACHE 1
+
+// Uncomment this line to direct the in-memory disk cache tracing to the base
+// logging system. On Windows this option will enable ETW (Event Tracing for
+// Windows) so logs across multiple runs can be collected.
+// #define DISK_CACHE_TRACE_TO_LOG 1
+
+// Uncomment this line to perform extended integrity checks during init. It is
+// not recommended to enable this option unless some corruption is being tracked
+// down.
+// #define STRESS_CACHE_EXTENDED_VALIDATION 1
+
+#if defined(NET_BUILD_STRESS_CACHE)
+#define STRESS_NOTREACHED() NOTREACHED()
+#define STRESS_DCHECK(a) DCHECK(a)
+#else
+// We don't support streams with these macros, but that's a small price to pay
+// to have a straightforward logic here. Please don't add something like
+// LogMessageVoidify.
+#define STRESS_NOTREACHED() {}
+#define STRESS_DCHECK(a) {}
+#endif
+
+} // namespace disk_cache
+
+#endif // NET_DISK_CACHE_STRESS_SUPPORT_H_
diff --git a/net/disk_cache/trace.cc b/net/disk_cache/trace.cc
index c16068a..15c083d 100644
--- a/net/disk_cache/trace.cc
+++ b/net/disk_cache/trace.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -10,6 +10,7 @@
#endif
#include "base/logging.h"
+#include "net/disk_cache/stress_support.h"
// Change this value to 1 to enable tracing on a release build. By default,
// tracing is enabled only on debug builds.
@@ -23,7 +24,13 @@
namespace {
const int kEntrySize = 48;
+#if defined(NET_BUILD_STRESS_CACHE)
+const int kNumberOfEntries = 500000;
+#else
const int kNumberOfEntries = 5000; // 240 KB.
+#endif
+
+bool s_trace_enabled = false;
struct TraceBuffer {
int num_traces;
@@ -67,11 +74,16 @@ TraceObject::~TraceObject() {
DestroyTrace();
}
+void TraceObject::EnableTracing(bool enable) {
+ s_trace_enabled = enable;
+}
+
#if ENABLE_TRACING
static TraceBuffer* s_trace_buffer = NULL;
void InitTrace(void) {
+ s_trace_enabled = true;
if (s_trace_buffer)
return;
@@ -86,7 +98,7 @@ void DestroyTrace(void) {
}
void Trace(const char* format, ...) {
- if (!s_trace_buffer)
+ if (!s_trace_buffer || !s_trace_enabled)
return;
va_list ap;
@@ -99,6 +111,14 @@ void Trace(const char* format, ...) {
sizeof(s_trace_buffer->buffer[s_trace_buffer->current]), format,
ap);
#endif
+
+#if defined(DISK_CACHE_TRACE_TO_LOG)
+ char line[kEntrySize + 2];
+ memcpy(line, s_trace_buffer->buffer[s_trace_buffer->current], kEntrySize);
+ line[kEntrySize] = '\0';
+ LOG(INFO) << line;
+#endif
+
s_trace_buffer->num_traces++;
s_trace_buffer->current++;
if (s_trace_buffer->current == kNumberOfEntries)
diff --git a/net/disk_cache/trace.h b/net/disk_cache/trace.h
index 99a35bd..ed840c4 100644
--- a/net/disk_cache/trace.h
+++ b/net/disk_cache/trace.h
@@ -26,6 +26,7 @@ class TraceObject : public base::RefCounted<TraceObject> {
friend class base::RefCounted<TraceObject>;
public:
static TraceObject* GetTraceObject();
+ void EnableTracing(bool enable);
private:
TraceObject();