 Chromium Code Reviews
 Chromium Code Reviews Issue 4821005:
  Make FileSystemOperation's lifetime more explicit.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src
    
  
    Issue 4821005:
  Make FileSystemOperation's lifetime more explicit.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src| Index: webkit/fileapi/file_system_operation.cc | 
| diff --git a/webkit/fileapi/file_system_operation.cc b/webkit/fileapi/file_system_operation.cc | 
| index fe077581fb7a4d3ad4da81370ffce8696da61471..88783411b5774a4516d7b731e3a1d7c771b7f7d3 100644 | 
| --- a/webkit/fileapi/file_system_operation.cc | 
| +++ b/webkit/fileapi/file_system_operation.cc | 
| @@ -11,11 +11,72 @@ | 
| namespace fileapi { | 
| +namespace { | 
| + | 
| +// A helper callback dispatcher class to make it easy to control | 
| +// FileSystemOperation's lifetime. Calling any callback methods of this | 
| +// class would delete the corresponding FileSystemOperation. | 
| +class DispatchAndDeleteCallbackWrapper | 
| + : public FileSystemCallbackDispatcher { | 
| + public: | 
| + DispatchAndDeleteCallbackWrapper( | 
| + FileSystemOperation* operation, | 
| + FileSystemCallbackDispatcher* dispatcher) | 
| + : operation_(operation), | 
| + dispatcher_(dispatcher) { } | 
| + | 
| + // Returns the wrapped dispatcher. | 
| + // This would be useful when the caller does not want to delete the operation. | 
| + FileSystemCallbackDispatcher* wrapped() const { return dispatcher_.get(); } | 
| + | 
| + virtual void DidSucceed() { | 
| + dispatcher_->DidSucceed(); | 
| + delete operation_; | 
| + } | 
| + | 
| + virtual void DidReadMetadata(const base::PlatformFileInfo& file_info) { | 
| + dispatcher_->DidReadMetadata(file_info); | 
| + delete operation_; | 
| + } | 
| + | 
| + virtual void DidReadDirectory( | 
| + const std::vector<base::FileUtilProxy::Entry>& entries, | 
| + bool has_more) { | 
| + dispatcher_->DidReadDirectory(entries, has_more); | 
| + delete operation_; | 
| + } | 
| + | 
| + virtual void DidOpenFileSystem(const std::string& name, | 
| + const FilePath& root_path) { | 
| + dispatcher_->DidOpenFileSystem(name, root_path); | 
| + delete operation_; | 
| + } | 
| + | 
| + virtual void DidFail(base::PlatformFileError error_code) { | 
| + dispatcher_->DidFail(error_code); | 
| + delete operation_; | 
| + } | 
| + | 
| + virtual void DidWrite(int64 bytes, bool complete) { | 
| + dispatcher_->DidWrite(bytes, complete); | 
| + if (complete) | 
| + delete operation_; | 
| + } | 
| + | 
| + private: | 
| + FileSystemOperation* operation_; | 
| + scoped_ptr<FileSystemCallbackDispatcher> dispatcher_; | 
| +}; | 
| + | 
| +} // namespace | 
| + | 
| FileSystemOperation::FileSystemOperation( | 
| FileSystemCallbackDispatcher* dispatcher, | 
| scoped_refptr<base::MessageLoopProxy> proxy) | 
| : proxy_(proxy), | 
| - dispatcher_(dispatcher), | 
| + destructive_dispatcher_( | 
| + new DispatchAndDeleteCallbackWrapper( | 
| + ALLOW_THIS_IN_INITIALIZER_LIST(this), dispatcher)), | 
| 
ericu
2010/11/16 19:26:54
This seems a bit odd to me.  We're creating a wrap
 | 
| callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), | 
| cancel_operation_(NULL) { | 
| DCHECK(dispatcher); | 
| @@ -158,7 +219,7 @@ void FileSystemOperation::OnFileOpenedForWrite( | 
| base::PassPlatformFile file, | 
| bool created) { | 
| if (base::PLATFORM_FILE_OK != rv) { | 
| - dispatcher_->DidFail(rv); | 
| + destructive_dispatcher()->DidFail(rv); | 
| return; | 
| } | 
| file_writer_delegate_->Start(file.ReleaseValue(), blob_request_.get()); | 
| @@ -204,8 +265,8 @@ void FileSystemOperation::Cancel(FileSystemOperation* cancel_operation) { | 
| blob_request_->Cancel(); | 
| // This deletes us, and by proxy deletes file_writer_delegate_ if any. | 
| - dispatcher_->DidFail(base::PLATFORM_FILE_ERROR_ABORT); | 
| - cancel_operation->dispatcher_->DidSucceed(); | 
| + destructive_dispatcher()->DidFail(base::PLATFORM_FILE_ERROR_ABORT); | 
| + cancel_operation->destructive_dispatcher()->DidSucceed(); | 
| } else { | 
| #ifndef NDEBUG | 
| DCHECK(kOperationTruncate == pending_operation_); | 
| @@ -214,15 +275,22 @@ void FileSystemOperation::Cancel(FileSystemOperation* cancel_operation) { | 
| // since it's been proxied to another thread. We need to save the | 
| // cancel_operation so that when the truncate returns, it can see that it's | 
| // been cancelled, report it, and report that the cancel has succeeded. | 
| + DCHECK(!cancel_operation_); | 
| cancel_operation_ = cancel_operation; | 
| } | 
| } | 
| +FileSystemCallbackDispatcher* | 
| + FileSystemOperation::non_destructive_dispatcher() const { | 
| + return static_cast<DispatchAndDeleteCallbackWrapper*>( | 
| + destructive_dispatcher_.get())->wrapped(); | 
| +} | 
| + | 
| void FileSystemOperation::DidEnsureFileExistsExclusive( | 
| base::PlatformFileError rv, bool created) { | 
| - if (rv == base::PLATFORM_FILE_OK && !created) | 
| - dispatcher_->DidFail(base::PLATFORM_FILE_ERROR_EXISTS); | 
| - else | 
| + if (rv == base::PLATFORM_FILE_OK && !created) { | 
| + destructive_dispatcher()->DidFail(base::PLATFORM_FILE_ERROR_EXISTS); | 
| + } else | 
| DidFinishFileOperation(rv); | 
| } | 
| @@ -237,14 +305,15 @@ void FileSystemOperation::DidFinishFileOperation( | 
| #ifndef NDEBUG | 
| DCHECK(kOperationTruncate == pending_operation_); | 
| #endif | 
| - FileSystemOperation *cancel_op = cancel_operation_; | 
| - // This call deletes us, so we have to extract cancel_op first. | 
| - dispatcher_->DidFail(base::PLATFORM_FILE_ERROR_ABORT); | 
| - cancel_op->dispatcher_->DidSucceed(); | 
| + | 
| + // Call non-destructive dispatcher's method not to delete this instance yet. | 
| + non_destructive_dispatcher()->DidFail(base::PLATFORM_FILE_ERROR_ABORT); | 
| + cancel_operation_->destructive_dispatcher()->DidSucceed(); | 
| + delete this; | 
| } else if (rv == base::PLATFORM_FILE_OK) { | 
| - dispatcher_->DidSucceed(); | 
| + destructive_dispatcher()->DidSucceed(); | 
| } else { | 
| - dispatcher_->DidFail(rv); | 
| + destructive_dispatcher()->DidFail(rv); | 
| } | 
| } | 
| @@ -253,11 +322,11 @@ void FileSystemOperation::DidDirectoryExists( | 
| const base::PlatformFileInfo& file_info) { | 
| if (rv == base::PLATFORM_FILE_OK) { | 
| if (file_info.is_directory) | 
| - dispatcher_->DidSucceed(); | 
| + destructive_dispatcher()->DidSucceed(); | 
| else | 
| - dispatcher_->DidFail(base::PLATFORM_FILE_ERROR_FAILED); | 
| + destructive_dispatcher()->DidFail(base::PLATFORM_FILE_ERROR_FAILED); | 
| } else { | 
| - dispatcher_->DidFail(rv); | 
| + destructive_dispatcher()->DidFail(rv); | 
| } | 
| } | 
| @@ -266,11 +335,11 @@ void FileSystemOperation::DidFileExists( | 
| const base::PlatformFileInfo& file_info) { | 
| if (rv == base::PLATFORM_FILE_OK) { | 
| if (file_info.is_directory) | 
| - dispatcher_->DidFail(base::PLATFORM_FILE_ERROR_FAILED); | 
| + destructive_dispatcher()->DidFail(base::PLATFORM_FILE_ERROR_FAILED); | 
| else | 
| - dispatcher_->DidSucceed(); | 
| + destructive_dispatcher()->DidSucceed(); | 
| } else { | 
| - dispatcher_->DidFail(rv); | 
| + destructive_dispatcher()->DidFail(rv); | 
| } | 
| } | 
| @@ -278,18 +347,18 @@ void FileSystemOperation::DidGetMetadata( | 
| base::PlatformFileError rv, | 
| const base::PlatformFileInfo& file_info) { | 
| if (rv == base::PLATFORM_FILE_OK) | 
| - dispatcher_->DidReadMetadata(file_info); | 
| + destructive_dispatcher()->DidReadMetadata(file_info); | 
| else | 
| - dispatcher_->DidFail(rv); | 
| + destructive_dispatcher()->DidFail(rv); | 
| } | 
| void FileSystemOperation::DidReadDirectory( | 
| base::PlatformFileError rv, | 
| const std::vector<base::FileUtilProxy::Entry>& entries) { | 
| if (rv == base::PLATFORM_FILE_OK) | 
| - dispatcher_->DidReadDirectory(entries, false /* has_more */); | 
| + destructive_dispatcher()->DidReadDirectory(entries, false /* has_more */); | 
| else | 
| - dispatcher_->DidFail(rv); | 
| + destructive_dispatcher()->DidFail(rv); | 
| } | 
| void FileSystemOperation::DidWrite( | 
| @@ -297,16 +366,16 @@ void FileSystemOperation::DidWrite( | 
| int64 bytes, | 
| bool complete) { | 
| if (rv == base::PLATFORM_FILE_OK) | 
| - dispatcher_->DidWrite(bytes, complete); | 
| + destructive_dispatcher()->DidWrite(bytes, complete); | 
| 
ericu
2010/11/16 19:26:54
Given that we explicitly don't want to delete the
 | 
| else | 
| - dispatcher_->DidFail(rv); | 
| + destructive_dispatcher()->DidFail(rv); | 
| } | 
| void FileSystemOperation::DidTouchFile(base::PlatformFileError rv) { | 
| if (rv == base::PLATFORM_FILE_OK) | 
| - dispatcher_->DidSucceed(); | 
| + destructive_dispatcher()->DidSucceed(); | 
| else | 
| - dispatcher_->DidFail(rv); | 
| + destructive_dispatcher()->DidFail(rv); | 
| } | 
| } // namespace fileapi |