Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / browser / appcache / appcache_disk_cache.cc
blobe26b88dbe599752f22be7c3fa64f8ed0f298f5e5
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 virtual int Read(int index, int64 offset, net::IOBuffer* buf, int buf_len,
63 const net::CompletionCallback& callback) OVERRIDE {
64 if (offset < 0 || offset > kint32max)
65 return net::ERR_INVALID_ARGUMENT;
66 if (!disk_cache_entry_)
67 return net::ERR_ABORTED;
68 return disk_cache_entry_->ReadData(
69 index, static_cast<int>(offset), buf, buf_len, callback);
72 virtual int Write(int index, int64 offset, net::IOBuffer* buf, int buf_len,
73 const net::CompletionCallback& callback) OVERRIDE {
74 if (offset < 0 || offset > kint32max)
75 return net::ERR_INVALID_ARGUMENT;
76 if (!disk_cache_entry_)
77 return net::ERR_ABORTED;
78 const bool kTruncate = true;
79 return disk_cache_entry_->WriteData(
80 index, static_cast<int>(offset), buf, buf_len, callback, kTruncate);
83 virtual int64 GetSize(int index) OVERRIDE {
84 return disk_cache_entry_ ? disk_cache_entry_->GetDataSize(index) : 0L;
87 virtual void Close() OVERRIDE {
88 if (disk_cache_entry_)
89 disk_cache_entry_->Close();
90 delete this;
93 void Abandon() {
94 owner_ = NULL;
95 disk_cache_entry_->Close();
96 disk_cache_entry_ = NULL;
99 private:
100 virtual ~EntryImpl() {
101 if (owner_)
102 owner_->RemoveOpenEntry(this);
105 disk_cache::Entry* disk_cache_entry_;
106 AppCacheDiskCache* owner_;
109 // Separate object to hold state for each Create, Delete, or Doom call
110 // while the call is in-flight and to produce an EntryImpl upon completion.
111 class AppCacheDiskCache::ActiveCall {
112 public:
113 explicit ActiveCall(AppCacheDiskCache* owner)
114 : entry_(NULL),
115 owner_(owner),
116 entry_ptr_(NULL) {
119 int CreateEntry(int64 key, Entry** entry,
120 const net::CompletionCallback& callback) {
121 int rv = owner_->disk_cache()->CreateEntry(
122 base::Int64ToString(key), &entry_ptr_,
123 base::Bind(&ActiveCall::OnAsyncCompletion, base::Unretained(this)));
124 return HandleImmediateReturnValue(rv, entry, callback);
127 int OpenEntry(int64 key, Entry** entry,
128 const net::CompletionCallback& callback) {
129 int rv = owner_->disk_cache()->OpenEntry(
130 base::Int64ToString(key), &entry_ptr_,
131 base::Bind(&ActiveCall::OnAsyncCompletion, base::Unretained(this)));
132 return HandleImmediateReturnValue(rv, entry, callback);
135 int DoomEntry(int64 key, const net::CompletionCallback& callback) {
136 int rv = owner_->disk_cache()->DoomEntry(
137 base::Int64ToString(key),
138 base::Bind(&ActiveCall::OnAsyncCompletion, base::Unretained(this)));
139 return HandleImmediateReturnValue(rv, NULL, callback);
142 private:
143 int HandleImmediateReturnValue(int rv, Entry** entry,
144 const net::CompletionCallback& callback) {
145 if (rv == net::ERR_IO_PENDING) {
146 // OnAsyncCompletion will be called later.
147 callback_ = callback;
148 entry_ = entry;
149 owner_->AddActiveCall(this);
150 return net::ERR_IO_PENDING;
152 if (rv == net::OK && entry)
153 *entry = new EntryImpl(entry_ptr_, owner_);
154 delete this;
155 return rv;
158 void OnAsyncCompletion(int rv) {
159 owner_->RemoveActiveCall(this);
160 if (rv == net::OK && entry_)
161 *entry_ = new EntryImpl(entry_ptr_, owner_);
162 callback_.Run(rv);
163 callback_.Reset();
164 delete this;
167 Entry** entry_;
168 net::CompletionCallback callback_;
169 AppCacheDiskCache* owner_;
170 disk_cache::Entry* entry_ptr_;
173 AppCacheDiskCache::AppCacheDiskCache()
174 : is_disabled_(false) {
177 AppCacheDiskCache::~AppCacheDiskCache() {
178 Disable();
181 int AppCacheDiskCache::InitWithDiskBackend(
182 const base::FilePath& disk_cache_directory,
183 int disk_cache_size,
184 bool force,
185 const scoped_refptr<base::SingleThreadTaskRunner>& cache_thread,
186 const net::CompletionCallback& callback) {
187 return Init(net::APP_CACHE,
188 disk_cache_directory,
189 disk_cache_size,
190 force,
191 cache_thread,
192 callback);
195 int AppCacheDiskCache::InitWithMemBackend(
196 int mem_cache_size, const net::CompletionCallback& callback) {
197 return Init(net::MEMORY_CACHE, base::FilePath(), mem_cache_size, false, NULL,
198 callback);
201 void AppCacheDiskCache::Disable() {
202 if (is_disabled_)
203 return;
205 is_disabled_ = true;
207 if (create_backend_callback_.get()) {
208 create_backend_callback_->Cancel();
209 create_backend_callback_ = NULL;
210 OnCreateBackendComplete(net::ERR_ABORTED);
213 // We need to close open file handles in order to reinitalize the
214 // appcache system on the fly. File handles held in both entries and in
215 // the main disk_cache::Backend class need to be released.
216 for (OpenEntries::const_iterator iter = open_entries_.begin();
217 iter != open_entries_.end(); ++iter) {
218 (*iter)->Abandon();
220 open_entries_.clear();
221 disk_cache_.reset();
222 STLDeleteElements(&active_calls_);
225 int AppCacheDiskCache::CreateEntry(int64 key, Entry** entry,
226 const net::CompletionCallback& callback) {
227 DCHECK(entry);
228 DCHECK(!callback.is_null());
229 if (is_disabled_)
230 return net::ERR_ABORTED;
232 if (is_initializing()) {
233 pending_calls_.push_back(PendingCall(CREATE, key, entry, callback));
234 return net::ERR_IO_PENDING;
237 if (!disk_cache_)
238 return net::ERR_FAILED;
240 return (new ActiveCall(this))->CreateEntry(key, entry, callback);
243 int AppCacheDiskCache::OpenEntry(int64 key, Entry** entry,
244 const net::CompletionCallback& callback) {
245 DCHECK(entry);
246 DCHECK(!callback.is_null());
247 if (is_disabled_)
248 return net::ERR_ABORTED;
250 if (is_initializing()) {
251 pending_calls_.push_back(PendingCall(OPEN, key, entry, callback));
252 return net::ERR_IO_PENDING;
255 if (!disk_cache_)
256 return net::ERR_FAILED;
258 return (new ActiveCall(this))->OpenEntry(key, entry, callback);
261 int AppCacheDiskCache::DoomEntry(int64 key,
262 const net::CompletionCallback& callback) {
263 DCHECK(!callback.is_null());
264 if (is_disabled_)
265 return net::ERR_ABORTED;
267 if (is_initializing()) {
268 pending_calls_.push_back(PendingCall(DOOM, key, NULL, callback));
269 return net::ERR_IO_PENDING;
272 if (!disk_cache_)
273 return net::ERR_FAILED;
275 return (new ActiveCall(this))->DoomEntry(key, callback);
278 AppCacheDiskCache::PendingCall::PendingCall()
279 : call_type(CREATE),
280 key(0),
281 entry(NULL) {
284 AppCacheDiskCache::PendingCall::PendingCall(PendingCallType call_type,
285 int64 key,
286 Entry** entry,
287 const net::CompletionCallback& callback)
288 : call_type(call_type),
289 key(key),
290 entry(entry),
291 callback(callback) {
294 AppCacheDiskCache::PendingCall::~PendingCall() {}
296 int AppCacheDiskCache::Init(
297 net::CacheType cache_type,
298 const base::FilePath& cache_directory,
299 int cache_size,
300 bool force,
301 const scoped_refptr<base::SingleThreadTaskRunner>& cache_thread,
302 const net::CompletionCallback& callback) {
303 DCHECK(!is_initializing() && !disk_cache_.get());
304 is_disabled_ = false;
305 create_backend_callback_ = new CreateBackendCallbackShim(this);
307 #if defined(APPCACHE_USE_SIMPLE_CACHE)
308 const net::BackendType backend_type = net::CACHE_BACKEND_SIMPLE;
309 #else
310 const net::BackendType backend_type = net::CACHE_BACKEND_DEFAULT;
311 #endif
312 int rv = disk_cache::CreateCacheBackend(
313 cache_type,
314 backend_type,
315 cache_directory,
316 cache_size,
317 force,
318 cache_thread,
319 NULL,
320 &(create_backend_callback_->backend_ptr_),
321 base::Bind(&CreateBackendCallbackShim::Callback,
322 create_backend_callback_));
323 if (rv == net::ERR_IO_PENDING)
324 init_callback_ = callback;
325 else
326 OnCreateBackendComplete(rv);
327 return rv;
330 void AppCacheDiskCache::OnCreateBackendComplete(int rv) {
331 if (rv == net::OK) {
332 disk_cache_ = create_backend_callback_->backend_ptr_.Pass();
334 create_backend_callback_ = NULL;
336 // Invoke our clients callback function.
337 if (!init_callback_.is_null()) {
338 init_callback_.Run(rv);
339 init_callback_.Reset();
342 // Service pending calls that were queued up while we were initializing.
343 for (PendingCalls::const_iterator iter = pending_calls_.begin();
344 iter < pending_calls_.end(); ++iter) {
345 int rv = net::ERR_FAILED;
346 switch (iter->call_type) {
347 case CREATE:
348 rv = CreateEntry(iter->key, iter->entry, iter->callback);
349 break;
350 case OPEN:
351 rv = OpenEntry(iter->key, iter->entry, iter->callback);
352 break;
353 case DOOM:
354 rv = DoomEntry(iter->key, iter->callback);
355 break;
356 default:
357 NOTREACHED();
358 break;
360 if (rv != net::ERR_IO_PENDING)
361 iter->callback.Run(rv);
363 pending_calls_.clear();
366 } // namespace content