// Copyright 2013 The Chromium Authors // 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_version_upgrade.h" #include <cstring> #include "base/containers/span.h" #include "base/files/file.h" #include "base/files/file_enumerator.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/files/memory_mapped_file.h" #include "base/logging.h" #include "base/pickle.h" #include "net/disk_cache/disk_cache.h" #include "net/disk_cache/simple/simple_backend_version.h" #include "net/disk_cache/simple/simple_entry_format_history.h" #include "third_party/zlib/zlib.h" namespace { // It is not possible to upgrade cache structures on disk that are of version // below this, the entire cache should be dropped for them. const uint32_t kMinVersionAbleToUpgrade = …; const char kFakeIndexFileName[] = …; const char kIndexDirName[] = …; const char kIndexFileName[] = …; void LogMessageFailedUpgradeFromVersion(int version) { … } bool WriteFakeIndexFile(disk_cache::BackendFileOperations* file_operations, const base::FilePath& file_name) { … } } // namespace namespace disk_cache { FakeIndexData::FakeIndexData() { … } // Migrates the cache directory from version 4 to version 5. // Returns true iff it succeeds. // // The V5 and V6 caches differ in the name of the index file (it moved to a // subdirectory) and in the file format (directory last-modified time observed // by the index writer has gotten appended to the pickled format). // // To keep complexity small this specific upgrade code *deletes* the old index // file. The directory for the new index file has to be created lazily anyway, // so it is not done in the upgrader. // // Below is the detailed description of index file format differences. It is for // reference purposes. This documentation would be useful to move closer to the // next index upgrader when the latter gets introduced. // // Path: // V5: $cachedir/the-real-index // V6: $cachedir/index-dir/the-real-index // // Pickled file format: // Both formats extend Pickle::Header by 32bit value of the CRC-32 of the // pickled data. // <v5-index> ::= <v5-index-metadata> <entry-info>* // <v5-index-metadata> ::= UInt64(kSimpleIndexMagicNumber) // UInt32(4) // UInt64(<number-of-entries>) // UInt64(<cache-size-in-bytes>) // <entry-info> ::= UInt64(<hash-of-the-key>) // Int64(<entry-last-used-time>) // UInt64(<entry-size-in-bytes>) // <v6-index> ::= <v6-index-metadata> // <entry-info>* // Int64(<cache-dir-mtime>) // <v6-index-metadata> ::= UInt64(kSimpleIndexMagicNumber) // UInt32(5) // UInt64(<number-of-entries>) // UInt64(<cache-size-in-bytes>) // Where: // <entry-size-in-bytes> is equal the sum of all file sizes of the entry. // <cache-dir-mtime> is the last modification time with nanosecond precision // of the directory, where all files for entries are stored. // <hash-of-the-key> represent the first 64 bits of a SHA-1 of the key. bool UpgradeIndexV5V6(BackendFileOperations* file_operations, const base::FilePath& cache_directory) { … } // Some points about the Upgrade process are still not clear: // 1. if the upgrade path requires dropping cache it would be faster to just // return an initialization error here and proceed with asynchronous cache // cleanup in CacheCreator. Should this hack be considered valid? Some smart // tests may fail. // 2. Because Android process management allows for killing a process at any // time, the upgrade process may need to deal with a partially completed // previous upgrade. For example, while upgrading A -> A + 2 we are the // process gets killed and some parts are remaining at version A + 1. There // are currently no generic mechanisms to resolve this situation, co the // upgrade codes need to ensure they can continue after being stopped in the // middle. It also means that the "fake index" must be flushed in between the // upgrade steps. Atomicity of this is an interesting research topic. The // intermediate fake index flushing must be added as soon as we add more // upgrade steps. SimpleCacheConsistencyResult UpgradeSimpleCacheOnDisk( BackendFileOperations* file_operations, const base::FilePath& path) { … } bool DeleteIndexFilesIfCacheIsEmpty(const base::FilePath& path) { … } } // namespace disk_cache