diff options
author | kinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-07 07:02:20 +0000 |
---|---|---|
committer | kinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-07 07:02:20 +0000 |
commit | caf6670cff5c72fd2c5f48db8ddd3f4670baeca4 (patch) | |
tree | 5c5bc5bee15e7f0cbac2538474ea8b5475f86024 /webkit | |
parent | 69df265b0c90a5d25888cb0452e3a310060525a8 (diff) | |
download | chromium_src-caf6670cff5c72fd2c5f48db8ddd3f4670baeca4.zip chromium_src-caf6670cff5c72fd2c5f48db8ddd3f4670baeca4.tar.gz chromium_src-caf6670cff5c72fd2c5f48db8ddd3f4670baeca4.tar.bz2 |
Add observer classes for fileapi to observe filesystem changes
- Add common observer helper class (task_runner_bound_observer_list.h)
- Add common file observers (file_observer.h)
- Replace current quota notification impl with the observer
BUG=146290
TEST=existing tests
TEST=more tests to be added
Review URL: https://chromiumcodereview.appspot.com/10909052
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@155345 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit')
23 files changed, 552 insertions, 443 deletions
diff --git a/webkit/fileapi/file_observers.h b/webkit/fileapi/file_observers.h new file mode 100644 index 0000000..2022b81 --- /dev/null +++ b/webkit/fileapi/file_observers.h @@ -0,0 +1,51 @@ +// 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. + +#ifndef WEBKIT_FILEAPI_FILE_OBSERVERS_H_ +#define WEBKIT_FILEAPI_FILE_OBSERVERS_H_ + +#include "webkit/fileapi/fileapi_export.h" + +// TODO(kinuko): Split this file into per-observer multiple files. + +namespace fileapi { + +class FileSystemURL; + +// An abstract interface to observe update operations. +// +// OnStartUpdate and OnEndUpdate are called once for each target url +// before and after following operations regardless of whether the operation +// is made recursively or not (i.e. StartUpdate() will be called only once +// for destination url regardless of whether it is recursive copy or not): +// CreateFile(), CreateDirectory(), +// Copy() (destination only), +// Move() (both for source and destination), +// Remove(), Write(), Truncate(), TouchFile() +// +// OnUpdate() is called each time the |url| is updated but works only for +// sandboxed files (where usage is tracked). +class FILEAPI_EXPORT FileUpdateObserver { + public: + virtual ~FileUpdateObserver() {} + + virtual void OnStartUpdate(const FileSystemURL& url) = 0; + virtual void OnUpdate(const FileSystemURL& url, int64 delta) = 0; + virtual void OnEndUpdate(const FileSystemURL& url) = 0; +}; + +// An abstract interface to observe file access. +// OnAccess is called whenever an operation reads file contents or metadata. +// (It is called only once per operation regardless of whether the operation +// is recursive or not) +class FILEAPI_EXPORT FileAccessObserver { + public: + virtual ~FileAccessObserver() {} + + virtual void OnAccess(const FileSystemURL& url) = 0; +}; + +} // namespace fileapi + +#endif // WEBKIT_FILEAPI_FILE_OBSERVERS_H_ diff --git a/webkit/fileapi/file_system_context.cc b/webkit/fileapi/file_system_context.cc index b28d893..4a9fe7a 100644 --- a/webkit/fileapi/file_system_context.cc +++ b/webkit/fileapi/file_system_context.cc @@ -18,6 +18,7 @@ #include "webkit/fileapi/file_system_util.h" #include "webkit/fileapi/isolated_mount_point_provider.h" #include "webkit/fileapi/sandbox_mount_point_provider.h" +#include "webkit/fileapi/test_mount_point_provider.h" #include "webkit/quota/quota_manager.h" #include "webkit/quota/special_storage_policy.h" @@ -45,7 +46,7 @@ void DidOpenFileSystem( callback.Run(error, filesystem_name, filesystem_root); } -} // anonymous namespace +} // namespace FileSystemContext::FileSystemContext( scoped_ptr<FileSystemTaskRunners> task_runners, @@ -57,6 +58,7 @@ FileSystemContext::FileSystemContext( quota_manager_proxy_(quota_manager_proxy), sandbox_provider_( new SandboxMountPointProvider( + quota_manager_proxy, task_runners_->file_task_runner(), profile_path, options)), @@ -136,6 +138,23 @@ FileSystemMountPointProvider* FileSystemContext::GetMountPointProvider( } } +const UpdateObserverList* FileSystemContext::GetUpdateObservers( + FileSystemType type) const { + // Currently update observer is only available in SandboxMountPointProvider + // and TestMountPointProvider. + // TODO(kinuko): Probably GetUpdateObservers() virtual method should be + // added to FileSystemMountPointProvider interface and be called like + // other GetFoo() methods do. + if (SandboxMountPointProvider::CanHandleType(type)) + return sandbox_provider()->GetUpdateObservers(type); + if (type != kFileSystemTypeTest) + return NULL; + FileSystemMountPointProvider* mount_point_provider = + GetMountPointProvider(type); + return static_cast<TestMountPointProvider*>( + mount_point_provider)->GetUpdateObservers(type); +} + SandboxMountPointProvider* FileSystemContext::sandbox_provider() const { return sandbox_provider_.get(); diff --git a/webkit/fileapi/file_system_context.h b/webkit/fileapi/file_system_context.h index e73caf1..dfb5664 100644 --- a/webkit/fileapi/file_system_context.h +++ b/webkit/fileapi/file_system_context.h @@ -9,12 +9,13 @@ #include <string> #include "base/callback.h" -#include "base/sequenced_task_runner_helpers.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/platform_file.h" -#include "webkit/fileapi/fileapi_export.h" +#include "base/sequenced_task_runner_helpers.h" #include "webkit/fileapi/file_system_types.h" +#include "webkit/fileapi/fileapi_export.h" +#include "webkit/fileapi/task_runner_bound_observer_list.h" #include "webkit/quota/special_storage_policy.h" class FilePath; @@ -84,6 +85,9 @@ class FILEAPI_EXPORT FileSystemContext FileSystemMountPointProvider* GetMountPointProvider( FileSystemType type) const; + // Returns update observers for the given filesystem type. + const UpdateObserverList* GetUpdateObservers(FileSystemType type) const; + // Returns a FileSystemMountPointProvider instance for sandboxed filesystem // types (e.g. TEMPORARY or PERSISTENT). This is equivalent to calling // GetMountPointProvider(kFileSystemType{Temporary, Persistent}). diff --git a/webkit/fileapi/file_system_operation_context.h b/webkit/fileapi/file_system_operation_context.h index ae044a0..f1dbda2 100644 --- a/webkit/fileapi/file_system_operation_context.h +++ b/webkit/fileapi/file_system_operation_context.h @@ -9,11 +9,12 @@ #include "base/memory/ref_counted.h" #include "base/sequenced_task_runner.h" #include "googleurl/src/gurl.h" -#include "webkit/fileapi/fileapi_export.h" #include "webkit/fileapi/file_system_context.h" #include "webkit/fileapi/file_system_file_util.h" #include "webkit/fileapi/file_system_types.h" +#include "webkit/fileapi/fileapi_export.h" #include "webkit/fileapi/media/media_file_system_config.h" +#include "webkit/fileapi/task_runner_bound_observer_list.h" #if defined(SUPPORT_MEDIA_FILESYSTEM) #include "webkit/fileapi/media/media_device_interface_impl.h" @@ -64,6 +65,16 @@ class FILEAPI_EXPORT_PRIVATE FileSystemOperationContext { return media_path_filter_; } + void set_access_observers(const AccessObserverList& list) { + access_observers_ = list; + } + AccessObserverList* access_observers() { return &access_observers_; } + + void set_update_observers(const UpdateObserverList& list) { + update_observers_ = list; + } + UpdateObserverList* update_observers() { return &update_observers_; } + private: scoped_refptr<FileSystemContext> file_system_context_; scoped_refptr<base::SequencedTaskRunner> task_runner_; @@ -71,6 +82,9 @@ class FILEAPI_EXPORT_PRIVATE FileSystemOperationContext { int64 allowed_bytes_growth_; MediaPathFilter* media_path_filter_; + AccessObserverList access_observers_; + UpdateObserverList update_observers_; + #if defined(SUPPORT_MEDIA_FILESYSTEM) // Store the current media device. scoped_refptr<MediaDeviceInterfaceImpl> media_device_; diff --git a/webkit/fileapi/file_system_quota_client_unittest.cc b/webkit/fileapi/file_system_quota_client_unittest.cc index cbda9de..1dd308f 100644 --- a/webkit/fileapi/file_system_quota_client_unittest.cc +++ b/webkit/fileapi/file_system_quota_client_unittest.cc @@ -117,10 +117,13 @@ class FileSystemQuotaClientTest : public testing::Test { weak_factory_.GetWeakPtr())); } - FileSystemOperationContext* CreateFileSystemOperationContext() { + FileSystemOperationContext* CreateFileSystemOperationContext( + FileSystemType type) { FileSystemOperationContext* context = new FileSystemOperationContext(file_system_context_); context->set_allowed_bytes_growth(100000000); + context->set_update_observers( + *file_system_context_->GetUpdateObservers(type)); return context; } @@ -132,7 +135,7 @@ class FileSystemQuotaClientTest : public testing::Test { FileSystemURL url(GURL(origin_url), type, file_path); scoped_ptr<FileSystemOperationContext> context( - CreateFileSystemOperationContext()); + CreateFileSystemOperationContext(type)); base::PlatformFileError result = file_util->CreateDirectory(context.get(), url, false, false); @@ -154,7 +157,7 @@ class FileSystemQuotaClientTest : public testing::Test { FileSystemURL url(GURL(origin_url), type, file_path); scoped_ptr<FileSystemOperationContext> context( - CreateFileSystemOperationContext()); + CreateFileSystemOperationContext(type)); bool created = false; if (base::PLATFORM_FILE_OK != diff --git a/webkit/fileapi/file_system_quota_util.cc b/webkit/fileapi/file_system_quota_util.cc deleted file mode 100644 index 286588d..0000000 --- a/webkit/fileapi/file_system_quota_util.cc +++ /dev/null @@ -1,74 +0,0 @@ -// 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 "webkit/fileapi/file_system_quota_util.h" - -#include "base/bind.h" -#include "base/compiler_specific.h" -#include "base/location.h" -#include "base/message_loop_proxy.h" -#include "base/sequenced_task_runner.h" - -namespace fileapi { - -void FileSystemQuotaUtil::Proxy::UpdateOriginUsage( - quota::QuotaManagerProxy* proxy, const GURL& origin_url, - fileapi::FileSystemType type, int64 delta) { - if (!file_task_runner_->RunsTasksOnCurrentThread()) { - file_task_runner_->PostTask( - FROM_HERE, - base::Bind(&Proxy::UpdateOriginUsage, this, proxy, origin_url, type, - delta)); - return; - } - if (quota_util_) - quota_util_->UpdateOriginUsageOnFileThread(proxy, origin_url, type, delta); -} - -void FileSystemQuotaUtil::Proxy::StartUpdateOrigin( - const GURL& origin_url, fileapi::FileSystemType type) { - if (!file_task_runner_->RunsTasksOnCurrentThread()) { - file_task_runner_->PostTask( - FROM_HERE, - base::Bind(&Proxy::StartUpdateOrigin, this, origin_url, type)); - return; - } - if (quota_util_) - quota_util_->StartUpdateOriginOnFileThread(origin_url, type); -} - -void FileSystemQuotaUtil::Proxy::EndUpdateOrigin( - const GURL& origin_url, fileapi::FileSystemType type) { - if (!file_task_runner_->RunsTasksOnCurrentThread()) { - file_task_runner_->PostTask( - FROM_HERE, - base::Bind(&Proxy::EndUpdateOrigin, this, origin_url, type)); - return; - } - if (quota_util_) - quota_util_->EndUpdateOriginOnFileThread(origin_url, type); -} - -FileSystemQuotaUtil::Proxy::Proxy( - FileSystemQuotaUtil* quota_util, - base::SequencedTaskRunner* file_task_runner) - : quota_util_(quota_util), - file_task_runner_(file_task_runner) { - DCHECK(quota_util); -} - -FileSystemQuotaUtil::Proxy::~Proxy() { -} - -FileSystemQuotaUtil::FileSystemQuotaUtil( - base::SequencedTaskRunner* file_task_runner) - : proxy_(new Proxy(ALLOW_THIS_IN_INITIALIZER_LIST(this), - file_task_runner)) { -} - -FileSystemQuotaUtil::~FileSystemQuotaUtil() { - proxy_->quota_util_ = NULL; -} - -} // namespace fileapi diff --git a/webkit/fileapi/file_system_quota_util.h b/webkit/fileapi/file_system_quota_util.h index f0abbc1..c97effe 100644 --- a/webkit/fileapi/file_system_quota_util.h +++ b/webkit/fileapi/file_system_quota_util.h @@ -9,7 +9,6 @@ #include <string> #include "base/basictypes.h" -#include "base/memory/ref_counted.h" #include "googleurl/src/gurl.h" #include "webkit/fileapi/fileapi_export.h" #include "webkit/fileapi/file_system_types.h" @@ -27,87 +26,28 @@ namespace fileapi { class FileSystemContext; // An abstract interface that provides common quota-related utility functions -// for internal filesystem modules. The main consumer of this class is -// file_system_quota_client and quota_file_util. +// for file_system_quota_client. // All the methods of this class are synchronous and need to be called on // the thread that the method name implies. class FILEAPI_EXPORT FileSystemQuotaUtil { public: - // Methods of this class can be called on any thread. - class FILEAPI_EXPORT Proxy : public base::RefCountedThreadSafe<Proxy> { - public: - void UpdateOriginUsage(quota::QuotaManagerProxy* proxy, - const GURL& origin_url, - fileapi::FileSystemType type, - int64 delta); - void StartUpdateOrigin(const GURL& origin_url, - fileapi::FileSystemType type); - void EndUpdateOrigin(const GURL& origin_url, - fileapi::FileSystemType type); + virtual ~FileSystemQuotaUtil() {} - private: - friend class FileSystemQuotaUtil; - friend class base::RefCountedThreadSafe<Proxy>; - Proxy(FileSystemQuotaUtil* quota_handler, - base::SequencedTaskRunner* file_task_runner); - ~Proxy(); - - FileSystemQuotaUtil* quota_util_; // Accessed only on the FILE thread. - scoped_refptr<base::SequencedTaskRunner> file_task_runner_; - DISALLOW_COPY_AND_ASSIGN(Proxy); - }; - - virtual ~FileSystemQuotaUtil(); - - // Called by quota client. virtual void GetOriginsForTypeOnFileThread(fileapi::FileSystemType type, std::set<GURL>* origins) = 0; - // Called by quota client. virtual void GetOriginsForHostOnFileThread(fileapi::FileSystemType type, const std::string& host, std::set<GURL>* origins) = 0; - // Called by quota client. // Returns the amount of data used for the origin for usage tracking. virtual int64 GetOriginUsageOnFileThread( fileapi::FileSystemContext* file_system_context, const GURL& origin_url, fileapi::FileSystemType type) = 0; - // Called by quota file util. - virtual void UpdateOriginUsageOnFileThread(quota::QuotaManagerProxy* proxy, - const GURL& origin_url, - fileapi::FileSystemType type, - int64 delta) = 0; - - // Called by file_system_operation. - // Called when a read operation accesses the origin's storage data. - virtual void NotifyOriginWasAccessedOnIOThread( - quota::QuotaManagerProxy* proxy, - const GURL& origin_url, - fileapi::FileSystemType type) = 0; - - // Called by quota_file_util or file_writer_delegate. - // Called before a write operation modifies the origin's storage data. - virtual void StartUpdateOriginOnFileThread(const GURL& origin_url, - fileapi::FileSystemType type) = 0; - - // Called by quota_file_util or file_writer_delegate. - // Called after a write operation modifies the origin's storage data. - virtual void EndUpdateOriginOnFileThread(const GURL& origin_url, - fileapi::FileSystemType type) = 0; - virtual void InvalidateUsageCache(const GURL& origin_url, fileapi::FileSystemType type) = 0; - - Proxy* proxy() { return proxy_.get(); } - - protected: - explicit FileSystemQuotaUtil(base::SequencedTaskRunner* file_task_runner); - - private: - scoped_refptr<Proxy> proxy_; }; } // namespace fileapi diff --git a/webkit/fileapi/file_writer_delegate_unittest.cc b/webkit/fileapi/file_writer_delegate_unittest.cc index 0ed0f27..edce017 100644 --- a/webkit/fileapi/file_writer_delegate_unittest.cc +++ b/webkit/fileapi/file_writer_delegate_unittest.cc @@ -98,7 +98,9 @@ class FileWriterDelegateTest : public PlatformTest { SandboxFileStreamWriter* writer = new SandboxFileStreamWriter( test_helper_.file_system_context(), GetFileSystemURL(test_file_path), - offset); + offset, + *test_helper_.file_system_context()->GetUpdateObservers( + test_helper_.type())); writer->set_default_quota(allowed_growth); return new FileWriterDelegate( base::Bind(&Result::DidWrite, base::Unretained(result)), diff --git a/webkit/fileapi/local_file_system_operation.cc b/webkit/fileapi/local_file_system_operation.cc index 5caff1b..1107257 100644 --- a/webkit/fileapi/local_file_system_operation.cc +++ b/webkit/fileapi/local_file_system_operation.cc @@ -11,11 +11,11 @@ #include "net/base/escape.h" #include "net/url_request/url_request_context.h" #include "webkit/blob/shareable_file_reference.h" +#include "webkit/fileapi/file_observers.h" #include "webkit/fileapi/file_system_context.h" #include "webkit/fileapi/file_system_file_util_proxy.h" #include "webkit/fileapi/file_system_mount_point_provider.h" #include "webkit/fileapi/file_system_operation_context.h" -#include "webkit/fileapi/file_system_quota_util.h" #include "webkit/fileapi/file_system_task_runners.h" #include "webkit/fileapi/file_system_types.h" #include "webkit/fileapi/file_system_url.h" @@ -45,47 +45,33 @@ bool IsCrossOperationAllowed(FileSystemType src_type, } // namespace -class LocalFileSystemOperation::ScopedQuotaNotifier { +class LocalFileSystemOperation::ScopedUpdateNotifier { public: - ScopedQuotaNotifier(FileSystemContext* context, - const GURL& origin_url, - FileSystemType type); - ~ScopedQuotaNotifier(); + ScopedUpdateNotifier(FileSystemOperationContext* operation_context, + const FileSystemURL& url); + ~ScopedUpdateNotifier(); private: // Not owned; owned by the owner of this instance // (i.e. LocalFileSystemOperation). - FileSystemQuotaUtil* quota_util_; - const GURL origin_url_; - FileSystemType type_; - DISALLOW_COPY_AND_ASSIGN(ScopedQuotaNotifier); + FileSystemOperationContext* operation_context_; + FileSystemURL url_; + DISALLOW_COPY_AND_ASSIGN(ScopedUpdateNotifier); }; -LocalFileSystemOperation::ScopedQuotaNotifier::ScopedQuotaNotifier( - FileSystemContext* context, const GURL& origin_url, FileSystemType type) - : origin_url_(origin_url), type_(type) { - DCHECK(context); - DCHECK(type_ != kFileSystemTypeUnknown); - quota_util_ = context->GetQuotaUtil(type_); - if (quota_util_) { - DCHECK(quota_util_->proxy()); - quota_util_->proxy()->StartUpdateOrigin(origin_url_, type_); - } -} - -LocalFileSystemOperation::ScopedQuotaNotifier::~ScopedQuotaNotifier() { - if (quota_util_) { - DCHECK(quota_util_->proxy()); - quota_util_->proxy()->EndUpdateOrigin(origin_url_, type_); - } +LocalFileSystemOperation::ScopedUpdateNotifier::ScopedUpdateNotifier( + FileSystemOperationContext* operation_context, + const FileSystemURL& url) + : operation_context_(operation_context), url_(url) { + operation_context_->update_observers()->Notify( + &FileUpdateObserver::OnStartUpdate, MakeTuple(url_)); } -LocalFileSystemOperation::TaskParamsForDidGetQuota::TaskParamsForDidGetQuota() { +LocalFileSystemOperation::ScopedUpdateNotifier::~ScopedUpdateNotifier() { + operation_context_->update_observers()->Notify( + &FileUpdateObserver::OnEndUpdate, MakeTuple(url_)); } -LocalFileSystemOperation::TaskParamsForDidGetQuota::~TaskParamsForDidGetQuota( - ) {} - LocalFileSystemOperation::~LocalFileSystemOperation() { } @@ -269,9 +255,6 @@ void LocalFileSystemOperation::Remove(const FileSystemURL& url, return; } - scoped_quota_notifier_.reset(new ScopedQuotaNotifier( - file_system_context(), url.origin(), url.type())); - FileSystemFileUtilProxy::Delete( operation_context_.get(), src_util_, url, recursive, base::Bind(&LocalFileSystemOperation::DidFinishFileOperation, @@ -504,35 +487,28 @@ void LocalFileSystemOperation::GetUsageAndQuotaThenRunTask( return; } - TaskParamsForDidGetQuota params; - params.url = url; - params.task = task; - params.error_callback = error_callback; - DCHECK(quota_manager_proxy); DCHECK(quota_manager_proxy->quota_manager()); quota_manager_proxy->quota_manager()->GetUsageAndQuota( url.origin(), FileSystemTypeToQuotaStorageType(url.type()), base::Bind(&LocalFileSystemOperation::DidGetUsageAndQuotaAndRunTask, - weak_factory_.GetWeakPtr(), params)); + weak_factory_.GetWeakPtr(), task, error_callback)); } void LocalFileSystemOperation::DidGetUsageAndQuotaAndRunTask( - const TaskParamsForDidGetQuota& params, + const base::Closure& task, + const base::Closure& error_callback, quota::QuotaStatusCode status, int64 usage, int64 quota) { if (status != quota::kQuotaStatusOk) { LOG(WARNING) << "Got unexpected quota error : " << status; - params.error_callback.Run(); + error_callback.Run(); return; } operation_context_->set_allowed_bytes_growth(quota - usage); - scoped_quota_notifier_.reset(new ScopedQuotaNotifier( - file_system_context(), params.url.origin(), params.url.type())); - - params.task.Run(); + task.Run(); } void LocalFileSystemOperation::DoCreateFile( @@ -730,22 +706,16 @@ base::PlatformFileError LocalFileSystemOperation::SetUp( return base::PLATFORM_FILE_ERROR_SECURITY; if (mode == SETUP_FOR_READ) { - // We notify this read access whether the read access succeeds or not. - // This must be ok since this is used to let the QM's eviction logic know - // someone is interested in reading the origin data and therefore to - // indicate that evicting this origin may not be a good idea. - FileSystemQuotaUtil* quota_util = file_system_context()->GetQuotaUtil( - url.type()); - if (quota_util) { - quota_util->NotifyOriginWasAccessedOnIOThread( - file_system_context()->quota_manager_proxy(), - url.origin(), url.type()); - } + operation_context_->access_observers()->Notify( + &FileAccessObserver::OnAccess, MakeTuple(url)); return base::PLATFORM_FILE_OK; } DCHECK(mode == SETUP_FOR_WRITE || mode == SETUP_FOR_CREATE); + scoped_update_notifiers_.push_back(new ScopedUpdateNotifier( + operation_context_.get(), url)); + // Any write access is disallowed on the root path. if (url.path().value().length() == 0 || url.path().DirName().value() == url.path().value()) diff --git a/webkit/fileapi/local_file_system_operation.h b/webkit/fileapi/local_file_system_operation.h index b665983..b005b64 100644 --- a/webkit/fileapi/local_file_system_operation.h +++ b/webkit/fileapi/local_file_system_operation.h @@ -13,6 +13,7 @@ #include "base/gtest_prod_util.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/scoped_vector.h" #include "base/platform_file.h" #include "base/process.h" #include "webkit/fileapi/file_system_operation.h" @@ -98,7 +99,7 @@ class FILEAPI_EXPORT LocalFileSystemOperation void SyncGetPlatformPath(const FileSystemURL& url, FilePath* platform_path); private: - class ScopedQuotaNotifier; + class ScopedUpdateNotifier; enum SetUpMode { SETUP_FOR_READ, @@ -106,16 +107,6 @@ class FILEAPI_EXPORT LocalFileSystemOperation SETUP_FOR_CREATE, }; - // A struct to pass arguments to DidGetUsageAndQuotaAndRunTask - // purely for compilation (as Bind doesn't recognize too many arguments). - struct TaskParamsForDidGetQuota { - TaskParamsForDidGetQuota(); - ~TaskParamsForDidGetQuota(); - FileSystemURL url; - base::Closure task; - base::Closure error_callback; - }; - // Only MountPointProviders or testing class can create a // new operation directly. friend class FileSystemTestHelper; @@ -159,7 +150,8 @@ class FILEAPI_EXPORT LocalFileSystemOperation // |task| if the returned quota status is successful, otherwise runs // |error_callback|. void DidGetUsageAndQuotaAndRunTask( - const TaskParamsForDidGetQuota& params, + const base::Closure& task, + const base::Closure& error_callback, quota::QuotaStatusCode status, int64 usage, int64 quota); @@ -242,11 +234,9 @@ class FILEAPI_EXPORT LocalFileSystemOperation FileSystemFileUtil* src_util_; // Not owned. FileSystemFileUtil* dest_util_; // Not owned. - // This is set before any write operations. The destructor of - // ScopedQuotaNotifier sends notification to the QuotaManager - // to tell the update is done; so that we can make sure notify - // the manager after any write operations are done. - scoped_ptr<ScopedQuotaNotifier> scoped_quota_notifier_; + // This is set before any write operations to dispatch + // FileUpdateObserver::StartUpdate and FileUpdateObserver::EndUpdate. + ScopedVector<ScopedUpdateNotifier> scoped_update_notifiers_; // These are all used only by Write(). friend class FileWriterDelegate; diff --git a/webkit/fileapi/local_file_system_test_helper.cc b/webkit/fileapi/local_file_system_test_helper.cc index dd50bd6..85f76ae 100644 --- a/webkit/fileapi/local_file_system_test_helper.cc +++ b/webkit/fileapi/local_file_system_test_helper.cc @@ -175,10 +175,9 @@ LocalFileSystemOperation* LocalFileSystemTestOriginHelper::NewOperation() { DCHECK(file_system_context_.get()); DCHECK(file_util_); scoped_ptr<FileSystemOperationContext> operation_context( - new FileSystemOperationContext(file_system_context_.get())); - LocalFileSystemOperation* operation = - new LocalFileSystemOperation(file_system_context_.get(), - operation_context.Pass()); + NewOperationContext()); + LocalFileSystemOperation* operation = static_cast<LocalFileSystemOperation*>( + file_system_context_->CreateFileSystemOperation(CreateURL(FilePath()))); operation->set_override_file_util(file_util_); return operation; } @@ -188,6 +187,8 @@ LocalFileSystemTestOriginHelper::NewOperationContext() { DCHECK(file_system_context_.get()); FileSystemOperationContext* context = new FileSystemOperationContext(file_system_context_.get()); + context->set_update_observers( + *file_system_context_->GetUpdateObservers(type_)); return context; } diff --git a/webkit/fileapi/obfuscated_file_util.cc b/webkit/fileapi/obfuscated_file_util.cc index bab9348..fddf937 100644 --- a/webkit/fileapi/obfuscated_file_util.cc +++ b/webkit/fileapi/obfuscated_file_util.cc @@ -18,9 +18,9 @@ #include "base/stringprintf.h" #include "base/sys_string_conversions.h" #include "googleurl/src/gurl.h" +#include "webkit/fileapi/file_observers.h" #include "webkit/fileapi/file_system_context.h" #include "webkit/fileapi/file_system_operation_context.h" -#include "webkit/fileapi/file_system_quota_util.h" #include "webkit/fileapi/file_system_url.h" #include "webkit/fileapi/file_system_util.h" #include "webkit/fileapi/native_file_util.h" @@ -80,15 +80,10 @@ bool AllocateQuota(FileSystemOperationContext* context, int64 growth) { void UpdateUsage( FileSystemOperationContext* context, - const GURL& origin, - FileSystemType type, + const FileSystemURL& url, int64 growth) { - FileSystemQuotaUtil* quota_util = - context->file_system_context()->GetQuotaUtil(type); - quota::QuotaManagerProxy* quota_manager_proxy = - context->file_system_context()->quota_manager_proxy(); - quota_util->UpdateOriginUsageOnFileThread( - quota_manager_proxy, origin, type, growth); + context->update_observers()->Notify( + &FileUpdateObserver::OnUpdate, MakeTuple(url, growth)); } void TouchDirectory(FileSystemDirectoryDatabase* db, FileId dir_id) { @@ -297,7 +292,7 @@ PlatformFileError ObfuscatedFileUtil::CreateOrOpen( file_flags, file_handle); if (created && base::PLATFORM_FILE_OK == error) { *created = true; - UpdateUsage(context, url.origin(), url.type(), growth); + UpdateUsage(context, url, growth); } return error; } @@ -336,7 +331,7 @@ PlatformFileError ObfuscatedFileUtil::CreateOrOpen( // If truncating we need to update the usage. if (error == base::PLATFORM_FILE_OK && delta) - UpdateUsage(context, url.origin(), url.type(), delta); + UpdateUsage(context, url, delta); return error; } @@ -383,7 +378,7 @@ PlatformFileError ObfuscatedFileUtil::EnsureFileExists( context, FilePath(), url.origin(), url.type(), &file_info, 0, NULL); if (created && base::PLATFORM_FILE_OK == error) { *created = true; - UpdateUsage(context, url.origin(), url.type(), growth); + UpdateUsage(context, url, growth); } return error; } @@ -440,7 +435,7 @@ PlatformFileError ObfuscatedFileUtil::CreateDirectory( NOTREACHED(); return base::PLATFORM_FILE_ERROR_FAILED; } - UpdateUsage(context, url.origin(), url.type(), growth); + UpdateUsage(context, url, growth); if (first) { first = false; TouchDirectory(db, file_info.parent_id); @@ -551,7 +546,7 @@ PlatformFileError ObfuscatedFileUtil::Truncate( return base::PLATFORM_FILE_ERROR_NO_SPACE; error = NativeFileUtil::Truncate(local_path, length); if (error == base::PLATFORM_FILE_OK) - UpdateUsage(context, url.origin(), url.type(), growth); + UpdateUsage(context, url, growth); return error; } @@ -704,7 +699,7 @@ PlatformFileError ObfuscatedFileUtil::CopyOrMoveFile( TouchDirectory(db, src_file_info.parent_id); TouchDirectory(db, dest_file_info.parent_id); - UpdateUsage(context, dest_url.origin(), dest_url.type(), growth); + UpdateUsage(context, dest_url, growth); return error; } @@ -774,7 +769,7 @@ PlatformFileError ObfuscatedFileUtil::CopyInForeignFile( if (error != base::PLATFORM_FILE_OK) return error; - UpdateUsage(context, dest_url.origin(), dest_url.type(), growth); + UpdateUsage(context, dest_url, growth); TouchDirectory(db, dest_file_info.parent_id); return base::PLATFORM_FILE_OK; } @@ -811,7 +806,7 @@ PlatformFileError ObfuscatedFileUtil::DeleteFile( NOTREACHED(); return base::PLATFORM_FILE_ERROR_FAILED; } - UpdateUsage(context, url.origin(), url.type(), growth); + UpdateUsage(context, url, growth); TouchDirectory(db, file_info.parent_id); if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND) @@ -843,7 +838,7 @@ PlatformFileError ObfuscatedFileUtil::DeleteSingleDirectory( return base::PLATFORM_FILE_ERROR_NOT_EMPTY; int64 growth = -UsageForPath(file_info.name.size()); AllocateQuota(context, growth); - UpdateUsage(context, url.origin(), url.type(), growth); + UpdateUsage(context, url, growth); TouchDirectory(db, file_info.parent_id); return base::PLATFORM_FILE_OK; } diff --git a/webkit/fileapi/sandbox_file_stream_writer.cc b/webkit/fileapi/sandbox_file_stream_writer.cc index 01b44d4..2dafb58 100644 --- a/webkit/fileapi/sandbox_file_stream_writer.cc +++ b/webkit/fileapi/sandbox_file_stream_writer.cc @@ -10,9 +10,9 @@ #include "net/base/io_buffer.h" #include "net/base/net_errors.h" #include "webkit/blob/local_file_stream_reader.h" +#include "webkit/fileapi/file_observers.h" #include "webkit/fileapi/file_system_context.h" #include "webkit/fileapi/file_system_operation.h" -#include "webkit/fileapi/file_system_quota_util.h" #include "webkit/fileapi/file_system_util.h" #include "webkit/fileapi/local_file_stream_writer.h" #include "webkit/quota/quota_manager.h" @@ -42,10 +42,12 @@ int64 AdjustQuotaForOverlap(int64 quota, SandboxFileStreamWriter::SandboxFileStreamWriter( FileSystemContext* file_system_context, const FileSystemURL& url, - int64 initial_offset) + int64 initial_offset, + const UpdateObserverList& observers) : file_system_context_(file_system_context), url_(url), initial_offset_(initial_offset), + observers_(observers), file_size_(0), total_bytes_written_(0), allowed_bytes_to_write_(0), @@ -55,10 +57,7 @@ SandboxFileStreamWriter::SandboxFileStreamWriter( DCHECK(url_.is_valid()); } -SandboxFileStreamWriter::~SandboxFileStreamWriter() { - if (quota_util()) - quota_util()->proxy()->EndUpdateOrigin(url_.origin(), url_.type()); -} +SandboxFileStreamWriter::~SandboxFileStreamWriter() {} int SandboxFileStreamWriter::Write( net::IOBuffer* buf, int buf_len, @@ -143,7 +142,7 @@ void SandboxFileStreamWriter::DidGetFileInfo( quota::QuotaManagerProxy* quota_manager_proxy = file_system_context_->quota_manager_proxy(); - if (!quota_manager_proxy || !quota_util()) { + if (!quota_manager_proxy) { // If we don't have the quota manager or the requested filesystem type // does not support quota, we should be able to let it go. allowed_bytes_to_write_ = default_quota_; @@ -151,7 +150,6 @@ void SandboxFileStreamWriter::DidGetFileInfo( return; } - quota_util()->proxy()->StartUpdateOrigin(url_.origin(), url_.type()); DCHECK(quota_manager_proxy->quota_manager()); quota_manager_proxy->quota_manager()->GetUsageAndQuota( url_.origin(), @@ -207,14 +205,12 @@ void SandboxFileStreamWriter::DidWrite( return; } - if (quota_util() && - total_bytes_written_ + write_response + initial_offset_ > file_size_) { + if (total_bytes_written_ + write_response + initial_offset_ > file_size_) { int overlapped = file_size_ - total_bytes_written_ - initial_offset_; if (overlapped < 0) overlapped = 0; - quota_util()->proxy()->UpdateOriginUsage( - file_system_context_->quota_manager_proxy(), - url_.origin(), url_.type(), write_response - overlapped); + observers_.Notify(&FileUpdateObserver::OnUpdate, + MakeTuple(url_, write_response - overlapped)); } total_bytes_written_ += write_response; @@ -234,9 +230,4 @@ bool SandboxFileStreamWriter::CancelIfRequested() { return true; } -FileSystemQuotaUtil* SandboxFileStreamWriter::quota_util() const { - DCHECK(file_system_context_.get()); - return file_system_context_->GetQuotaUtil(url_.type()); -} - } // namespace fileapi diff --git a/webkit/fileapi/sandbox_file_stream_writer.h b/webkit/fileapi/sandbox_file_stream_writer.h index f95ff22..daf3b6a 100644 --- a/webkit/fileapi/sandbox_file_stream_writer.h +++ b/webkit/fileapi/sandbox_file_stream_writer.h @@ -13,6 +13,7 @@ #include "webkit/fileapi/file_system_types.h" #include "webkit/fileapi/file_system_url.h" #include "webkit/fileapi/fileapi_export.h" +#include "webkit/fileapi/task_runner_bound_observer_list.h" #include "webkit/quota/quota_types.h" namespace fileapi { @@ -25,7 +26,8 @@ class FILEAPI_EXPORT_PRIVATE SandboxFileStreamWriter : public FileStreamWriter { public: SandboxFileStreamWriter(FileSystemContext* file_system_context, const FileSystemURL& url, - int64 initial_offset); + int64 initial_offset, + const UpdateObserverList& observers); virtual ~SandboxFileStreamWriter(); // FileStreamWriter overrides. @@ -62,14 +64,14 @@ class FILEAPI_EXPORT_PRIVATE SandboxFileStreamWriter : public FileStreamWriter { // if there's a pending cancel request. bool CancelIfRequested(); - FileSystemQuotaUtil* quota_util() const; - scoped_refptr<FileSystemContext> file_system_context_; FileSystemURL url_; int64 initial_offset_; scoped_ptr<LocalFileStreamWriter> local_file_writer_; net::CompletionCallback cancel_callback_; + UpdateObserverList observers_; + FilePath file_path_; int64 file_size_; int64 total_bytes_written_; diff --git a/webkit/fileapi/sandbox_mount_point_provider.cc b/webkit/fileapi/sandbox_mount_point_provider.cc index 9932b2c..2f3614d 100644 --- a/webkit/fileapi/sandbox_mount_point_provider.cc +++ b/webkit/fileapi/sandbox_mount_point_provider.cc @@ -27,6 +27,7 @@ #include "webkit/fileapi/native_file_util.h" #include "webkit/fileapi/obfuscated_file_util.h" #include "webkit/fileapi/sandbox_file_stream_writer.h" +#include "webkit/fileapi/sandbox_quota_observer.h" #include "webkit/glue/webkit_glue.h" #include "webkit/quota/quota_manager.h" @@ -316,18 +317,38 @@ const FilePath::CharType SandboxMountPointProvider::kRenamedOldFileSystemDirectory[] = FILE_PATH_LITERAL("FS.old"); +// static +bool SandboxMountPointProvider::CanHandleType(FileSystemType type) { + return type == kFileSystemTypeTemporary || type == kFileSystemTypePersistent; +} + SandboxMountPointProvider::SandboxMountPointProvider( + quota::QuotaManagerProxy* quota_manager_proxy, base::SequencedTaskRunner* file_task_runner, const FilePath& profile_path, const FileSystemOptions& file_system_options) - : FileSystemQuotaUtil(file_task_runner), - file_task_runner_(file_task_runner), + : file_task_runner_(file_task_runner), profile_path_(profile_path), file_system_options_(file_system_options), - sandbox_file_util_( - new ObfuscatedFileUtil( - profile_path.Append(kNewFileSystemDirectory))), + sandbox_file_util_(new ObfuscatedFileUtil( + profile_path.Append(kNewFileSystemDirectory))), + quota_observer_(new SandboxQuotaObserver( + quota_manager_proxy, + file_task_runner, + ALLOW_THIS_IN_INITIALIZER_LIST(this))), weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { + + // Set quota observers. + UpdateObserverList::Source update_observers_src; + AccessObserverList::Source access_observers_src; + + update_observers_src.AddObserver(quota_observer_.get(), file_task_runner_); + access_observers_src.AddObserver(quota_observer_.get(), NULL); + update_observers_src.AddObserver(quota_observer_.get(), file_task_runner_); + access_observers_src.AddObserver(quota_observer_.get(), NULL); + + update_observers_ = UpdateObserverList(update_observers_src); + access_observers_ = AccessObserverList(access_observers_src); } SandboxMountPointProvider::~SandboxMountPointProvider() { @@ -430,6 +451,11 @@ FileSystemOperation* SandboxMountPointProvider::CreateFileSystemOperation( FileSystemContext* context) const { scoped_ptr<FileSystemOperationContext> operation_context( new FileSystemOperationContext(context)); + + // Copy the observer lists (assuming we only have small number of observers). + operation_context->set_update_observers(update_observers_); + operation_context->set_access_observers(access_observers_); + return new LocalFileSystemOperation(context, operation_context.Pass()); } @@ -445,7 +471,8 @@ fileapi::FileStreamWriter* SandboxMountPointProvider::CreateFileStreamWriter( const FileSystemURL& url, int64 offset, FileSystemContext* context) const { - return new SandboxFileStreamWriter(context, url, offset); + return new SandboxFileStreamWriter( + context, url, offset, update_observers_); } FileSystemQuotaUtil* SandboxMountPointProvider::GetQuotaUtil() { @@ -529,8 +556,7 @@ SandboxMountPointProvider::DeleteOriginDataOnFileThread( void SandboxMountPointProvider::GetOriginsForTypeOnFileThread( fileapi::FileSystemType type, std::set<GURL>* origins) { - DCHECK(type == kFileSystemTypeTemporary || - type == kFileSystemTypePersistent); + DCHECK(CanHandleType(type)); DCHECK(origins); scoped_ptr<OriginEnumerator> enumerator(CreateOriginEnumerator()); GURL origin; @@ -550,8 +576,7 @@ void SandboxMountPointProvider::GetOriginsForTypeOnFileThread( void SandboxMountPointProvider::GetOriginsForHostOnFileThread( fileapi::FileSystemType type, const std::string& host, std::set<GURL>* origins) { - DCHECK(type == kFileSystemTypeTemporary || - type == kFileSystemTypePersistent); + DCHECK(CanHandleType(type)); DCHECK(origins); scoped_ptr<OriginEnumerator> enumerator(CreateOriginEnumerator()); GURL origin; @@ -566,8 +591,7 @@ int64 SandboxMountPointProvider::GetOriginUsageOnFileThread( FileSystemContext* file_system_context, const GURL& origin_url, fileapi::FileSystemType type) { - DCHECK(type == kFileSystemTypeTemporary || - type == kFileSystemTypePersistent); + DCHECK(CanHandleType(type)); FilePath base_path = GetBaseDirectoryForOriginAndType(origin_url, type, false); if (base_path.empty() || !file_util::DirectoryExists(base_path)) return 0; @@ -606,39 +630,7 @@ int64 SandboxMountPointProvider::GetOriginUsageOnFileThread( return usage; } -void SandboxMountPointProvider::NotifyOriginWasAccessedOnIOThread( - QuotaManagerProxy* proxy, const GURL& origin_url, - fileapi::FileSystemType type) { - DCHECK(type == kFileSystemTypeTemporary || - type == kFileSystemTypePersistent); - if (proxy) { - proxy->NotifyStorageAccessed( - quota::QuotaClient::kFileSystem, - origin_url, - FileSystemTypeToQuotaStorageType(type)); - } -} - -void SandboxMountPointProvider::UpdateOriginUsageOnFileThread( - QuotaManagerProxy* proxy, const GURL& origin_url, - fileapi::FileSystemType type, int64 delta) { - DCHECK(type == kFileSystemTypeTemporary || - type == kFileSystemTypePersistent); - FilePath usage_file_path = GetUsageCachePathForOriginAndType( - origin_url, type); - DCHECK(!usage_file_path.empty()); - // TODO(dmikurbe): Make sure that usage_file_path is available. - FileSystemUsageCache::AtomicUpdateUsageByDelta(usage_file_path, delta); - if (proxy) { - proxy->NotifyStorageModified( - quota::QuotaClient::kFileSystem, - origin_url, - FileSystemTypeToQuotaStorageType(type), - delta); - } -} - -void SandboxMountPointProvider::StartUpdateOriginOnFileThread( +void SandboxMountPointProvider::InvalidateUsageCache( const GURL& origin_url, fileapi::FileSystemType type) { DCHECK(type == kFileSystemTypeTemporary || type == kFileSystemTypePersistent); @@ -647,22 +639,51 @@ void SandboxMountPointProvider::StartUpdateOriginOnFileThread( FileSystemUsageCache::IncrementDirty(usage_file_path); } -void SandboxMountPointProvider::EndUpdateOriginOnFileThread( - const GURL& origin_url, fileapi::FileSystemType type) { - DCHECK(type == kFileSystemTypeTemporary || - type == kFileSystemTypePersistent); - FilePath usage_file_path = GetUsageCachePathForOriginAndType( - origin_url, type); - FileSystemUsageCache::DecrementDirty(usage_file_path); +void SandboxMountPointProvider::CollectOpenFileSystemMetrics( + base::PlatformFileError error_code) { + base::Time now = base::Time::Now(); + bool throttled = now < next_release_time_for_open_filesystem_stat_; + if (!throttled) { + next_release_time_for_open_filesystem_stat_ = + now + base::TimeDelta::FromHours(kMinimumStatsCollectionIntervalHours); + } + +#define REPORT(report_value) \ + UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailLabel, \ + (report_value), \ + kFileSystemErrorMax); \ + if (!throttled) { \ + UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailNonThrottledLabel, \ + (report_value), \ + kFileSystemErrorMax); \ + } + + switch (error_code) { + case base::PLATFORM_FILE_OK: + REPORT(kOK); + break; + case base::PLATFORM_FILE_ERROR_INVALID_URL: + REPORT(kInvalidSchemeError); + break; + case base::PLATFORM_FILE_ERROR_NOT_FOUND: + REPORT(kNotFound); + break; + case base::PLATFORM_FILE_ERROR_FAILED: + default: + REPORT(kUnknownError); + break; + } +#undef REPORT } -void SandboxMountPointProvider::InvalidateUsageCache( - const GURL& origin_url, fileapi::FileSystemType type) { - DCHECK(type == kFileSystemTypeTemporary || - type == kFileSystemTypePersistent); - FilePath usage_file_path = GetUsageCachePathForOriginAndType( - origin_url, type); - FileSystemUsageCache::IncrementDirty(usage_file_path); +const UpdateObserverList* SandboxMountPointProvider::GetUpdateObservers( + FileSystemType type) const { + return &update_observers_; +} + +void SandboxMountPointProvider::ResetObservers() { + update_observers_ = UpdateObserverList(); + access_observers_ = AccessObserverList(); } FilePath SandboxMountPointProvider::GetUsageCachePathForOriginAndType( @@ -717,41 +738,4 @@ bool SandboxMountPointProvider::IsAllowedScheme(const GURL& url) const { return false; } -void SandboxMountPointProvider::CollectOpenFileSystemMetrics( - base::PlatformFileError error_code) { - base::Time now = base::Time::Now(); - bool throttled = now < next_release_time_for_open_filesystem_stat_; - if (!throttled) { - next_release_time_for_open_filesystem_stat_ = - now + base::TimeDelta::FromHours(kMinimumStatsCollectionIntervalHours); - } - -#define REPORT(report_value) \ - UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailLabel, \ - (report_value), \ - kFileSystemErrorMax); \ - if (!throttled) { \ - UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailNonThrottledLabel, \ - (report_value), \ - kFileSystemErrorMax); \ - } - - switch (error_code) { - case base::PLATFORM_FILE_OK: - REPORT(kOK); - break; - case base::PLATFORM_FILE_ERROR_INVALID_URL: - REPORT(kInvalidSchemeError); - break; - case base::PLATFORM_FILE_ERROR_NOT_FOUND: - REPORT(kNotFound); - break; - case base::PLATFORM_FILE_ERROR_FAILED: - default: - REPORT(kUnknownError); - break; - } -#undef REPORT -} - } // namespace fileapi diff --git a/webkit/fileapi/sandbox_mount_point_provider.h b/webkit/fileapi/sandbox_mount_point_provider.h index 514abe4..74e4d75 100644 --- a/webkit/fileapi/sandbox_mount_point_provider.h +++ b/webkit/fileapi/sandbox_mount_point_provider.h @@ -19,6 +19,7 @@ #include "webkit/fileapi/file_system_mount_point_provider.h" #include "webkit/fileapi/file_system_options.h" #include "webkit/fileapi/file_system_quota_util.h" +#include "webkit/fileapi/task_runner_bound_observer_list.h" namespace base { class SequencedTaskRunner; @@ -31,6 +32,7 @@ class QuotaManagerProxy; namespace fileapi { class ObfuscatedFileUtil; +class SandboxQuotaObserver; // An interface to construct or crack sandboxed filesystem paths for // TEMPORARY or PERSISTENT filesystems, which are placed under the user's @@ -65,9 +67,12 @@ class FILEAPI_EXPORT SandboxMountPointProvider // Where we move the old filesystem directory if migration fails. static const FilePath::CharType kRenamedOldFileSystemDirectory[]; + static bool CanHandleType(FileSystemType type); + // |file_task_runner| is used to validate the root directory and delete the // obfuscated file util. SandboxMountPointProvider( + quota::QuotaManagerProxy* quota_manager_proxy, base::SequencedTaskRunner* file_task_runner, const FilePath& profile_path, const FileSystemOptions& file_system_options); @@ -134,7 +139,7 @@ class FILEAPI_EXPORT SandboxMountPointProvider const GURL& origin_url, FileSystemType type); - // Quota util methods. + // FileSystemQuotaUtil overrides. virtual void GetOriginsForTypeOnFileThread( FileSystemType type, std::set<GURL>* origins) OVERRIDE; @@ -146,27 +151,21 @@ class FILEAPI_EXPORT SandboxMountPointProvider FileSystemContext* context, const GURL& origin_url, FileSystemType type) OVERRIDE; - virtual void NotifyOriginWasAccessedOnIOThread( - quota::QuotaManagerProxy* proxy, - const GURL& origin_url, - FileSystemType type) OVERRIDE; - virtual void UpdateOriginUsageOnFileThread( - quota::QuotaManagerProxy* proxy, - const GURL& origin_url, - FileSystemType type, - int64 delta) OVERRIDE; - virtual void StartUpdateOriginOnFileThread( - const GURL& origin_url, - FileSystemType type) OVERRIDE; - virtual void EndUpdateOriginOnFileThread( - const GURL& origin_url, - FileSystemType type) OVERRIDE; + virtual void InvalidateUsageCache(const GURL& origin_url, FileSystemType type) OVERRIDE; void CollectOpenFileSystemMetrics(base::PlatformFileError error_code); + // Returns update observers for the given type. + const UpdateObserverList* GetUpdateObservers(FileSystemType type) const; + + // Reset all observers. + void ResetObservers(); + private: + friend class SandboxQuotaObserver; + // Returns a path to the usage cache file. FilePath GetUsageCachePathForOriginAndType( const GURL& origin_url, @@ -191,9 +190,15 @@ class FILEAPI_EXPORT SandboxMountPointProvider scoped_ptr<ObfuscatedFileUtil> sandbox_file_util_; + scoped_ptr<SandboxQuotaObserver> quota_observer_; + // Acccessed only on the file thread. std::set<GURL> visited_origins_; + // Observers. + UpdateObserverList update_observers_; + AccessObserverList access_observers_; + base::Time next_release_time_for_open_filesystem_stat_; base::WeakPtrFactory<SandboxMountPointProvider> weak_factory_; diff --git a/webkit/fileapi/sandbox_mount_point_provider_unittest.cc b/webkit/fileapi/sandbox_mount_point_provider_unittest.cc index d66a379..0c665af 100644 --- a/webkit/fileapi/sandbox_mount_point_provider_unittest.cc +++ b/webkit/fileapi/sandbox_mount_point_provider_unittest.cc @@ -36,9 +36,10 @@ class SandboxMountPointProviderOriginEnumeratorTest : public testing::Test { ASSERT_TRUE(data_dir_.CreateUniqueTempDir()); sandbox_provider_.reset( new SandboxMountPointProvider( - base::MessageLoopProxy::current(), - data_dir_.path(), - CreateAllowFileAccessOptions())); + NULL, + base::MessageLoopProxy::current(), + data_dir_.path(), + CreateAllowFileAccessOptions())); } SandboxMountPointProvider::OriginEnumerator* CreateEnumerator() const { @@ -274,7 +275,6 @@ class SandboxMountPointProviderMigrationTest : public testing::Test { bool create = false; std::set<GURL> origins; std::string host = "the host with the most"; - int64 delta = 0; // We want to make sure that all the public methods of // SandboxMountPointProvider which might access the filesystem will cause a @@ -309,25 +309,6 @@ class SandboxMountPointProviderMigrationTest : public testing::Test { sandbox_provider()->GetOriginUsageOnFileThread( file_system_context_, origin_url, type); break; - case 7: - // This case has to use an origin that already exists in the - // migrated data. - sandbox_provider()->UpdateOriginUsageOnFileThread( - NULL, kMigrationTestRecords[0].origin, - kFileSystemTypeTemporary, delta); - break; - case 8: - // This case has to use a filesystem that already exists in the - // migrated data. - sandbox_provider()->StartUpdateOriginOnFileThread( - kMigrationTestRecords[0].origin, kFileSystemTypeTemporary); - break; - case 9: - // This case has to use a filesystem that already exists in the - // migrated data. - sandbox_provider()->EndUpdateOriginOnFileThread( - kMigrationTestRecords[0].origin, kFileSystemTypeTemporary); - break; default: FAIL(); break; @@ -378,16 +359,4 @@ TEST_F(SandboxMountPointProviderMigrationTest, TestMigrateViaMethod6) { RunMigrationTest(6); } -TEST_F(SandboxMountPointProviderMigrationTest, TestMigrateViaMethod7) { - RunMigrationTest(7); -} - -TEST_F(SandboxMountPointProviderMigrationTest, TestMigrateViaMethod8) { - RunMigrationTest(8); -} - -TEST_F(SandboxMountPointProviderMigrationTest, TestMigrateViaMethod9) { - RunMigrationTest(9); -} - } // namespace fileapi diff --git a/webkit/fileapi/sandbox_quota_observer.cc b/webkit/fileapi/sandbox_quota_observer.cc new file mode 100644 index 0000000..4c744ec --- /dev/null +++ b/webkit/fileapi/sandbox_quota_observer.cc @@ -0,0 +1,74 @@ +// 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 "webkit/fileapi/sandbox_quota_observer.h" + +#include "base/sequenced_task_runner.h" +#include "webkit/fileapi/file_system_url.h" +#include "webkit/fileapi/file_system_usage_cache.h" +#include "webkit/fileapi/file_system_util.h" +#include "webkit/fileapi/sandbox_mount_point_provider.h" +#include "webkit/quota/quota_client.h" +#include "webkit/quota/quota_manager.h" + +namespace fileapi { + +SandboxQuotaObserver::SandboxQuotaObserver( + quota::QuotaManagerProxy* quota_manager_proxy, + base::SequencedTaskRunner* update_notify_runner, + SandboxMountPointProvider* sandbox_provider) + : quota_manager_proxy_(quota_manager_proxy), + update_notify_runner_(update_notify_runner), + sandbox_provider_(sandbox_provider) {} + +SandboxQuotaObserver::~SandboxQuotaObserver() {} + +void SandboxQuotaObserver::OnStartUpdate(const FileSystemURL& url) { + DCHECK(SandboxMountPointProvider::CanHandleType(url.type())); + DCHECK(update_notify_runner_->RunsTasksOnCurrentThread()); + FilePath usage_file_path = GetUsageCachePath(url); + FileSystemUsageCache::IncrementDirty(usage_file_path); +} + +void SandboxQuotaObserver::OnUpdate(const FileSystemURL& url, + int64 delta) { + DCHECK(SandboxMountPointProvider::CanHandleType(url.type())); + DCHECK(update_notify_runner_->RunsTasksOnCurrentThread()); + FilePath usage_file_path = GetUsageCachePath(url); + DCHECK(!usage_file_path.empty()); + // TODO(dmikurbe): Make sure that usage_file_path is available. + FileSystemUsageCache::AtomicUpdateUsageByDelta(usage_file_path, delta); + if (quota_manager_proxy_) { + quota_manager_proxy_->NotifyStorageModified( + quota::QuotaClient::kFileSystem, + url.origin(), + FileSystemTypeToQuotaStorageType(url.type()), + delta); + } +} + +void SandboxQuotaObserver::OnEndUpdate(const FileSystemURL& url) { + DCHECK(SandboxMountPointProvider::CanHandleType(url.type())); + DCHECK(update_notify_runner_->RunsTasksOnCurrentThread()); + FilePath usage_file_path = GetUsageCachePath(url); + FileSystemUsageCache::DecrementDirty(usage_file_path); +} + +void SandboxQuotaObserver::OnAccess(const FileSystemURL& url) { + DCHECK(SandboxMountPointProvider::CanHandleType(url.type())); + if (quota_manager_proxy_) { + quota_manager_proxy_->NotifyStorageAccessed( + quota::QuotaClient::kFileSystem, + url.origin(), + FileSystemTypeToQuotaStorageType(url.type())); + } +} + +FilePath SandboxQuotaObserver::GetUsageCachePath(const FileSystemURL& url) { + DCHECK(sandbox_provider_); + return sandbox_provider_->GetUsageCachePathForOriginAndType( + url.origin(), url.type()); +} + +} // namespace fileapi diff --git a/webkit/fileapi/sandbox_quota_observer.h b/webkit/fileapi/sandbox_quota_observer.h new file mode 100644 index 0000000..82b239f --- /dev/null +++ b/webkit/fileapi/sandbox_quota_observer.h @@ -0,0 +1,60 @@ +// 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. + +#ifndef WEBKIT_FILEAPI_SANDBOX_QUOTA_OBSERVER_H_ +#define WEBKIT_FILEAPI_SANDBOX_QUOTA_OBSERVER_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/file_path.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "webkit/fileapi/file_observers.h" + +namespace base { +class SequencedTaskRunner; +} + +namespace quota { +class QuotaManagerProxy; +} + +namespace fileapi { + +class FileSystemURL; +class SandboxMountPointProvider; + +class SandboxQuotaObserver + : public FileUpdateObserver, + public FileAccessObserver { + public: + SandboxQuotaObserver( + quota::QuotaManagerProxy* quota_manager_proxy, + base::SequencedTaskRunner* update_notify_runner, + SandboxMountPointProvider* sandbox_provider); + virtual ~SandboxQuotaObserver(); + + // FileUpdateObserver overrides. + virtual void OnStartUpdate(const FileSystemURL& url) OVERRIDE; + virtual void OnUpdate(const FileSystemURL& url, int64 delta) OVERRIDE; + virtual void OnEndUpdate(const FileSystemURL& url) OVERRIDE; + + // FileAccessObserver overrides. + virtual void OnAccess(const FileSystemURL& url) OVERRIDE; + + private: + FilePath GetUsageCachePath(const FileSystemURL& url); + + scoped_refptr<quota::QuotaManagerProxy> quota_manager_proxy_; + scoped_refptr<base::SequencedTaskRunner> update_notify_runner_; + + // Not owned; provider owns this. + SandboxMountPointProvider* sandbox_provider_; + + DISALLOW_COPY_AND_ASSIGN(SandboxQuotaObserver); +}; + +} // namespace fileapi + +#endif // WEBKIT_FILEAPI_SANDBOX_QUOTA_OBSERVER_H_ diff --git a/webkit/fileapi/task_runner_bound_observer_list.h b/webkit/fileapi/task_runner_bound_observer_list.h new file mode 100644 index 0000000..17a8eec --- /dev/null +++ b/webkit/fileapi/task_runner_bound_observer_list.h @@ -0,0 +1,104 @@ +// 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. + +#ifndef WEBKIT_FILEAPI_TASK_RUNNER_BOUND_OBSERVER_LIST_H_ +#define WEBKIT_FILEAPI_TASK_RUNNER_BOUND_OBSERVER_LIST_H_ + +#include <map> + +#include "base/basictypes.h" +#include "base/bind.h" +#include "base/memory/ref_counted.h" +#include "base/sequenced_task_runner.h" +#include "base/threading/thread.h" + +namespace fileapi { + +// A wrapper for dispatching method. +template <class T, class Method, class Params> +void NotifyWrapper(T obj, Method m, const Params& p) { + DispatchToMethod(base::internal::UnwrapTraits<T>::Unwrap(obj), m, p); +} + +// An observer list helper to notify on a given task runner. +// Observer pointers (stored as ObserverStoreType) must be kept alive +// until this list dispatches all the notifications. +// +// Unlike regular ObserverList or ObserverListThreadSafe internal observer +// list is immutable (though not declared const) and cannot be modified after +// constructed. +// +// It is ok to specify scoped_refptr<Observer> as ObserverStoreType to +// explicitly keep references if necessary. +template <class Observer, class ObserverStoreType = Observer*> +class TaskRunnerBoundObserverList { + public: + // A constructor parameter class. + class Source { + public: + typedef scoped_refptr<base::SequencedTaskRunner> TaskRunnerPtr; + typedef std::map<ObserverStoreType, TaskRunnerPtr> ObserversListMap; + + // Add |observer| to the list parameter. The |observer| will be notified on + // the |runner_to_notify| runner. It is valid to give NULL as + // |runner_to_notify| (in such case notifications are dispatched on + // the current runner). + void AddObserver(Observer* observer, + base::SequencedTaskRunner* runner_to_notify) { + observers_.insert(std::make_pair(observer, runner_to_notify)); + } + + const ObserversListMap& observers() const { return observers_; } + + private: + ObserversListMap observers_; + }; + + // Creates an empty list. + TaskRunnerBoundObserverList<Observer, ObserverStoreType>() {} + + // Creates a new list with given |observers_param|. + explicit TaskRunnerBoundObserverList<Observer, ObserverStoreType>( + const Source& source) + : observers_(source.observers()) {} + + virtual ~TaskRunnerBoundObserverList<Observer, ObserverStoreType>() {} + + // Notify on the task runner that is given to AddObserver. + // If we're already on the runner this just dispatches the method. + template <class Method, class Params> + void Notify(Method method, const Params& params) const { + COMPILE_ASSERT( + (base::internal::ParamsUseScopedRefptrCorrectly<Params>::value), + badunboundmethodparams); + for (typename ObserversListMap::const_iterator it = observers_.begin(); + it != observers_.end(); ++it) { + if (!it->second.get() || it->second->RunsTasksOnCurrentThread()) { + DispatchToMethod(UnwrapTraits::Unwrap(it->first), method, params); + continue; + } + it->second->PostTask( + FROM_HERE, + base::Bind(&NotifyWrapper<ObserverStoreType, Method, Params>, + it->first, method, params)); + } + } + + private: + typedef base::internal::UnwrapTraits<ObserverStoreType> UnwrapTraits; + typedef scoped_refptr<base::SequencedTaskRunner> TaskRunnerPtr; + typedef std::map<ObserverStoreType, TaskRunnerPtr> ObserversListMap; + + ObserversListMap observers_; +}; + +class FileAccessObserver; +class FileUpdateObserver; + +typedef TaskRunnerBoundObserverList<FileAccessObserver> AccessObserverList; +typedef TaskRunnerBoundObserverList<FileUpdateObserver> UpdateObserverList; + +} // namespace fileapi + +#endif // WEBKIT_FILEAPI_TASK_RUNNER_BOUND_OBSERVER_LIST_H_ diff --git a/webkit/fileapi/test_mount_point_provider.cc b/webkit/fileapi/test_mount_point_provider.cc index 0e2af00..58f4a47 100644 --- a/webkit/fileapi/test_mount_point_provider.cc +++ b/webkit/fileapi/test_mount_point_provider.cc @@ -10,6 +10,7 @@ #include "base/file_util.h" #include "base/sequenced_task_runner.h" +#include "webkit/fileapi/file_observers.h" #include "webkit/fileapi/file_system_file_stream_reader.h" #include "webkit/fileapi/file_system_quota_util.h" #include "webkit/fileapi/file_system_util.h" @@ -21,15 +22,15 @@ namespace fileapi { -namespace { - // This only supports single origin. -class TestFileSystemQuotaUtil : public FileSystemQuotaUtil { +class TestMountPointProvider::QuotaUtil + : public FileSystemQuotaUtil, + public FileUpdateObserver { public: - explicit TestFileSystemQuotaUtil(base::SequencedTaskRunner* task_runner) - : FileSystemQuotaUtil(task_runner), usage_(0) {} - virtual ~TestFileSystemQuotaUtil() {} + QuotaUtil() : usage_(0) {} + virtual ~QuotaUtil() {} + // FileSystemQuotaUtil overrides. virtual void GetOriginsForTypeOnFileThread( FileSystemType type, std::set<GURL>* origins) OVERRIDE { @@ -47,44 +48,32 @@ class TestFileSystemQuotaUtil : public FileSystemQuotaUtil { FileSystemType type) OVERRIDE { return usage_; } - virtual void NotifyOriginWasAccessedOnIOThread( - quota::QuotaManagerProxy* proxy, - const GURL& origin_url, - FileSystemType type) OVERRIDE { - // Do nothing. - } - virtual void UpdateOriginUsageOnFileThread( - quota::QuotaManagerProxy* proxy, - const GURL& origin_url, - FileSystemType type, - int64 delta) OVERRIDE { - usage_ += delta; - } - virtual void StartUpdateOriginOnFileThread( - const GURL& origin_url, - FileSystemType type) OVERRIDE { - // Do nothing. - } - virtual void EndUpdateOriginOnFileThread( - const GURL& origin_url, - FileSystemType type) OVERRIDE {} virtual void InvalidateUsageCache(const GURL& origin_url, FileSystemType type) OVERRIDE { // Do nothing. } + // FileUpdateObserver overrides. + virtual void OnStartUpdate(const FileSystemURL& url) OVERRIDE {} + virtual void OnUpdate(const FileSystemURL& url, int64 delta) OVERRIDE { + usage_ += delta; + } + virtual void OnEndUpdate(const FileSystemURL& url) OVERRIDE {} + private: int64 usage_; }; -} // namespace - TestMountPointProvider::TestMountPointProvider( base::SequencedTaskRunner* task_runner, const FilePath& base_path) : base_path_(base_path), + task_runner_(task_runner), local_file_util_(new LocalFileUtil()), - quota_util_(new TestFileSystemQuotaUtil(task_runner)) { + quota_util_(new QuotaUtil) { + UpdateObserverList::Source source; + source.AddObserver(quota_util_.get(), task_runner_); + observers_ = UpdateObserverList(source); } TestMountPointProvider::~TestMountPointProvider() { @@ -137,6 +126,7 @@ FileSystemOperation* TestMountPointProvider::CreateFileSystemOperation( FileSystemContext* context) const { scoped_ptr<FileSystemOperationContext> operation_context( new FileSystemOperationContext(context)); + operation_context->set_update_observers(observers_); return new LocalFileSystemOperation(context, operation_context.Pass()); } @@ -151,7 +141,7 @@ fileapi::FileStreamWriter* TestMountPointProvider::CreateFileStreamWriter( const FileSystemURL& url, int64 offset, FileSystemContext* context) const { - return new SandboxFileStreamWriter(context, url, offset); + return new SandboxFileStreamWriter(context, url, offset, observers_); } FileSystemQuotaUtil* TestMountPointProvider::GetQuotaUtil() { @@ -169,4 +159,9 @@ void TestMountPointProvider::DeleteFileSystem( callback.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION); } +const UpdateObserverList* TestMountPointProvider::GetUpdateObservers( + FileSystemType type) const { + return &observers_; +} + } // namespace fileapi diff --git a/webkit/fileapi/test_mount_point_provider.h b/webkit/fileapi/test_mount_point_provider.h index 7e88c45..6f9b04c 100644 --- a/webkit/fileapi/test_mount_point_provider.h +++ b/webkit/fileapi/test_mount_point_provider.h @@ -8,8 +8,9 @@ #include "base/file_path.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" -#include "webkit/fileapi/fileapi_export.h" #include "webkit/fileapi/file_system_mount_point_provider.h" +#include "webkit/fileapi/fileapi_export.h" +#include "webkit/fileapi/task_runner_bound_observer_list.h" namespace base { class SequencedTaskRunner; @@ -68,10 +69,16 @@ class FILEAPI_EXPORT_PRIVATE TestMountPointProvider FileSystemContext* context, const DeleteFileSystemCallback& callback) OVERRIDE; + const UpdateObserverList* GetUpdateObservers(FileSystemType type) const; + private: + class QuotaUtil; + FilePath base_path_; + scoped_refptr<base::SequencedTaskRunner> task_runner_; scoped_ptr<LocalFileUtil> local_file_util_; - scoped_ptr<FileSystemQuotaUtil> quota_util_; + scoped_ptr<QuotaUtil> quota_util_; + UpdateObserverList observers_; }; } // namespace fileapi diff --git a/webkit/fileapi/webkit_fileapi.gypi b/webkit/fileapi/webkit_fileapi.gypi index 51eb80d..2b144e2 100644 --- a/webkit/fileapi/webkit_fileapi.gypi +++ b/webkit/fileapi/webkit_fileapi.gypi @@ -19,6 +19,7 @@ ], 'defines': ['FILEAPI_IMPLEMENTATION'], 'sources': [ + 'file_observers.h', 'file_stream_writer.h', 'file_system_callback_dispatcher.cc', 'file_system_callback_dispatcher.h', @@ -44,11 +45,10 @@ 'file_system_origin_database.h', 'file_system_quota_client.cc', 'file_system_quota_client.h', - 'file_system_quota_util.cc', 'file_system_quota_util.h', - 'file_system_types.h', 'file_system_task_runners.cc', 'file_system_task_runners.h', + 'file_system_types.h', 'file_system_url.cc', 'file_system_url.h', 'file_system_url_request_job.cc', @@ -90,6 +90,9 @@ 'sandbox_file_stream_writer.h', 'sandbox_mount_point_provider.cc', 'sandbox_mount_point_provider.h', + 'sandbox_quota_observer.cc', + 'sandbox_quota_observer.h', + 'task_runner_bound_observer_list.h', 'test_mount_point_provider.cc', 'test_mount_point_provider.h', 'webfilewriter_base.cc', |