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 "net/disk_cache/blockfile/file.h"
8 #include "base/location.h"
9 #include "base/logging.h"
10 #include "base/threading/worker_pool.h"
11 #include "net/base/net_errors.h"
12 #include "net/disk_cache/blockfile/in_flight_io.h"
13 #include "net/disk_cache/disk_cache.h"
17 // This class represents a single asynchronous IO operation while it is being
18 // bounced between threads.
19 class FileBackgroundIO
: public disk_cache::BackgroundIO
{
21 // Other than the actual parameters for the IO operation (including the
22 // |callback| that must be notified at the end), we need the controller that
23 // is keeping track of all operations. When done, we notify the controller
24 // (we do NOT invoke the callback), in the worker thead that completed the
26 FileBackgroundIO(disk_cache::File
* file
, const void* buf
, size_t buf_len
,
27 size_t offset
, disk_cache::FileIOCallback
* callback
,
28 disk_cache::InFlightIO
* controller
)
29 : disk_cache::BackgroundIO(controller
), callback_(callback
), file_(file
),
30 buf_(buf
), buf_len_(buf_len
), offset_(offset
) {
33 disk_cache::FileIOCallback
* callback() {
37 disk_cache::File
* file() {
41 // Read and Write are the operations that can be performed asynchronously.
42 // The actual parameters for the operation are setup in the constructor of
43 // the object. Both methods should be called from a worker thread, by posting
44 // a task to the WorkerPool (they are RunnableMethods). When finished,
45 // controller->OnIOComplete() is called.
50 ~FileBackgroundIO() override
{}
52 disk_cache::FileIOCallback
* callback_
;
54 disk_cache::File
* file_
;
59 DISALLOW_COPY_AND_ASSIGN(FileBackgroundIO
);
63 // The specialized controller that keeps track of current operations.
64 class FileInFlightIO
: public disk_cache::InFlightIO
{
67 ~FileInFlightIO() override
{}
69 // These methods start an asynchronous operation. The arguments have the same
70 // semantics of the File asynchronous operations, with the exception that the
71 // operation never finishes synchronously.
72 void PostRead(disk_cache::File
* file
, void* buf
, size_t buf_len
,
73 size_t offset
, disk_cache::FileIOCallback
* callback
);
74 void PostWrite(disk_cache::File
* file
, const void* buf
, size_t buf_len
,
75 size_t offset
, disk_cache::FileIOCallback
* callback
);
78 // Invokes the users' completion callback at the end of the IO operation.
79 // |cancel| is true if the actual task posted to the thread is still
80 // queued (because we are inside WaitForPendingIO), and false if said task is
81 // the one performing the call.
82 void OnOperationComplete(disk_cache::BackgroundIO
* operation
,
83 bool cancel
) override
;
86 DISALLOW_COPY_AND_ASSIGN(FileInFlightIO
);
89 // ---------------------------------------------------------------------------
91 // Runs on a worker thread.
92 void FileBackgroundIO::Read() {
93 if (file_
->Read(const_cast<void*>(buf_
), buf_len_
, offset_
)) {
94 result_
= static_cast<int>(buf_len_
);
96 result_
= net::ERR_CACHE_READ_FAILURE
;
101 // Runs on a worker thread.
102 void FileBackgroundIO::Write() {
103 bool rv
= file_
->Write(buf_
, buf_len_
, offset_
);
105 result_
= rv
? static_cast<int>(buf_len_
) : net::ERR_CACHE_WRITE_FAILURE
;
109 // ---------------------------------------------------------------------------
111 void FileInFlightIO::PostRead(disk_cache::File
*file
, void* buf
, size_t buf_len
,
112 size_t offset
, disk_cache::FileIOCallback
*callback
) {
113 scoped_refptr
<FileBackgroundIO
> operation(
114 new FileBackgroundIO(file
, buf
, buf_len
, offset
, callback
, this));
115 file
->AddRef(); // Balanced on OnOperationComplete()
117 base::WorkerPool::PostTask(FROM_HERE
,
118 base::Bind(&FileBackgroundIO::Read
, operation
.get()), true);
119 OnOperationPosted(operation
.get());
122 void FileInFlightIO::PostWrite(disk_cache::File
* file
, const void* buf
,
123 size_t buf_len
, size_t offset
,
124 disk_cache::FileIOCallback
* callback
) {
125 scoped_refptr
<FileBackgroundIO
> operation(
126 new FileBackgroundIO(file
, buf
, buf_len
, offset
, callback
, this));
127 file
->AddRef(); // Balanced on OnOperationComplete()
129 base::WorkerPool::PostTask(FROM_HERE
,
130 base::Bind(&FileBackgroundIO::Write
, operation
.get()), true);
131 OnOperationPosted(operation
.get());
134 // Runs on the IO thread.
135 void FileInFlightIO::OnOperationComplete(disk_cache::BackgroundIO
* operation
,
137 FileBackgroundIO
* op
= static_cast<FileBackgroundIO
*>(operation
);
139 disk_cache::FileIOCallback
* callback
= op
->callback();
140 int bytes
= operation
->result();
142 // Release the references acquired in PostRead / PostWrite.
143 op
->file()->Release();
144 callback
->OnFileIOComplete(bytes
);
147 // A static object that will broker all async operations.
148 FileInFlightIO
* s_file_operations
= NULL
;
150 // Returns the current FileInFlightIO.
151 FileInFlightIO
* GetFileInFlightIO() {
152 if (!s_file_operations
) {
153 s_file_operations
= new FileInFlightIO
;
155 return s_file_operations
;
158 // Deletes the current FileInFlightIO.
159 void DeleteFileInFlightIO() {
160 DCHECK(s_file_operations
);
161 delete s_file_operations
;
162 s_file_operations
= NULL
;
167 namespace disk_cache
{
169 File::File(base::File file
)
172 base_file_(file
.Pass()) {
175 bool File::Init(const base::FilePath
& name
) {
176 if (base_file_
.IsValid())
179 int flags
= base::File::FLAG_OPEN
| base::File::FLAG_READ
|
180 base::File::FLAG_WRITE
;
181 base_file_
.Initialize(name
, flags
);
182 return base_file_
.IsValid();
185 bool File::IsValid() const {
186 return base_file_
.IsValid();
189 bool File::Read(void* buffer
, size_t buffer_len
, size_t offset
) {
190 DCHECK(base_file_
.IsValid());
191 if (buffer_len
> static_cast<size_t>(kint32max
) ||
192 offset
> static_cast<size_t>(kint32max
)) {
196 int ret
= base_file_
.Read(offset
, static_cast<char*>(buffer
), buffer_len
);
197 return (static_cast<size_t>(ret
) == buffer_len
);
200 bool File::Write(const void* buffer
, size_t buffer_len
, size_t offset
) {
201 DCHECK(base_file_
.IsValid());
202 if (buffer_len
> static_cast<size_t>(kint32max
) ||
203 offset
> static_cast<size_t>(kint32max
)) {
207 int ret
= base_file_
.Write(offset
, static_cast<const char*>(buffer
),
209 return (static_cast<size_t>(ret
) == buffer_len
);
212 // We have to increase the ref counter of the file before performing the IO to
213 // prevent the completion to happen with an invalid handle (if the file is
214 // closed while the IO is in flight).
215 bool File::Read(void* buffer
, size_t buffer_len
, size_t offset
,
216 FileIOCallback
* callback
, bool* completed
) {
217 DCHECK(base_file_
.IsValid());
221 return Read(buffer
, buffer_len
, offset
);
224 if (buffer_len
> ULONG_MAX
|| offset
> ULONG_MAX
)
227 GetFileInFlightIO()->PostRead(this, buffer
, buffer_len
, offset
, callback
);
233 bool File::Write(const void* buffer
, size_t buffer_len
, size_t offset
,
234 FileIOCallback
* callback
, bool* completed
) {
235 DCHECK(base_file_
.IsValid());
239 return Write(buffer
, buffer_len
, offset
);
242 return AsyncWrite(buffer
, buffer_len
, offset
, callback
, completed
);
245 bool File::SetLength(size_t length
) {
246 DCHECK(base_file_
.IsValid());
247 if (length
> kuint32max
)
250 return base_file_
.SetLength(length
);
253 size_t File::GetLength() {
254 DCHECK(base_file_
.IsValid());
255 int64 len
= base_file_
.GetLength();
257 if (len
> static_cast<int64
>(kuint32max
))
260 return static_cast<size_t>(len
);
264 void File::WaitForPendingIO(int* num_pending_io
) {
265 // We may be running unit tests so we should allow be able to reset the
267 GetFileInFlightIO()->WaitForPendingIO();
268 DeleteFileInFlightIO();
272 void File::DropPendingIO() {
273 GetFileInFlightIO()->DropPendingIO();
274 DeleteFileInFlightIO();
280 base::PlatformFile
File::platform_file() const {
281 return base_file_
.GetPlatformFile();
284 bool File::AsyncWrite(const void* buffer
, size_t buffer_len
, size_t offset
,
285 FileIOCallback
* callback
, bool* completed
) {
286 DCHECK(base_file_
.IsValid());
287 if (buffer_len
> ULONG_MAX
|| offset
> ULONG_MAX
)
290 GetFileInFlightIO()->PostWrite(this, buffer
, buffer_len
, offset
, callback
);
297 } // namespace disk_cache