Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / net / disk_cache / blockfile / file_ios.cc
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 "net/disk_cache/blockfile/file.h"
6
7 #include "base/bind.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"
14
15 namespace {
16
17 // This class represents a single asynchronous IO operation while it is being
18 // bounced between threads.
19 class FileBackgroundIO : public disk_cache::BackgroundIO {
20  public:
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
25   // operation.
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) {
31   }
32
33   disk_cache::FileIOCallback* callback() {
34     return callback_;
35   }
36
37   disk_cache::File* file() {
38     return file_;
39   }
40
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.
46   void Read();
47   void Write();
48
49  private:
50   virtual ~FileBackgroundIO() {}
51
52   disk_cache::FileIOCallback* callback_;
53
54   disk_cache::File* file_;
55   const void* buf_;
56   size_t buf_len_;
57   size_t offset_;
58
59   DISALLOW_COPY_AND_ASSIGN(FileBackgroundIO);
60 };
61
62
63 // The specialized controller that keeps track of current operations.
64 class FileInFlightIO : public disk_cache::InFlightIO {
65  public:
66   FileInFlightIO() {}
67   virtual ~FileInFlightIO() {}
68
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);
76
77  protected:
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   virtual void OnOperationComplete(disk_cache::BackgroundIO* operation,
83                                    bool cancel) override;
84
85  private:
86   DISALLOW_COPY_AND_ASSIGN(FileInFlightIO);
87 };
88
89 // ---------------------------------------------------------------------------
90
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_);
95   } else {
96     result_ = net::ERR_CACHE_READ_FAILURE;
97   }
98   NotifyController();
99 }
100
101 // Runs on a worker thread.
102 void FileBackgroundIO::Write() {
103   bool rv = file_->Write(buf_, buf_len_, offset_);
104
105   result_ = rv ? static_cast<int>(buf_len_) : net::ERR_CACHE_WRITE_FAILURE;
106   NotifyController();
107 }
108
109 // ---------------------------------------------------------------------------
110
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()
116
117   base::WorkerPool::PostTask(FROM_HERE,
118       base::Bind(&FileBackgroundIO::Read, operation.get()), true);
119   OnOperationPosted(operation.get());
120 }
121
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()
128
129   base::WorkerPool::PostTask(FROM_HERE,
130       base::Bind(&FileBackgroundIO::Write, operation.get()), true);
131   OnOperationPosted(operation.get());
132 }
133
134 // Runs on the IO thread.
135 void FileInFlightIO::OnOperationComplete(disk_cache::BackgroundIO* operation,
136                                          bool cancel) {
137   FileBackgroundIO* op = static_cast<FileBackgroundIO*>(operation);
138
139   disk_cache::FileIOCallback* callback = op->callback();
140   int bytes = operation->result();
141
142   // Release the references acquired in PostRead / PostWrite.
143   op->file()->Release();
144   callback->OnFileIOComplete(bytes);
145 }
146
147 // A static object that will broker all async operations.
148 FileInFlightIO* s_file_operations = NULL;
149
150 // Returns the current FileInFlightIO.
151 FileInFlightIO* GetFileInFlightIO() {
152   if (!s_file_operations) {
153     s_file_operations = new FileInFlightIO;
154   }
155   return s_file_operations;
156 }
157
158 // Deletes the current FileInFlightIO.
159 void DeleteFileInFlightIO() {
160   DCHECK(s_file_operations);
161   delete s_file_operations;
162   s_file_operations = NULL;
163 }
164
165 }  // namespace
166
167 namespace disk_cache {
168
169 File::File(base::File file)
170     : init_(true),
171       mixed_(true),
172       base_file_(file.Pass()) {
173 }
174
175 bool File::Init(const base::FilePath& name) {
176   if (base_file_.IsValid())
177     return false;
178
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();
183 }
184
185 bool File::IsValid() const {
186   return base_file_.IsValid();
187 }
188
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)) {
193     return false;
194   }
195
196   int ret = base_file_.Read(offset, static_cast<char*>(buffer), buffer_len);
197   return (static_cast<size_t>(ret) == buffer_len);
198 }
199
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)) {
204     return false;
205   }
206
207   int ret = base_file_.Write(offset, static_cast<const char*>(buffer),
208                              buffer_len);
209   return (static_cast<size_t>(ret) == buffer_len);
210 }
211
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());
218   if (!callback) {
219     if (completed)
220       *completed = true;
221     return Read(buffer, buffer_len, offset);
222   }
223
224   if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
225     return false;
226
227   GetFileInFlightIO()->PostRead(this, buffer, buffer_len, offset, callback);
228
229   *completed = false;
230   return true;
231 }
232
233 bool File::Write(const void* buffer, size_t buffer_len, size_t offset,
234                  FileIOCallback* callback, bool* completed) {
235   DCHECK(base_file_.IsValid());
236   if (!callback) {
237     if (completed)
238       *completed = true;
239     return Write(buffer, buffer_len, offset);
240   }
241
242   return AsyncWrite(buffer, buffer_len, offset, callback, completed);
243 }
244
245 bool File::SetLength(size_t length) {
246   DCHECK(base_file_.IsValid());
247   if (length > kuint32max)
248     return false;
249
250   return base_file_.SetLength(length);
251 }
252
253 size_t File::GetLength() {
254   DCHECK(base_file_.IsValid());
255   int64 len = base_file_.GetLength();
256
257   if (len > static_cast<int64>(kuint32max))
258     return kuint32max;
259
260   return static_cast<size_t>(len);
261 }
262
263 // Static.
264 void File::WaitForPendingIO(int* num_pending_io) {
265   // We may be running unit tests so we should allow be able to reset the
266   // message loop.
267   GetFileInFlightIO()->WaitForPendingIO();
268   DeleteFileInFlightIO();
269 }
270
271 // Static.
272 void File::DropPendingIO() {
273   GetFileInFlightIO()->DropPendingIO();
274   DeleteFileInFlightIO();
275 }
276
277 File::~File() {
278 }
279
280 base::PlatformFile File::platform_file() const {
281   return base_file_.GetPlatformFile();
282 }
283
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)
288     return false;
289
290   GetFileInFlightIO()->PostWrite(this, buffer, buffer_len, offset, callback);
291
292   if (completed)
293     *completed = false;
294   return true;
295 }
296
297 }  // namespace disk_cache