diff options
author | kinaba@chromium.org <kinaba@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-01 05:54:26 +0000 |
---|---|---|
committer | kinaba@chromium.org <kinaba@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-01 05:54:26 +0000 |
commit | a95ce07699b8ce79df8b59e36fe53b345a5921b2 (patch) | |
tree | c4b54622b37e7aa21e004e3570b6fb6299b00973 /net | |
parent | 2f729cd95a5452af56269f594ffbe4f539303182 (diff) | |
download | chromium_src-a95ce07699b8ce79df8b59e36fe53b345a5921b2.zip chromium_src-a95ce07699b8ce79df8b59e36fe53b345a5921b2.tar.gz chromium_src-a95ce07699b8ce79df8b59e36fe53b345a5921b2.tar.bz2 |
Flush at the end of local file writing in FileWriter API.
This CL ensures the written content is flushed physically before
fileWriter.write() invokes the "onwriteend" event, for native local files.
Remote files (Google Drive files in Chrome OS) nor FileSystem API
files (in PERSISTENT or TEMPORARY storage) aren't affected.
The summary of the changes:
* Call Flush() before the final callback.
(webkit/fileapi/file_writer_delegate.cc)
* Delegate Flush() to net::FileStream::Flush
(webkit/fileapi/local_file_stream_writer.cc)
* No-op implementation for Flush().
(webkit/fileapi/sanbox_file_stream_writer.cc)
(webkit/chromeos/fileapi/remote_file_stream_writer.cc)
* Implementation of asynchronous Flush.
(net/base/file_stream_{posix,win}.cc)
* Other files are just for reflecting the rename Flush -> FlushSync.
BUG=144790
R=willchan@chromium.org,kinuko@chromium.org,benjhayden@chromium.org
TBR=marja@chromium.org
TEST=out/Debug/browser_tests --gtest_filter='*FileSystemApi*'
TEST=./webkit/tools/layout_tests/run_webkit_tests.sh fast/filesystem
TEST=Manual steps reported in the issue.
Review URL: https://codereview.chromium.org/10986045
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@159454 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/base/file_stream.cc | 8 | ||||
-rw-r--r-- | net/base/file_stream.h | 25 | ||||
-rw-r--r-- | net/base/file_stream_posix.cc | 37 | ||||
-rw-r--r-- | net/base/file_stream_posix.h | 3 | ||||
-rw-r--r-- | net/base/file_stream_win.cc | 49 | ||||
-rw-r--r-- | net/base/file_stream_win.h | 9 | ||||
-rw-r--r-- | net/base/mock_file_stream.cc | 8 | ||||
-rw-r--r-- | net/base/mock_file_stream.h | 3 |
8 files changed, 131 insertions, 11 deletions
diff --git a/net/base/file_stream.cc b/net/base/file_stream.cc index 1707fb7..df18ad0 100644 --- a/net/base/file_stream.cc +++ b/net/base/file_stream.cc @@ -78,8 +78,12 @@ int64 FileStream::Truncate(int64 bytes) { return impl_.Truncate(bytes); } -int FileStream::Flush() { - return impl_.Flush(); +int FileStream::Flush(const CompletionCallback& callback) { + return impl_.Flush(callback); +} + +int FileStream::FlushSync() { + return impl_.FlushSync(); } void FileStream::EnableErrorStatistics() { diff --git a/net/base/file_stream.h b/net/base/file_stream.h index 2031bd0..f4cfff2 100644 --- a/net/base/file_stream.h +++ b/net/base/file_stream.h @@ -197,10 +197,31 @@ class NET_EXPORT FileStream { // not have to be called, it just forces one to happen at the time of // calling. // - /// Returns an error code if the operation could not be performed. + // The file must be opened with PLATFORM_FILE_ASYNC, and a non-null + // callback must be passed to this method. If the write could not + // complete synchronously, then ERR_IO_PENDING is returned, and the + // callback will be run on the thread where Flush() was called when + // the write has completed. + // + // It is valid to destroy or close the file stream while there is an + // asynchronous flush in progress. That will cancel the flush and allow + // the buffer to be freed. + // + // It is invalid to request any asynchronous operations while there is an + // in-flight asynchronous operation. + // + // This method should not be called if the stream was opened READ_ONLY. + virtual int Flush(const CompletionCallback& callback); + + // Forces out a filesystem sync on this file to make sure that the file was + // written out to disk and is not currently sitting in the buffer. This does + // not have to be called, it just forces one to happen at the time of + // calling. + // + // Returns an error code if the operation could not be performed. // // This method should not be called if the stream was opened READ_ONLY. - virtual int Flush(); + virtual int FlushSync(); // Turns on UMA error statistics gathering. void EnableErrorStatistics(); diff --git a/net/base/file_stream_posix.cc b/net/base/file_stream_posix.cc index 0cbd0bd..5613fe3 100644 --- a/net/base/file_stream_posix.cc +++ b/net/base/file_stream_posix.cc @@ -231,6 +231,16 @@ int FlushFile(base::PlatformFile file, return res; } +// Flushes a file using FlushFile() and signals the completion. +void FlushFileAndSignal(base::PlatformFile file, + int* result, + bool record_uma, + base::WaitableEvent* on_io_complete, + const net::BoundNetLog& bound_net_log) { + *result = FlushFile(file, record_uma, bound_net_log); + on_io_complete->Signal(); +} + // Called when Read(), Write() or Seek() is completed. // |result| contains the result or a network error code. template <typename R> @@ -588,7 +598,32 @@ int64 FileStreamPosix::Truncate(int64 bytes) { bound_net_log_); } -int FileStreamPosix::Flush() { +int FileStreamPosix::Flush(const CompletionCallback& callback) { + if (!IsOpen()) + return ERR_UNEXPECTED; + + // Make sure we're async and we have no other in-flight async operations. + DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); + DCHECK(!weak_ptr_factory_.HasWeakPtrs()); + DCHECK(!on_io_complete_.get()); + + on_io_complete_.reset(new base::WaitableEvent( + false /* manual_reset */, false /* initially_signaled */)); + + int* result = new int(OK); + const bool posted = base::WorkerPool::PostTaskAndReply( + FROM_HERE, + base::Bind(&FlushFileAndSignal, file_, result, + record_uma_, on_io_complete_.get(), bound_net_log_), + base::Bind(&OnIOComplete<int>, + weak_ptr_factory_.GetWeakPtr(), + callback, base::Owned(result)), + true /* task is slow */); + DCHECK(posted); + return ERR_IO_PENDING; +} + +int FileStreamPosix::FlushSync() { if (!IsOpen()) return ERR_UNEXPECTED; diff --git a/net/base/file_stream_posix.h b/net/base/file_stream_posix.h index 0f1ee01..2ac7d63 100644 --- a/net/base/file_stream_posix.h +++ b/net/base/file_stream_posix.h @@ -48,7 +48,8 @@ class NET_EXPORT FileStreamPosix { int Write(IOBuffer* buf, int buf_len, const CompletionCallback& callback); int WriteSync(const char* buf, int buf_len); int64 Truncate(int64 bytes); - int Flush(); + int Flush(const CompletionCallback& callback); + int FlushSync(); void EnableErrorStatistics(); void SetBoundNetLogSource( const net::BoundNetLog& owner_bound_net_log); diff --git a/net/base/file_stream_win.cc b/net/base/file_stream_win.cc index fe820b1..88e1dc7 100644 --- a/net/base/file_stream_win.cc +++ b/net/base/file_stream_win.cc @@ -587,7 +587,37 @@ int FileStreamWin::WriteSync( return rv; } -int FileStreamWin::Flush() { +int FileStreamWin::Flush(const CompletionCallback& callback) { + if (!IsOpen()) + return ERR_UNEXPECTED; + + // Make sure we're async and we have no other in-flight async operations. + DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); + DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); + DCHECK(!weak_ptr_factory_.HasWeakPtrs()); + DCHECK(!on_io_complete_.get()); + + on_io_complete_.reset(new base::WaitableEvent( + false /* manual_reset */, false /* initially_signaled */)); + + int* result = new int(OK); + const bool posted = base::WorkerPool::PostTaskAndReply( + FROM_HERE, + base::Bind(&InvokeAndSignal, + // Unretained should be fine as we wait for a signal on + // on_io_complete_ at the destructor. + base::Bind(&FileStreamWin::FlushFile, base::Unretained(this), + result), + on_io_complete_.get()), + base::Bind(&FileStreamWin::OnFlushed, + weak_ptr_factory_.GetWeakPtr(), + callback, base::Owned(result)), + true /* task is slow */); + DCHECK(posted); + return ERR_IO_PENDING; +} + +int FileStreamWin::FlushSync() { base::ThreadRestrictions::AssertIOAllowed(); if (!IsOpen()) @@ -692,6 +722,17 @@ void FileStreamWin::SeekFile(Whence whence, int64 offset, int64* result) { *result = res.QuadPart; } +void FileStreamWin::FlushFile(int* result) { + if (FlushFileBuffers(file_)) { + *result = OK; + } else { + *result = RecordAndMapError(GetLastError(), + FILE_ERROR_SOURCE_FLUSH, + record_uma_, + bound_net_log_); + } +} + void FileStreamWin::OnOpened(const CompletionCallback& callback, int* result) { if (*result == OK) { async_context_.reset(new AsyncContext(bound_net_log_)); @@ -714,6 +755,12 @@ void FileStreamWin::OnSeeked( callback.Run(*result); } +void FileStreamWin::OnFlushed(const CompletionCallback& callback, int* result) { + // Reset this before Run() as Run() may issue a new async operation. + ResetOnIOComplete(); + callback.Run(*result); +} + void FileStreamWin::ResetOnIOComplete() { on_io_complete_.reset(); weak_ptr_factory_.InvalidateWeakPtrs(); diff --git a/net/base/file_stream_win.h b/net/base/file_stream_win.h index 4feb7a2..e241f4c 100644 --- a/net/base/file_stream_win.h +++ b/net/base/file_stream_win.h @@ -49,7 +49,8 @@ class NET_EXPORT FileStreamWin { int Write(IOBuffer* buf, int buf_len, const CompletionCallback& callback); int WriteSync(const char* buf, int buf_len); int64 Truncate(int64 bytes); - int Flush(); + int Flush(const CompletionCallback& callback); + int FlushSync(); void EnableErrorStatistics(); void SetBoundNetLogSource(const net::BoundNetLog& owner_bound_net_log); base::PlatformFile GetPlatformFileForTesting(); @@ -60,6 +61,9 @@ class NET_EXPORT FileStreamWin { // A helper method for Seek. void SeekFile(Whence whence, int64 offset, int64* result); + // A helper method for Flush. + void FlushFile(int* result); + // Called when the file_ is opened asynchronously. |result| contains the // result as a network error code. void OnOpened(const CompletionCallback& callback, int* result); @@ -70,6 +74,9 @@ class NET_EXPORT FileStreamWin { // Called when the file_ is seeked asynchronously. void OnSeeked(const Int64CompletionCallback& callback, int64* result); + // Called when the file_ is flushed asynchronously. + void OnFlushed(const CompletionCallback& callback, int* result); + // Resets on_io_complete_ and WeakPtr's. // Called in OnOpened, OnClosed and OnSeeked. void ResetOnIOComplete(); diff --git a/net/base/mock_file_stream.cc b/net/base/mock_file_stream.cc index 42c23cb..fccb7a0 100644 --- a/net/base/mock_file_stream.cc +++ b/net/base/mock_file_stream.cc @@ -54,8 +54,12 @@ int64 MockFileStream::Truncate(int64 bytes) { return ReturnError64(FileStream::Truncate(bytes)); } -int MockFileStream::Flush() { - return ReturnError(FileStream::Flush()); +int MockFileStream::Flush(const CompletionCallback& callback) { + return ReturnError(FileStream::Flush(callback)); +} + +int MockFileStream::FlushSync() { + return ReturnError(FileStream::FlushSync()); } } // namespace testing diff --git a/net/base/mock_file_stream.h b/net/base/mock_file_stream.h index 18b7127..f9c8bbd 100644 --- a/net/base/mock_file_stream.h +++ b/net/base/mock_file_stream.h @@ -43,7 +43,8 @@ class MockFileStream : public net::FileStream { const CompletionCallback& callback) OVERRIDE; virtual int WriteSync(const char* buf, int buf_len) OVERRIDE; virtual int64 Truncate(int64 bytes) OVERRIDE; - virtual int Flush() OVERRIDE; + virtual int Flush(const CompletionCallback& callback) OVERRIDE; + virtual int FlushSync() OVERRIDE; void set_forced_error(int error) { forced_error_ = error; } void clear_forced_error() { forced_error_ = net::OK; } |