diff options
author | kinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-18 14:06:11 +0000 |
---|---|---|
committer | kinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-18 14:06:11 +0000 |
commit | fc2e14faf27be8cb92f54029b4b8eccb9e5705b0 (patch) | |
tree | e17a402d900fef82804e5a817d37181450055d01 /webkit/fileapi | |
parent | 3e62727dcb4fbb74386271beea01dd0708491883 (diff) | |
download | chromium_src-fc2e14faf27be8cb92f54029b4b8eccb9e5705b0.zip chromium_src-fc2e14faf27be8cb92f54029b4b8eccb9e5705b0.tar.gz chromium_src-fc2e14faf27be8cb92f54029b4b8eccb9e5705b0.tar.bz2 |
Add operation runner for SyncableFileSystem
BUG=148897
TEST=Syncable*,LocalFileSync*
Review URL: https://codereview.chromium.org/11093071
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@162700 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/fileapi')
15 files changed, 1007 insertions, 70 deletions
diff --git a/webkit/fileapi/local_file_system_test_helper.cc b/webkit/fileapi/local_file_system_test_helper.cc index bdd9957..1983c1e 100644 --- a/webkit/fileapi/local_file_system_test_helper.cc +++ b/webkit/fileapi/local_file_system_test_helper.cc @@ -174,6 +174,8 @@ LocalFileSystemTestOriginHelper::ComputeCurrentDirectoryDatabaseUsage() const { LocalFileSystemOperation* LocalFileSystemTestOriginHelper::NewOperation() { DCHECK(file_system_context_.get()); DCHECK(file_util_); + scoped_ptr<FileSystemOperationContext> operation_context( + NewOperationContext()); LocalFileSystemOperation* operation = static_cast<LocalFileSystemOperation*>( file_system_context_->CreateFileSystemOperation( CreateURL(FilePath()), NULL)); diff --git a/webkit/fileapi/sandbox_mount_point_provider.cc b/webkit/fileapi/sandbox_mount_point_provider.cc index 400cea6..3773f227 100644 --- a/webkit/fileapi/sandbox_mount_point_provider.cc +++ b/webkit/fileapi/sandbox_mount_point_provider.cc @@ -29,6 +29,7 @@ #include "webkit/fileapi/obfuscated_file_util.h" #include "webkit/fileapi/sandbox_file_stream_writer.h" #include "webkit/fileapi/sandbox_quota_observer.h" +#include "webkit/fileapi/syncable/syncable_file_system_operation.h" #include "webkit/glue/webkit_glue.h" #include "webkit/quota/quota_manager.h" @@ -458,11 +459,15 @@ FileSystemOperation* SandboxMountPointProvider::CreateFileSystemOperation( if (url.type() == kFileSystemTypeSyncable) { operation_context->set_update_observers(syncable_update_observers_); operation_context->set_change_observers(syncable_change_observers_); - } else { - operation_context->set_update_observers(update_observers_); + operation_context->set_access_observers(access_observers_); + return new SyncableFileSystemOperation( + context, + new LocalFileSystemOperation(context, operation_context.Pass())); } - operation_context->set_access_observers(access_observers_); + // For regular sandboxed types. + operation_context->set_update_observers(update_observers_); + operation_context->set_access_observers(access_observers_); return new LocalFileSystemOperation(context, operation_context.Pass()); } diff --git a/webkit/fileapi/syncable/canned_syncable_file_system.cc b/webkit/fileapi/syncable/canned_syncable_file_system.cc index ff7992b..d78c328 100644 --- a/webkit/fileapi/syncable/canned_syncable_file_system.cc +++ b/webkit/fileapi/syncable/canned_syncable_file_system.cc @@ -226,6 +226,24 @@ PlatformFileError CannedSyncableFileSystem::Remove( base::Unretained(this), url, recursive)); } +PlatformFileError CannedSyncableFileSystem::FileExists( + const FileSystemURL& url) { + return RunOnThread<PlatformFileError>( + io_task_runner_, + FROM_HERE, + base::Bind(&CannedSyncableFileSystem::DoFileExists, + base::Unretained(this), url)); +} + +PlatformFileError CannedSyncableFileSystem::DirectoryExists( + const FileSystemURL& url) { + return RunOnThread<PlatformFileError>( + io_task_runner_, + FROM_HERE, + base::Bind(&CannedSyncableFileSystem::DoDirectoryExists, + base::Unretained(this), url)); +} + int64 CannedSyncableFileSystem::Write( net::URLRequestContext* url_request_context, const FileSystemURL& url, const GURL& blob_url) { @@ -296,6 +314,18 @@ void CannedSyncableFileSystem::DoRemove( NewOperation()->Remove(url, recursive, callback); } +void CannedSyncableFileSystem::DoFileExists( + const FileSystemURL& url, const StatusCallback& callback) { + EXPECT_TRUE(is_filesystem_opened_); + NewOperation()->FileExists(url, callback); +} + +void CannedSyncableFileSystem::DoDirectoryExists( + const FileSystemURL& url, const StatusCallback& callback) { + EXPECT_TRUE(is_filesystem_opened_); + NewOperation()->DirectoryExists(url, callback); +} + void CannedSyncableFileSystem::DoWrite( net::URLRequestContext* url_request_context, const FileSystemURL& url, const GURL& blob_url, diff --git a/webkit/fileapi/syncable/canned_syncable_file_system.h b/webkit/fileapi/syncable/canned_syncable_file_system.h index 4fa634e..6c94b01 100644 --- a/webkit/fileapi/syncable/canned_syncable_file_system.h +++ b/webkit/fileapi/syncable/canned_syncable_file_system.h @@ -87,6 +87,8 @@ class CannedSyncableFileSystem { const FileSystemURL& dest_url); base::PlatformFileError TruncateFile(const FileSystemURL& url, int64 size); base::PlatformFileError Remove(const FileSystemURL& url, bool recursive); + base::PlatformFileError FileExists(const FileSystemURL& url); + base::PlatformFileError DirectoryExists(const FileSystemURL& url); // Returns the # of bytes written (>=0) or an error code (<0). int64 Write(net::URLRequestContext* url_request_context, @@ -116,6 +118,10 @@ class CannedSyncableFileSystem { void DoRemove(const FileSystemURL& url, bool recursive, const StatusCallback& callback); + void DoFileExists(const FileSystemURL& url, + const StatusCallback& callback); + void DoDirectoryExists(const FileSystemURL& url, + const StatusCallback& callback); void DoWrite(net::URLRequestContext* url_request_context, const FileSystemURL& url, const GURL& blob_url, diff --git a/webkit/fileapi/syncable/local_file_sync_context.cc b/webkit/fileapi/syncable/local_file_sync_context.cc index a8a89f5..a325829 100644 --- a/webkit/fileapi/syncable/local_file_sync_context.cc +++ b/webkit/fileapi/syncable/local_file_sync_context.cc @@ -13,6 +13,7 @@ #include "webkit/fileapi/file_system_context.h" #include "webkit/fileapi/file_system_task_runners.h" #include "webkit/fileapi/syncable/local_file_change_tracker.h" +#include "webkit/fileapi/syncable/syncable_file_operation_runner.h" namespace fileapi { @@ -59,10 +60,20 @@ void LocalFileSyncContext::ShutdownOnUIThread() { this)); } -LocalFileSyncContext::~LocalFileSyncContext() {} +base::WeakPtr<SyncableFileOperationRunner> +LocalFileSyncContext::operation_runner() const { + DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); + if (operation_runner_.get()) + return operation_runner_->AsWeakPtr(); + return base::WeakPtr<SyncableFileOperationRunner>(); +} + +LocalFileSyncContext::~LocalFileSyncContext() { +} void LocalFileSyncContext::ShutdownOnIOThread() { DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); + operation_runner_.reset(); } void LocalFileSyncContext::InitializeFileSystemContextOnIOThread( @@ -87,6 +98,8 @@ void LocalFileSyncContext::InitializeFileSystemContextOnIOThread( make_scoped_refptr(file_system_context))); return; } + if (!operation_runner_.get()) + operation_runner_.reset(new SyncableFileOperationRunner); file_system_context->set_sync_context(this); DidInitialize(source_url, file_system_context, SYNC_STATUS_OK); } diff --git a/webkit/fileapi/syncable/local_file_sync_context.h b/webkit/fileapi/syncable/local_file_sync_context.h index aeba4d4..c02d81a 100644 --- a/webkit/fileapi/syncable/local_file_sync_context.h +++ b/webkit/fileapi/syncable/local_file_sync_context.h @@ -15,6 +15,7 @@ #include "base/logging.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" #include "googleurl/src/gurl.h" #include "webkit/fileapi/syncable/file_change.h" #include "webkit/fileapi/syncable/sync_status_code.h" @@ -28,6 +29,7 @@ namespace fileapi { class FileSystemContext; class LocalFileChangeTracker; +class SyncableFileOperationRunner; // This class works as a bridge between LocalFileSyncService (which is a // per-profile object) and FileSystemContext's (which is a per-storage-partition @@ -54,6 +56,9 @@ class WEBKIT_STORAGE_EXPORT LocalFileSyncContext // This method must be called on UI thread. void ShutdownOnUIThread(); + // OperationRunner is accessible only on IO thread. + base::WeakPtr<SyncableFileOperationRunner> operation_runner() const; + private: typedef std::deque<StatusCallback> StatusCallbackQueue; friend class base::RefCountedThreadSafe<LocalFileSyncContext>; @@ -83,6 +88,9 @@ class WEBKIT_STORAGE_EXPORT LocalFileSyncContext scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_; scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; + // OperationRunner. This must be accessed only on IO thread. + scoped_ptr<SyncableFileOperationRunner> operation_runner_; + // Pointers to file system contexts that have been initialized for // synchronization (i.e. that own this instance). // This must be accessed only on UI thread. diff --git a/webkit/fileapi/syncable/local_file_sync_status.cc b/webkit/fileapi/syncable/local_file_sync_status.cc index b3aea58..3be00e3 100644 --- a/webkit/fileapi/syncable/local_file_sync_status.cc +++ b/webkit/fileapi/syncable/local_file_sync_status.cc @@ -12,32 +12,26 @@ LocalFileSyncStatus::LocalFileSyncStatus() {} LocalFileSyncStatus::~LocalFileSyncStatus() {} -bool LocalFileSyncStatus::TryIncrementWriting(const FileSystemURL& url) { +void LocalFileSyncStatus::StartWriting(const FileSystemURL& url) { DCHECK(CalledOnValidThread()); - if (IsChildOrParentSyncing(url)) - return false; + DCHECK(!IsChildOrParentSyncing(url)); writing_[url]++; - return true; } -void LocalFileSyncStatus::DecrementWriting(const FileSystemURL& url) { +void LocalFileSyncStatus::EndWriting(const FileSystemURL& url) { DCHECK(CalledOnValidThread()); int count = --writing_[url]; - if (count == 0) { + if (count == 0) writing_.erase(url); - // TODO(kinuko): fire NeedsSynchronization notification. - } } -bool LocalFileSyncStatus::TryDisableWriting(const FileSystemURL& url) { +void LocalFileSyncStatus::StartSyncing(const FileSystemURL& url) { DCHECK(CalledOnValidThread()); - if (IsChildOrParentWriting(url)) - return false; + DCHECK(!IsChildOrParentWriting(url)); syncing_.insert(url); - return true; } -void LocalFileSyncStatus::EnableWriting(const FileSystemURL& url) { +void LocalFileSyncStatus::EndSyncing(const FileSystemURL& url) { DCHECK(CalledOnValidThread()); syncing_.erase(url); } diff --git a/webkit/fileapi/syncable/local_file_sync_status.h b/webkit/fileapi/syncable/local_file_sync_status.h index 3410a54..f99b84e 100644 --- a/webkit/fileapi/syncable/local_file_sync_status.h +++ b/webkit/fileapi/syncable/local_file_sync_status.h @@ -30,19 +30,19 @@ class WEBKIT_STORAGE_EXPORT LocalFileSyncStatus : public base::NonThreadSafe { LocalFileSyncStatus(); ~LocalFileSyncStatus(); - // Tries to increment writing counter for |url|. - // This fails if the target |url| is in syncing. - bool TryIncrementWriting(const FileSystemURL& url); + // Increment writing counter for |url|. + // This should not be called if the |url| is not writable. + void StartWriting(const FileSystemURL& url); // Decrement writing counter for |url|. - void DecrementWriting(const FileSystemURL& url); + void EndWriting(const FileSystemURL& url); - // Tries to mark syncing flag for |url| to enable writing. - // This fails if the target |url| is in writing. - bool TryDisableWriting(const FileSystemURL& url); + // Start syncing for |url| and disable writing. + // This should not be called if |url| is in writing. + void StartSyncing(const FileSystemURL& url); - // Clears the syncing flag for |url| to disable writing. - void EnableWriting(const FileSystemURL& url); + // Clears the syncing flag for |url| and enable writing. + void EndSyncing(const FileSystemURL& url); // Returns true if the |url| or its parent or child is in writing. bool IsWriting(const FileSystemURL& url) const; @@ -54,7 +54,6 @@ class WEBKIT_STORAGE_EXPORT LocalFileSyncStatus : public base::NonThreadSafe { typedef std::map<FileSystemURL, int64, FileSystemURL::Comparator> URLCountMap; typedef std::set<FileSystemURL, FileSystemURL::Comparator> URLSet; - // These private methods must be called with the lock_ held. bool IsChildOrParentWriting(const FileSystemURL& url) const; bool IsChildOrParentSyncing(const FileSystemURL& url) const; diff --git a/webkit/fileapi/syncable/local_file_sync_status_unittest.cc b/webkit/fileapi/syncable/local_file_sync_status_unittest.cc index d165aca..c402369 100644 --- a/webkit/fileapi/syncable/local_file_sync_status_unittest.cc +++ b/webkit/fileapi/syncable/local_file_sync_status_unittest.cc @@ -27,9 +27,10 @@ FileSystemURL URL(const char* spec) { TEST(LocalFileSyncStatusTest, WritingSimple) { LocalFileSyncStatus status; - ASSERT_TRUE(status.TryIncrementWriting(URL(kFile))); - ASSERT_TRUE(status.TryIncrementWriting(URL(kFile))); - status.DecrementWriting(URL(kFile)); + + status.StartWriting(URL(kFile)); + status.StartWriting(URL(kFile)); + status.EndWriting(URL(kFile)); EXPECT_TRUE(status.IsWriting(URL(kFile))); EXPECT_TRUE(status.IsWriting(URL(kParent))); @@ -37,16 +38,16 @@ TEST(LocalFileSyncStatusTest, WritingSimple) { EXPECT_FALSE(status.IsWriting(URL(kOther1))); EXPECT_FALSE(status.IsWriting(URL(kOther2))); - status.DecrementWriting(URL(kFile)); + status.EndWriting(URL(kFile)); EXPECT_FALSE(status.IsWriting(URL(kFile))); EXPECT_FALSE(status.IsWriting(URL(kParent))); EXPECT_FALSE(status.IsWriting(URL(kChild))); } -TEST(LocalFileSyncStatusTest, DisableWritingSimple) { +TEST(LocalFileSyncStatusTest, SyncingSimple) { LocalFileSyncStatus status; - ASSERT_TRUE(status.TryDisableWriting(URL(kFile))); + status.StartSyncing(URL(kFile)); EXPECT_FALSE(status.IsWritable(URL(kFile))); EXPECT_FALSE(status.IsWritable(URL(kParent))); @@ -54,47 +55,11 @@ TEST(LocalFileSyncStatusTest, DisableWritingSimple) { EXPECT_TRUE(status.IsWritable(URL(kOther1))); EXPECT_TRUE(status.IsWritable(URL(kOther2))); - status.EnableWriting(URL(kFile)); + status.EndSyncing(URL(kFile)); EXPECT_TRUE(status.IsWritable(URL(kFile))); EXPECT_TRUE(status.IsWritable(URL(kParent))); EXPECT_TRUE(status.IsWritable(URL(kChild))); } -TEST(LocalFileSyncStatusTest, TryWriting) { - LocalFileSyncStatus status; - - ASSERT_TRUE(status.TryDisableWriting(URL(kFile))); - EXPECT_FALSE(status.IsWritable(URL(kFile))); - - ASSERT_FALSE(status.TryIncrementWriting(URL(kFile))); - ASSERT_FALSE(status.TryIncrementWriting(URL(kParent))); - ASSERT_FALSE(status.TryIncrementWriting(URL(kChild))); - - status.EnableWriting(URL(kFile)); - EXPECT_TRUE(status.IsWritable(URL(kFile))); - - ASSERT_TRUE(status.TryIncrementWriting(URL(kFile))); - ASSERT_TRUE(status.TryIncrementWriting(URL(kParent))); - ASSERT_TRUE(status.TryIncrementWriting(URL(kChild))); -} - -TEST(LocalFileSyncStatusTest, TryDisableWriting) { - LocalFileSyncStatus status; - - ASSERT_TRUE(status.TryIncrementWriting(URL(kFile))); - EXPECT_TRUE(status.IsWritable(URL(kFile))); - - ASSERT_FALSE(status.TryDisableWriting(URL(kFile))); - ASSERT_FALSE(status.TryDisableWriting(URL(kParent))); - ASSERT_FALSE(status.TryDisableWriting(URL(kChild))); - - status.DecrementWriting(URL(kFile)); - EXPECT_FALSE(status.IsWriting(URL(kFile))); - - ASSERT_TRUE(status.TryDisableWriting(URL(kFile))); - ASSERT_TRUE(status.TryDisableWriting(URL(kParent))); - ASSERT_TRUE(status.TryDisableWriting(URL(kChild))); -} - } // namespace fileapi diff --git a/webkit/fileapi/syncable/syncable_file_operation_runner.cc b/webkit/fileapi/syncable/syncable_file_operation_runner.cc new file mode 100644 index 0000000..ef9c899 --- /dev/null +++ b/webkit/fileapi/syncable/syncable_file_operation_runner.cc @@ -0,0 +1,83 @@ +// 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/syncable/syncable_file_operation_runner.h" + +#include <algorithm> +#include <functional> + +#include "base/callback.h" +#include "base/stl_util.h" +#include "webkit/fileapi/syncable/local_file_sync_status.h" + +namespace fileapi { + +// SyncableFileOperationRunner::Task ------------------------------------------- + +// static +void SyncableFileOperationRunner::Task::CancelAndDelete( + SyncableFileOperationRunner::Task* task) { + task->Cancel(); + delete task; +} + +bool SyncableFileOperationRunner::Task::IsRunnable( + LocalFileSyncStatus* status) const { + for (size_t i = 0; i < target_paths().size(); ++i) { + if (!status->IsWritable(target_paths()[i])) + return false; + } + return true; +} + +void SyncableFileOperationRunner::Task::Start(LocalFileSyncStatus* status) { + for (size_t i = 0; i < target_paths().size(); ++i) { + DCHECK(status->IsWritable(target_paths()[i])); + status->StartWriting(target_paths()[i]); + } + Run(); +} + +// SyncableFileOperationRunner ------------------------------------------------- + +SyncableFileOperationRunner::SyncableFileOperationRunner() + : sync_status_(new LocalFileSyncStatus) { + DCHECK(CalledOnValidThread()); +} + +SyncableFileOperationRunner::~SyncableFileOperationRunner() { + DCHECK(CalledOnValidThread()); + for_each(pending_operations_.begin(), pending_operations_.end(), + SyncableFileOperationRunner::Task::CancelAndDelete); +} + +void SyncableFileOperationRunner::PostOperationTask(scoped_ptr<Task> task) { + DCHECK(CalledOnValidThread()); + pending_operations_.push_back(task.release()); + RunNextRunnableTask(); +} + +void SyncableFileOperationRunner::RunNextRunnableTask() { + DCHECK(CalledOnValidThread()); + for (std::list<Task*>::iterator iter = pending_operations_.begin(); + iter != pending_operations_.end(); ++iter) { + if ((*iter)->IsRunnable(sync_status())) { + scoped_ptr<Task> task(*iter); + pending_operations_.erase(iter); + task->Start(sync_status()); + return; + } + } +} + +void SyncableFileOperationRunner::OnOperationCompleted( + const std::vector<FileSystemURL>& target_paths) { + for (size_t i = 0; i < target_paths.size(); ++i) { + DCHECK(sync_status()->IsWriting(target_paths[i])); + sync_status()->EndWriting(target_paths[i]); + } + RunNextRunnableTask(); +} + +} // namespace fileapi diff --git a/webkit/fileapi/syncable/syncable_file_operation_runner.h b/webkit/fileapi/syncable/syncable_file_operation_runner.h new file mode 100644 index 0000000..95cf5c6 --- /dev/null +++ b/webkit/fileapi/syncable/syncable_file_operation_runner.h @@ -0,0 +1,85 @@ +// 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_SYNCABLE_SYNCABLE_FILE_OPERATION_RUNNER_H_ +#define WEBKIT_FILEAPI_SYNCABLE_SYNCABLE_FILE_OPERATION_RUNNER_H_ + +#include <list> +#include <vector> + +#include "base/basictypes.h" +#include "base/callback.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/threading/non_thread_safe.h" +#include "webkit/fileapi/file_system_url.h" +#include "webkit/storage/webkit_storage_export.h" + +namespace fileapi { + +class FileSystemURL; +class LocalFileSyncStatus; + +// This class must run only on IO thread. +// Owned by LocalFileSyncContext. +class WEBKIT_STORAGE_EXPORT SyncableFileOperationRunner + : public base::NonThreadSafe, + public base::SupportsWeakPtr<SyncableFileOperationRunner> { + public: + // Represents an operation task (which usually wraps one FileSystemOperation). + class Task { + public: + Task() {} + virtual ~Task() {} + + // Only one of Run() or Cancel() is called. + virtual void Run() = 0; + virtual void Cancel() = 0; + + protected: + // This is never called after Run() or Cancel() is called. + virtual const std::vector<FileSystemURL>& target_paths() const = 0; + + private: + friend class SyncableFileOperationRunner; + bool IsRunnable(LocalFileSyncStatus* status) const; + void Start(LocalFileSyncStatus* status); + static void CancelAndDelete(Task* task); + + DISALLOW_COPY_AND_ASSIGN(Task); + }; + + SyncableFileOperationRunner(); + ~SyncableFileOperationRunner(); + + // Runs the given |task| if no sync operation is running on any of + // its target_paths(). This also runs pending operations that have become + // runnable (before running the given operation). + // If there're ongoing sync operations on the target_paths this method + // just queues up the |task|. + // Pending operations are cancelled when this class is destructed. + void PostOperationTask(scoped_ptr<Task> task); + + // Runs a next runnable task (if there's any). + void RunNextRunnableTask(); + + // Called when an operation is completed. This will make |target_paths| + // writable and may start a next runnable task. + void OnOperationCompleted(const std::vector<FileSystemURL>& target_paths); + + // For syncable file systems. + LocalFileSyncStatus* sync_status() const { return sync_status_.get(); } + + private: + // Keeps track of the writing/syncing status. + scoped_ptr<LocalFileSyncStatus> sync_status_; + + std::list<Task*> pending_operations_; + + DISALLOW_COPY_AND_ASSIGN(SyncableFileOperationRunner); +}; + +} // namespace fileapi + +#endif // WEBKIT_FILEAPI_SYNCABLE_SYNCABLE_FILE_OPERATION_RUNNER_H_ diff --git a/webkit/fileapi/syncable/syncable_file_operation_runner_unittest.cc b/webkit/fileapi/syncable/syncable_file_operation_runner_unittest.cc new file mode 100644 index 0000000..f577e91 --- /dev/null +++ b/webkit/fileapi/syncable/syncable_file_operation_runner_unittest.cc @@ -0,0 +1,334 @@ +// 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 "base/basictypes.h" +#include "base/location.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "webkit/blob/mock_blob_url_request_context.h" +#include "webkit/fileapi/file_system_context.h" +#include "webkit/fileapi/syncable/canned_syncable_file_system.h" +#include "webkit/fileapi/syncable/local_file_change_tracker.h" +#include "webkit/fileapi/syncable/local_file_sync_context.h" +#include "webkit/fileapi/syncable/local_file_sync_status.h" +#include "webkit/fileapi/syncable/syncable_file_operation_runner.h" +#include "webkit/fileapi/syncable/syncable_file_system_operation.h" +#include "webkit/fileapi/syncable/syncable_file_system_util.h" + +using webkit_blob::MockBlobURLRequestContext; +using webkit_blob::ScopedTextBlob; +using base::PlatformFileError; + +namespace fileapi { + +namespace { +const std::string kServiceName = "test"; +const std::string kParent = "foo"; +const std::string kFile = "foo/file"; +const std::string kDir = "foo/dir"; +const std::string kChild = "foo/dir/bar"; +const std::string kOther = "bar"; +} // namespace + +class SyncableFileOperationRunnerTest : public testing::Test { + protected: + typedef FileSystemOperation::StatusCallback StatusCallback; + + // Use the current thread as IO thread so that we can directly call + // operations in the tests. + SyncableFileOperationRunnerTest() + : message_loop_(MessageLoop::TYPE_IO), + file_system_(GURL("http://example.com"), kServiceName, + base::MessageLoopProxy::current()), + callback_count_(0), + write_status_(base::PLATFORM_FILE_ERROR_FAILED), + write_bytes_(0), + write_complete_(false), + weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {} + + virtual void SetUp() OVERRIDE { + file_system_.SetUp(); + sync_context_ = new LocalFileSyncContext(base::MessageLoopProxy::current(), + base::MessageLoopProxy::current()); + ASSERT_EQ(SYNC_STATUS_OK, + file_system_.MaybeInitializeFileSystemContext(sync_context_)); + + ASSERT_EQ(base::PLATFORM_FILE_OK, file_system_.OpenFileSystem()); + ASSERT_EQ(base::PLATFORM_FILE_OK, + file_system_.CreateDirectory(URL(kParent))); + } + + virtual void TearDown() OVERRIDE { + if (sync_context_) + sync_context_->ShutdownOnUIThread(); + sync_context_ = NULL; + + file_system_.TearDown(); + message_loop_.RunAllPending(); + RevokeSyncableFileSystem(kServiceName); + } + + FileSystemURL URL(const std::string& path) { + return file_system_.URL(path); + } + + LocalFileSyncContext* sync_context() { + return file_system_.file_system_context()->sync_context(); + } + + SyncableFileOperationRunner* operation_runner() { + return sync_context()->operation_runner().get(); + } + + LocalFileSyncStatus* sync_status() { + return operation_runner()->sync_status(); + } + + void ResetCallbackStatus() { + write_status_ = base::PLATFORM_FILE_ERROR_FAILED; + write_bytes_ = 0; + write_complete_ = false; + callback_count_ = 0; + } + + StatusCallback ExpectStatus(const tracked_objects::Location& location, + PlatformFileError expect) { + return base::Bind(&SyncableFileOperationRunnerTest::DidFinish, + weak_factory_.GetWeakPtr(), location, expect); + } + + FileSystemOperation::WriteCallback GetWriteCallback( + const tracked_objects::Location& location) { + return base::Bind(&SyncableFileOperationRunnerTest::DidWrite, + weak_factory_.GetWeakPtr(), location); + } + + void DidWrite(const tracked_objects::Location& location, + PlatformFileError status, int64 bytes, bool complete) { + SCOPED_TRACE(testing::Message() << location.ToString()); + write_status_ = status; + write_bytes_ += bytes; + write_complete_ = complete; + ++callback_count_; + } + + void DidFinish(const tracked_objects::Location& location, + PlatformFileError expect, PlatformFileError status) { + SCOPED_TRACE(testing::Message() << location.ToString()); + EXPECT_EQ(expect, status); + ++callback_count_; + } + + MessageLoop message_loop_; + CannedSyncableFileSystem file_system_; + scoped_refptr<LocalFileSyncContext> sync_context_; + + int callback_count_; + PlatformFileError write_status_; + size_t write_bytes_; + bool write_complete_; + + MockBlobURLRequestContext url_request_context_; + + base::WeakPtrFactory<SyncableFileOperationRunnerTest> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(SyncableFileOperationRunnerTest); +}; + +TEST_F(SyncableFileOperationRunnerTest, SimpleQueue) { + sync_status()->StartSyncing(URL(kFile)); + ASSERT_FALSE(sync_status()->IsWritable(URL(kFile))); + + // The URL is in syncing so the write operations won't run. + ResetCallbackStatus(); + file_system_.NewOperation()->CreateFile( + URL(kFile), false /* exclusive */, + ExpectStatus(FROM_HERE, base::PLATFORM_FILE_OK)); + file_system_.NewOperation()->Truncate( + URL(kFile), 1, + ExpectStatus(FROM_HERE, base::PLATFORM_FILE_OK)); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(0, callback_count_); + + // Read operations are not blocked (and are executed before queued ones). + file_system_.NewOperation()->FileExists( + URL(kFile), ExpectStatus(FROM_HERE, base::PLATFORM_FILE_ERROR_NOT_FOUND)); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(1, callback_count_); + + // End syncing (to enable write). + sync_status()->EndSyncing(URL(kFile)); + ASSERT_TRUE(sync_status()->IsWritable(URL(kFile))); + + ResetCallbackStatus(); + operation_runner()->RunNextRunnableTask(); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(2, callback_count_); + + // Now the file must have been created and updated. + ResetCallbackStatus(); + file_system_.NewOperation()->FileExists( + URL(kFile), ExpectStatus(FROM_HERE, base::PLATFORM_FILE_OK)); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(1, callback_count_); +} + +TEST_F(SyncableFileOperationRunnerTest, WriteToParentAndChild) { + // First create the kDir directory and kChild in the dir. + EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_.CreateDirectory(URL(kDir))); + EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_.CreateFile(URL(kChild))); + + // Start syncing the kDir directory. + sync_status()->StartSyncing(URL(kDir)); + ASSERT_FALSE(sync_status()->IsWritable(URL(kDir))); + + // Writes to kParent, kDir and kChild should be all queued up. + ResetCallbackStatus(); + file_system_.NewOperation()->Truncate( + URL(kChild), 1, ExpectStatus(FROM_HERE, base::PLATFORM_FILE_OK)); + file_system_.NewOperation()->Remove( + URL(kDir), true /* recursive */, + ExpectStatus(FROM_HERE, base::PLATFORM_FILE_OK)); + file_system_.NewOperation()->Remove( + URL(kParent), true /* recursive */, + ExpectStatus(FROM_HERE, base::PLATFORM_FILE_OK)); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(0, callback_count_); + + // Read operations are not blocked (and are executed before queued ones). + file_system_.NewOperation()->DirectoryExists( + URL(kDir), ExpectStatus(FROM_HERE, base::PLATFORM_FILE_OK)); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(1, callback_count_); + + // Writes to unrelated files must succeed as well. + ResetCallbackStatus(); + file_system_.NewOperation()->CreateDirectory( + URL(kOther), false /* exclusive */, false /* recursive */, + ExpectStatus(FROM_HERE, base::PLATFORM_FILE_OK)); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(1, callback_count_); + + // End syncing (to enable write). + sync_status()->EndSyncing(URL(kDir)); + ASSERT_TRUE(sync_status()->IsWritable(URL(kDir))); + + ResetCallbackStatus(); + operation_runner()->RunNextRunnableTask(); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(3, callback_count_); +} + +TEST_F(SyncableFileOperationRunnerTest, CopyAndMove) { + // First create the kDir directory and kChild in the dir. + EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_.CreateDirectory(URL(kDir))); + EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_.CreateFile(URL(kChild))); + + // Start syncing the kParent directory. + sync_status()->StartSyncing(URL(kParent)); + + // Copying kDir to other directory should succeed, while moving would fail + // (since the source directory is in syncing). + ResetCallbackStatus(); + file_system_.NewOperation()->Copy( + URL(kDir), URL("dest-copy"), + ExpectStatus(FROM_HERE, base::PLATFORM_FILE_OK)); + file_system_.NewOperation()->Move( + URL(kDir), URL("dest-move"), + ExpectStatus(FROM_HERE, base::PLATFORM_FILE_OK)); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(1, callback_count_); + + // Only "dest-copy1" should exist. + EXPECT_EQ(base::PLATFORM_FILE_OK, + file_system_.DirectoryExists(URL("dest-copy"))); + EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, + file_system_.DirectoryExists(URL("dest-move"))); + + // Start syncing the "dest-copy2" directory. + sync_status()->StartSyncing(URL("dest-copy2")); + + // Now the destination is also locked copying kDir should be queued. + ResetCallbackStatus(); + file_system_.NewOperation()->Copy( + URL(kDir), URL("dest-copy2"), + ExpectStatus(FROM_HERE, base::PLATFORM_FILE_OK)); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(0, callback_count_); + + // Finish syncing the "dest-copy2" directory to unlock Copy. + sync_status()->EndSyncing(URL("dest-copy2")); + ResetCallbackStatus(); + operation_runner()->RunNextRunnableTask(); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(1, callback_count_); + + // Now we should have "dest-copy2". + EXPECT_EQ(base::PLATFORM_FILE_OK, + file_system_.DirectoryExists(URL("dest-copy2"))); + + // Finish syncing the kParent to unlock Move. + sync_status()->EndSyncing(URL(kParent)); + ResetCallbackStatus(); + operation_runner()->RunNextRunnableTask(); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(1, callback_count_); + + // Now we should have "dest-move". + EXPECT_EQ(base::PLATFORM_FILE_OK, + file_system_.DirectoryExists(URL("dest-move"))); +} + +TEST_F(SyncableFileOperationRunnerTest, Write) { + EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_.CreateFile(URL(kFile))); + const GURL kBlobURL("blob:foo"); + const std::string kData("Lorem ipsum."); + ScopedTextBlob blob(url_request_context_, kBlobURL, kData); + + sync_status()->StartSyncing(URL(kFile)); + + ResetCallbackStatus(); + file_system_.NewOperation()->Write( + &url_request_context_, + URL(kFile), kBlobURL, 0, GetWriteCallback(FROM_HERE)); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(0, callback_count_); + + sync_status()->EndSyncing(URL(kFile)); + ResetCallbackStatus(); + operation_runner()->RunNextRunnableTask(); + + while (!write_complete_) + MessageLoop::current()->RunAllPending(); + + EXPECT_EQ(base::PLATFORM_FILE_OK, write_status_); + EXPECT_EQ(kData.size(), write_bytes_); + EXPECT_TRUE(write_complete_); +} + +TEST_F(SyncableFileOperationRunnerTest, QueueAndCancel) { + sync_status()->StartSyncing(URL(kFile)); + ASSERT_FALSE(sync_status()->IsWritable(URL(kFile))); + + ResetCallbackStatus(); + file_system_.NewOperation()->CreateFile( + URL(kFile), false /* exclusive */, + ExpectStatus(FROM_HERE, base::PLATFORM_FILE_ERROR_ABORT)); + file_system_.NewOperation()->Truncate( + URL(kFile), 1, + ExpectStatus(FROM_HERE, base::PLATFORM_FILE_ERROR_ABORT)); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(0, callback_count_); + + ResetCallbackStatus(); + + // This shouldn't crash nor leak memory. + sync_context_->ShutdownOnUIThread(); + sync_context_ = NULL; + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(2, callback_count_); +} + +} // namespace fileapi diff --git a/webkit/fileapi/syncable/syncable_file_system_operation.cc b/webkit/fileapi/syncable/syncable_file_system_operation.cc new file mode 100644 index 0000000..33cf51d --- /dev/null +++ b/webkit/fileapi/syncable/syncable_file_system_operation.cc @@ -0,0 +1,305 @@ +// 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/syncable/syncable_file_system_operation.h" + +#include "base/logging.h" +#include "webkit/fileapi/file_system_context.h" +#include "webkit/fileapi/file_system_url.h" +#include "webkit/fileapi/local_file_system_operation.h" +#include "webkit/fileapi/syncable/local_file_sync_context.h" +#include "webkit/fileapi/syncable/syncable_file_operation_runner.h" + +namespace fileapi { + +namespace { + +void WriteCallbackAdapter( + const SyncableFileSystemOperation::WriteCallback& callback, + base::PlatformFileError status) { + callback.Run(status, 0, true); +} + +} // namespace + +class SyncableFileSystemOperation::QueueableTask + : public SyncableFileOperationRunner::Task { + public: + QueueableTask(SyncableFileSystemOperation* operation, + const base::Closure& task) + : operation_(operation), task_(task) {} + + virtual ~QueueableTask() { + DCHECK(!operation_); + } + + virtual void Run() OVERRIDE { + DCHECK(!task_.is_null()); + task_.Run(); + operation_ = NULL; + } + + virtual void Cancel() OVERRIDE { + DCHECK(!task_.is_null()); + DCHECK(operation_); + operation_->OnCancelled(); + task_.Reset(); // This will delete operation_. + operation_ = NULL; + } + + virtual std::vector<FileSystemURL>& target_paths() const OVERRIDE { + DCHECK(operation_); + return operation_->target_paths_; + } + + private: + SyncableFileSystemOperation* operation_; + base::Closure task_; + DISALLOW_COPY_AND_ASSIGN(QueueableTask); +}; + +SyncableFileSystemOperation::~SyncableFileSystemOperation() {} + +void SyncableFileSystemOperation::CreateFile( + const FileSystemURL& url, + bool exclusive, + const StatusCallback& callback) { + DCHECK(CalledOnValidThread()); + DCHECK(operation_runner_.get()); + target_paths_.push_back(url); + completion_callback_ = callback; + scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask( + this, + base::Bind(&FileSystemOperation::CreateFile, + base::Unretained(file_system_operation_), + url, exclusive, + base::Bind(&self::DidFinish, base::Owned(this))))); + operation_runner_->PostOperationTask(task.Pass()); +} + +void SyncableFileSystemOperation::CreateDirectory( + const FileSystemURL& url, + bool exclusive, + bool recursive, + const StatusCallback& callback) { + DCHECK(CalledOnValidThread()); + DCHECK(operation_runner_.get()); + target_paths_.push_back(url); + completion_callback_ = callback; + scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask( + this, + base::Bind(&FileSystemOperation::CreateDirectory, + base::Unretained(file_system_operation_), + url, exclusive, recursive, + base::Bind(&self::DidFinish, base::Owned(this))))); + operation_runner_->PostOperationTask(task.Pass()); +} + +void SyncableFileSystemOperation::Copy( + const FileSystemURL& src_url, + const FileSystemURL& dest_url, + const StatusCallback& callback) { + DCHECK(CalledOnValidThread()); + DCHECK(operation_runner_.get()); + target_paths_.push_back(dest_url); + completion_callback_ = callback; + scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask( + this, + base::Bind(&FileSystemOperation::Copy, + base::Unretained(file_system_operation_), + src_url, dest_url, + base::Bind(&self::DidFinish, base::Owned(this))))); + operation_runner_->PostOperationTask(task.Pass()); +} + +void SyncableFileSystemOperation::Move( + const FileSystemURL& src_url, + const FileSystemURL& dest_url, + const StatusCallback& callback) { + DCHECK(CalledOnValidThread()); + DCHECK(operation_runner_.get()); + target_paths_.push_back(src_url); + target_paths_.push_back(dest_url); + completion_callback_ = callback; + scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask( + this, + base::Bind(&FileSystemOperation::Move, + base::Unretained(file_system_operation_), + src_url, dest_url, + base::Bind(&self::DidFinish, base::Owned(this))))); + operation_runner_->PostOperationTask(task.Pass()); +} + +void SyncableFileSystemOperation::DirectoryExists( + const FileSystemURL& url, + const StatusCallback& callback) { + DCHECK(CalledOnValidThread()); + file_system_operation_->DirectoryExists(url, callback); + delete this; +} + +void SyncableFileSystemOperation::FileExists( + const FileSystemURL& url, + const StatusCallback& callback) { + DCHECK(CalledOnValidThread()); + file_system_operation_->FileExists(url, callback); + delete this; +} + +void SyncableFileSystemOperation::GetMetadata( + const FileSystemURL& url, + const GetMetadataCallback& callback) { + DCHECK(CalledOnValidThread()); + file_system_operation_->GetMetadata(url, callback); + delete this; +} + +void SyncableFileSystemOperation::ReadDirectory( + const FileSystemURL& url, + const ReadDirectoryCallback& callback) { + DCHECK(CalledOnValidThread()); + file_system_operation_->ReadDirectory(url, callback); + delete this; +} + +void SyncableFileSystemOperation::Remove( + const FileSystemURL& url, bool recursive, + const StatusCallback& callback) { + DCHECK(CalledOnValidThread()); + DCHECK(operation_runner_.get()); + target_paths_.push_back(url); + completion_callback_ = callback; + scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask( + this, + base::Bind(&FileSystemOperation::Remove, + base::Unretained(file_system_operation_), + url, recursive, + base::Bind(&self::DidFinish, base::Owned(this))))); + operation_runner_->PostOperationTask(task.Pass()); +} + +void SyncableFileSystemOperation::Write( + const net::URLRequestContext* url_request_context, + const FileSystemURL& url, + const GURL& blob_url, + int64 offset, + const WriteCallback& callback) { + DCHECK(CalledOnValidThread()); + DCHECK(operation_runner_.get()); + target_paths_.push_back(url); + completion_callback_ = base::Bind(&WriteCallbackAdapter, callback); + scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask( + this, + file_system_operation_->GetWriteClosure( + url_request_context, url, blob_url, offset, + base::Bind(&self::DidWrite, base::Owned(this), callback)))); + operation_runner_->PostOperationTask(task.Pass()); +} + +void SyncableFileSystemOperation::Truncate( + const FileSystemURL& url, int64 length, + const StatusCallback& callback) { + DCHECK(CalledOnValidThread()); + DCHECK(operation_runner_.get()); + target_paths_.push_back(url); + completion_callback_ = callback; + scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask( + this, + base::Bind(&FileSystemOperation::Truncate, + base::Unretained(file_system_operation_), + url, length, + base::Bind(&self::DidFinish, base::Owned(this))))); + operation_runner_->PostOperationTask(task.Pass()); +} + +void SyncableFileSystemOperation::TouchFile( + const FileSystemURL& url, + const base::Time& last_access_time, + const base::Time& last_modified_time, + const StatusCallback& callback) { + DCHECK(CalledOnValidThread()); + file_system_operation_->TouchFile(url, last_access_time, + last_modified_time, callback); + delete this; +} + +void SyncableFileSystemOperation::OpenFile( + const FileSystemURL& url, + int file_flags, + base::ProcessHandle peer_handle, + const OpenFileCallback& callback) { + NOTREACHED(); + delete this; +} + +void SyncableFileSystemOperation::NotifyCloseFile( + const FileSystemURL& url) { + NOTREACHED(); + delete this; +} + +void SyncableFileSystemOperation::Cancel( + const StatusCallback& cancel_callback) { + DCHECK(CalledOnValidThread()); + DCHECK(file_system_operation_); + DCHECK(file_system_operation_); + completion_callback_ = cancel_callback; + file_system_operation_->Cancel( + base::Bind(&self::DidFinish, base::Owned(this))); +} + +LocalFileSystemOperation* +SyncableFileSystemOperation::AsLocalFileSystemOperation() { + NOTREACHED(); + return NULL; +} + +void SyncableFileSystemOperation::CreateSnapshotFile( + const FileSystemURL& path, + const SnapshotFileCallback& callback) { + DCHECK(CalledOnValidThread()); + file_system_operation_->CreateSnapshotFile(path, callback); + delete this; +} + +SyncableFileSystemOperation::SyncableFileSystemOperation( + FileSystemContext* file_system_context, + FileSystemOperation* file_system_operation) { + DCHECK(file_system_context); + DCHECK(file_system_operation); + operation_runner_ = file_system_context->sync_context()->operation_runner(); + file_system_operation_ = file_system_operation->AsLocalFileSystemOperation(); + DCHECK(file_system_operation_); +} + +void SyncableFileSystemOperation::DidFinish(base::PlatformFileError status) { + DCHECK(CalledOnValidThread()); + DCHECK(!completion_callback_.is_null()); + if (operation_runner_.get()) + operation_runner_->OnOperationCompleted(target_paths_); + completion_callback_.Run(status); +} + +void SyncableFileSystemOperation::DidWrite( + const WriteCallback& callback, + base::PlatformFileError result, + int64 bytes, + bool complete) { + DCHECK(CalledOnValidThread()); + if (!complete) { + callback.Run(result, bytes, complete); + return; + } + if (operation_runner_.get()) + operation_runner_->OnOperationCompleted(target_paths_); + callback.Run(result, bytes, complete); +} + +void SyncableFileSystemOperation::OnCancelled() { + DCHECK(!completion_callback_.is_null()); + completion_callback_.Run(base::PLATFORM_FILE_ERROR_ABORT); + delete file_system_operation_; +} + +} // namespace fileapi diff --git a/webkit/fileapi/syncable/syncable_file_system_operation.h b/webkit/fileapi/syncable/syncable_file_system_operation.h new file mode 100644 index 0000000..009759e --- /dev/null +++ b/webkit/fileapi/syncable/syncable_file_system_operation.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_SYNCABLE_SYNCABLE_FILE_SYSTEM_OPERATION_H_ +#define WEBKIT_FILEAPI_SYNCABLE_SYNCABLE_FILE_SYSTEM_OPERATION_H_ + +#include <vector> + +#include "base/callback.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/threading/non_thread_safe.h" +#include "webkit/fileapi/file_system_operation.h" +#include "webkit/storage/webkit_storage_export.h" + +namespace fileapi { + +class FileSystemContext; +class SyncableFileOperationRunner; + +// A wrapper class of LocalFileSystemOperation for syncable file system. +class WEBKIT_STORAGE_EXPORT SyncableFileSystemOperation + : public NON_EXPORTED_BASE(FileSystemOperation), + public base::NonThreadSafe { + public: + virtual ~SyncableFileSystemOperation(); + + // FileSystemOperation overrides. + virtual void CreateFile(const FileSystemURL& url, + bool exclusive, + const StatusCallback& callback) OVERRIDE; + virtual void CreateDirectory(const FileSystemURL& url, + bool exclusive, + bool recursive, + const StatusCallback& callback) OVERRIDE; + virtual void Copy(const FileSystemURL& src_url, + const FileSystemURL& dest_url, + const StatusCallback& callback) OVERRIDE; + virtual void Move(const FileSystemURL& src_url, + const FileSystemURL& dest_url, + const StatusCallback& callback) OVERRIDE; + virtual void DirectoryExists(const FileSystemURL& url, + const StatusCallback& callback) OVERRIDE; + virtual void FileExists(const FileSystemURL& url, + const StatusCallback& callback) OVERRIDE; + virtual void GetMetadata(const FileSystemURL& url, + const GetMetadataCallback& callback) OVERRIDE; + virtual void ReadDirectory(const FileSystemURL& url, + const ReadDirectoryCallback& callback) OVERRIDE; + virtual void Remove(const FileSystemURL& url, bool recursive, + const StatusCallback& callback) OVERRIDE; + virtual void Write(const net::URLRequestContext* url_request_context, + const FileSystemURL& url, + const GURL& blob_url, + int64 offset, + const WriteCallback& callback) OVERRIDE; + virtual void Truncate(const FileSystemURL& url, int64 length, + const StatusCallback& callback) OVERRIDE; + virtual void TouchFile(const FileSystemURL& url, + const base::Time& last_access_time, + const base::Time& last_modified_time, + const StatusCallback& callback) OVERRIDE; + virtual void OpenFile(const FileSystemURL& url, + int file_flags, + base::ProcessHandle peer_handle, + const OpenFileCallback& callback) OVERRIDE; + virtual void NotifyCloseFile(const FileSystemURL& url) OVERRIDE; + virtual void Cancel(const StatusCallback& cancel_callback) OVERRIDE; + virtual LocalFileSystemOperation* AsLocalFileSystemOperation() OVERRIDE; + virtual void CreateSnapshotFile( + const FileSystemURL& path, + const SnapshotFileCallback& callback) OVERRIDE; + + private: + typedef SyncableFileSystemOperation self; + class QueueableTask; + + // Only MountPointProviders can create a new operation directly. + friend class SandboxMountPointProvider; + SyncableFileSystemOperation(FileSystemContext* file_system_context, + FileSystemOperation* file_system_operation); + + void DidFinish(base::PlatformFileError status); + void DidWrite(const WriteCallback& callback, + base::PlatformFileError result, + int64 bytes, + bool complete); + + void OnCancelled(); + + base::WeakPtr<SyncableFileOperationRunner> operation_runner_; + LocalFileSystemOperation* file_system_operation_; + std::vector<FileSystemURL> target_paths_; + + StatusCallback completion_callback_; + + DISALLOW_COPY_AND_ASSIGN(SyncableFileSystemOperation); +}; + +} // namespace fileapi + +#endif // WEBKIT_FILEAPI_SYNCABLE_SYNCABLE_FILE_SYSTEM_OPERATION_H_ diff --git a/webkit/fileapi/webkit_fileapi.gypi b/webkit/fileapi/webkit_fileapi.gypi index 6a0e20c..cfeb95f 100644 --- a/webkit/fileapi/webkit_fileapi.gypi +++ b/webkit/fileapi/webkit_fileapi.gypi @@ -88,6 +88,10 @@ '../fileapi/syncable/local_file_sync_status.h', '../fileapi/syncable/sync_status_code.cc', '../fileapi/syncable/sync_status_code.h', + '../fileapi/syncable/syncable_file_operation_runner.cc', + '../fileapi/syncable/syncable_file_operation_runner.h', + '../fileapi/syncable/syncable_file_system_operation.cc', + '../fileapi/syncable/syncable_file_system_operation.h', '../fileapi/syncable/syncable_file_system_util.cc', '../fileapi/syncable/syncable_file_system_util.h', '../fileapi/task_runner_bound_observer_list.h', |