OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/chromeos/file_system_provider/fileapi/buffering_file_st
ream_writer.h" |
| 6 |
| 7 #include <algorithm> |
| 8 |
| 9 #include "net/base/io_buffer.h" |
| 10 #include "net/base/net_errors.h" |
| 11 |
| 12 namespace chromeos { |
| 13 namespace file_system_provider { |
| 14 |
| 15 BufferingFileStreamWriter::BufferingFileStreamWriter( |
| 16 scoped_ptr<storage::FileStreamWriter> file_stream_writer, |
| 17 int intermediate_buffer_length) |
| 18 : file_stream_writer_(file_stream_writer.Pass()), |
| 19 intermediate_buffer_length_(intermediate_buffer_length), |
| 20 intermediate_buffer_(new net::IOBuffer(intermediate_buffer_length_)), |
| 21 buffered_bytes_(0), |
| 22 weak_ptr_factory_(this) { |
| 23 } |
| 24 |
| 25 BufferingFileStreamWriter::~BufferingFileStreamWriter() { |
| 26 if (buffered_bytes_) |
| 27 LOG(ERROR) << "File stream writer not flushed. Data will be lost."; |
| 28 } |
| 29 |
| 30 int BufferingFileStreamWriter::Write(net::IOBuffer* buffer, |
| 31 int buffer_length, |
| 32 const net::CompletionCallback& callback) { |
| 33 // If |buffer_length| is larger than the intermediate buffer, then call the |
| 34 // inner file stream writer directly. Note, that the intermediate buffer |
| 35 // (used for buffering) must be flushed first. |
| 36 if (buffer_length > intermediate_buffer_length_) { |
| 37 if (buffered_bytes_) { |
| 38 FlushIntermediateBuffer( |
| 39 base::Bind(&BufferingFileStreamWriter:: |
| 40 OnFlushIntermediateBufferForDirectWriteCompleted, |
| 41 weak_ptr_factory_.GetWeakPtr(), |
| 42 make_scoped_refptr(buffer), |
| 43 buffer_length, |
| 44 callback)); |
| 45 } else { |
| 46 // Nothing to flush, so skip it. |
| 47 OnFlushIntermediateBufferForDirectWriteCompleted( |
| 48 make_scoped_refptr(buffer), buffer_length, callback, net::OK); |
| 49 } |
| 50 return net::ERR_IO_PENDING; |
| 51 } |
| 52 |
| 53 // Buffer consecutive writes to larger chunks. |
| 54 const int buffer_bytes = |
| 55 std::min(intermediate_buffer_length_ - buffered_bytes_, buffer_length); |
| 56 |
| 57 CopyToIntermediateBuffer( |
| 58 make_scoped_refptr(buffer), 0 /* buffer_offset */, buffer_bytes); |
| 59 const int bytes_left = buffer_length - buffer_bytes; |
| 60 |
| 61 if (buffered_bytes_ == intermediate_buffer_length_) { |
| 62 FlushIntermediateBuffer( |
| 63 base::Bind(&BufferingFileStreamWriter:: |
| 64 OnFlushIntermediateBufferForBufferedWriteCompleted, |
| 65 weak_ptr_factory_.GetWeakPtr(), |
| 66 make_scoped_refptr(buffer), |
| 67 buffer_bytes, |
| 68 bytes_left, |
| 69 callback)); |
| 70 return net::ERR_IO_PENDING; |
| 71 } |
| 72 |
| 73 // Optimistically return a success. |
| 74 return buffer_length; |
| 75 } |
| 76 |
| 77 int BufferingFileStreamWriter::Cancel(const net::CompletionCallback& callback) { |
| 78 // Since there is no any asynchronous call in this class other than on |
| 79 // |file_stream_writer_|, then there must be an in-flight operation going on. |
| 80 return file_stream_writer_->Cancel(callback); |
| 81 } |
| 82 |
| 83 int BufferingFileStreamWriter::Flush(const net::CompletionCallback& callback) { |
| 84 // Flush all the buffered bytes first, then invoke Flush() on the inner file |
| 85 // stream writer. |
| 86 FlushIntermediateBuffer(base::Bind( |
| 87 &BufferingFileStreamWriter::OnFlushIntermediateBufferForFlushCompleted, |
| 88 weak_ptr_factory_.GetWeakPtr(), |
| 89 callback)); |
| 90 return net::ERR_IO_PENDING; |
| 91 } |
| 92 |
| 93 void BufferingFileStreamWriter::CopyToIntermediateBuffer( |
| 94 scoped_refptr<net::IOBuffer> buffer, |
| 95 int buffer_offset, |
| 96 int buffer_length) { |
| 97 DCHECK_GE(intermediate_buffer_length_, buffer_length + buffered_bytes_); |
| 98 memcpy(intermediate_buffer_->data() + buffered_bytes_, |
| 99 buffer->data() + buffer_offset, |
| 100 buffer_length); |
| 101 buffered_bytes_ += buffer_length; |
| 102 } |
| 103 |
| 104 void BufferingFileStreamWriter::FlushIntermediateBuffer( |
| 105 const net::CompletionCallback& callback) { |
| 106 const int result = file_stream_writer_->Write( |
| 107 intermediate_buffer_.get(), |
| 108 buffered_bytes_, |
| 109 base::Bind(&BufferingFileStreamWriter::OnFlushIntermediateBufferCompleted, |
| 110 weak_ptr_factory_.GetWeakPtr(), |
| 111 buffered_bytes_, |
| 112 callback)); |
| 113 DCHECK_EQ(net::ERR_IO_PENDING, result); |
| 114 } |
| 115 |
| 116 void BufferingFileStreamWriter::OnFlushIntermediateBufferCompleted( |
| 117 int length, |
| 118 const net::CompletionCallback& callback, |
| 119 int result) { |
| 120 if (result < 0) { |
| 121 callback.Run(result); |
| 122 return; |
| 123 } |
| 124 |
| 125 DCHECK_EQ(length, result) << "Partial writes are not supported."; |
| 126 buffered_bytes_ = 0; |
| 127 |
| 128 callback.Run(net::OK); |
| 129 } |
| 130 |
| 131 void |
| 132 BufferingFileStreamWriter::OnFlushIntermediateBufferForDirectWriteCompleted( |
| 133 scoped_refptr<net::IOBuffer> buffer, |
| 134 int length, |
| 135 const net::CompletionCallback& callback, |
| 136 int result) { |
| 137 if (result < 0) { |
| 138 callback.Run(result); |
| 139 return; |
| 140 } |
| 141 |
| 142 // The following logic is only valid if the intermediate buffer is empty. |
| 143 DCHECK_EQ(0, buffered_bytes_); |
| 144 |
| 145 const int write_result = |
| 146 file_stream_writer_->Write(buffer.get(), length, callback); |
| 147 DCHECK_EQ(net::ERR_IO_PENDING, write_result); |
| 148 } |
| 149 |
| 150 void |
| 151 BufferingFileStreamWriter::OnFlushIntermediateBufferForBufferedWriteCompleted( |
| 152 scoped_refptr<net::IOBuffer> buffer, |
| 153 int buffered_bytes, |
| 154 int bytes_left, |
| 155 const net::CompletionCallback& callback, |
| 156 int result) { |
| 157 if (result < 0) { |
| 158 callback.Run(result); |
| 159 return; |
| 160 } |
| 161 |
| 162 // Copy the rest of bytes to the buffer. |
| 163 DCHECK_EQ(net::OK, result); |
| 164 DCHECK_EQ(0, buffered_bytes_); |
| 165 DCHECK_GE(intermediate_buffer_length_, bytes_left); |
| 166 CopyToIntermediateBuffer(buffer, buffered_bytes, bytes_left); |
| 167 |
| 168 callback.Run(buffered_bytes + bytes_left); |
| 169 } |
| 170 |
| 171 void BufferingFileStreamWriter::OnFlushIntermediateBufferForFlushCompleted( |
| 172 const net::CompletionCallback& callback, |
| 173 int result) { |
| 174 if (result < 0) { |
| 175 callback.Run(result); |
| 176 return; |
| 177 } |
| 178 |
| 179 const int flush_result = file_stream_writer_->Flush(callback); |
| 180 DCHECK_EQ(net::ERR_IO_PENDING, flush_result); |
| 181 } |
| 182 |
| 183 } // namespace file_system_provider |
| 184 } // namespace chromeos |
OLD | NEW |