Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / chromeos / file_system_provider / fileapi / buffering_file_stream_writer.cc
blob039f0a6baa30f280e04379c8093b7f7c5647c703
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.
5 #include "chrome/browser/chromeos/file_system_provider/fileapi/buffering_file_stream_writer.h"
7 #include <algorithm>
9 #include "net/base/io_buffer.h"
10 #include "net/base/net_errors.h"
12 namespace chromeos {
13 namespace file_system_provider {
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) {
25 BufferingFileStreamWriter::~BufferingFileStreamWriter() {
26 if (buffered_bytes_)
27 LOG(ERROR) << "File stream writer not flushed. Data will be lost.";
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);
50 return net::ERR_IO_PENDING;
53 // Buffer consecutive writes to larger chunks.
54 const int buffer_bytes =
55 std::min(intermediate_buffer_length_ - buffered_bytes_, buffer_length);
57 CopyToIntermediateBuffer(
58 make_scoped_refptr(buffer), 0 /* buffer_offset */, buffer_bytes);
59 const int bytes_left = buffer_length - buffer_bytes;
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;
73 // Optimistically return a success.
74 return buffer_length;
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);
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;
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;
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);
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;
125 DCHECK_EQ(length, result) << "Partial writes are not supported.";
126 buffered_bytes_ = 0;
128 callback.Run(net::OK);
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;
142 // The following logic is only valid if the intermediate buffer is empty.
143 DCHECK_EQ(0, buffered_bytes_);
145 const int write_result =
146 file_stream_writer_->Write(buffer.get(), length, callback);
147 DCHECK_EQ(net::ERR_IO_PENDING, write_result);
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;
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);
168 callback.Run(buffered_bytes + bytes_left);
171 void BufferingFileStreamWriter::OnFlushIntermediateBufferForFlushCompleted(
172 const net::CompletionCallback& callback,
173 int result) {
174 if (result < 0) {
175 callback.Run(result);
176 return;
179 const int flush_result = file_stream_writer_->Flush(callback);
180 DCHECK_EQ(net::ERR_IO_PENDING, flush_result);
183 } // namespace file_system_provider
184 } // namespace chromeos