summaryrefslogtreecommitdiffstats
path: root/webkit
diff options
context:
space:
mode:
authorkinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-26 04:40:59 +0000
committerkinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-26 04:40:59 +0000
commitc4388a32fd9fc6bc8975c61685a7a21bba2e1fd7 (patch)
tree93125ce67b43a5fe1338cb1bd55f06668fdbc9e0 /webkit
parent3da61e534205ebd44bbaa6d7416b6253ef627fcf (diff)
downloadchromium_src-c4388a32fd9fc6bc8975c61685a7a21bba2e1fd7.zip
chromium_src-c4388a32fd9fc6bc8975c61685a7a21bba2e1fd7.tar.gz
chromium_src-c4388a32fd9fc6bc8975c61685a7a21bba2e1fd7.tar.bz2
Add ScopedFile class which supports scope-out deletion and/or callbacks
and re-implement ShareableFileReference using ScopedFile. A follow-up change to change existing code to use the new ScopedFile is uploaded here: https://codereview.chromium.org/14075016/ BUG=162598 Review URL: https://codereview.chromium.org/14261015 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@196611 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit')
-rw-r--r--webkit/blob/scoped_file.cc83
-rw-r--r--webkit/blob/scoped_file.h94
-rw-r--r--webkit/blob/shareable_file_reference.cc68
-rw-r--r--webkit/blob/shareable_file_reference.h58
-rw-r--r--webkit/blob/webkit_blob.gypi2
5 files changed, 238 insertions, 67 deletions
diff --git a/webkit/blob/scoped_file.cc b/webkit/blob/scoped_file.cc
new file mode 100644
index 0000000..72e0982
--- /dev/null
+++ b/webkit/blob/scoped_file.cc
@@ -0,0 +1,83 @@
+// 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 "webkit/blob/scoped_file.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/files/file_util_proxy.h"
+#include "base/location.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/task_runner.h"
+
+namespace webkit_blob {
+
+ScopedFile::ScopedFile()
+ : scope_out_policy_(DONT_DELETE_ON_SCOPE_OUT) {
+}
+
+ScopedFile::ScopedFile(
+ const base::FilePath& path, ScopeOutPolicy policy,
+ base::TaskRunner* file_task_runner)
+ : path_(path),
+ scope_out_policy_(policy),
+ file_task_runner_(file_task_runner) {
+ DCHECK(path.empty() || policy != DELETE_ON_SCOPE_OUT || file_task_runner)
+ << "path:" << path.value()
+ << " policy:" << policy
+ << " runner:" << file_task_runner;
+}
+
+ScopedFile::ScopedFile(RValue other) {
+ MoveFrom(*other.object);
+}
+
+ScopedFile::~ScopedFile() {
+ Reset();
+}
+
+void ScopedFile::AddScopeOutCallback(
+ const ScopeOutCallback& callback,
+ base::TaskRunner* callback_runner) {
+ if (!callback_runner)
+ callback_runner = base::MessageLoopProxy::current();
+ scope_out_callbacks_.push_back(std::make_pair(callback, callback_runner));
+}
+
+base::FilePath ScopedFile::Release() {
+ base::FilePath path = path_;
+ path_.clear();
+ scope_out_callbacks_.clear();
+ scope_out_policy_ = DONT_DELETE_ON_SCOPE_OUT;
+ return path;
+}
+
+void ScopedFile::Reset() {
+ if (path_.empty())
+ return;
+
+ for (ScopeOutCallbackList::iterator iter = scope_out_callbacks_.begin();
+ iter != scope_out_callbacks_.end(); ++iter) {
+ iter->second->PostTask(FROM_HERE, base::Bind(iter->first, path_));
+ }
+
+ if (scope_out_policy_ == DELETE_ON_SCOPE_OUT) {
+ base::FileUtilProxy::Delete(file_task_runner_, path_, false /* recursive */,
+ base::FileUtilProxy::StatusCallback());
+ }
+
+ // Clear all fields.
+ Release();
+}
+
+void ScopedFile::MoveFrom(ScopedFile& other) {
+ Reset();
+
+ scope_out_policy_ = other.scope_out_policy_;
+ scope_out_callbacks_.swap(other.scope_out_callbacks_);
+ file_task_runner_ = other.file_task_runner_;
+ path_ = other.Release();
+}
+
+} // namespace webkit_blob
diff --git a/webkit/blob/scoped_file.h b/webkit/blob/scoped_file.h
new file mode 100644
index 0000000..3d68c40
--- /dev/null
+++ b/webkit/blob/scoped_file.h
@@ -0,0 +1,94 @@
+// 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.
+
+#ifndef WEBKIT_BLOB_SCOPED_FILE_H_
+#define WEBKIT_BLOB_SCOPED_FILE_H_
+
+#include <map>
+
+#include "base/callback_forward.h"
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/move.h"
+#include "webkit/storage/webkit_storage_export.h"
+
+namespace base {
+class TaskRunner;
+}
+
+namespace webkit_blob {
+
+// A scoped reference for a FilePath that can optionally schedule the file
+// to be deleted and/or to notify a consumer when it is going to be scoped out.
+// This class supports move semantics, i.e. consumers can call Pass() to
+// pass the ownership of ScopedFile.
+//
+// TODO(kinuko): Probably this can be moved under base or somewhere more
+// common place.
+class WEBKIT_STORAGE_EXPORT ScopedFile {
+ // To support destructive assignment from an l-value assignment.
+ // This provides Pass() method which creates an r-value for the current
+ // instance. (See base/move.h for details)
+ MOVE_ONLY_TYPE_FOR_CPP_03(ScopedFile, RValue)
+
+ public:
+ typedef base::Callback<void(const base::FilePath&)> ScopeOutCallback;
+ typedef std::pair<ScopeOutCallback, scoped_refptr<base::TaskRunner> >
+ ScopeOutCallbackPair;
+ typedef std::vector<ScopeOutCallbackPair> ScopeOutCallbackList;
+
+ enum ScopeOutPolicy {
+ DELETE_ON_SCOPE_OUT,
+ DONT_DELETE_ON_SCOPE_OUT,
+ };
+
+ ScopedFile();
+
+ // |file_task_runner| is used to schedule a file deletion if |policy|
+ // is DELETE_ON_SCOPE_OUT.
+ ScopedFile(const base::FilePath& path,
+ ScopeOutPolicy policy,
+ base::TaskRunner* file_task_runner);
+
+ // Move constructor and operator. The data of r-value will be transfered
+ // in a destructive way. (See base/move.h)
+ ScopedFile(RValue other);
+ ScopedFile& operator=(RValue rhs) {
+ MoveFrom(*rhs.object);
+ return *this;
+ }
+
+ ~ScopedFile();
+
+ // The |callback| is fired on |callback_runner| when the final reference
+ // of this instance is released.
+ // If release policy is DELETE_ON_SCOPE_OUT the
+ // callback task(s) is/are posted before the deletion is scheduled.
+ void AddScopeOutCallback(const ScopeOutCallback& callback,
+ base::TaskRunner* callback_runner);
+
+ // The full file path.
+ const base::FilePath& path() const { return path_; }
+
+ // Releases the file. After calling this, this instance will hold
+ // an empty file path and scoping out won't make any file deletion
+ // or callback dispatch. (If an owned pointer is attached to any of
+ // callbacks the pointer will be deleted.)
+ base::FilePath Release();
+
+ void Reset();
+
+ private:
+ // Performs destructive move from |other| to this.
+ void MoveFrom(ScopedFile& other);
+
+ base::FilePath path_;
+ ScopeOutPolicy scope_out_policy_;
+ scoped_refptr<base::TaskRunner> file_task_runner_;
+ ScopeOutCallbackList scope_out_callbacks_;
+};
+
+} // namespace webkit_blob
+
+#endif // WEBKIT_BLOB_SCOPED_FILE_H_
diff --git a/webkit/blob/shareable_file_reference.cc b/webkit/blob/shareable_file_reference.cc
index 07acac3..fd75917 100644
--- a/webkit/blob/shareable_file_reference.cc
+++ b/webkit/blob/shareable_file_reference.cc
@@ -6,22 +6,17 @@
#include <map>
-#include "base/file_util.h"
-#include "base/files/file_util_proxy.h"
#include "base/lazy_instance.h"
+#include "base/message_loop/message_loop_proxy.h"
#include "base/task_runner.h"
-#include "base/threading/thread_checker.h"
+#include "base/threading/non_thread_safe.h"
namespace webkit_blob {
namespace {
// A shareable file map with enforcement of thread checker.
-// This map may get deleted on a different thread in AtExitManager at the
-// very end on the main thread (at the point all other threads must be
-// terminated), so we use ThreadChecker rather than NonThreadSafe and do not
-// check thread in the dtor.
-class ShareableFileMap {
+class ShareableFileMap : public base::NonThreadSafe {
public:
typedef std::map<base::FilePath, ShareableFileReference*> FileMap;
typedef FileMap::iterator iterator;
@@ -30,6 +25,10 @@ class ShareableFileMap {
ShareableFileMap() {}
+ ~ShareableFileMap() {
+ DetachFromThread();
+ }
+
iterator Find(key_type key) {
DCHECK(CalledOnValidThread());
return file_map_.find(key);
@@ -50,13 +49,8 @@ class ShareableFileMap {
file_map_.erase(key);
}
- bool CalledOnValidThread() const {
- return thread_checker_.CalledOnValidThread();
- }
-
private:
FileMap file_map_;
- base::ThreadChecker thread_checker_;
DISALLOW_COPY_AND_ASSIGN(ShareableFileMap);
};
@@ -75,21 +69,33 @@ scoped_refptr<ShareableFileReference> ShareableFileReference::Get(
// static
scoped_refptr<ShareableFileReference> ShareableFileReference::GetOrCreate(
- const base::FilePath& path, FinalReleasePolicy policy,
+ const base::FilePath& path,
+ FinalReleasePolicy policy,
base::TaskRunner* file_task_runner) {
- DCHECK(file_task_runner);
- typedef std::pair<ShareableFileMap::iterator, bool> InsertResult;
+ return GetOrCreate(
+ ScopedFile(path, static_cast<ScopedFile::ScopeOutPolicy>(policy),
+ file_task_runner));
+}
+
+// static
+scoped_refptr<ShareableFileReference> ShareableFileReference::GetOrCreate(
+ ScopedFile scoped_file) {
+ if (scoped_file.path().empty())
+ return scoped_refptr<ShareableFileReference>();
+ typedef std::pair<ShareableFileMap::iterator, bool> InsertResult;
// Required for VS2010: http://connect.microsoft.com/VisualStudio/feedback/details/520043/error-converting-from-null-to-a-pointer-type-in-std-pair
webkit_blob::ShareableFileReference* null_reference = NULL;
InsertResult result = g_file_map.Get().Insert(
- ShareableFileMap::value_type(path, null_reference));
- if (result.second == false)
+ ShareableFileMap::value_type(scoped_file.path(), null_reference));
+ if (result.second == false) {
+ scoped_file.Release();
return scoped_refptr<ShareableFileReference>(result.first->second);
+ }
// Wasn't in the map, create a new reference and store the pointer.
scoped_refptr<ShareableFileReference> reference(
- new ShareableFileReference(path, policy, file_task_runner));
+ new ShareableFileReference(scoped_file.Pass()));
result.first->second = reference.get();
return reference;
}
@@ -97,29 +103,17 @@ scoped_refptr<ShareableFileReference> ShareableFileReference::GetOrCreate(
void ShareableFileReference::AddFinalReleaseCallback(
const FinalReleaseCallback& callback) {
DCHECK(g_file_map.Get().CalledOnValidThread());
- final_release_callbacks_.push_back(callback);
+ scoped_file_.AddScopeOutCallback(callback, NULL);
}
-ShareableFileReference::ShareableFileReference(
- const base::FilePath& path, FinalReleasePolicy policy,
- base::TaskRunner* file_task_runner)
- : path_(path),
- final_release_policy_(policy),
- file_task_runner_(file_task_runner) {
- DCHECK(g_file_map.Get().Find(path_)->second == NULL);
+ShareableFileReference::ShareableFileReference(ScopedFile scoped_file)
+ : scoped_file_(scoped_file.Pass()) {
+ DCHECK(g_file_map.Get().Find(path())->second == NULL);
}
ShareableFileReference::~ShareableFileReference() {
- DCHECK(g_file_map.Get().Find(path_)->second == this);
- g_file_map.Get().Erase(path_);
-
- for (size_t i = 0; i < final_release_callbacks_.size(); i++)
- final_release_callbacks_[i].Run(path_);
-
- if (final_release_policy_ == DELETE_ON_FINAL_RELEASE) {
- base::FileUtilProxy::Delete(file_task_runner_, path_, false /* recursive */,
- base::FileUtilProxy::StatusCallback());
- }
+ DCHECK(g_file_map.Get().Find(path())->second == this);
+ g_file_map.Get().Erase(path());
}
} // namespace webkit_blob
diff --git a/webkit/blob/shareable_file_reference.h b/webkit/blob/shareable_file_reference.h
index 1eaff08..eb600ec 100644
--- a/webkit/blob/shareable_file_reference.h
+++ b/webkit/blob/shareable_file_reference.h
@@ -7,29 +7,22 @@
#include <vector>
-#include "base/callback.h"
-#include "base/files/file_path.h"
-#include "base/memory/ref_counted.h"
-#include "webkit/storage/webkit_storage_export.h"
-
-namespace base {
-class TaskRunner;
-}
+#include "webkit/blob/scoped_file.h"
namespace webkit_blob {
-// A refcounted wrapper around a FilePath that can optionally schedule
-// the file to be deleted upon final release and/or to notify a consumer
-// when final release occurs. This class is single-threaded and should
-// only be invoked on the IO thread in chrome.
+// ShareableFileReference allows consumers to share FileReference for the
+// same path if it already exists in its internal map.
+// This class is non-thread-safe and all methods must be called on a single
+// thread.
class WEBKIT_STORAGE_EXPORT ShareableFileReference
: public base::RefCounted<ShareableFileReference> {
public:
- typedef base::Callback<void(const base::FilePath&)> FinalReleaseCallback;
+ typedef ScopedFile::ScopeOutCallback FinalReleaseCallback;
enum FinalReleasePolicy {
- DELETE_ON_FINAL_RELEASE,
- DONT_DELETE_ON_FINAL_RELEASE,
+ DELETE_ON_FINAL_RELEASE = ScopedFile::DELETE_ON_SCOPE_OUT,
+ DONT_DELETE_ON_FINAL_RELEASE = ScopedFile::DONT_DELETE_ON_SCOPE_OUT,
};
// Returns a ShareableFileReference for the given path, if no reference
@@ -38,35 +31,40 @@ class WEBKIT_STORAGE_EXPORT ShareableFileReference
// Returns a ShareableFileReference for the given path, creating a new
// reference if none yet exists. If there's a pre-existing reference for
- // the path, the deletable parameter of this method is ignored.
+ // the path, the policy parameter of this method is ignored.
static scoped_refptr<ShareableFileReference> GetOrCreate(
const base::FilePath& path,
FinalReleasePolicy policy,
base::TaskRunner* file_task_runner);
- // The full file path.
- const base::FilePath& path() const { return path_; }
+ // Returns a ShareableFileReference for the given path of the |scoped_file|,
+ // creating a new reference if none yet exists. The ownership of |scoped_file|
+ // is passed to this reference.
+ // If there's a pre-existing reference for the path, the scope out policy
+ // and scope-out-callbacks of the given |scoped_file| is ignored.
+ // If the given scoped_file has an empty path (e.g. maybe already
+ // released) this returns NULL reference.
+ //
+ // TODO(kinuko): Make sure if this behavior is ok, we could alternatively
+ // merge callbacks to the existing one.
+ static scoped_refptr<ShareableFileReference> GetOrCreate(
+ ScopedFile scoped_file);
- // Whether it's to be deleted on final release.
- FinalReleasePolicy final_release_policy() const {
- return final_release_policy_;
- }
+ // The full file path.
+ const base::FilePath& path() const { return scoped_file_.path(); }
+ // The |callback| is fired when the final reference of this instance
+ // is released. If release policy is DELETE_ON_FINAL_RELEASE the
+ // callback task(s) is/are posted before the deletion is scheduled.
void AddFinalReleaseCallback(const FinalReleaseCallback& callback);
private:
friend class base::RefCounted<ShareableFileReference>;
- ShareableFileReference(
- const base::FilePath& path,
- FinalReleasePolicy policy,
- base::TaskRunner* file_task_runner);
+ ShareableFileReference(ScopedFile scoped_file);
~ShareableFileReference();
- const base::FilePath path_;
- const FinalReleasePolicy final_release_policy_;
- const scoped_refptr<base::TaskRunner> file_task_runner_;
- std::vector<FinalReleaseCallback> final_release_callbacks_;
+ ScopedFile scoped_file_;
DISALLOW_COPY_AND_ASSIGN(ShareableFileReference);
};
diff --git a/webkit/blob/webkit_blob.gypi b/webkit/blob/webkit_blob.gypi
index e15e4b0..afb45d7 100644
--- a/webkit/blob/webkit_blob.gypi
+++ b/webkit/blob/webkit_blob.gypi
@@ -15,6 +15,8 @@
'../blob/blob_url_request_job_factory.h',
'../blob/local_file_stream_reader.cc',
'../blob/local_file_stream_reader.h',
+ '../blob/scoped_file.cc',
+ '../blob/scoped_file.h',
'../blob/shareable_file_reference.cc',
'../blob/shareable_file_reference.h',
'../blob/view_blob_internals_job.cc',