Home | History | Annotate | Download | only in blockfile
      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.
      4 
      5 #include "net/disk_cache/blockfile/file.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/lazy_instance.h"
      9 #include "base/location.h"
     10 #include "base/logging.h"
     11 #include "base/run_loop.h"
     12 #include "base/task_runner_util.h"
     13 #include "base/threading/sequenced_worker_pool.h"
     14 #include "net/base/net_errors.h"
     15 #include "net/disk_cache/disk_cache.h"
     16 
     17 namespace {
     18 
     19 // The maximum number of threads for this pool.
     20 const int kMaxThreads = 5;
     21 
     22 class FileWorkerPool : public base::SequencedWorkerPool {
     23  public:
     24   FileWorkerPool() : base::SequencedWorkerPool(kMaxThreads, "CachePool") {}
     25 
     26  protected:
     27   virtual ~FileWorkerPool() {}
     28 };
     29 
     30 base::LazyInstance<FileWorkerPool>::Leaky s_worker_pool =
     31     LAZY_INSTANCE_INITIALIZER;
     32 
     33 }  // namespace
     34 
     35 namespace disk_cache {
     36 
     37 File::File(base::File file)
     38     : init_(true),
     39       mixed_(true),
     40       base_file_(file.Pass()) {
     41 }
     42 
     43 bool File::Init(const base::FilePath& name) {
     44   if (base_file_.IsValid())
     45     return false;
     46 
     47   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
     48               base::File::FLAG_WRITE;
     49   base_file_.Initialize(name, flags);
     50   return base_file_.IsValid();
     51 }
     52 
     53 bool File::IsValid() const {
     54   return base_file_.IsValid();
     55 }
     56 
     57 bool File::Read(void* buffer, size_t buffer_len, size_t offset) {
     58   DCHECK(base_file_.IsValid());
     59   if (buffer_len > static_cast<size_t>(kint32max) ||
     60       offset > static_cast<size_t>(kint32max)) {
     61     return false;
     62   }
     63 
     64   int ret = base_file_.Read(offset, static_cast<char*>(buffer), buffer_len);
     65   return (static_cast<size_t>(ret) == buffer_len);
     66 }
     67 
     68 bool File::Write(const void* buffer, size_t buffer_len, size_t offset) {
     69   DCHECK(base_file_.IsValid());
     70   if (buffer_len > static_cast<size_t>(kint32max) ||
     71       offset > static_cast<size_t>(kint32max)) {
     72     return false;
     73   }
     74 
     75   int ret = base_file_.Write(offset, static_cast<const char*>(buffer),
     76                              buffer_len);
     77   return (static_cast<size_t>(ret) == buffer_len);
     78 }
     79 
     80 bool File::Read(void* buffer, size_t buffer_len, size_t offset,
     81                 FileIOCallback* callback, bool* completed) {
     82   DCHECK(base_file_.IsValid());
     83   if (!callback) {
     84     if (completed)
     85       *completed = true;
     86     return Read(buffer, buffer_len, offset);
     87   }
     88 
     89   if (buffer_len > static_cast<size_t>(kint32max) ||
     90       offset > static_cast<size_t>(kint32max)) {
     91     return false;
     92   }
     93 
     94   base::PostTaskAndReplyWithResult(
     95       s_worker_pool.Pointer(), FROM_HERE,
     96       base::Bind(&File::DoRead, this, buffer, buffer_len, offset),
     97       base::Bind(&File::OnOperationComplete, this, callback));
     98 
     99   *completed = false;
    100   return true;
    101 }
    102 
    103 bool File::Write(const void* buffer, size_t buffer_len, size_t offset,
    104                  FileIOCallback* callback, bool* completed) {
    105   DCHECK(base_file_.IsValid());
    106   if (!callback) {
    107     if (completed)
    108       *completed = true;
    109     return Write(buffer, buffer_len, offset);
    110   }
    111 
    112   if (buffer_len > static_cast<size_t>(kint32max) ||
    113       offset > static_cast<size_t>(kint32max)) {
    114     return false;
    115   }
    116 
    117   base::PostTaskAndReplyWithResult(
    118       s_worker_pool.Pointer(), FROM_HERE,
    119       base::Bind(&File::DoWrite, this, buffer, buffer_len, offset),
    120       base::Bind(&File::OnOperationComplete, this, callback));
    121 
    122   *completed = false;
    123   return true;
    124 }
    125 
    126 bool File::SetLength(size_t length) {
    127   DCHECK(base_file_.IsValid());
    128   if (length > kuint32max)
    129     return false;
    130 
    131   return base_file_.SetLength(length);
    132 }
    133 
    134 size_t File::GetLength() {
    135   DCHECK(base_file_.IsValid());
    136   int64 len = base_file_.GetLength();
    137 
    138   if (len > static_cast<int64>(kuint32max))
    139     return kuint32max;
    140 
    141   return static_cast<size_t>(len);
    142 }
    143 
    144 // Static.
    145 void File::WaitForPendingIO(int* num_pending_io) {
    146   // We are running unit tests so we should wait for all callbacks. Sadly, the
    147   // worker pool only waits for tasks on the worker pool, not the "Reply" tasks
    148   // so we have to let the current message loop to run.
    149   s_worker_pool.Get().FlushForTesting();
    150   base::RunLoop().RunUntilIdle();
    151 }
    152 
    153 // Static.
    154 void File::DropPendingIO() {
    155 }
    156 
    157 
    158 File::~File() {
    159 }
    160 
    161 base::PlatformFile File::platform_file() const {
    162   return base_file_.GetPlatformFile();
    163 }
    164 
    165 // Runs on a worker thread.
    166 int File::DoRead(void* buffer, size_t buffer_len, size_t offset) {
    167   if (Read(const_cast<void*>(buffer), buffer_len, offset))
    168     return static_cast<int>(buffer_len);
    169 
    170   return net::ERR_CACHE_READ_FAILURE;
    171 }
    172 
    173 // Runs on a worker thread.
    174 int File::DoWrite(const void* buffer, size_t buffer_len, size_t offset) {
    175   if (Write(const_cast<void*>(buffer), buffer_len, offset))
    176     return static_cast<int>(buffer_len);
    177 
    178   return net::ERR_CACHE_WRITE_FAILURE;
    179 }
    180 
    181 // This method actually makes sure that the last reference to the file doesn't
    182 // go away on the worker pool.
    183 void File::OnOperationComplete(FileIOCallback* callback, int result) {
    184   callback->OnFileIOComplete(result);
    185 }
    186 
    187 }  // namespace disk_cache
    188