Chromium Code Reviews| Index: chrome/browser/chromeos/file_system_provider/fileapi/buffering_file_stream_writer.cc |
| diff --git a/chrome/browser/chromeos/file_system_provider/fileapi/buffering_file_stream_writer.cc b/chrome/browser/chromeos/file_system_provider/fileapi/buffering_file_stream_writer.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..5b75ff87def23df93b545bd3a776fea0d7fb2282 |
| --- /dev/null |
| +++ b/chrome/browser/chromeos/file_system_provider/fileapi/buffering_file_stream_writer.cc |
| @@ -0,0 +1,178 @@ |
| +// Copyright 2014 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 "chrome/browser/chromeos/file_system_provider/fileapi/buffering_file_stream_writer.h" |
| + |
| +#include <algorithm> |
| + |
| +#include "net/base/io_buffer.h" |
| +#include "net/base/net_errors.h" |
| + |
| +namespace chromeos { |
| +namespace file_system_provider { |
| + |
| +BufferingFileStreamWriter::BufferingFileStreamWriter( |
| + scoped_ptr<storage::FileStreamWriter> file_stream_writer, |
| + int intermediate_buffer_length) |
| + : file_stream_writer_(file_stream_writer.Pass()), |
| + intermediate_buffer_length_(intermediate_buffer_length), |
| + intermediate_buffer_(new net::IOBuffer(intermediate_buffer_length_)), |
| + buffered_bytes_(0), |
| + weak_ptr_factory_(this) { |
| +} |
| + |
| +BufferingFileStreamWriter::~BufferingFileStreamWriter() { |
| +} |
| + |
| +int BufferingFileStreamWriter::Write(net::IOBuffer* buffer, |
| + int buffer_length, |
| + const net::CompletionCallback& callback) { |
| + // If |buffer_length| is larger than the intermediate buffer, then call the |
| + // internal file stream writer directly. Note, that the intermediate buffer |
| + // (used for buffering) must be flushed first. |
| + if (buffer_length > intermediate_buffer_length_) { |
| + if (buffered_bytes_) { |
| + FlushIntermediateBuffer( |
| + base::Bind(&BufferingFileStreamWriter:: |
| + OnFlushIntermediateBufferForDirectWriteCompleted, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + make_scoped_refptr(buffer), |
| + buffer_length, |
| + callback)); |
| + } else { |
| + // Nothing to flush, so skip it. |
| + OnFlushIntermediateBufferForDirectWriteCompleted( |
| + make_scoped_refptr(buffer), buffer_length, callback, net::OK); |
| + } |
| + return net::ERR_IO_PENDING; |
| + } |
| + |
| + // Buffer consecutive writes to larger chunks. |
| + const int buffer_bytes = |
| + std::min(intermediate_buffer_length_ - buffered_bytes_, buffer_length); |
| + |
| + CopyToIntermediateBuffer( |
| + make_scoped_refptr(buffer), 0 /* offset */, buffer_bytes); |
| + const int bytes_left = buffer_length - buffer_bytes; |
| + |
| + if (buffered_bytes_ == intermediate_buffer_length_) { |
| + FlushIntermediateBuffer( |
| + base::Bind(&BufferingFileStreamWriter:: |
| + OnFlushIntermediateBufferForBufferedWriteCompleted, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + make_scoped_refptr(buffer), |
| + buffer_bytes, |
| + bytes_left, |
| + callback)); |
| + return net::ERR_IO_PENDING; |
| + } |
| + |
| + // Optimistically return a success. |
| + return buffer_length; |
| +} |
| + |
| +int BufferingFileStreamWriter::Cancel(const net::CompletionCallback& callback) { |
| + return file_stream_writer_->Cancel(callback); |
| +} |
| + |
| +int BufferingFileStreamWriter::Flush(const net::CompletionCallback& callback) { |
| + // Flush all the buffered bytes first, then invoke Flush() on the inner file |
| + // stream writer. |
| + FlushIntermediateBuffer(base::Bind( |
| + &BufferingFileStreamWriter::OnFlushIntermediateBufferForFlushCompleted, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + callback)); |
| + return net::ERR_IO_PENDING; |
| +} |
| + |
| +void BufferingFileStreamWriter::CopyToIntermediateBuffer( |
| + scoped_refptr<net::IOBuffer> buffer, |
| + int offset, |
| + int length) { |
| + DCHECK_GE(intermediate_buffer_length_, offset + length + buffered_bytes_); |
| + memcpy(intermediate_buffer_->data() + buffered_bytes_, |
| + buffer->data() + offset, |
| + length); |
| + buffered_bytes_ += length; |
| +} |
| + |
| +void BufferingFileStreamWriter::FlushIntermediateBuffer( |
| + const net::CompletionCallback& callback) { |
| + const int result = file_stream_writer_->Write( |
| + intermediate_buffer_, |
| + buffered_bytes_, |
| + base::Bind(&BufferingFileStreamWriter::OnFlushIntermediateBufferCompleted, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + buffered_bytes_, |
| + callback)); |
| + DCHECK_EQ(net::ERR_IO_PENDING, result); |
| +} |
| + |
| +void BufferingFileStreamWriter::OnFlushIntermediateBufferCompleted( |
| + int length, |
| + const net::CompletionCallback& callback, |
| + int result) { |
| + if (result < 0) { |
| + callback.Run(result); |
| + return; |
| + } |
| + |
| + DCHECK_EQ(length, result) << "Partial reads are not supported."; |
| + buffered_bytes_ = 0; |
| + callback.Run(net::OK); |
| +} |
| + |
| +void |
| +BufferingFileStreamWriter::OnFlushIntermediateBufferForDirectWriteCompleted( |
| + scoped_refptr<net::IOBuffer> buffer, |
| + int length, |
| + const net::CompletionCallback& callback, |
| + int result) { |
| + if (result < 0) { |
| + callback.Run(result); |
| + return; |
| + } |
| + |
| + // Write all bytes directly. |
| + DCHECK_EQ(net::OK, result); |
| + DCHECK_EQ(0, buffered_bytes_); |
| + const int write_result = file_stream_writer_->Write(buffer, length, callback); |
| + DCHECK_EQ(net::ERR_IO_PENDING, write_result); |
| +} |
| + |
| +void |
| +BufferingFileStreamWriter::OnFlushIntermediateBufferForBufferedWriteCompleted( |
| + scoped_refptr<net::IOBuffer> buffer, |
| + int buffered_bytes, |
| + int bytes_left, |
| + const net::CompletionCallback& callback, |
| + int result) { |
| + if (result < 0) { |
| + callback.Run(result); |
| + return; |
| + } |
| + |
| + // Copy the rest of bytes to the buffer. |
| + DCHECK_EQ(net::OK, result); |
| + DCHECK_EQ(0, buffered_bytes_); |
| + DCHECK_GE(intermediate_buffer_length_, bytes_left); |
| + CopyToIntermediateBuffer(buffer, buffered_bytes, bytes_left); |
| + |
| + callback.Run(buffered_bytes + bytes_left); |
| +} |
| + |
| +void BufferingFileStreamWriter::OnFlushIntermediateBufferForFlushCompleted( |
| + const net::CompletionCallback& callback, |
| + int result) { |
| + if (result < 0) { |
| + callback.Run(result); |
| + return; |
| + } |
| + |
| + const int flush_result = file_stream_writer_->Flush(callback); |
| + DCHECK_EQ(net::ERR_IO_PENDING, flush_result); |
|
hashimoto
2014/08/28 08:32:17
It seems FileStreamWriter::Flush doesn't return ER
mtomasz
2014/08/29 02:49:00
Done.
|
| +} |
| + |
| +} // namespace file_system_provider |
| +} // namespace chromeos |