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 "base/files/file_path.h"
6#include "base/metrics/field_trial.h"
7#include "base/single_thread_task_runner.h"
8#include "base/strings/stringprintf.h"
9#include "net/base/cache_type.h"
10#include "net/base/net_errors.h"
11#include "net/disk_cache/blockfile/backend_impl.h"
12#include "net/disk_cache/cache_util.h"
13#include "net/disk_cache/disk_cache.h"
14#include "net/disk_cache/memory/mem_backend_impl.h"
15#include "net/disk_cache/simple/simple_backend_impl.h"
16
17namespace {
18
19// Builds an instance of the backend depending on platform, type, experiments
20// etc. Takes care of the retry state. This object will self-destroy when
21// finished.
22class CacheCreator {
23 public:
24  CacheCreator(const base::FilePath& path,
25               bool force,
26               int max_bytes,
27               net::CacheType type,
28               net::BackendType backend_type,
29               uint32 flags,
30               const scoped_refptr<base::SingleThreadTaskRunner>& thread,
31               net::NetLog* net_log,
32               scoped_ptr<disk_cache::Backend>* backend,
33               const net::CompletionCallback& callback);
34
35  // Creates the backend.
36  int Run();
37
38 private:
39  ~CacheCreator();
40
41  void DoCallback(int result);
42
43  void OnIOComplete(int result);
44
45  const base::FilePath path_;
46  bool force_;
47  bool retry_;
48  int max_bytes_;
49  net::CacheType type_;
50  net::BackendType backend_type_;
51  uint32 flags_;
52  scoped_refptr<base::SingleThreadTaskRunner> thread_;
53  scoped_ptr<disk_cache::Backend>* backend_;
54  net::CompletionCallback callback_;
55  scoped_ptr<disk_cache::Backend> created_cache_;
56  net::NetLog* net_log_;
57
58  DISALLOW_COPY_AND_ASSIGN(CacheCreator);
59};
60
61CacheCreator::CacheCreator(
62    const base::FilePath& path,
63    bool force,
64    int max_bytes,
65    net::CacheType type,
66    net::BackendType backend_type,
67    uint32 flags,
68    const scoped_refptr<base::SingleThreadTaskRunner>& thread,
69    net::NetLog* net_log,
70    scoped_ptr<disk_cache::Backend>* backend,
71    const net::CompletionCallback& callback)
72    : path_(path),
73      force_(force),
74      retry_(false),
75      max_bytes_(max_bytes),
76      type_(type),
77      backend_type_(backend_type),
78      flags_(flags),
79      thread_(thread),
80      backend_(backend),
81      callback_(callback),
82      net_log_(net_log) {
83}
84
85CacheCreator::~CacheCreator() {
86}
87
88int CacheCreator::Run() {
89#if defined(OS_ANDROID)
90  static const bool kSimpleBackendIsDefault = true;
91#else
92  static const bool kSimpleBackendIsDefault = false;
93#endif
94  if (backend_type_ == net::CACHE_BACKEND_SIMPLE ||
95      (backend_type_ == net::CACHE_BACKEND_DEFAULT &&
96       kSimpleBackendIsDefault)) {
97    disk_cache::SimpleBackendImpl* simple_cache =
98        new disk_cache::SimpleBackendImpl(
99            path_, max_bytes_, type_, thread_, net_log_);
100    created_cache_.reset(simple_cache);
101    return simple_cache->Init(
102        base::Bind(&CacheCreator::OnIOComplete, base::Unretained(this)));
103  }
104
105  // Avoid references to blockfile functions on Android to reduce binary size.
106#if defined(OS_ANDROID)
107  return net::ERR_FAILED;
108#else
109  disk_cache::BackendImpl* new_cache =
110      new disk_cache::BackendImpl(path_, thread_, net_log_);
111  created_cache_.reset(new_cache);
112  new_cache->SetMaxSize(max_bytes_);
113  new_cache->SetType(type_);
114  new_cache->SetFlags(flags_);
115  int rv = new_cache->Init(
116      base::Bind(&CacheCreator::OnIOComplete, base::Unretained(this)));
117  DCHECK_EQ(net::ERR_IO_PENDING, rv);
118  return rv;
119#endif
120}
121
122void CacheCreator::DoCallback(int result) {
123  DCHECK_NE(net::ERR_IO_PENDING, result);
124  if (result == net::OK) {
125#ifndef USE_TRACING_CACHE_BACKEND
126    *backend_ = created_cache_.Pass();
127#else
128    *backend_.reset(
129        new disk_cache::TracingCacheBackend(created_cache_.Pass()));
130#endif
131  } else {
132    LOG(ERROR) << "Unable to create cache";
133    created_cache_.reset();
134  }
135  callback_.Run(result);
136  delete this;
137}
138
139// If the initialization of the cache fails, and |force| is true, we will
140// discard the whole cache and create a new one.
141void CacheCreator::OnIOComplete(int result) {
142  if (result == net::OK || !force_ || retry_)
143    return DoCallback(result);
144
145  // This is a failure and we are supposed to try again, so delete the object,
146  // delete all the files, and try again.
147  retry_ = true;
148  created_cache_.reset();
149  if (!disk_cache::DelayedCacheCleanup(path_))
150    return DoCallback(result);
151
152  // The worker thread will start deleting files soon, but the original folder
153  // is not there anymore... let's create a new set of files.
154  int rv = Run();
155  DCHECK_EQ(net::ERR_IO_PENDING, rv);
156}
157
158}  // namespace
159
160namespace disk_cache {
161
162int CreateCacheBackend(
163    net::CacheType type,
164    net::BackendType backend_type,
165    const base::FilePath& path,
166    int max_bytes,
167    bool force,
168    const scoped_refptr<base::SingleThreadTaskRunner>& thread,
169    net::NetLog* net_log,
170    scoped_ptr<Backend>* backend,
171    const net::CompletionCallback& callback) {
172  DCHECK(!callback.is_null());
173  if (type == net::MEMORY_CACHE) {
174    *backend = disk_cache::MemBackendImpl::CreateBackend(max_bytes, net_log);
175    return *backend ? net::OK : net::ERR_FAILED;
176  }
177  DCHECK(thread.get());
178  CacheCreator* creator = new CacheCreator(path,
179                                           force,
180                                           max_bytes,
181                                           type,
182                                           backend_type,
183                                           kNone,
184                                           thread,
185                                           net_log,
186                                           backend,
187                                           callback);
188  return creator->Run();
189}
190
191}  // namespace disk_cache
192