1 // Copyright (c) 2012 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/file.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/threading/worker_pool.h"
13 #include "net/base/net_errors.h"
14 #include "net/disk_cache/disk_cache.h"
15 #include "net/disk_cache/in_flight_io.h"
19 // This class represents a single asynchronous IO operation while it is being
20 // bounced between threads.
21 class FileBackgroundIO
: public disk_cache::BackgroundIO
{
23 // Other than the actual parameters for the IO operation (including the
24 // |callback| that must be notified at the end), we need the controller that
25 // is keeping track of all operations. When done, we notify the controller
26 // (we do NOT invoke the callback), in the worker thead that completed the
28 FileBackgroundIO(disk_cache::File
* file
, const void* buf
, size_t buf_len
,
29 size_t offset
, disk_cache::FileIOCallback
* callback
,
30 disk_cache::InFlightIO
* controller
)
31 : disk_cache::BackgroundIO(controller
), callback_(callback
), file_(file
),
32 buf_(buf
), buf_len_(buf_len
), offset_(offset
) {
35 disk_cache::FileIOCallback
* callback() {
39 disk_cache::File
* file() {
43 // Read and Write are the operations that can be performed asynchronously.
44 // The actual parameters for the operation are setup in the constructor of
45 // the object. Both methods should be called from a worker thread, by posting
46 // a task to the WorkerPool (they are RunnableMethods). When finished,
47 // controller->OnIOComplete() is called.
52 virtual ~FileBackgroundIO() {}
54 disk_cache::FileIOCallback
* callback_
;
56 disk_cache::File
* file_
;
61 DISALLOW_COPY_AND_ASSIGN(FileBackgroundIO
);
65 // The specialized controller that keeps track of current operations.
66 class FileInFlightIO
: public disk_cache::InFlightIO
{
69 virtual ~FileInFlightIO() {}
71 // These methods start an asynchronous operation. The arguments have the same
72 // semantics of the File asynchronous operations, with the exception that the
73 // operation never finishes synchronously.
74 void PostRead(disk_cache::File
* file
, void* buf
, size_t buf_len
,
75 size_t offset
, disk_cache::FileIOCallback
* callback
);
76 void PostWrite(disk_cache::File
* file
, const void* buf
, size_t buf_len
,
77 size_t offset
, disk_cache::FileIOCallback
* callback
);
80 // Invokes the users' completion callback at the end of the IO operation.
81 // |cancel| is true if the actual task posted to the thread is still
82 // queued (because we are inside WaitForPendingIO), and false if said task is
83 // the one performing the call.
84 virtual void OnOperationComplete(disk_cache::BackgroundIO
* operation
,
85 bool cancel
) OVERRIDE
;
88 DISALLOW_COPY_AND_ASSIGN(FileInFlightIO
);
91 // ---------------------------------------------------------------------------
93 // Runs on a worker thread.
94 void FileBackgroundIO::Read() {
95 if (file_
->Read(const_cast<void*>(buf_
), buf_len_
, offset_
)) {
96 result_
= static_cast<int>(buf_len_
);
98 result_
= net::ERR_CACHE_READ_FAILURE
;
103 // Runs on a worker thread.
104 void FileBackgroundIO::Write() {
105 bool rv
= file_
->Write(buf_
, buf_len_
, offset_
);
107 result_
= rv
? static_cast<int>(buf_len_
) : net::ERR_CACHE_WRITE_FAILURE
;
111 // ---------------------------------------------------------------------------
113 void FileInFlightIO::PostRead(disk_cache::File
*file
, void* buf
, size_t buf_len
,
114 size_t offset
, disk_cache::FileIOCallback
*callback
) {
115 scoped_refptr
<FileBackgroundIO
> operation(
116 new FileBackgroundIO(file
, buf
, buf_len
, offset
, callback
, this));
117 file
->AddRef(); // Balanced on OnOperationComplete()
119 base::WorkerPool::PostTask(FROM_HERE
,
120 base::Bind(&FileBackgroundIO::Read
, operation
.get()), true);
121 OnOperationPosted(operation
);
124 void FileInFlightIO::PostWrite(disk_cache::File
* file
, const void* buf
,
125 size_t buf_len
, size_t offset
,
126 disk_cache::FileIOCallback
* callback
) {
127 scoped_refptr
<FileBackgroundIO
> operation(
128 new FileBackgroundIO(file
, buf
, buf_len
, offset
, callback
, this));
129 file
->AddRef(); // Balanced on OnOperationComplete()
131 base::WorkerPool::PostTask(FROM_HERE
,
132 base::Bind(&FileBackgroundIO::Write
, operation
.get()), true);
133 OnOperationPosted(operation
);
136 // Runs on the IO thread.
137 void FileInFlightIO::OnOperationComplete(disk_cache::BackgroundIO
* operation
,
139 FileBackgroundIO
* op
= static_cast<FileBackgroundIO
*>(operation
);
141 disk_cache::FileIOCallback
* callback
= op
->callback();
142 int bytes
= operation
->result();
144 // Release the references acquired in PostRead / PostWrite.
145 op
->file()->Release();
146 callback
->OnFileIOComplete(bytes
);
149 // A static object tha will broker all async operations.
150 FileInFlightIO
* s_file_operations
= NULL
;
152 // Returns the current FileInFlightIO.
153 FileInFlightIO
* GetFileInFlightIO() {
154 if (!s_file_operations
) {
155 s_file_operations
= new FileInFlightIO
;
157 return s_file_operations
;
160 // Deletes the current FileInFlightIO.
161 void DeleteFileInFlightIO() {
162 DCHECK(s_file_operations
);
163 delete s_file_operations
;
164 s_file_operations
= NULL
;
169 namespace disk_cache
{
171 File::File(base::PlatformFile file
)
174 platform_file_(file
),
175 sync_platform_file_(base::kInvalidPlatformFileValue
) {
178 bool File::Init(const base::FilePath
& name
) {
182 int flags
= base::PLATFORM_FILE_OPEN
|
183 base::PLATFORM_FILE_READ
|
184 base::PLATFORM_FILE_WRITE
;
185 platform_file_
= base::CreatePlatformFile(name
, flags
, NULL
, NULL
);
186 if (platform_file_
< 0) {
195 base::PlatformFile
File::platform_file() const {
196 return platform_file_
;
199 bool File::IsValid() const {
202 return (base::kInvalidPlatformFileValue
!= platform_file_
);
205 bool File::Read(void* buffer
, size_t buffer_len
, size_t offset
) {
207 if (buffer_len
> static_cast<size_t>(kint32max
) ||
208 offset
> static_cast<size_t>(kint32max
))
211 int ret
= base::ReadPlatformFile(platform_file_
, offset
,
212 static_cast<char*>(buffer
), buffer_len
);
213 return (static_cast<size_t>(ret
) == buffer_len
);
216 bool File::Write(const void* buffer
, size_t buffer_len
, size_t offset
) {
218 if (buffer_len
> static_cast<size_t>(kint32max
) ||
219 offset
> static_cast<size_t>(kint32max
))
222 int ret
= base::WritePlatformFile(platform_file_
, offset
,
223 static_cast<const char*>(buffer
),
225 return (static_cast<size_t>(ret
) == buffer_len
);
228 // We have to increase the ref counter of the file before performing the IO to
229 // prevent the completion to happen with an invalid handle (if the file is
230 // closed while the IO is in flight).
231 bool File::Read(void* buffer
, size_t buffer_len
, size_t offset
,
232 FileIOCallback
* callback
, bool* completed
) {
237 return Read(buffer
, buffer_len
, offset
);
240 if (buffer_len
> ULONG_MAX
|| offset
> ULONG_MAX
)
243 GetFileInFlightIO()->PostRead(this, buffer
, buffer_len
, offset
, callback
);
249 bool File::Write(const void* buffer
, size_t buffer_len
, size_t offset
,
250 FileIOCallback
* callback
, bool* completed
) {
255 return Write(buffer
, buffer_len
, offset
);
258 return AsyncWrite(buffer
, buffer_len
, offset
, callback
, completed
);
261 bool File::SetLength(size_t length
) {
263 if (length
> ULONG_MAX
)
266 return base::TruncatePlatformFile(platform_file_
, length
);
269 size_t File::GetLength() {
271 off_t ret
= lseek(platform_file_
, 0, SEEK_END
);
278 void File::WaitForPendingIO(int* num_pending_io
) {
279 // We may be running unit tests so we should allow be able to reset the
281 GetFileInFlightIO()->WaitForPendingIO();
282 DeleteFileInFlightIO();
286 void File::DropPendingIO() {
287 GetFileInFlightIO()->DropPendingIO();
288 DeleteFileInFlightIO();
293 base::ClosePlatformFile(platform_file_
);
296 bool File::AsyncWrite(const void* buffer
, size_t buffer_len
, size_t offset
,
297 FileIOCallback
* callback
, bool* completed
) {
299 if (buffer_len
> ULONG_MAX
|| offset
> ULONG_MAX
)
302 GetFileInFlightIO()->PostWrite(this, buffer
, buffer_len
, offset
, callback
);
309 } // namespace disk_cache