Commit 33f5a4ed authored by kinuko@chromium.org's avatar kinuko@chromium.org

Dispatch FileSystemOperationRunner callbacks always synchronously

- Re-post callbacks only if they are called synchronously
- Always return a valid operation ID (even if it's finished immediately)
- Fix cancel callbacks ordering

BUG=279288
TEST=existing tests
TBR=hidehiko@chromium.org, tzik@chromium.org

Review URL: https://codereview.chromium.org/23898002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@221384 0039d316-1c4b-4281-b951-d872f2087c98
parent 09a8b25c
...@@ -497,6 +497,7 @@ ...@@ -497,6 +497,7 @@
'../webkit/browser/fileapi/file_system_file_stream_reader_unittest.cc', '../webkit/browser/fileapi/file_system_file_stream_reader_unittest.cc',
'../webkit/browser/fileapi/file_system_operation_impl_unittest.cc', '../webkit/browser/fileapi/file_system_operation_impl_unittest.cc',
'../webkit/browser/fileapi/file_system_operation_impl_write_unittest.cc', '../webkit/browser/fileapi/file_system_operation_impl_write_unittest.cc',
'../webkit/browser/fileapi/file_system_operation_runner_unittest.cc',
'../webkit/browser/fileapi/file_system_quota_client_unittest.cc', '../webkit/browser/fileapi/file_system_quota_client_unittest.cc',
'../webkit/browser/fileapi/file_system_url_request_job_unittest.cc', '../webkit/browser/fileapi/file_system_url_request_job_unittest.cc',
'../webkit/browser/fileapi/file_system_url_unittest.cc', '../webkit/browser/fileapi/file_system_url_unittest.cc',
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#include "webkit/browser/fileapi/file_system_operation_runner.h" #include "webkit/browser/fileapi/file_system_operation_runner.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/stl_util.h"
#include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context.h"
#include "webkit/browser/fileapi/file_observers.h" #include "webkit/browser/fileapi/file_observers.h"
#include "webkit/browser/fileapi/file_stream_writer.h" #include "webkit/browser/fileapi/file_stream_writer.h"
...@@ -17,7 +19,17 @@ namespace fileapi { ...@@ -17,7 +19,17 @@ namespace fileapi {
typedef FileSystemOperationRunner::OperationID OperationID; typedef FileSystemOperationRunner::OperationID OperationID;
const OperationID FileSystemOperationRunner::kErrorOperationID = -1; class FileSystemOperationRunner::BeginOperationScoper
: public base::SupportsWeakPtr<
FileSystemOperationRunner::BeginOperationScoper> {
public:
BeginOperationScoper() {}
private:
DISALLOW_COPY_AND_ASSIGN(BeginOperationScoper);
};
FileSystemOperationRunner::OperationHandle::OperationHandle() {}
FileSystemOperationRunner::OperationHandle::~OperationHandle() {}
FileSystemOperationRunner::~FileSystemOperationRunner() { FileSystemOperationRunner::~FileSystemOperationRunner() {
} }
...@@ -33,17 +45,19 @@ OperationID FileSystemOperationRunner::CreateFile( ...@@ -33,17 +45,19 @@ OperationID FileSystemOperationRunner::CreateFile(
base::PlatformFileError error = base::PLATFORM_FILE_OK; base::PlatformFileError error = base::PLATFORM_FILE_OK;
FileSystemOperation* operation = FileSystemOperation* operation =
file_system_context_->CreateFileSystemOperation(url, &error); file_system_context_->CreateFileSystemOperation(url, &error);
BeginOperationScoper scope;
OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
if (!operation) { if (!operation) {
callback.Run(error); DidFinish(handle, callback, error);
return kErrorOperationID; return handle.id;
} }
OperationID id = operations_.Add(operation); PrepareForWrite(handle.id, url);
PrepareForWrite(id, url);
operation->CreateFile( operation->CreateFile(
url, exclusive, url, exclusive,
base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
id, callback)); handle, callback));
return id; return handle.id;
} }
OperationID FileSystemOperationRunner::CreateDirectory( OperationID FileSystemOperationRunner::CreateDirectory(
...@@ -54,17 +68,18 @@ OperationID FileSystemOperationRunner::CreateDirectory( ...@@ -54,17 +68,18 @@ OperationID FileSystemOperationRunner::CreateDirectory(
base::PlatformFileError error = base::PLATFORM_FILE_OK; base::PlatformFileError error = base::PLATFORM_FILE_OK;
FileSystemOperation* operation = FileSystemOperation* operation =
file_system_context_->CreateFileSystemOperation(url, &error); file_system_context_->CreateFileSystemOperation(url, &error);
BeginOperationScoper scope;
OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
if (!operation) { if (!operation) {
callback.Run(error); DidFinish(handle, callback, error);
return kErrorOperationID; return handle.id;
} }
OperationID id = operations_.Add(operation); PrepareForWrite(handle.id, url);
PrepareForWrite(id, url);
operation->CreateDirectory( operation->CreateDirectory(
url, exclusive, recursive, url, exclusive, recursive,
base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
id, callback)); handle, callback));
return id; return handle.id;
} }
OperationID FileSystemOperationRunner::Copy( OperationID FileSystemOperationRunner::Copy(
...@@ -74,18 +89,19 @@ OperationID FileSystemOperationRunner::Copy( ...@@ -74,18 +89,19 @@ OperationID FileSystemOperationRunner::Copy(
base::PlatformFileError error = base::PLATFORM_FILE_OK; base::PlatformFileError error = base::PLATFORM_FILE_OK;
FileSystemOperation* operation = FileSystemOperation* operation =
file_system_context_->CreateFileSystemOperation(dest_url, &error); file_system_context_->CreateFileSystemOperation(dest_url, &error);
BeginOperationScoper scope;
OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
if (!operation) { if (!operation) {
callback.Run(error); DidFinish(handle, callback, error);
return kErrorOperationID; return handle.id;
} }
OperationID id = operations_.Add(operation); PrepareForWrite(handle.id, dest_url);
PrepareForWrite(id, dest_url); PrepareForRead(handle.id, src_url);
PrepareForRead(id, src_url);
operation->Copy( operation->Copy(
src_url, dest_url, src_url, dest_url,
base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
id, callback)); handle, callback));
return id; return handle.id;
} }
OperationID FileSystemOperationRunner::Move( OperationID FileSystemOperationRunner::Move(
...@@ -95,18 +111,19 @@ OperationID FileSystemOperationRunner::Move( ...@@ -95,18 +111,19 @@ OperationID FileSystemOperationRunner::Move(
base::PlatformFileError error = base::PLATFORM_FILE_OK; base::PlatformFileError error = base::PLATFORM_FILE_OK;
FileSystemOperation* operation = FileSystemOperation* operation =
file_system_context_->CreateFileSystemOperation(dest_url, &error); file_system_context_->CreateFileSystemOperation(dest_url, &error);
BeginOperationScoper scope;
OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
if (!operation) { if (!operation) {
callback.Run(error); DidFinish(handle, callback, error);
return kErrorOperationID; return handle.id;
} }
OperationID id = operations_.Add(operation); PrepareForWrite(handle.id, dest_url);
PrepareForWrite(id, dest_url); PrepareForWrite(handle.id, src_url);
PrepareForWrite(id, src_url);
operation->Move( operation->Move(
src_url, dest_url, src_url, dest_url,
base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
id, callback)); handle, callback));
return id; return handle.id;
} }
OperationID FileSystemOperationRunner::DirectoryExists( OperationID FileSystemOperationRunner::DirectoryExists(
...@@ -115,17 +132,18 @@ OperationID FileSystemOperationRunner::DirectoryExists( ...@@ -115,17 +132,18 @@ OperationID FileSystemOperationRunner::DirectoryExists(
base::PlatformFileError error = base::PLATFORM_FILE_OK; base::PlatformFileError error = base::PLATFORM_FILE_OK;
FileSystemOperation* operation = FileSystemOperation* operation =
file_system_context_->CreateFileSystemOperation(url, &error); file_system_context_->CreateFileSystemOperation(url, &error);
BeginOperationScoper scope;
OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
if (!operation) { if (!operation) {
callback.Run(error); DidFinish(handle, callback, error);
return kErrorOperationID; return handle.id;
} }
OperationID id = operations_.Add(operation); PrepareForRead(handle.id, url);
PrepareForRead(id, url);
operation->DirectoryExists( operation->DirectoryExists(
url, url,
base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
id, callback)); handle, callback));
return id; return handle.id;
} }
OperationID FileSystemOperationRunner::FileExists( OperationID FileSystemOperationRunner::FileExists(
...@@ -134,17 +152,18 @@ OperationID FileSystemOperationRunner::FileExists( ...@@ -134,17 +152,18 @@ OperationID FileSystemOperationRunner::FileExists(
base::PlatformFileError error = base::PLATFORM_FILE_OK; base::PlatformFileError error = base::PLATFORM_FILE_OK;
FileSystemOperation* operation = FileSystemOperation* operation =
file_system_context_->CreateFileSystemOperation(url, &error); file_system_context_->CreateFileSystemOperation(url, &error);
BeginOperationScoper scope;
OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
if (!operation) { if (!operation) {
callback.Run(error); DidFinish(handle, callback, error);
return kErrorOperationID; return handle.id;
} }
OperationID id = operations_.Add(operation); PrepareForRead(handle.id, url);
PrepareForRead(id, url);
operation->FileExists( operation->FileExists(
url, url,
base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
id, callback)); handle, callback));
return id; return handle.id;
} }
OperationID FileSystemOperationRunner::GetMetadata( OperationID FileSystemOperationRunner::GetMetadata(
...@@ -153,17 +172,18 @@ OperationID FileSystemOperationRunner::GetMetadata( ...@@ -153,17 +172,18 @@ OperationID FileSystemOperationRunner::GetMetadata(
base::PlatformFileError error = base::PLATFORM_FILE_OK; base::PlatformFileError error = base::PLATFORM_FILE_OK;
FileSystemOperation* operation = FileSystemOperation* operation =
file_system_context_->CreateFileSystemOperation(url, &error); file_system_context_->CreateFileSystemOperation(url, &error);
BeginOperationScoper scope;
OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
if (!operation) { if (!operation) {
callback.Run(error, base::PlatformFileInfo()); DidGetMetadata(handle, callback, error, base::PlatformFileInfo());
return kErrorOperationID; return handle.id;
} }
OperationID id = operations_.Add(operation); PrepareForRead(handle.id, url);
PrepareForRead(id, url);
operation->GetMetadata( operation->GetMetadata(
url, url,
base::Bind(&FileSystemOperationRunner::DidGetMetadata, AsWeakPtr(), base::Bind(&FileSystemOperationRunner::DidGetMetadata, AsWeakPtr(),
id, callback)); handle, callback));
return id; return handle.id;
} }
OperationID FileSystemOperationRunner::ReadDirectory( OperationID FileSystemOperationRunner::ReadDirectory(
...@@ -172,17 +192,19 @@ OperationID FileSystemOperationRunner::ReadDirectory( ...@@ -172,17 +192,19 @@ OperationID FileSystemOperationRunner::ReadDirectory(
base::PlatformFileError error = base::PLATFORM_FILE_OK; base::PlatformFileError error = base::PLATFORM_FILE_OK;
FileSystemOperation* operation = FileSystemOperation* operation =
file_system_context_->CreateFileSystemOperation(url, &error); file_system_context_->CreateFileSystemOperation(url, &error);
BeginOperationScoper scope;
OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
if (!operation) { if (!operation) {
callback.Run(error, std::vector<DirectoryEntry>(), false); DidReadDirectory(handle, callback, error, std::vector<DirectoryEntry>(),
return kErrorOperationID; false);
return handle.id;
} }
OperationID id = operations_.Add(operation); PrepareForRead(handle.id, url);
PrepareForRead(id, url);
operation->ReadDirectory( operation->ReadDirectory(
url, url,
base::Bind(&FileSystemOperationRunner::DidReadDirectory, AsWeakPtr(), base::Bind(&FileSystemOperationRunner::DidReadDirectory, AsWeakPtr(),
id, callback)); handle, callback));
return id; return handle.id;
} }
OperationID FileSystemOperationRunner::Remove( OperationID FileSystemOperationRunner::Remove(
...@@ -191,17 +213,18 @@ OperationID FileSystemOperationRunner::Remove( ...@@ -191,17 +213,18 @@ OperationID FileSystemOperationRunner::Remove(
base::PlatformFileError error = base::PLATFORM_FILE_OK; base::PlatformFileError error = base::PLATFORM_FILE_OK;
FileSystemOperation* operation = FileSystemOperation* operation =
file_system_context_->CreateFileSystemOperation(url, &error); file_system_context_->CreateFileSystemOperation(url, &error);
BeginOperationScoper scope;
OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
if (!operation) { if (!operation) {
callback.Run(error); DidFinish(handle, callback, error);
return kErrorOperationID; return handle.id;
} }
OperationID id = operations_.Add(operation); PrepareForWrite(handle.id, url);
PrepareForWrite(id, url);
operation->Remove( operation->Remove(
url, recursive, url, recursive,
base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
id, callback)); handle, callback));
return id; return handle.id;
} }
OperationID FileSystemOperationRunner::Write( OperationID FileSystemOperationRunner::Write(
...@@ -213,17 +236,20 @@ OperationID FileSystemOperationRunner::Write( ...@@ -213,17 +236,20 @@ OperationID FileSystemOperationRunner::Write(
base::PlatformFileError error = base::PLATFORM_FILE_OK; base::PlatformFileError error = base::PLATFORM_FILE_OK;
FileSystemOperation* operation = FileSystemOperation* operation =
file_system_context_->CreateFileSystemOperation(url, &error); file_system_context_->CreateFileSystemOperation(url, &error);
BeginOperationScoper scope;
OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
if (!operation) { if (!operation) {
callback.Run(error, 0, true); DidWrite(handle, callback, error, 0, true);
return kErrorOperationID; return handle.id;
} }
scoped_ptr<FileStreamWriter> writer( scoped_ptr<FileStreamWriter> writer(
file_system_context_->CreateFileStreamWriter(url, offset)); file_system_context_->CreateFileStreamWriter(url, offset));
if (!writer) { if (!writer) {
// Write is not supported. // Write is not supported.
callback.Run(base::PLATFORM_FILE_ERROR_SECURITY, 0, true); DidWrite(handle, callback, base::PLATFORM_FILE_ERROR_SECURITY, 0, true);
return kErrorOperationID; return handle.id;
} }
DCHECK(blob_url.is_valid()); DCHECK(blob_url.is_valid());
...@@ -232,13 +258,12 @@ OperationID FileSystemOperationRunner::Write( ...@@ -232,13 +258,12 @@ OperationID FileSystemOperationRunner::Write(
scoped_ptr<net::URLRequest> blob_request(url_request_context->CreateRequest( scoped_ptr<net::URLRequest> blob_request(url_request_context->CreateRequest(
blob_url, writer_delegate.get())); blob_url, writer_delegate.get()));
OperationID id = operations_.Add(operation); PrepareForWrite(handle.id, url);
PrepareForWrite(id, url);
operation->Write( operation->Write(
url, writer_delegate.Pass(), blob_request.Pass(), url, writer_delegate.Pass(), blob_request.Pass(),
base::Bind(&FileSystemOperationRunner::DidWrite, AsWeakPtr(), base::Bind(&FileSystemOperationRunner::DidWrite, AsWeakPtr(),
id, callback)); handle, callback));
return id; return handle.id;
} }
OperationID FileSystemOperationRunner::Truncate( OperationID FileSystemOperationRunner::Truncate(
...@@ -247,28 +272,30 @@ OperationID FileSystemOperationRunner::Truncate( ...@@ -247,28 +272,30 @@ OperationID FileSystemOperationRunner::Truncate(
base::PlatformFileError error = base::PLATFORM_FILE_OK; base::PlatformFileError error = base::PLATFORM_FILE_OK;
FileSystemOperation* operation = FileSystemOperation* operation =
file_system_context_->CreateFileSystemOperation(url, &error); file_system_context_->CreateFileSystemOperation(url, &error);
BeginOperationScoper scope;
OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
if (!operation) { if (!operation) {
callback.Run(error); DidFinish(handle, callback, error);
return kErrorOperationID; return handle.id;
} }
OperationID id = operations_.Add(operation); PrepareForWrite(handle.id, url);
PrepareForWrite(id, url);
operation->Truncate( operation->Truncate(
url, length, url, length,
base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
id, callback)); handle, callback));
return id; return handle.id;
} }
void FileSystemOperationRunner::Cancel( void FileSystemOperationRunner::Cancel(
OperationID id, OperationID id,
const StatusCallback& callback) { const StatusCallback& callback) {
FileSystemOperation* operation = operations_.Lookup(id); if (ContainsKey(finished_operations_, id)) {
if (!operation) { DCHECK(!ContainsKey(stray_cancel_callbacks_, id));
// The operation is already finished; report that we failed to stop it. stray_cancel_callbacks_[id] = callback;
callback.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION);
return; return;
} }
FileSystemOperation* operation = operations_.Lookup(id);
DCHECK(operation);
operation->Cancel(callback); operation->Cancel(callback);
} }
...@@ -280,17 +307,18 @@ OperationID FileSystemOperationRunner::TouchFile( ...@@ -280,17 +307,18 @@ OperationID FileSystemOperationRunner::TouchFile(
base::PlatformFileError error = base::PLATFORM_FILE_OK; base::PlatformFileError error = base::PLATFORM_FILE_OK;
FileSystemOperation* operation = FileSystemOperation* operation =
file_system_context_->CreateFileSystemOperation(url, &error); file_system_context_->CreateFileSystemOperation(url, &error);
BeginOperationScoper scope;
OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
if (!operation) { if (!operation) {
callback.Run(error); DidFinish(handle, callback, error);
return kErrorOperationID; return handle.id;
} }
OperationID id = operations_.Add(operation); PrepareForWrite(handle.id, url);
PrepareForWrite(id, url);
operation->TouchFile( operation->TouchFile(
url, last_access_time, last_modified_time, url, last_access_time, last_modified_time,
base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
id, callback)); handle, callback));
return id; return handle.id;
} }
OperationID FileSystemOperationRunner::OpenFile( OperationID FileSystemOperationRunner::OpenFile(
...@@ -301,27 +329,28 @@ OperationID FileSystemOperationRunner::OpenFile( ...@@ -301,27 +329,28 @@ OperationID FileSystemOperationRunner::OpenFile(
base::PlatformFileError error = base::PLATFORM_FILE_OK; base::PlatformFileError error = base::PLATFORM_FILE_OK;
FileSystemOperation* operation = FileSystemOperation* operation =
file_system_context_->CreateFileSystemOperation(url, &error); file_system_context_->CreateFileSystemOperation(url, &error);
BeginOperationScoper scope;
OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
if (!operation) { if (!operation) {
callback.Run(error, base::kInvalidPlatformFileValue, DidOpenFile(handle, callback, error, base::kInvalidPlatformFileValue,
base::Closure(), base::ProcessHandle()); base::Closure(), base::ProcessHandle());
return kErrorOperationID; return handle.id;
} }
OperationID id = operations_.Add(operation);
if (file_flags & if (file_flags &
(base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_OPEN_ALWAYS | (base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_OPEN_ALWAYS |
base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_OPEN_TRUNCATED | base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_OPEN_TRUNCATED |
base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_EXCLUSIVE_WRITE | base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_EXCLUSIVE_WRITE |
base::PLATFORM_FILE_DELETE_ON_CLOSE | base::PLATFORM_FILE_DELETE_ON_CLOSE |
base::PLATFORM_FILE_WRITE_ATTRIBUTES)) { base::PLATFORM_FILE_WRITE_ATTRIBUTES)) {
PrepareForWrite(id, url); PrepareForWrite(handle.id, url);
} else { } else {
PrepareForRead(id, url); PrepareForRead(handle.id, url);
} }
operation->OpenFile( operation->OpenFile(
url, file_flags, peer_handle, url, file_flags, peer_handle,
base::Bind(&FileSystemOperationRunner::DidOpenFile, AsWeakPtr(), base::Bind(&FileSystemOperationRunner::DidOpenFile, AsWeakPtr(),
id, callback)); handle, callback));
return id; return handle.id;
} }
OperationID FileSystemOperationRunner::CreateSnapshotFile( OperationID FileSystemOperationRunner::CreateSnapshotFile(
...@@ -330,17 +359,19 @@ OperationID FileSystemOperationRunner::CreateSnapshotFile( ...@@ -330,17 +359,19 @@ OperationID FileSystemOperationRunner::CreateSnapshotFile(
base::PlatformFileError error = base::PLATFORM_FILE_OK; base::PlatformFileError error = base::PLATFORM_FILE_OK;
FileSystemOperation* operation = FileSystemOperation* operation =
file_system_context_->CreateFileSystemOperation(url, &error); file_system_context_->CreateFileSystemOperation(url, &error);
BeginOperationScoper scope;
OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
if (!operation) { if (!operation) {
callback.Run(error, base::PlatformFileInfo(), base::FilePath(), NULL); DidCreateSnapshot(handle, callback, error, base::PlatformFileInfo(),
return kErrorOperationID; base::FilePath(), NULL);
return handle.id;
} }
OperationID id = operations_.Add(operation); PrepareForRead(handle.id, url);
PrepareForRead(id, url);
operation->CreateSnapshotFile( operation->CreateSnapshotFile(
url, url,
base::Bind(&FileSystemOperationRunner::DidCreateSnapshot, AsWeakPtr(), base::Bind(&FileSystemOperationRunner::DidCreateSnapshot, AsWeakPtr(),
id, callback)); handle, callback));
return id; return handle.id;
} }
OperationID FileSystemOperationRunner::CopyInForeignFile( OperationID FileSystemOperationRunner::CopyInForeignFile(
...@@ -350,16 +381,17 @@ OperationID FileSystemOperationRunner::CopyInForeignFile( ...@@ -350,16 +381,17 @@ OperationID FileSystemOperationRunner::CopyInForeignFile(
base::PlatformFileError error = base::PLATFORM_FILE_OK; base::PlatformFileError error = base::PLATFORM_FILE_OK;
FileSystemOperation* operation = FileSystemOperation* operation =
file_system_context_->CreateFileSystemOperation(dest_url, &error); file_system_context_->CreateFileSystemOperation(dest_url, &error);
BeginOperationScoper scope;
OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
if (!operation) { if (!operation) {
callback.Run(error); DidFinish(handle, callback, error);
return kErrorOperationID; return handle.id;
} }
OperationID id = operations_.Add(operation);
operation->CopyInForeignFile( operation->CopyInForeignFile(
src_local_disk_path, dest_url, src_local_disk_path, dest_url,
base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
id, callback)); handle, callback));
return id; return handle.id;
} }
OperationID FileSystemOperationRunner::RemoveFile( OperationID FileSystemOperationRunner::RemoveFile(
...@@ -368,16 +400,17 @@ OperationID FileSystemOperationRunner::RemoveFile( ...@@ -368,16 +400,17 @@ OperationID FileSystemOperationRunner::RemoveFile(
base::PlatformFileError error = base::PLATFORM_FILE_OK; base::PlatformFileError error = base::PLATFORM_FILE_OK;
FileSystemOperation* operation = FileSystemOperation* operation =
file_system_context_->CreateFileSystemOperation(url, &error); file_system_context_->CreateFileSystemOperation(url, &error);
BeginOperationScoper scope;
OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
if (!operation) { if (!operation) {
callback.Run(error); DidFinish(handle, callback, error);
return kErrorOperationID; return handle.id;
} }
OperationID id = operations_.Add(operation);
operation->RemoveFile( operation->RemoveFile(
url, url,
base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
id, callback)); handle, callback));
return id; return handle.id;
} }
OperationID FileSystemOperationRunner::RemoveDirectory( OperationID FileSystemOperationRunner::RemoveDirectory(
...@@ -386,16 +419,17 @@ OperationID FileSystemOperationRunner::RemoveDirectory( ...@@ -386,16 +419,17 @@ OperationID FileSystemOperationRunner::RemoveDirectory(
base::PlatformFileError error = base::PLATFORM_FILE_OK; base::PlatformFileError error = base::PLATFORM_FILE_OK;
FileSystemOperation* operation = FileSystemOperation* operation =
file_system_context_->CreateFileSystemOperation(url, &error); file_system_context_->CreateFileSystemOperation(url, &error);
BeginOperationScoper scope;
OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
if (!operation) { if (!operation) {
callback.Run(error); DidFinish(handle, callback, error);
return kErrorOperationID; return handle.id;
} }
OperationID id = operations_.Add(operation);
operation->RemoveDirectory( operation->RemoveDirectory(
url, url,
base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
id, callback)); handle, callback));
return id; return handle.id;
} }
OperationID FileSystemOperationRunner::CopyFileLocal( OperationID FileSystemOperationRunner::CopyFileLocal(
...@@ -405,16 +439,17 @@ OperationID FileSystemOperationRunner::CopyFileLocal( ...@@ -405,16 +439,17 @@ OperationID FileSystemOperationRunner::CopyFileLocal(
base::PlatformFileError error = base::PLATFORM_FILE_OK; base::PlatformFileError error = base::PLATFORM_FILE_OK;
FileSystemOperation* operation = FileSystemOperation* operation =
file_system_context_->CreateFileSystemOperation(src_url, &error); file_system_context_->CreateFileSystemOperation(src_url, &error);
BeginOperationScoper scope;
OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
if (!operation) { if (!operation) {
callback.Run(error); DidFinish(handle, callback, error);
return kErrorOperationID; return handle.id;
} }
OperationID id = operations_.Add(operation);
operation->CopyFileLocal( operation->CopyFileLocal(
src_url, dest_url, src_url, dest_url,
base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
id, callback)); handle, callback));
return id; return handle.id;
} }
OperationID FileSystemOperationRunner::MoveFileLocal( OperationID FileSystemOperationRunner::MoveFileLocal(
...@@ -424,16 +459,17 @@ OperationID FileSystemOperationRunner::MoveFileLocal( ...@@ -424,16 +459,17 @@ OperationID FileSystemOperationRunner::MoveFileLocal(
base::PlatformFileError error = base::PLATFORM_FILE_OK; base::PlatformFileError error = base::PLATFORM_FILE_OK;
FileSystemOperation* operation = FileSystemOperation* operation =
file_system_context_->CreateFileSystemOperation(src_url, &error); file_system_context_->CreateFileSystemOperation(src_url, &error);
BeginOperationScoper scope;
OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
if (!operation) { if (!operation) {
callback.Run(error); DidFinish(handle, callback, error);
return kErrorOperationID; return handle.id;
} }
OperationID id = operations_.Add(operation);
operation->MoveFileLocal( operation->MoveFileLocal(
src_url, dest_url, src_url, dest_url,
base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
id, callback)); handle, callback));
return id; return handle.id;
} }
base::PlatformFileError FileSystemOperationRunner::SyncGetPlatformPath( base::PlatformFileError FileSystemOperationRunner::SyncGetPlatformPath(
...@@ -452,64 +488,109 @@ FileSystemOperationRunner::FileSystemOperationRunner( ...@@ -452,64 +488,109 @@ FileSystemOperationRunner::FileSystemOperationRunner(
: file_system_context_(file_system_context) {} : file_system_context_(file_system_context) {}
void FileSystemOperationRunner::DidFinish( void FileSystemOperationRunner::DidFinish(
OperationID id, const OperationHandle& handle,
const StatusCallback& callback, const StatusCallback& callback,
base::PlatformFileError rv) { base::PlatformFileError rv) {
if (handle.scope) {
finished_operations_.insert(handle.id);
base::MessageLoopProxy::current()->PostTask(
FROM_HERE, base::Bind(&FileSystemOperationRunner::DidFinish,
AsWeakPtr(), handle, callback, rv));
return;
}
callback.Run(rv); callback.Run(rv);
FinishOperation(id); FinishOperation(handle.id);
} }
void FileSystemOperationRunner::DidGetMetadata( void FileSystemOperationRunner::DidGetMetadata(
OperationID id, const OperationHandle& handle,
const GetMetadataCallback& callback, const GetMetadataCallback& callback,
base::PlatformFileError rv, base::PlatformFileError rv,
const base::PlatformFileInfo& file_info) { const base::PlatformFileInfo& file_info) {
if (handle.scope) {
finished_operations_.insert(handle.id);
base::MessageLoopProxy::current()->PostTask(
FROM_HERE, base::Bind(&FileSystemOperationRunner::DidGetMetadata,
AsWeakPtr(), handle, callback, rv, file_info));
return;
}
callback.Run(rv, file_info); callback.Run(rv, file_info);
FinishOperation(id); FinishOperation(handle.id);
} }
void FileSystemOperationRunner::DidReadDirectory( void FileSystemOperationRunner::DidReadDirectory(
OperationID id, const OperationHandle& handle,
const ReadDirectoryCallback& callback, const ReadDirectoryCallback& callback,
base::PlatformFileError rv, base::PlatformFileError rv,
const std::vector<DirectoryEntry>& entries, const std::vector<DirectoryEntry>& entries,
bool has_more) { bool has_more) {
if (handle.scope) {
finished_operations_.insert(handle.id);
base::MessageLoopProxy::current()->PostTask(
FROM_HERE, base::Bind(&FileSystemOperationRunner::DidReadDirectory,
AsWeakPtr(), handle, callback, rv,
entries, has_more));
return;
}
callback.Run(rv, entries, has_more); callback.Run(rv, entries, has_more);
if (rv != base::PLATFORM_FILE_OK || !has_more) if (rv != base::PLATFORM_FILE_OK || !has_more)
FinishOperation(id); FinishOperation(handle.id);
} }
void FileSystemOperationRunner::DidWrite( void FileSystemOperationRunner::DidWrite(
OperationID id, const OperationHandle& handle,
const WriteCallback& callback, const WriteCallback& callback,
base::PlatformFileError rv, base::PlatformFileError rv,
int64 bytes, int64 bytes,
bool complete) { bool complete) {
if (handle.scope) {
finished_operations_.insert(handle.id);
base::MessageLoopProxy::current()->PostTask(
FROM_HERE, base::Bind(&FileSystemOperationRunner::DidWrite, AsWeakPtr(),
handle, callback, rv, bytes, complete));
return;
}
callback.Run(rv, bytes, complete); callback.Run(rv, bytes, complete);
if (rv != base::PLATFORM_FILE_OK || complete) if (rv != base::PLATFORM_FILE_OK || complete)
FinishOperation(id); FinishOperation(handle.id);
} }
void FileSystemOperationRunner::DidOpenFile( void FileSystemOperationRunner::DidOpenFile(
OperationID id, const OperationHandle& handle,
const OpenFileCallback& callback, const OpenFileCallback& callback,
base::PlatformFileError rv, base::PlatformFileError rv,
base::PlatformFile file, base::PlatformFile file,
const base::Closure& on_close_callback, const base::Closure& on_close_callback,
base::ProcessHandle peer_handle) { base::ProcessHandle peer_handle) {
if (handle.scope) {
finished_operations_.insert(handle.id);
base::MessageLoopProxy::current()->PostTask(
FROM_HERE, base::Bind(&FileSystemOperationRunner::DidOpenFile,
AsWeakPtr(), handle, callback, rv, file,
on_close_callback, peer_handle));
return;
}
callback.Run(rv, file, on_close_callback, peer_handle); callback.Run(rv, file, on_close_callback, peer_handle);
FinishOperation(id); FinishOperation(handle.id);
} }
void FileSystemOperationRunner::DidCreateSnapshot( void FileSystemOperationRunner::DidCreateSnapshot(
OperationID id, const OperationHandle& handle,
const SnapshotFileCallback& callback, const SnapshotFileCallback& callback,
base::PlatformFileError rv, base::PlatformFileError rv,
const base::PlatformFileInfo& file_info, const base::PlatformFileInfo& file_info,
const base::FilePath& platform_path, const base::FilePath& platform_path,
const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) { const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) {
if (handle.scope) {
finished_operations_.insert(handle.id);
base::MessageLoopProxy::current()->PostTask(
FROM_HERE, base::Bind(&FileSystemOperationRunner::DidCreateSnapshot,
AsWeakPtr(), handle, callback, rv, file_info,
platform_path, file_ref));
return;
}
callback.Run(rv, file_info, platform_path, file_ref); callback.Run(rv, file_info, platform_path, file_ref);
FinishOperation(id); FinishOperation(handle.id);
} }
void FileSystemOperationRunner::PrepareForWrite(OperationID id, void FileSystemOperationRunner::PrepareForWrite(OperationID id,
...@@ -529,6 +610,16 @@ void FileSystemOperationRunner::PrepareForRead(OperationID id, ...@@ -529,6 +610,16 @@ void FileSystemOperationRunner::PrepareForRead(OperationID id,
} }
} }
FileSystemOperationRunner::OperationHandle
FileSystemOperationRunner::BeginOperation(
FileSystemOperation* operation,
base::WeakPtr<BeginOperationScoper> scope) {
OperationHandle handle;
handle.id = operations_.Add(operation);
handle.scope = scope;
return handle;
}
void FileSystemOperationRunner::FinishOperation(OperationID id) { void FileSystemOperationRunner::FinishOperation(OperationID id) {
OperationToURLSet::iterator found = write_target_urls_.find(id); OperationToURLSet::iterator found = write_target_urls_.find(id);
if (found != write_target_urls_.end()) { if (found != write_target_urls_.end()) {
...@@ -542,8 +633,22 @@ void FileSystemOperationRunner::FinishOperation(OperationID id) { ...@@ -542,8 +633,22 @@ void FileSystemOperationRunner::FinishOperation(OperationID id) {
} }
write_target_urls_.erase(found); write_target_urls_.erase(found);
} }
DCHECK(operations_.Lookup(id));
// IDMap::Lookup fails if the operation is NULL, so we don't check
// operations_.Lookup(id) here.
operations_.Remove(id); operations_.Remove(id);
finished_operations_.erase(id);
// Dispatch stray cancel callback if exists.
std::map<OperationID, StatusCallback>::iterator found_cancel =
stray_cancel_callbacks_.find(id);
if (found_cancel != stray_cancel_callbacks_.end()) {
// This cancel has been requested after the operation has finished,
// so report that we failed to stop it.
found_cancel->second.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION);
stray_cancel_callbacks_.erase(found_cancel);
}
} }
} // namespace fileapi } // namespace fileapi
...@@ -43,8 +43,6 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemOperationRunner ...@@ -43,8 +43,6 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemOperationRunner
typedef int OperationID; typedef int OperationID;
static const OperationID kErrorOperationID;
virtual ~FileSystemOperationRunner(); virtual ~FileSystemOperationRunner();
// Cancels all inflight operations. // Cancels all inflight operations.
...@@ -222,35 +220,45 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemOperationRunner ...@@ -222,35 +220,45 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemOperationRunner
base::FilePath* platform_path); base::FilePath* platform_path);
private: private:
class BeginOperationScoper;
struct OperationHandle {
OperationID id;
base::WeakPtr<BeginOperationScoper> scope;
OperationHandle();
~OperationHandle();
};
friend class FileSystemContext; friend class FileSystemContext;
explicit FileSystemOperationRunner(FileSystemContext* file_system_context); explicit FileSystemOperationRunner(FileSystemContext* file_system_context);
void DidFinish(OperationID id, void DidFinish(const OperationHandle& handle,
const StatusCallback& callback, const StatusCallback& callback,
base::PlatformFileError rv); base::PlatformFileError rv);
void DidGetMetadata(OperationID id, void DidGetMetadata(const OperationHandle& handle,
const GetMetadataCallback& callback, const GetMetadataCallback& callback,
base::PlatformFileError rv, base::PlatformFileError rv,
const base::PlatformFileInfo& file_info); const base::PlatformFileInfo& file_info);
void DidReadDirectory(OperationID id, void DidReadDirectory(const OperationHandle& handle,
const ReadDirectoryCallback& callback, const ReadDirectoryCallback& callback,
base::PlatformFileError rv, base::PlatformFileError rv,
const std::vector<DirectoryEntry>& entries, const std::vector<DirectoryEntry>& entries,
bool has_more); bool has_more);
void DidWrite(OperationID id, void DidWrite(const OperationHandle& handle,
const WriteCallback& callback, const WriteCallback& callback,
base::PlatformFileError rv, base::PlatformFileError rv,
int64 bytes, int64 bytes,
bool complete); bool complete);
void DidOpenFile( void DidOpenFile(
OperationID id, const OperationHandle& handle,
const OpenFileCallback& callback, const OpenFileCallback& callback,
base::PlatformFileError rv, base::PlatformFileError rv,
base::PlatformFile file, base::PlatformFile file,
const base::Closure& on_close_callback, const base::Closure& on_close_callback,
base::ProcessHandle peer_handle); base::ProcessHandle peer_handle);
void DidCreateSnapshot( void DidCreateSnapshot(
OperationID id, const OperationHandle& handle,
const SnapshotFileCallback& callback, const SnapshotFileCallback& callback,
base::PlatformFileError rv, base::PlatformFileError rv,
const base::PlatformFileInfo& file_info, const base::PlatformFileInfo& file_info,
...@@ -260,7 +268,9 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemOperationRunner ...@@ -260,7 +268,9 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemOperationRunner
void PrepareForWrite(OperationID id, const FileSystemURL& url); void PrepareForWrite(OperationID id, const FileSystemURL& url);
void PrepareForRead(OperationID id, const FileSystemURL& url); void PrepareForRead(OperationID id, const FileSystemURL& url);
// This must be called at the end of any async operations. // These must be called at the beginning and end of any async operations.
OperationHandle BeginOperation(FileSystemOperation* operation,
base::WeakPtr<BeginOperationScoper> scope);
void FinishOperation(OperationID id); void FinishOperation(OperationID id);
// Not owned; file_system_context owns this. // Not owned; file_system_context owns this.
...@@ -274,6 +284,12 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemOperationRunner ...@@ -274,6 +284,12 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemOperationRunner
typedef std::map<OperationID, FileSystemURLSet> OperationToURLSet; typedef std::map<OperationID, FileSystemURLSet> OperationToURLSet;
OperationToURLSet write_target_urls_; OperationToURLSet write_target_urls_;
// Operations that are finished but not yet fire their callbacks.
std::set<OperationID> finished_operations_;
// Callbacks for stray cancels whose target operation is already finished.
std::map<OperationID, StatusCallback> stray_cancel_callbacks_;
DISALLOW_COPY_AND_ASSIGN(FileSystemOperationRunner); DISALLOW_COPY_AND_ASSIGN(FileSystemOperationRunner);
}; };
......
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/basictypes.h"
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
#include "base/message_loop/message_loop.h"
#include "base/platform_file.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/browser/fileapi/file_system_context.h"
#include "webkit/browser/fileapi/file_system_operation_runner.h"
#include "webkit/browser/fileapi/mock_file_system_context.h"
namespace fileapi {
void GetStatus(bool* done,
base::PlatformFileError *status_out,
base::PlatformFileError status) {
ASSERT_FALSE(*done);
*done = true;
*status_out = status;
}
void GetCancelStatus(bool* operation_done,
bool* cancel_done,
base::PlatformFileError *status_out,
base::PlatformFileError status) {
// Cancel callback must be always called after the operation's callback.
ASSERT_TRUE(*operation_done);
ASSERT_FALSE(*cancel_done);
*cancel_done = true;
*status_out = status;
}
class FileSystemOperationRunnerTest : public testing::Test {
protected:
FileSystemOperationRunnerTest() {}
virtual ~FileSystemOperationRunnerTest() {}
virtual void SetUp() OVERRIDE {
ASSERT_TRUE(base_.CreateUniqueTempDir());
base::FilePath base_dir = base_.path();
file_system_context_ =
CreateFileSystemContextForTesting(NULL, base_dir);
}
virtual void TearDown() OVERRIDE {
file_system_context_ = NULL;
base::MessageLoop::current()->RunUntilIdle();
}
FileSystemURL URL(const std::string& path) {
return file_system_context_->CreateCrackedFileSystemURL(
GURL("http://example.com"), kFileSystemTypeTemporary,
base::FilePath::FromUTF8Unsafe(path));
}
FileSystemOperationRunner* operation_runner() {
return file_system_context_->operation_runner();
}
private:
base::ScopedTempDir base_;
base::MessageLoop message_loop_;
scoped_refptr<FileSystemContext> file_system_context_;
DISALLOW_COPY_AND_ASSIGN(FileSystemOperationRunnerTest);
};
TEST_F(FileSystemOperationRunnerTest, NotFoundError) {
bool done = false;
base::PlatformFileError status = base::PLATFORM_FILE_ERROR_FAILED;
// Regular NOT_FOUND error, which is called asynchronously.
operation_runner()->Truncate(URL("foo"), 0,
base::Bind(&GetStatus, &done, &status));
ASSERT_FALSE(done);
base::MessageLoop::current()->RunUntilIdle();
ASSERT_TRUE(done);
ASSERT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status);
}
TEST_F(FileSystemOperationRunnerTest, InvalidURLError) {
bool done = false;
base::PlatformFileError status = base::PLATFORM_FILE_ERROR_FAILED;
// Invalid URL error, which calls DidFinish synchronously.
operation_runner()->Truncate(FileSystemURL(), 0,
base::Bind(&GetStatus, &done, &status));
// The error call back shouldn't be fired synchronously.
ASSERT_FALSE(done);
base::MessageLoop::current()->RunUntilIdle();
ASSERT_TRUE(done);
ASSERT_EQ(base::PLATFORM_FILE_ERROR_INVALID_URL, status);
}
TEST_F(FileSystemOperationRunnerTest, NotFoundErrorAndCancel) {
bool done = false;
bool cancel_done = false;
base::PlatformFileError status = base::PLATFORM_FILE_ERROR_FAILED;
base::PlatformFileError cancel_status = base::PLATFORM_FILE_ERROR_FAILED;
// Call Truncate with non-existent URL, and try to cancel it immediately
// after that (before its callback is fired).
FileSystemOperationRunner::OperationID id =
operation_runner()->Truncate(URL("foo"), 0,
base::Bind(&GetStatus, &done, &status));
operation_runner()->Cancel(id, base::Bind(&GetCancelStatus,
&done, &cancel_done,
&cancel_status));
ASSERT_FALSE(done);
ASSERT_FALSE(cancel_done);
base::MessageLoop::current()->RunUntilIdle();
ASSERT_TRUE(done);
ASSERT_TRUE(cancel_done);
ASSERT_EQ(base::PLATFORM_FILE_ERROR_ABORT, status);
ASSERT_EQ(base::PLATFORM_FILE_OK, cancel_status);
}
TEST_F(FileSystemOperationRunnerTest, InvalidURLErrorAndCancel) {
bool done = false;
bool cancel_done = false;
base::PlatformFileError status = base::PLATFORM_FILE_ERROR_FAILED;
base::PlatformFileError cancel_status = base::PLATFORM_FILE_ERROR_FAILED;
// Call Truncate with invalid URL, and try to cancel it immediately
// after that (before its callback is fired).
FileSystemOperationRunner::OperationID id =
operation_runner()->Truncate(FileSystemURL(), 0,
base::Bind(&GetStatus, &done, &status));
operation_runner()->Cancel(id, base::Bind(&GetCancelStatus,
&done, &cancel_done,
&cancel_status));
ASSERT_FALSE(done);
ASSERT_FALSE(cancel_done);
base::MessageLoop::current()->RunUntilIdle();
ASSERT_TRUE(done);
ASSERT_TRUE(cancel_done);
ASSERT_EQ(base::PLATFORM_FILE_ERROR_INVALID_URL, status);
ASSERT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, cancel_status);
}
} // namespace fileapi
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment