Apply _RELATIVE relocations ahead of others.
[chromium-blink-merge.git] / content / browser / appcache / appcache_disk_cache.cc
blob382ed45fed2197ae8be5b861e1f310d18a118694
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 "content/browser/appcache/appcache_disk_cache.h"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/files/file_path.h"
10 #include "base/logging.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "net/base/cache_type.h"
15 #include "net/base/net_errors.h"
17 namespace content {
19 // A callback shim that provides storage for the 'backend_ptr' value
20 // and will delete a resulting ptr if completion occurs after its
21 // been canceled.
22 class AppCacheDiskCache::CreateBackendCallbackShim
23 : public base::RefCounted<CreateBackendCallbackShim> {
24 public:
25 explicit CreateBackendCallbackShim(AppCacheDiskCache* object)
26 : appcache_diskcache_(object) {
29 void Cancel() {
30 appcache_diskcache_ = NULL;
33 void Callback(int rv) {
34 if (appcache_diskcache_)
35 appcache_diskcache_->OnCreateBackendComplete(rv);
38 scoped_ptr<disk_cache::Backend> backend_ptr_; // Accessed directly.
40 private:
41 friend class base::RefCounted<CreateBackendCallbackShim>;
43 ~CreateBackendCallbackShim() {
46 AppCacheDiskCache* appcache_diskcache_; // Unowned pointer.
49 // An implementation of AppCacheDiskCacheInterface::Entry that's a thin
50 // wrapper around disk_cache::Entry.
51 class AppCacheDiskCache::EntryImpl : public Entry {
52 public:
53 EntryImpl(disk_cache::Entry* disk_cache_entry,
54 AppCacheDiskCache* owner)
55 : disk_cache_entry_(disk_cache_entry), owner_(owner) {
56 DCHECK(disk_cache_entry);
57 DCHECK(owner);
58 owner_->AddOpenEntry(this);
61 // Entry implementation.
62 int Read(int index,
63 int64 offset,
64 net::IOBuffer* buf,
65 int buf_len,
66 const net::CompletionCallback& callback) override {
67 if (offset < 0 || offset > kint32max)
68 return net::ERR_INVALID_ARGUMENT;
69 if (!disk_cache_entry_)
70 return net::ERR_ABORTED;
71 return disk_cache_entry_->ReadData(
72 index, static_cast<int>(offset), buf, buf_len, callback);
75 int Write(int index,
76 int64 offset,
77 net::IOBuffer* buf,
78 int buf_len,
79 const net::CompletionCallback& callback) override {
80 if (offset < 0 || offset > kint32max)
81 return net::ERR_INVALID_ARGUMENT;
82 if (!disk_cache_entry_)
83 return net::ERR_ABORTED;
84 const bool kTruncate = true;
85 return disk_cache_entry_->WriteData(
86 index, static_cast<int>(offset), buf, buf_len, callback, kTruncate);
89 int64 GetSize(int index) override {
90 return disk_cache_entry_ ? disk_cache_entry_->GetDataSize(index) : 0L;
93 void Close() override {
94 if (disk_cache_entry_)
95 disk_cache_entry_->Close();
96 delete this;
99 void Abandon() {
100 owner_ = NULL;
101 disk_cache_entry_->Close();
102 disk_cache_entry_ = NULL;
105 private:
106 ~EntryImpl() override {
107 if (owner_)
108 owner_->RemoveOpenEntry(this);
111 disk_cache::Entry* disk_cache_entry_;
112 AppCacheDiskCache* owner_;
115 // Separate object to hold state for each Create, Delete, or Doom call
116 // while the call is in-flight and to produce an EntryImpl upon completion.
117 class AppCacheDiskCache::ActiveCall {
118 public:
119 explicit ActiveCall(AppCacheDiskCache* owner)
120 : entry_(NULL),
121 owner_(owner),
122 entry_ptr_(NULL) {
125 int CreateEntry(int64 key, Entry** entry,
126 const net::CompletionCallback& callback) {
127 int rv = owner_->disk_cache()->CreateEntry(
128 base::Int64ToString(key), &entry_ptr_,
129 base::Bind(&ActiveCall::OnAsyncCompletion, base::Unretained(this)));
130 return HandleImmediateReturnValue(rv, entry, callback);
133 int OpenEntry(int64 key, Entry** entry,
134 const net::CompletionCallback& callback) {
135 int rv = owner_->disk_cache()->OpenEntry(
136 base::Int64ToString(key), &entry_ptr_,
137 base::Bind(&ActiveCall::OnAsyncCompletion, base::Unretained(this)));
138 return HandleImmediateReturnValue(rv, entry, callback);
141 int DoomEntry(int64 key, const net::CompletionCallback& callback) {
142 int rv = owner_->disk_cache()->DoomEntry(
143 base::Int64ToString(key),
144 base::Bind(&ActiveCall::OnAsyncCompletion, base::Unretained(this)));
145 return HandleImmediateReturnValue(rv, NULL, callback);
148 private:
149 int HandleImmediateReturnValue(int rv, Entry** entry,
150 const net::CompletionCallback& callback) {
151 if (rv == net::ERR_IO_PENDING) {
152 // OnAsyncCompletion will be called later.
153 callback_ = callback;
154 entry_ = entry;
155 owner_->AddActiveCall(this);
156 return net::ERR_IO_PENDING;
158 if (rv == net::OK && entry)
159 *entry = new EntryImpl(entry_ptr_, owner_);
160 delete this;
161 return rv;
164 void OnAsyncCompletion(int rv) {
165 owner_->RemoveActiveCall(this);
166 if (rv == net::OK && entry_)
167 *entry_ = new EntryImpl(entry_ptr_, owner_);
168 callback_.Run(rv);
169 callback_.Reset();
170 delete this;
173 Entry** entry_;
174 net::CompletionCallback callback_;
175 AppCacheDiskCache* owner_;
176 disk_cache::Entry* entry_ptr_;
179 AppCacheDiskCache::AppCacheDiskCache()
180 : is_disabled_(false) {
183 AppCacheDiskCache::~AppCacheDiskCache() {
184 Disable();
187 int AppCacheDiskCache::InitWithDiskBackend(
188 const base::FilePath& disk_cache_directory,
189 int disk_cache_size,
190 bool force,
191 const scoped_refptr<base::SingleThreadTaskRunner>& cache_thread,
192 const net::CompletionCallback& callback) {
193 return Init(net::APP_CACHE,
194 disk_cache_directory,
195 disk_cache_size,
196 force,
197 cache_thread,
198 callback);
201 int AppCacheDiskCache::InitWithMemBackend(
202 int mem_cache_size, const net::CompletionCallback& callback) {
203 return Init(net::MEMORY_CACHE, base::FilePath(), mem_cache_size, false, NULL,
204 callback);
207 void AppCacheDiskCache::Disable() {
208 if (is_disabled_)
209 return;
211 is_disabled_ = true;
213 if (create_backend_callback_.get()) {
214 create_backend_callback_->Cancel();
215 create_backend_callback_ = NULL;
216 OnCreateBackendComplete(net::ERR_ABORTED);
219 // We need to close open file handles in order to reinitalize the
220 // appcache system on the fly. File handles held in both entries and in
221 // the main disk_cache::Backend class need to be released.
222 for (OpenEntries::const_iterator iter = open_entries_.begin();
223 iter != open_entries_.end(); ++iter) {
224 (*iter)->Abandon();
226 open_entries_.clear();
227 disk_cache_.reset();
228 STLDeleteElements(&active_calls_);
231 int AppCacheDiskCache::CreateEntry(int64 key, Entry** entry,
232 const net::CompletionCallback& callback) {
233 DCHECK(entry);
234 DCHECK(!callback.is_null());
235 if (is_disabled_)
236 return net::ERR_ABORTED;
238 if (is_initializing()) {
239 pending_calls_.push_back(PendingCall(CREATE, key, entry, callback));
240 return net::ERR_IO_PENDING;
243 if (!disk_cache_)
244 return net::ERR_FAILED;
246 return (new ActiveCall(this))->CreateEntry(key, entry, callback);
249 int AppCacheDiskCache::OpenEntry(int64 key, Entry** entry,
250 const net::CompletionCallback& callback) {
251 DCHECK(entry);
252 DCHECK(!callback.is_null());
253 if (is_disabled_)
254 return net::ERR_ABORTED;
256 if (is_initializing()) {
257 pending_calls_.push_back(PendingCall(OPEN, key, entry, callback));
258 return net::ERR_IO_PENDING;
261 if (!disk_cache_)
262 return net::ERR_FAILED;
264 return (new ActiveCall(this))->OpenEntry(key, entry, callback);
267 int AppCacheDiskCache::DoomEntry(int64 key,
268 const net::CompletionCallback& callback) {
269 DCHECK(!callback.is_null());
270 if (is_disabled_)
271 return net::ERR_ABORTED;
273 if (is_initializing()) {
274 pending_calls_.push_back(PendingCall(DOOM, key, NULL, callback));
275 return net::ERR_IO_PENDING;
278 if (!disk_cache_)
279 return net::ERR_FAILED;
281 return (new ActiveCall(this))->DoomEntry(key, callback);
284 AppCacheDiskCache::PendingCall::PendingCall()
285 : call_type(CREATE),
286 key(0),
287 entry(NULL) {
290 AppCacheDiskCache::PendingCall::PendingCall(PendingCallType call_type,
291 int64 key,
292 Entry** entry,
293 const net::CompletionCallback& callback)
294 : call_type(call_type),
295 key(key),
296 entry(entry),
297 callback(callback) {
300 AppCacheDiskCache::PendingCall::~PendingCall() {}
302 int AppCacheDiskCache::Init(
303 net::CacheType cache_type,
304 const base::FilePath& cache_directory,
305 int cache_size,
306 bool force,
307 const scoped_refptr<base::SingleThreadTaskRunner>& cache_thread,
308 const net::CompletionCallback& callback) {
309 DCHECK(!is_initializing() && !disk_cache_.get());
310 is_disabled_ = false;
311 create_backend_callback_ = new CreateBackendCallbackShim(this);
313 #if defined(APPCACHE_USE_SIMPLE_CACHE)
314 const net::BackendType backend_type = net::CACHE_BACKEND_SIMPLE;
315 #else
316 const net::BackendType backend_type = net::CACHE_BACKEND_DEFAULT;
317 #endif
318 int rv = disk_cache::CreateCacheBackend(
319 cache_type,
320 backend_type,
321 cache_directory,
322 cache_size,
323 force,
324 cache_thread,
325 NULL,
326 &(create_backend_callback_->backend_ptr_),
327 base::Bind(&CreateBackendCallbackShim::Callback,
328 create_backend_callback_));
329 if (rv == net::ERR_IO_PENDING)
330 init_callback_ = callback;
331 else
332 OnCreateBackendComplete(rv);
333 return rv;
336 void AppCacheDiskCache::OnCreateBackendComplete(int rv) {
337 if (rv == net::OK) {
338 disk_cache_ = create_backend_callback_->backend_ptr_.Pass();
340 create_backend_callback_ = NULL;
342 // Invoke our clients callback function.
343 if (!init_callback_.is_null()) {
344 init_callback_.Run(rv);
345 init_callback_.Reset();
348 // Service pending calls that were queued up while we were initializing.
349 for (PendingCalls::const_iterator iter = pending_calls_.begin();
350 iter < pending_calls_.end(); ++iter) {
351 int rv = net::ERR_FAILED;
352 switch (iter->call_type) {
353 case CREATE:
354 rv = CreateEntry(iter->key, iter->entry, iter->callback);
355 break;
356 case OPEN:
357 rv = OpenEntry(iter->key, iter->entry, iter->callback);
358 break;
359 case DOOM:
360 rv = DoomEntry(iter->key, iter->callback);
361 break;
362 default:
363 NOTREACHED();
364 break;
366 if (rv != net::ERR_IO_PENDING)
367 iter->callback.Run(rv);
369 pending_calls_.clear();
372 } // namespace content