Index: net/disk_cache/simple/simple_index_file.cc |
diff --git a/net/disk_cache/simple/simple_index_file.cc b/net/disk_cache/simple/simple_index_file.cc |
deleted file mode 100644 |
index 95b2baee52f3fab518a1fbda1d808bd5b886a93e..0000000000000000000000000000000000000000 |
--- a/net/disk_cache/simple/simple_index_file.cc |
+++ /dev/null |
@@ -1,482 +0,0 @@ |
-// 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_file.h" |
- |
-#include <vector> |
- |
-#include "base/files/file.h" |
-#include "base/files/file_util.h" |
-#include "base/files/memory_mapped_file.h" |
-#include "base/hash.h" |
-#include "base/logging.h" |
-#include "base/pickle.h" |
-#include "base/single_thread_task_runner.h" |
-#include "base/task_runner_util.h" |
-#include "base/threading/thread_restrictions.h" |
-#include "net/disk_cache/simple/simple_backend_version.h" |
-#include "net/disk_cache/simple/simple_entry_format.h" |
-#include "net/disk_cache/simple/simple_histogram_macros.h" |
-#include "net/disk_cache/simple/simple_index.h" |
-#include "net/disk_cache/simple/simple_synchronous_entry.h" |
-#include "net/disk_cache/simple/simple_util.h" |
-#include "third_party/zlib/zlib.h" |
- |
-using base::File; |
- |
-namespace disk_cache { |
-namespace { |
- |
-const int kEntryFilesHashLength = 16; |
-const int kEntryFilesSuffixLength = 2; |
- |
-const uint64 kMaxEntiresInIndex = 100000000; |
- |
-uint32 CalculatePickleCRC(const Pickle& pickle) { |
- return crc32(crc32(0, Z_NULL, 0), |
- reinterpret_cast<const Bytef*>(pickle.payload()), |
- pickle.payload_size()); |
-} |
- |
-// Used in histograms. Please only add new values at the end. |
-enum IndexFileState { |
- INDEX_STATE_CORRUPT = 0, |
- INDEX_STATE_STALE = 1, |
- INDEX_STATE_FRESH = 2, |
- INDEX_STATE_FRESH_CONCURRENT_UPDATES = 3, |
- INDEX_STATE_MAX = 4, |
-}; |
- |
-void UmaRecordIndexFileState(IndexFileState state, net::CacheType cache_type) { |
- SIMPLE_CACHE_UMA(ENUMERATION, |
- "IndexFileStateOnLoad", cache_type, state, INDEX_STATE_MAX); |
-} |
- |
-// Used in histograms. Please only add new values at the end. |
-enum IndexInitMethod { |
- INITIALIZE_METHOD_RECOVERED = 0, |
- INITIALIZE_METHOD_LOADED = 1, |
- INITIALIZE_METHOD_NEWCACHE = 2, |
- INITIALIZE_METHOD_MAX = 3, |
-}; |
- |
-void UmaRecordIndexInitMethod(IndexInitMethod method, |
- net::CacheType cache_type) { |
- SIMPLE_CACHE_UMA(ENUMERATION, |
- "IndexInitializeMethod", cache_type, |
- method, INITIALIZE_METHOD_MAX); |
-} |
- |
-bool WritePickleFile(Pickle* pickle, const base::FilePath& file_name) { |
- File file( |
- file_name, |
- File::FLAG_CREATE | File::FLAG_WRITE | File::FLAG_SHARE_DELETE); |
- if (!file.IsValid()) |
- return false; |
- |
- int bytes_written = |
- file.Write(0, static_cast<const char*>(pickle->data()), pickle->size()); |
- if (bytes_written != implicit_cast<int>(pickle->size())) { |
- simple_util::SimpleCacheDeleteFile(file_name); |
- return false; |
- } |
- return true; |
-} |
- |
-// Called for each cache directory traversal iteration. |
-void ProcessEntryFile(SimpleIndex::EntrySet* entries, |
- const base::FilePath& file_path) { |
- static const size_t kEntryFilesLength = |
- kEntryFilesHashLength + kEntryFilesSuffixLength; |
- // Converting to std::string is OK since we never use UTF8 wide chars in our |
- // file names. |
- const base::FilePath::StringType base_name = file_path.BaseName().value(); |
- const std::string file_name(base_name.begin(), base_name.end()); |
- if (file_name.size() != kEntryFilesLength) |
- return; |
- const base::StringPiece hash_string( |
- file_name.begin(), file_name.begin() + kEntryFilesHashLength); |
- uint64 hash_key = 0; |
- if (!simple_util::GetEntryHashKeyFromHexString(hash_string, &hash_key)) { |
- LOG(WARNING) << "Invalid entry hash key filename while restoring index from" |
- << " disk: " << file_name; |
- return; |
- } |
- |
- File::Info file_info; |
- if (!base::GetFileInfo(file_path, &file_info)) { |
- LOG(ERROR) << "Could not get file info for " << file_path.value(); |
- return; |
- } |
- base::Time last_used_time; |
-#if defined(OS_POSIX) |
- // For POSIX systems, a last access time is available. However, it's not |
- // guaranteed to be more accurate than mtime. It is no worse though. |
- last_used_time = file_info.last_accessed; |
-#endif |
- if (last_used_time.is_null()) |
- last_used_time = file_info.last_modified; |
- |
- int64 file_size = file_info.size; |
- SimpleIndex::EntrySet::iterator it = entries->find(hash_key); |
- if (it == entries->end()) { |
- SimpleIndex::InsertInEntrySet( |
- hash_key, |
- EntryMetadata(last_used_time, file_size), |
- entries); |
- } else { |
- // Summing up the total size of the entry through all the *_[0-1] files |
- it->second.SetEntrySize(it->second.GetEntrySize() + file_size); |
- } |
-} |
- |
-} // namespace |
- |
-SimpleIndexLoadResult::SimpleIndexLoadResult() : did_load(false), |
- flush_required(false) { |
-} |
- |
-SimpleIndexLoadResult::~SimpleIndexLoadResult() { |
-} |
- |
-void SimpleIndexLoadResult::Reset() { |
- did_load = false; |
- flush_required = false; |
- entries.clear(); |
-} |
- |
-// static |
-const char SimpleIndexFile::kIndexFileName[] = "the-real-index"; |
-// static |
-const char SimpleIndexFile::kIndexDirectory[] = "index-dir"; |
-// static |
-const char SimpleIndexFile::kTempIndexFileName[] = "temp-index"; |
- |
-SimpleIndexFile::IndexMetadata::IndexMetadata() |
- : magic_number_(kSimpleIndexMagicNumber), |
- version_(kSimpleVersion), |
- number_of_entries_(0), |
- cache_size_(0) {} |
- |
-SimpleIndexFile::IndexMetadata::IndexMetadata( |
- uint64 number_of_entries, uint64 cache_size) |
- : magic_number_(kSimpleIndexMagicNumber), |
- version_(kSimpleVersion), |
- number_of_entries_(number_of_entries), |
- cache_size_(cache_size) {} |
- |
-void SimpleIndexFile::IndexMetadata::Serialize(Pickle* pickle) const { |
- DCHECK(pickle); |
- pickle->WriteUInt64(magic_number_); |
- pickle->WriteUInt32(version_); |
- pickle->WriteUInt64(number_of_entries_); |
- pickle->WriteUInt64(cache_size_); |
-} |
- |
-// static |
-bool SimpleIndexFile::SerializeFinalData(base::Time cache_modified, |
- Pickle* pickle) { |
- if (!pickle->WriteInt64(cache_modified.ToInternalValue())) |
- return false; |
- SimpleIndexFile::PickleHeader* header_p = pickle->headerT<PickleHeader>(); |
- header_p->crc = CalculatePickleCRC(*pickle); |
- return true; |
-} |
- |
-bool SimpleIndexFile::IndexMetadata::Deserialize(PickleIterator* it) { |
- DCHECK(it); |
- return it->ReadUInt64(&magic_number_) && |
- it->ReadUInt32(&version_) && |
- it->ReadUInt64(&number_of_entries_)&& |
- it->ReadUInt64(&cache_size_); |
-} |
- |
-void SimpleIndexFile::SyncWriteToDisk(net::CacheType cache_type, |
- const base::FilePath& cache_directory, |
- const base::FilePath& index_filename, |
- const base::FilePath& temp_index_filename, |
- scoped_ptr<Pickle> pickle, |
- const base::TimeTicks& start_time, |
- bool app_on_background) { |
- DCHECK_EQ(index_filename.DirName().value(), |
- temp_index_filename.DirName().value()); |
- base::FilePath index_file_directory = temp_index_filename.DirName(); |
- if (!base::DirectoryExists(index_file_directory) && |
- !base::CreateDirectory(index_file_directory)) { |
- LOG(ERROR) << "Could not create a directory to hold the index file"; |
- return; |
- } |
- |
- // There is a chance that the index containing all the necessary data about |
- // newly created entries will appear to be stale. This can happen if on-disk |
- // part of a Create operation does not fit into the time budget for the index |
- // flush delay. This simple approach will be reconsidered if it does not allow |
- // for maintaining freshness. |
- base::Time cache_dir_mtime; |
- if (!simple_util::GetMTime(cache_directory, &cache_dir_mtime)) { |
- LOG(ERROR) << "Could obtain information about cache age"; |
- return; |
- } |
- SerializeFinalData(cache_dir_mtime, pickle.get()); |
- if (!WritePickleFile(pickle.get(), temp_index_filename)) { |
- LOG(ERROR) << "Failed to write the temporary index file"; |
- return; |
- } |
- |
- // Atomically rename the temporary index file to become the real one. |
- // TODO(gavinp): DCHECK when not shutting down, since that is very strange. |
- // The rename failing during shutdown is legal because it's legal to begin |
- // erasing a cache as soon as the destructor has been called. |
- if (!base::ReplaceFile(temp_index_filename, index_filename, NULL)) |
- return; |
- |
- if (app_on_background) { |
- SIMPLE_CACHE_UMA(TIMES, |
- "IndexWriteToDiskTime.Background", cache_type, |
- (base::TimeTicks::Now() - start_time)); |
- } else { |
- SIMPLE_CACHE_UMA(TIMES, |
- "IndexWriteToDiskTime.Foreground", cache_type, |
- (base::TimeTicks::Now() - start_time)); |
- } |
-} |
- |
-bool SimpleIndexFile::IndexMetadata::CheckIndexMetadata() { |
- return number_of_entries_ <= kMaxEntiresInIndex && |
- magic_number_ == kSimpleIndexMagicNumber && |
- version_ == kSimpleVersion; |
-} |
- |
-SimpleIndexFile::SimpleIndexFile( |
- const scoped_refptr<base::SingleThreadTaskRunner>& cache_thread, |
- const scoped_refptr<base::TaskRunner>& worker_pool, |
- net::CacheType cache_type, |
- const base::FilePath& cache_directory) |
- : cache_thread_(cache_thread), |
- worker_pool_(worker_pool), |
- cache_type_(cache_type), |
- cache_directory_(cache_directory), |
- index_file_(cache_directory_.AppendASCII(kIndexDirectory) |
- .AppendASCII(kIndexFileName)), |
- temp_index_file_(cache_directory_.AppendASCII(kIndexDirectory) |
- .AppendASCII(kTempIndexFileName)) { |
-} |
- |
-SimpleIndexFile::~SimpleIndexFile() {} |
- |
-void SimpleIndexFile::LoadIndexEntries(base::Time cache_last_modified, |
- const base::Closure& callback, |
- SimpleIndexLoadResult* out_result) { |
- base::Closure task = base::Bind(&SimpleIndexFile::SyncLoadIndexEntries, |
- cache_type_, |
- cache_last_modified, cache_directory_, |
- index_file_, out_result); |
- worker_pool_->PostTaskAndReply(FROM_HERE, task, callback); |
-} |
- |
-void SimpleIndexFile::WriteToDisk(const SimpleIndex::EntrySet& entry_set, |
- uint64 cache_size, |
- const base::TimeTicks& start, |
- bool app_on_background, |
- const base::Closure& callback) { |
- IndexMetadata index_metadata(entry_set.size(), cache_size); |
- scoped_ptr<Pickle> pickle = Serialize(index_metadata, entry_set); |
- base::Closure task = |
- base::Bind(&SimpleIndexFile::SyncWriteToDisk, |
- cache_type_, cache_directory_, index_file_, temp_index_file_, |
- base::Passed(&pickle), start, app_on_background); |
- if (callback.is_null()) |
- cache_thread_->PostTask(FROM_HERE, task); |
- else |
- cache_thread_->PostTaskAndReply(FROM_HERE, task, callback); |
-} |
- |
-// static |
-void SimpleIndexFile::SyncLoadIndexEntries( |
- net::CacheType cache_type, |
- base::Time cache_last_modified, |
- const base::FilePath& cache_directory, |
- const base::FilePath& index_file_path, |
- SimpleIndexLoadResult* out_result) { |
- // Load the index and find its age. |
- base::Time last_cache_seen_by_index; |
- SyncLoadFromDisk(index_file_path, &last_cache_seen_by_index, out_result); |
- |
- // Consider the index loaded if it is fresh. |
- const bool index_file_existed = base::PathExists(index_file_path); |
- if (!out_result->did_load) { |
- if (index_file_existed) |
- UmaRecordIndexFileState(INDEX_STATE_CORRUPT, cache_type); |
- } else { |
- if (cache_last_modified <= last_cache_seen_by_index) { |
- base::Time latest_dir_mtime; |
- simple_util::GetMTime(cache_directory, &latest_dir_mtime); |
- if (LegacyIsIndexFileStale(latest_dir_mtime, index_file_path)) { |
- UmaRecordIndexFileState(INDEX_STATE_FRESH_CONCURRENT_UPDATES, |
- cache_type); |
- } else { |
- UmaRecordIndexFileState(INDEX_STATE_FRESH, cache_type); |
- } |
- UmaRecordIndexInitMethod(INITIALIZE_METHOD_LOADED, cache_type); |
- return; |
- } |
- UmaRecordIndexFileState(INDEX_STATE_STALE, cache_type); |
- } |
- |
- // Reconstruct the index by scanning the disk for entries. |
- const base::TimeTicks start = base::TimeTicks::Now(); |
- SyncRestoreFromDisk(cache_directory, index_file_path, out_result); |
- SIMPLE_CACHE_UMA(MEDIUM_TIMES, "IndexRestoreTime", cache_type, |
- base::TimeTicks::Now() - start); |
- SIMPLE_CACHE_UMA(COUNTS, "IndexEntriesRestored", cache_type, |
- out_result->entries.size()); |
- if (index_file_existed) { |
- UmaRecordIndexInitMethod(INITIALIZE_METHOD_RECOVERED, cache_type); |
- } else { |
- UmaRecordIndexInitMethod(INITIALIZE_METHOD_NEWCACHE, cache_type); |
- SIMPLE_CACHE_UMA(COUNTS, |
- "IndexCreatedEntryCount", cache_type, |
- out_result->entries.size()); |
- } |
-} |
- |
-// static |
-void SimpleIndexFile::SyncLoadFromDisk(const base::FilePath& index_filename, |
- base::Time* out_last_cache_seen_by_index, |
- SimpleIndexLoadResult* out_result) { |
- out_result->Reset(); |
- |
- File file(index_filename, |
- File::FLAG_OPEN | File::FLAG_READ | File::FLAG_SHARE_DELETE); |
- if (!file.IsValid()) |
- return; |
- |
- base::MemoryMappedFile index_file_map; |
- if (!index_file_map.Initialize(file.Pass())) { |
- simple_util::SimpleCacheDeleteFile(index_filename); |
- return; |
- } |
- |
- SimpleIndexFile::Deserialize( |
- reinterpret_cast<const char*>(index_file_map.data()), |
- index_file_map.length(), |
- out_last_cache_seen_by_index, |
- out_result); |
- |
- if (!out_result->did_load) |
- simple_util::SimpleCacheDeleteFile(index_filename); |
-} |
- |
-// static |
-scoped_ptr<Pickle> SimpleIndexFile::Serialize( |
- const SimpleIndexFile::IndexMetadata& index_metadata, |
- const SimpleIndex::EntrySet& entries) { |
- scoped_ptr<Pickle> pickle(new Pickle(sizeof(SimpleIndexFile::PickleHeader))); |
- |
- index_metadata.Serialize(pickle.get()); |
- for (SimpleIndex::EntrySet::const_iterator it = entries.begin(); |
- it != entries.end(); ++it) { |
- pickle->WriteUInt64(it->first); |
- it->second.Serialize(pickle.get()); |
- } |
- return pickle.Pass(); |
-} |
- |
-// static |
-void SimpleIndexFile::Deserialize(const char* data, int data_len, |
- base::Time* out_cache_last_modified, |
- SimpleIndexLoadResult* out_result) { |
- DCHECK(data); |
- |
- out_result->Reset(); |
- SimpleIndex::EntrySet* entries = &out_result->entries; |
- |
- Pickle pickle(data, data_len); |
- if (!pickle.data()) { |
- LOG(WARNING) << "Corrupt Simple Index File."; |
- return; |
- } |
- |
- PickleIterator pickle_it(pickle); |
- SimpleIndexFile::PickleHeader* header_p = |
- pickle.headerT<SimpleIndexFile::PickleHeader>(); |
- const uint32 crc_read = header_p->crc; |
- const uint32 crc_calculated = CalculatePickleCRC(pickle); |
- |
- if (crc_read != crc_calculated) { |
- LOG(WARNING) << "Invalid CRC in Simple Index file."; |
- return; |
- } |
- |
- SimpleIndexFile::IndexMetadata index_metadata; |
- if (!index_metadata.Deserialize(&pickle_it)) { |
- LOG(ERROR) << "Invalid index_metadata on Simple Cache Index."; |
- return; |
- } |
- |
- if (!index_metadata.CheckIndexMetadata()) { |
- LOG(ERROR) << "Invalid index_metadata on Simple Cache Index."; |
- return; |
- } |
- |
-#if !defined(OS_WIN) |
- // TODO(gavinp): Consider using std::unordered_map. |
- entries->resize(index_metadata.GetNumberOfEntries() + kExtraSizeForMerge); |
-#endif |
- while (entries->size() < index_metadata.GetNumberOfEntries()) { |
- uint64 hash_key; |
- EntryMetadata entry_metadata; |
- if (!pickle_it.ReadUInt64(&hash_key) || |
- !entry_metadata.Deserialize(&pickle_it)) { |
- LOG(WARNING) << "Invalid EntryMetadata in Simple Index file."; |
- entries->clear(); |
- return; |
- } |
- SimpleIndex::InsertInEntrySet(hash_key, entry_metadata, entries); |
- } |
- |
- int64 cache_last_modified; |
- if (!pickle_it.ReadInt64(&cache_last_modified)) { |
- entries->clear(); |
- return; |
- } |
- DCHECK(out_cache_last_modified); |
- *out_cache_last_modified = base::Time::FromInternalValue(cache_last_modified); |
- |
- out_result->did_load = true; |
-} |
- |
-// static |
-void SimpleIndexFile::SyncRestoreFromDisk( |
- const base::FilePath& cache_directory, |
- const base::FilePath& index_file_path, |
- SimpleIndexLoadResult* out_result) { |
- VLOG(1) << "Simple Cache Index is being restored from disk."; |
- simple_util::SimpleCacheDeleteFile(index_file_path); |
- out_result->Reset(); |
- SimpleIndex::EntrySet* entries = &out_result->entries; |
- |
- const bool did_succeed = TraverseCacheDirectory( |
- cache_directory, base::Bind(&ProcessEntryFile, entries)); |
- if (!did_succeed) { |
- LOG(ERROR) << "Could not reconstruct index from disk"; |
- return; |
- } |
- out_result->did_load = true; |
- // When we restore from disk we write the merged index file to disk right |
- // away, this might save us from having to restore again next time. |
- out_result->flush_required = true; |
-} |
- |
-// static |
-bool SimpleIndexFile::LegacyIsIndexFileStale( |
- base::Time cache_last_modified, |
- const base::FilePath& index_file_path) { |
- base::Time index_mtime; |
- if (!simple_util::GetMTime(index_file_path, &index_mtime)) |
- return true; |
- return index_mtime < cache_last_modified; |
-} |
- |
-} // namespace disk_cache |