Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(44)

Unified Diff: net/disk_cache/mapped_file_avoid_mmap_posix.cc

Issue 18834003: Revert "Updating the mapped_file_avoid_mmap_posix implementation." (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/disk_cache/mapped_file.h ('k') | net/disk_cache/mapped_file_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/disk_cache/mapped_file_avoid_mmap_posix.cc
diff --git a/net/disk_cache/mapped_file_avoid_mmap_posix.cc b/net/disk_cache/mapped_file_avoid_mmap_posix.cc
index 3d91265ff8eb6b70f2b325211926f34226b78d4e..cd514a366e2fcc7b42965f38675799c9268855e5 100644
--- a/net/disk_cache/mapped_file_avoid_mmap_posix.cc
+++ b/net/disk_cache/mapped_file_avoid_mmap_posix.cc
@@ -5,221 +5,9 @@
#include "net/disk_cache/mapped_file.h"
#include <stdlib.h>
-#include <sys/mman.h>
-
-#include <map>
#include "base/files/file_path.h"
-#include "base/lazy_instance.h"
#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
-#include "base/threading/thread_local.h"
-
-// This implementation of MappedFile doesn't use a shared RW mmap for
-// performance reason. Instead it will use a private RO mmap and install a SEGV
-// signal handler. When the memory is modified, the handler will register the
-// modified address and change the protection of the page to RW. When a flush is
-// then executed, it has access to the exact pages that have been modified and
-// will only write those to disk. The handler will only track half of the dirty
-// pages. If more than half the pages are modified, the flush will instead write
-// the full buffer to disk.
-
-namespace {
-
-// Choose 4k as a reasonable page size. As this file is used mainly on Android,
-// this is the real android page size.
-const size_t kPageSize = 4096;
-
-// Variable capacity array, optimized for capacity of 1. Most of the mapped file
-// are used to map exactly 2 pages. Tracking 1 page is then optimal because if
-// both pages are modified, writing the full view is the optimal behavior.
-class SmallArray {
- public:
- SmallArray() : capacity_(0), array_(NULL) {}
- ~SmallArray() { SetCapacity(0); }
-
- size_t capacity() { return capacity_; }
- char** array() { return array_; }
- void SetCapacity(size_t capacity) {
- if (capacity_ > 1)
- delete[] array_;
- capacity_ = capacity;
- if (capacity > 1)
- array_ = new char*[capacity];
- else
- array_ = small_array_;
- }
-
- private:
- size_t capacity_;
- char** array_;
- char* small_array_[1];
-};
-
-// Information about the memory mapped part of a file.
-struct MappedFileInfo {
- // Stat address of the memory.
- char* start_address;
- // Size of the memory map.
- size_t size;
- // Number of dirty page. A page is dirty if the memory content is different
- // from the file content.
- size_t num_dirty_pages;
- // The dirty pages.
- SmallArray dirty_pages;
-};
-
-// The maximum number of dirty pages that can be tracked. Limit the memory
-// overhead to 2kb per file.
-const size_t kMaxDirtyPagesCacheSize =
- kPageSize / sizeof(char*) / 2 - sizeof(MappedFileInfo);
-
-class ThreadLocalMappedFileInfo {
- public:
- ThreadLocalMappedFileInfo() {}
- ~ThreadLocalMappedFileInfo() {}
-
- void RegisterMappedFile(disk_cache::MappedFile* mapped_file, size_t size) {
- scoped_ptr<MappedFileInfo> new_info(new MappedFileInfo);
- new_info->start_address = static_cast<char*>(mapped_file->buffer());
- new_info->size = size;
- new_info->num_dirty_pages = 0;
- // Track half of the dirty pages, after this, just overwrite the full
- // content.
- size_t capacity = (size + kPageSize - 1) / kPageSize / 2;
- if (capacity > kMaxDirtyPagesCacheSize)
- capacity = kMaxDirtyPagesCacheSize;
- new_info->dirty_pages.SetCapacity(capacity);
- info_per_map_file_[mapped_file] = new_info.get();
- infos_.push_back(new_info.release());
- Update();
- }
-
- void UnregisterMappedFile(disk_cache::MappedFile* mapped_file) {
- MappedFileInfo* info = InfoForMappedFile(mapped_file);
- DCHECK(info);
- info_per_map_file_.erase(mapped_file);
- infos_.erase(std::find(infos_.begin(), infos_.end(), info));
- Update();
- }
-
- MappedFileInfo* InfoForMappedFile(disk_cache::MappedFile* mapped_file) {
- return info_per_map_file_[mapped_file];
- }
-
- MappedFileInfo** infos_ptr() { return infos_ptr_; }
- size_t infos_size() { return infos_size_; }
-
- private:
- // Update |infos_ptr_| and |infos_size_| when |infos_| change.
- void Update() {
- infos_ptr_ = &infos_[0];
- infos_size_ = infos_.size();
- }
-
- // Link to the MappedFileInfo for a given MappedFile.
- std::map<disk_cache::MappedFile*, MappedFileInfo*> info_per_map_file_;
- // Vector of information about all current MappedFile belonging to the current
- // thread.
- ScopedVector<MappedFileInfo> infos_;
- // Pointer to the storage part of |infos_|. This is kept as a variable to
- // prevent the signal handler from calling any C++ method that might allocate
- // memory.
- MappedFileInfo** infos_ptr_;
- // Size of |infos_|.
- size_t infos_size_;
-};
-
-class SegvHandler {
- public:
- // Register the signal handler.
- SegvHandler();
- ~SegvHandler() {}
-
- // SEGV signal handler. This handler will check that the address that
- // generated the fault is one associated with a mapped file. If that's the
- // case, it will register the address and change the protection to RW then
- // return. This will cause the instruction that generated the fault to be
- // re-executed. If not, it will just reinstall the old handler and return,
- // which will generate the fault again and let the initial handler get called.
- static void SigSegvHandler(int sig, siginfo_t* si, void* unused);
-
- base::ThreadLocalPointer<ThreadLocalMappedFileInfo>& thread_local_infos() {
- return thread_local_infos_;
- }
-
- private:
- // Install the SEGV handler, storing the current sigaction in |old_sigaction|
- // if it is not NULL.
- static void InstallSigHandler(struct sigaction* old_sigaction);
-
- base::ThreadLocalPointer<ThreadLocalMappedFileInfo> thread_local_infos_;
- struct sigaction old_sigaction_;
-};
-
-static base::LazyInstance<SegvHandler> g_segv_handler =
- LAZY_INSTANCE_INITIALIZER;
-
-// Initialisation method.
-SegvHandler::SegvHandler() {
- // Setup the SIGV signal handler.
- InstallSigHandler(&old_sigaction_);
-}
-
-// static
-void SegvHandler::SigSegvHandler(int sig, siginfo_t* si, void* unused) {
- // First, check if the current sighandler has the SA_SIGINFO flag. If it
- // doesn't it means an external library installed temporarly a signal handler
- // using signal, and so incorrectly restored the current one. The parameters
- // are then useless.
- struct sigaction current_action;
- sigaction(SIGSEGV, NULL, &current_action);
- if (!(current_action.sa_flags & SA_SIGINFO)) {
- LOG(WARNING) << "Signal handler have been re-installed incorrectly.";
- InstallSigHandler(NULL);
- // Returning will re-run the signal with the correct parameters.
- return;
- }
- ThreadLocalMappedFileInfo* thread_local_info =
- g_segv_handler.Pointer()->thread_local_infos().Get();
- if (thread_local_info) {
- char* addr = reinterpret_cast<char*>(si->si_addr);
- for (size_t i = 0; i < thread_local_info->infos_size(); ++i) {
- MappedFileInfo* info = thread_local_info->infos_ptr()[i];
- if (info->start_address <= addr &&
- addr < info->start_address + info->size) {
- // Only track new dirty pages if the array has still some capacity.
- // Otherwise, the full buffer will be written to disk and it is not
- // necessary to track changes until the next flush.
- if (info->num_dirty_pages < info->dirty_pages.capacity()) {
- char* aligned_address = reinterpret_cast<char*>(
- reinterpret_cast<size_t>(addr) & ~(kPageSize - 1));
- mprotect(aligned_address, kPageSize, PROT_READ | PROT_WRITE);
- info->dirty_pages.array()[info->num_dirty_pages] = aligned_address;
- } else {
- mprotect(info->start_address, info->size, PROT_READ | PROT_WRITE);
- }
- info->num_dirty_pages++;
- return;
- }
- }
- }
- // The address it not handled by any mapped filed. Let the default handler get
- // called.
- sigaction(SIGSEGV, &g_segv_handler.Pointer()->old_sigaction_, NULL);
-}
-
-// static
-void SegvHandler::InstallSigHandler(struct sigaction* old_sigaction) {
- struct sigaction action;
- action.sa_sigaction = SigSegvHandler;
- sigemptyset(&action.sa_mask);
- action.sa_flags = SA_SIGINFO | SA_RESTART;
- sigaction(SIGSEGV, &action, old_sigaction);
-}
-
-} // namespace
namespace disk_cache {
@@ -231,21 +19,14 @@ void* MappedFile::Init(const base::FilePath& name, size_t size) {
if (!size)
size = GetLength();
- buffer_ = mmap(NULL, size, PROT_READ, MAP_PRIVATE, platform_file(), 0);
- if (reinterpret_cast<ptrdiff_t>(buffer_) == -1) {
- NOTREACHED();
- buffer_ = 0;
- }
-
- if (buffer_) {
- ThreadLocalMappedFileInfo* thread_local_info =
- g_segv_handler.Pointer()->thread_local_infos().Get();
- if (!thread_local_info) {
- thread_local_info = new ThreadLocalMappedFileInfo();
- g_segv_handler.Pointer()->thread_local_infos().Set(thread_local_info);
- }
- DCHECK(size);
- thread_local_info->RegisterMappedFile(this, size);
+ 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;
@@ -265,39 +46,28 @@ bool MappedFile::Store(const FileBlock* block) {
void MappedFile::Flush() {
DCHECK(buffer_);
- MappedFileInfo* info = g_segv_handler.Pointer()->thread_local_infos().Get()->
- InfoForMappedFile(this);
- DCHECK(info);
- if (info->num_dirty_pages > info->dirty_pages.capacity()) {
- Write(buffer_, view_size_, 0);
- } else {
- const char* buffer_ptr = static_cast<const char*>(buffer_);
- for (size_t i = 0; i < info->num_dirty_pages; ++i) {
- const char* ptr = info->dirty_pages.array()[i];
- size_t size_to_write = kPageSize;
- // The view_size is not a full number of page. Only write the fraction of
- // the page that is in the view.
- if (ptr - buffer_ptr + kPageSize > view_size_)
- size_to_write = view_size_ - (ptr - buffer_ptr);
- Write(ptr, size_to_write, ptr - buffer_ptr);
+ DCHECK(snapshot_);
+ const char* buffer_ptr = static_cast<const char*>(buffer_);
+ char* snapshot_ptr = static_cast<char*>(snapshot_);
+ const size_t block_size = 4096;
+ for (size_t offset = 0; offset < view_size_; offset += block_size) {
+ size_t size = std::min(view_size_ - offset, block_size);
+ if (memcmp(snapshot_ptr + offset, buffer_ptr + offset, size)) {
+ memcpy(snapshot_ptr + offset, buffer_ptr + offset, size);
+ Write(snapshot_ptr + offset, size, offset);
}
}
- info->num_dirty_pages = 0;
- mprotect(buffer_, view_size_, PROT_READ);
}
MappedFile::~MappedFile() {
if (!init_)
return;
- if (buffer_) {
+ if (buffer_ && snapshot_) {
Flush();
- ThreadLocalMappedFileInfo* thread_local_info =
- g_segv_handler.Pointer()->thread_local_infos().Get();
- DCHECK(thread_local_info);
- thread_local_info->UnregisterMappedFile(this);
- munmap(buffer_, 0);
}
+ free(buffer_);
+ free(snapshot_);
}
} // namespace disk_cache
« no previous file with comments | « net/disk_cache/mapped_file.h ('k') | net/disk_cache/mapped_file_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698