diff options
author | husky@chromium.org <husky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-26 13:38:02 +0000 |
---|---|---|
committer | husky@chromium.org <husky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-26 13:38:02 +0000 |
commit | 9e079cb3fc680c2d6eb45ed2c073cbf9a95ff64e (patch) | |
tree | 78ad4516274b6c626fe4c5628b7034b47d11fef2 /net/disk_cache | |
parent | 470cc4c60b55fc95f3638ff7b4c443300c60dfdd (diff) | |
download | chromium_src-9e079cb3fc680c2d6eb45ed2c073cbf9a95ff64e.zip chromium_src-9e079cb3fc680c2d6eb45ed2c073cbf9a95ff64e.tar.gz chromium_src-9e079cb3fc680c2d6eb45ed2c073cbf9a95ff64e.tar.bz2 |
Optionally disable mmap() in the disk cache.
The disk cache mmaps the headers of certain important files
(the main index file, plus block files). Unfortunately on
some Android devices mmap performs badly on flash storage,
and it's actually better to write the data manually.
This patch adds the macro USE_MMAP_FOR_DISK_CACHE macro and
the method disk_cache::MappedFile::FlushHeader(). By default,
the macro is defined, the new method is a no-op, and there's
no change in behavior.
TEST=DiskCacheTest
BUG=
Review URL: https://chromiumcodereview.appspot.com/10573032
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@144166 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/disk_cache')
-rw-r--r-- | net/disk_cache/backend_impl.cc | 16 | ||||
-rw-r--r-- | net/disk_cache/backend_impl.h | 3 | ||||
-rw-r--r-- | net/disk_cache/block_files.cc | 9 | ||||
-rw-r--r-- | net/disk_cache/block_files.h | 2 | ||||
-rw-r--r-- | net/disk_cache/mapped_file.h | 21 | ||||
-rw-r--r-- | net/disk_cache/mapped_file_avoid_mmap_posix.cc | 87 | ||||
-rw-r--r-- | net/disk_cache/mapped_file_posix.cc | 3 | ||||
-rw-r--r-- | net/disk_cache/mapped_file_win.cc | 5 | ||||
-rw-r--r-- | net/disk_cache/rankings.cc | 3 |
9 files changed, 143 insertions, 6 deletions
diff --git a/net/disk_cache/backend_impl.cc b/net/disk_cache/backend_impl.cc index 8ed1a4e..00970b7 100644 --- a/net/disk_cache/backend_impl.cc +++ b/net/disk_cache/backend_impl.cc @@ -500,9 +500,11 @@ int BackendImpl::SyncInit() { if (previous_crash) { ReportError(ERR_PREVIOUS_CRASH); } else if (!restarted_) { - ReportError(ERR_NO_ERROR); + ReportError(ERR_NO_ERROR); } + FlushIndex(); + return disabled_ ? net::ERR_FAILED : net::OK; } @@ -525,6 +527,7 @@ void BackendImpl::CleanupCache() { } } block_files_.CloseFiles(); + FlushIndex(); index_ = NULL; ptr_factory_.InvalidateWeakPtrs(); done_.Signal(); @@ -798,6 +801,7 @@ EntryImpl* BackendImpl::CreateEntryImpl(const std::string& key) { stats_.OnEvent(Stats::CREATE_HIT); SIMPLE_STATS_COUNTER("disk_cache.miss"); Trace("create entry hit "); + FlushIndex(); return cache_entry.release(); } @@ -925,6 +929,7 @@ void BackendImpl::RecoveredEntry(CacheRankingsBlock* rankings) { return; data_->table[hash & mask_] = address.value(); + FlushIndex(); } void BackendImpl::InternalDoomEntry(EntryImpl* entry) { @@ -953,6 +958,8 @@ void BackendImpl::InternalDoomEntry(EntryImpl* entry) { } else if (!error) { data_->table[hash & mask_] = child; } + + FlushIndex(); } #if defined(NET_BUILD_STRESS_CACHE) @@ -1306,6 +1313,11 @@ int BackendImpl::SelfCheck() { return CheckAllEntries(); } +void BackendImpl::FlushIndex() { + if (index_ && !disabled_) + index_->Flush(); +} + // ------------------------------------------------------------------------ int32 BackendImpl::GetEntryCount() const { @@ -1541,6 +1553,7 @@ void BackendImpl::PrepareForRestart() { disabled_ = true; data_->header.crash = 0; + index_->Flush(); index_ = NULL; data_ = NULL; block_files_.CloseFiles(); @@ -1724,6 +1737,7 @@ EntryImpl* BackendImpl::MatchEntry(const std::string& key, uint32 hash, cache_entry = NULL; find_parent ? parent_entry.swap(&tmp) : cache_entry.swap(&tmp); + FlushIndex(); return tmp; } diff --git a/net/disk_cache/backend_impl.h b/net/disk_cache/backend_impl.h index f2e6666..fed977f 100644 --- a/net/disk_cache/backend_impl.h +++ b/net/disk_cache/backend_impl.h @@ -253,6 +253,9 @@ class NET_EXPORT_PRIVATE BackendImpl : public Backend { // or an error code (negative value). int SelfCheck(); + // Ensures the index is flushed to disk (a no-op on platforms with mmap). + void FlushIndex(); + // Backend implementation. virtual int32 GetEntryCount() const OVERRIDE; virtual int OpenEntry(const std::string& key, Entry** entry, diff --git a/net/disk_cache/block_files.cc b/net/disk_cache/block_files.cc index 931599b..0f7b729 100644 --- a/net/disk_cache/block_files.cc +++ b/net/disk_cache/block_files.cc @@ -284,6 +284,7 @@ bool BlockFiles::CreateBlock(FileType block_type, int block_count, if (!file) return false; + ScopedFlush flush(file); BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); int target_size = 0; @@ -328,6 +329,7 @@ void BlockFiles::DeleteBlock(Addr address, bool deep) { BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); DeleteMapBlock(address.start_block(), address.num_blocks(), header); + file->Flush(); if (!header->num_entries) { // This file is now empty. Let's try to delete it. @@ -467,6 +469,7 @@ bool BlockFiles::OpenBlockFile(int index) { return false; } + ScopedFlush flush(file); DCHECK(!block_files_[index]); file.swap(&block_files_[index]); return true; @@ -476,6 +479,7 @@ bool BlockFiles::GrowBlockFile(MappedFile* file, BlockFileHeader* header) { if (kMaxBlocks == header->max_entries) return false; + ScopedFlush flush(file); DCHECK(!header->empty[3]); int new_size = header->max_entries + 1024; if (new_size > kMaxBlocks) @@ -524,7 +528,8 @@ MappedFile* BlockFiles::FileForNewBlock(FileType block_type, int block_count) { return file; } -MappedFile* BlockFiles::NextFile(const MappedFile* file) { +MappedFile* BlockFiles::NextFile(MappedFile* file) { + ScopedFlush flush(file); BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); int new_file = header->next_file; if (!new_file) { @@ -576,6 +581,7 @@ bool BlockFiles::RemoveEmptyFile(FileType block_type) { int file_index = header->next_file; header->next_file = next_header->next_file; DCHECK(block_files_.size() >= static_cast<unsigned int>(file_index)); + file->Flush(); // We get a new handle to the file and release the old one so that the // file gets unmmaped... so we can delete it. @@ -601,6 +607,7 @@ bool BlockFiles::RemoveEmptyFile(FileType block_type) { // Note that we expect to be called outside of a FileLock... however, we cannot // DCHECK on header->updating because we may be fixing a crash. bool BlockFiles::FixBlockFileHeader(MappedFile* file) { + ScopedFlush flush(file); BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); int file_size = static_cast<int>(file->GetLength()); if (file_size < static_cast<int>(sizeof(*header))) diff --git a/net/disk_cache/block_files.h b/net/disk_cache/block_files.h index 5abc64e..961a8f1 100644 --- a/net/disk_cache/block_files.h +++ b/net/disk_cache/block_files.h @@ -69,7 +69,7 @@ class NET_EXPORT_PRIVATE BlockFiles { MappedFile* FileForNewBlock(FileType block_type, int block_count); // Returns the next block file on this chain, creating new files if needed. - MappedFile* NextFile(const MappedFile* file); + MappedFile* NextFile(MappedFile* file); // Creates an empty block file and returns its index. int CreateNextBlockFile(FileType block_type); diff --git a/net/disk_cache/mapped_file.h b/net/disk_cache/mapped_file.h index 7886ad7..1e794bd 100644 --- a/net/disk_cache/mapped_file.h +++ b/net/disk_cache/mapped_file.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -26,7 +26,7 @@ class NET_EXPORT_PRIVATE MappedFile : public File { MappedFile() : File(true), init_(false) {} // Performs object initialization. name is the file to use, and size is the - // ammount of data to memory map from th efile. If size is 0, the whole file + // amount of data to memory map from the file. If size is 0, the whole file // will be mapped in memory. void* Init(const FilePath& name, size_t size); @@ -38,6 +38,9 @@ class NET_EXPORT_PRIVATE MappedFile : public File { bool Load(const FileBlock* block); bool Store(const FileBlock* block); + // Flush the memory-mapped section to disk (synchronously). + void Flush(); + private: virtual ~MappedFile(); @@ -47,10 +50,24 @@ class NET_EXPORT_PRIVATE MappedFile : public File { #endif void* buffer_; // Address of the memory mapped buffer. size_t view_size_; // Size of the memory pointed by buffer_. +#if defined(POSIX_AVOID_MMAP) + void* snapshot_; // Copy of the buffer taken when it was last flushed. +#endif DISALLOW_COPY_AND_ASSIGN(MappedFile); }; +// Helper class for calling Flush() on exit from the current scope. +class ScopedFlush { + public: + explicit ScopedFlush(MappedFile* file) : file_(file) {} + ~ScopedFlush() { + file_->Flush(); + } + private: + MappedFile* file_; +}; + } // namespace disk_cache #endif // NET_DISK_CACHE_MAPPED_FILE_H_ diff --git a/net/disk_cache/mapped_file_avoid_mmap_posix.cc b/net/disk_cache/mapped_file_avoid_mmap_posix.cc new file mode 100644 index 0000000..0fd6d2b --- /dev/null +++ b/net/disk_cache/mapped_file_avoid_mmap_posix.cc @@ -0,0 +1,87 @@ +// Copyright (c) 2012 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/mapped_file.h" + +#include <stdlib.h> + +#include "base/file_path.h" +#include "base/logging.h" + +namespace disk_cache { + +void* MappedFile::Init(const FilePath& name, size_t size) { + DCHECK(!init_); + if (init_ || !File::Init(name)) + return NULL; + + if (!size) + size = GetLength(); + + buffer_ = malloc(size); + snapshot_ = malloc(size); + if (buffer_ && snapshot_ && Read(buffer_, size, 0)) { + memcpy(snapshot_, buffer_, size); + } else { + free(buffer_); + free(snapshot_); + buffer_ = snapshot_ = 0; + } + + init_ = true; + view_size_ = size; + return buffer_; +} + +bool MappedFile::Load(const FileBlock* block) { + size_t offset = block->offset() + view_size_; + return Read(block->buffer(), block->size(), offset); +} + +bool MappedFile::Store(const FileBlock* block) { + size_t offset = block->offset() + view_size_; + return Write(block->buffer(), block->size(), offset); +} + +void MappedFile::Flush() { + DCHECK(buffer_); + DCHECK(snapshot_); + if (0 == memcmp(buffer_, snapshot_, view_size_)) { + // Nothing changed, no need to flush. + return; + } + + const char* buffer_ptr = static_cast<const char*>(buffer_); + char* snapshot_ptr = static_cast<char*>(snapshot_); + size_t i = 0; + while (i < view_size_) { + size_t run_start = i; + // Look for a run of changed bytes (possibly zero-sized). Write them out. + while(i < view_size_ && snapshot_ptr[i] != buffer_ptr[i]) { + snapshot_ptr[i] = buffer_ptr[i]; + i++; + } + if (i > run_start) { + Write(snapshot_ptr + run_start, i - run_start, run_start); + } + // Look for a run of unchanged bytes (possibly zero-sized). Skip them. + while (i < view_size_ && snapshot_ptr[i] == buffer_ptr[i]) { + i++; + } + } + DCHECK(0 == memcmp(buffer_, snapshot_, view_size_)); +} + +MappedFile::~MappedFile() { + if (!init_) + return; + + if (buffer_ && snapshot_) { + Flush(); + } + free(buffer_); + free(snapshot_); +} + +} // namespace disk_cache diff --git a/net/disk_cache/mapped_file_posix.cc b/net/disk_cache/mapped_file_posix.cc index 46bbc24..2dfa7ae 100644 --- a/net/disk_cache/mapped_file_posix.cc +++ b/net/disk_cache/mapped_file_posix.cc @@ -48,6 +48,9 @@ bool MappedFile::Store(const FileBlock* block) { return Write(block->buffer(), block->size(), offset); } +void MappedFile::Flush() { +} + MappedFile::~MappedFile() { if (!init_) return; diff --git a/net/disk_cache/mapped_file_win.cc b/net/disk_cache/mapped_file_win.cc index 9931e3e..f7575ef 100644 --- a/net/disk_cache/mapped_file_win.cc +++ b/net/disk_cache/mapped_file_win.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -59,4 +59,7 @@ bool MappedFile::Store(const FileBlock* block) { return Write(block->buffer(), block->size(), offset); } +void MappedFile::Flush() { +} + } // namespace disk_cache diff --git a/net/disk_cache/rankings.cc b/net/disk_cache/rankings.cc index 8d8a4df..d8da9f4 100644 --- a/net/disk_cache/rankings.cc +++ b/net/disk_cache/rankings.cc @@ -273,6 +273,7 @@ void Rankings::Insert(CacheRankingsBlock* node, bool modified, List list) { WriteHead(list); IncrementCounter(list); GenerateCrash(ON_INSERT_4); + backend_->FlushIndex(); } // If a, b and r are elements on the list, and we want to remove r, the possible @@ -379,6 +380,7 @@ void Rankings::Remove(CacheRankingsBlock* node, List list, bool strict) { DecrementCounter(list); UpdateIterators(&next); UpdateIterators(&prev); + backend_->FlushIndex(); } // A crash in between Remove and Insert will lead to a dirty entry not on the @@ -728,6 +730,7 @@ void Rankings::RevertRemove(CacheRankingsBlock* node) { prev.Store(); control_data_->transaction = 0; control_data_->operation = 0; + backend_->FlushIndex(); } bool Rankings::CheckLinks(CacheRankingsBlock* node, CacheRankingsBlock* prev, |