summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-15 19:50:05 +0000
committerrvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-15 19:50:05 +0000
commit39f31bdd23cfcdad842fd63b4f1211d06cd25670 (patch)
tree628cffe28ef83a55abafcb141198dd02c44c5c5d
parentb5913fd53a6246ea5ac1e00552e2920ed9d26a3c (diff)
downloadchromium_src-39f31bdd23cfcdad842fd63b4f1211d06cd25670.zip
chromium_src-39f31bdd23cfcdad842fd63b4f1211d06cd25670.tar.gz
chromium_src-39f31bdd23cfcdad842fd63b4f1211d06cd25670.tar.bz2
Merge 243495 "Disk Cache: Use the old WorkerPool for Async IO on..."
> Disk Cache: Use the old WorkerPool for Async IO on iOS. > > This basically reverts r222408 for iOS > > BUG=330074 > TEST=net_unittests > > Review URL: https://codereview.chromium.org/103533012 TBR=rvargas@chromium.org Review URL: https://codereview.chromium.org/137483004 git-svn-id: svn://svn.chromium.org/chrome/branches/1750/src@244964 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--net/disk_cache/backend_impl.cc2
-rw-r--r--net/disk_cache/backend_unittest.cc9
-rw-r--r--net/disk_cache/file.h3
-rw-r--r--net/disk_cache/file_ios.cc312
-rw-r--r--net/disk_cache/file_posix.cc5
-rw-r--r--net/disk_cache/file_win.cc4
-rw-r--r--net/net.gyp1
7 files changed, 335 insertions, 1 deletions
diff --git a/net/disk_cache/backend_impl.cc b/net/disk_cache/backend_impl.cc
index a3250ff..9e21317 100644
--- a/net/disk_cache/backend_impl.cc
+++ b/net/disk_cache/backend_impl.cc
@@ -305,6 +305,8 @@ void BackendImpl::CleanupCache() {
// This is a net_unittest, verify that we are not 'leaking' entries.
File::WaitForPendingIO(&num_pending_io_);
DCHECK(!num_refs_);
+ } else {
+ File::DropPendingIO();
}
}
block_files_.CloseFiles();
diff --git a/net/disk_cache/backend_unittest.cc b/net/disk_cache/backend_unittest.cc
index b25001f..f3c02fd 100644
--- a/net/disk_cache/backend_unittest.cc
+++ b/net/disk_cache/backend_unittest.cc
@@ -518,9 +518,13 @@ void DiskCacheBackendTest::BackendShutdownWithPendingFileIO(bool fast) {
base::MessageLoop::current()->RunUntilIdle();
+#if !defined(OS_IOS)
// Wait for the actual operation to complete, or we'll keep a file handle that
- // may cause issues later.
+ // may cause issues later. Note that on iOS systems even though this test
+ // uses a single thread, the actual IO is posted to a worker thread and the
+ // cache destructor breaks the link to reach cb when the operation completes.
rv = cb.GetResult(rv);
+#endif
}
TEST_F(DiskCacheBackendTest, ShutdownWithPendingFileIO) {
@@ -543,6 +547,8 @@ TEST_F(DiskCacheBackendTest, ShutdownWithPendingFileIO_Fast) {
}
#endif
+// See crbug.com/330074
+#if !defined(OS_IOS)
// Tests that one cache instance is not affected by another one going away.
TEST_F(DiskCacheBackendTest, MultipleInstancesWithPendingFileIO) {
base::ScopedTempDir store;
@@ -576,6 +582,7 @@ TEST_F(DiskCacheBackendTest, MultipleInstancesWithPendingFileIO) {
// may cause issues later.
rv = cb.GetResult(rv);
}
+#endif
// Tests that we deal with background-thread pending operations.
void DiskCacheBackendTest::BackendShutdownWithPendingIO(bool fast) {
diff --git a/net/disk_cache/file.h b/net/disk_cache/file.h
index eb9a9ec..190f7cb 100644
--- a/net/disk_cache/file.h
+++ b/net/disk_cache/file.h
@@ -70,6 +70,9 @@ class NET_EXPORT_PRIVATE File : public base::RefCounted<File> {
// Blocks until |num_pending_io| IO operations complete.
static void WaitForPendingIO(int* num_pending_io);
+ // Drops current pending operations without waiting for them to complete.
+ static void DropPendingIO();
+
protected:
virtual ~File();
diff --git a/net/disk_cache/file_ios.cc b/net/disk_cache/file_ios.cc
new file mode 100644
index 0000000..9cad155
--- /dev/null
+++ b/net/disk_cache/file_ios.cc
@@ -0,0 +1,312 @@
+// Copyright 2014 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/file.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/threading/worker_pool.h"
+#include "net/base/net_errors.h"
+#include "net/disk_cache/disk_cache.h"
+#include "net/disk_cache/in_flight_io.h"
+
+namespace {
+
+// This class represents a single asynchronous IO operation while it is being
+// bounced between threads.
+class FileBackgroundIO : public disk_cache::BackgroundIO {
+ public:
+ // Other than the actual parameters for the IO operation (including the
+ // |callback| that must be notified at the end), we need the controller that
+ // is keeping track of all operations. When done, we notify the controller
+ // (we do NOT invoke the callback), in the worker thead that completed the
+ // operation.
+ FileBackgroundIO(disk_cache::File* file, const void* buf, size_t buf_len,
+ size_t offset, disk_cache::FileIOCallback* callback,
+ disk_cache::InFlightIO* controller)
+ : disk_cache::BackgroundIO(controller), callback_(callback), file_(file),
+ buf_(buf), buf_len_(buf_len), offset_(offset) {
+ }
+
+ disk_cache::FileIOCallback* callback() {
+ return callback_;
+ }
+
+ disk_cache::File* file() {
+ return file_;
+ }
+
+ // Read and Write are the operations that can be performed asynchronously.
+ // The actual parameters for the operation are setup in the constructor of
+ // the object. Both methods should be called from a worker thread, by posting
+ // a task to the WorkerPool (they are RunnableMethods). When finished,
+ // controller->OnIOComplete() is called.
+ void Read();
+ void Write();
+
+ private:
+ virtual ~FileBackgroundIO() {}
+
+ disk_cache::FileIOCallback* callback_;
+
+ disk_cache::File* file_;
+ const void* buf_;
+ size_t buf_len_;
+ size_t offset_;
+
+ DISALLOW_COPY_AND_ASSIGN(FileBackgroundIO);
+};
+
+
+// The specialized controller that keeps track of current operations.
+class FileInFlightIO : public disk_cache::InFlightIO {
+ public:
+ FileInFlightIO() {}
+ virtual ~FileInFlightIO() {}
+
+ // These methods start an asynchronous operation. The arguments have the same
+ // semantics of the File asynchronous operations, with the exception that the
+ // operation never finishes synchronously.
+ void PostRead(disk_cache::File* file, void* buf, size_t buf_len,
+ size_t offset, disk_cache::FileIOCallback* callback);
+ void PostWrite(disk_cache::File* file, const void* buf, size_t buf_len,
+ size_t offset, disk_cache::FileIOCallback* callback);
+
+ protected:
+ // Invokes the users' completion callback at the end of the IO operation.
+ // |cancel| is true if the actual task posted to the thread is still
+ // queued (because we are inside WaitForPendingIO), and false if said task is
+ // the one performing the call.
+ virtual void OnOperationComplete(disk_cache::BackgroundIO* operation,
+ bool cancel) OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FileInFlightIO);
+};
+
+// ---------------------------------------------------------------------------
+
+// Runs on a worker thread.
+void FileBackgroundIO::Read() {
+ if (file_->Read(const_cast<void*>(buf_), buf_len_, offset_)) {
+ result_ = static_cast<int>(buf_len_);
+ } else {
+ result_ = net::ERR_CACHE_READ_FAILURE;
+ }
+ NotifyController();
+}
+
+// Runs on a worker thread.
+void FileBackgroundIO::Write() {
+ bool rv = file_->Write(buf_, buf_len_, offset_);
+
+ result_ = rv ? static_cast<int>(buf_len_) : net::ERR_CACHE_WRITE_FAILURE;
+ NotifyController();
+}
+
+// ---------------------------------------------------------------------------
+
+void FileInFlightIO::PostRead(disk_cache::File *file, void* buf, size_t buf_len,
+ size_t offset, disk_cache::FileIOCallback *callback) {
+ scoped_refptr<FileBackgroundIO> operation(
+ new FileBackgroundIO(file, buf, buf_len, offset, callback, this));
+ file->AddRef(); // Balanced on OnOperationComplete()
+
+ base::WorkerPool::PostTask(FROM_HERE,
+ base::Bind(&FileBackgroundIO::Read, operation.get()), true);
+ OnOperationPosted(operation.get());
+}
+
+void FileInFlightIO::PostWrite(disk_cache::File* file, const void* buf,
+ size_t buf_len, size_t offset,
+ disk_cache::FileIOCallback* callback) {
+ scoped_refptr<FileBackgroundIO> operation(
+ new FileBackgroundIO(file, buf, buf_len, offset, callback, this));
+ file->AddRef(); // Balanced on OnOperationComplete()
+
+ base::WorkerPool::PostTask(FROM_HERE,
+ base::Bind(&FileBackgroundIO::Write, operation.get()), true);
+ OnOperationPosted(operation.get());
+}
+
+// Runs on the IO thread.
+void FileInFlightIO::OnOperationComplete(disk_cache::BackgroundIO* operation,
+ bool cancel) {
+ FileBackgroundIO* op = static_cast<FileBackgroundIO*>(operation);
+
+ disk_cache::FileIOCallback* callback = op->callback();
+ int bytes = operation->result();
+
+ // Release the references acquired in PostRead / PostWrite.
+ op->file()->Release();
+ callback->OnFileIOComplete(bytes);
+}
+
+// A static object tha will broker all async operations.
+FileInFlightIO* s_file_operations = NULL;
+
+// Returns the current FileInFlightIO.
+FileInFlightIO* GetFileInFlightIO() {
+ if (!s_file_operations) {
+ s_file_operations = new FileInFlightIO;
+ }
+ return s_file_operations;
+}
+
+// Deletes the current FileInFlightIO.
+void DeleteFileInFlightIO() {
+ DCHECK(s_file_operations);
+ delete s_file_operations;
+ s_file_operations = NULL;
+}
+
+} // namespace
+
+namespace disk_cache {
+
+File::File(base::PlatformFile file)
+ : init_(true),
+ mixed_(true),
+ platform_file_(file),
+ sync_platform_file_(base::kInvalidPlatformFileValue) {
+}
+
+bool File::Init(const base::FilePath& name) {
+ if (init_)
+ return false;
+
+ int flags = base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_READ |
+ base::PLATFORM_FILE_WRITE;
+ platform_file_ = base::CreatePlatformFile(name, flags, NULL, NULL);
+ if (platform_file_ < 0) {
+ platform_file_ = 0;
+ return false;
+ }
+
+ init_ = true;
+ return true;
+}
+
+base::PlatformFile File::platform_file() const {
+ return platform_file_;
+}
+
+bool File::IsValid() const {
+ if (!init_)
+ return false;
+ return (base::kInvalidPlatformFileValue != platform_file_);
+}
+
+bool File::Read(void* buffer, size_t buffer_len, size_t offset) {
+ DCHECK(init_);
+ if (buffer_len > static_cast<size_t>(kint32max) ||
+ offset > static_cast<size_t>(kint32max)) {
+ return false;
+ }
+
+ int ret = base::ReadPlatformFile(platform_file_, offset,
+ static_cast<char*>(buffer), buffer_len);
+ return (static_cast<size_t>(ret) == buffer_len);
+}
+
+bool File::Write(const void* buffer, size_t buffer_len, size_t offset) {
+ DCHECK(init_);
+ if (buffer_len > static_cast<size_t>(kint32max) ||
+ offset > static_cast<size_t>(kint32max)) {
+ return false;
+ }
+
+ int ret = base::WritePlatformFile(platform_file_, offset,
+ static_cast<const char*>(buffer),
+ buffer_len);
+ return (static_cast<size_t>(ret) == buffer_len);
+}
+
+// We have to increase the ref counter of the file before performing the IO to
+// prevent the completion to happen with an invalid handle (if the file is
+// closed while the IO is in flight).
+bool File::Read(void* buffer, size_t buffer_len, size_t offset,
+ FileIOCallback* callback, bool* completed) {
+ DCHECK(init_);
+ if (!callback) {
+ if (completed)
+ *completed = true;
+ return Read(buffer, buffer_len, offset);
+ }
+
+ if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
+ return false;
+
+ GetFileInFlightIO()->PostRead(this, buffer, buffer_len, offset, callback);
+
+ *completed = false;
+ return true;
+}
+
+bool File::Write(const void* buffer, size_t buffer_len, size_t offset,
+ FileIOCallback* callback, bool* completed) {
+ DCHECK(init_);
+ if (!callback) {
+ if (completed)
+ *completed = true;
+ return Write(buffer, buffer_len, offset);
+ }
+
+ return AsyncWrite(buffer, buffer_len, offset, callback, completed);
+}
+
+bool File::SetLength(size_t length) {
+ DCHECK(init_);
+ if (length > kuint32max)
+ return false;
+
+ return base::TruncatePlatformFile(platform_file_, length);
+}
+
+size_t File::GetLength() {
+ DCHECK(init_);
+ int64 len = base::SeekPlatformFile(platform_file_,
+ base::PLATFORM_FILE_FROM_END, 0);
+
+ if (len > static_cast<int64>(kuint32max))
+ return kuint32max;
+
+ return static_cast<size_t>(len);
+}
+
+// Static.
+void File::WaitForPendingIO(int* num_pending_io) {
+ // We may be running unit tests so we should allow be able to reset the
+ // message loop.
+ GetFileInFlightIO()->WaitForPendingIO();
+ DeleteFileInFlightIO();
+}
+
+// Static.
+void File::DropPendingIO() {
+ GetFileInFlightIO()->DropPendingIO();
+ DeleteFileInFlightIO();
+}
+
+File::~File() {
+ if (IsValid())
+ base::ClosePlatformFile(platform_file_);
+}
+
+bool File::AsyncWrite(const void* buffer, size_t buffer_len, size_t offset,
+ FileIOCallback* callback, bool* completed) {
+ DCHECK(init_);
+ if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
+ return false;
+
+ GetFileInFlightIO()->PostWrite(this, buffer, buffer_len, offset, callback);
+
+ if (completed)
+ *completed = false;
+ return true;
+}
+
+} // namespace disk_cache
diff --git a/net/disk_cache/file_posix.cc b/net/disk_cache/file_posix.cc
index a4d1964..e1ff6fc 100644
--- a/net/disk_cache/file_posix.cc
+++ b/net/disk_cache/file_posix.cc
@@ -167,6 +167,11 @@ void File::WaitForPendingIO(int* num_pending_io) {
base::RunLoop().RunUntilIdle();
}
+// Static.
+void File::DropPendingIO() {
+}
+
+
File::~File() {
if (IsValid())
base::ClosePlatformFile(platform_file_);
diff --git a/net/disk_cache/file_win.cc b/net/disk_cache/file_win.cc
index dbb34f3..1492c42 100644
--- a/net/disk_cache/file_win.cc
+++ b/net/disk_cache/file_win.cc
@@ -267,4 +267,8 @@ void File::WaitForPendingIO(int* num_pending_io) {
}
}
+// Static.
+void File::DropPendingIO() {
+}
+
} // namespace disk_cache
diff --git a/net/net.gyp b/net/net.gyp
index 29aad0f..8296763 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -376,6 +376,7 @@
'disk_cache/file.cc',
'disk_cache/file.h',
'disk_cache/file_block.h',
+ 'disk_cache/file_ios.cc',
'disk_cache/file_lock.cc',
'disk_cache/file_lock.h',
'disk_cache/file_posix.cc',