Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(205)

Side by Side Diff: net/disk_cache/simple/simple_backend_impl.cc

Issue 992733002: Remove //net (except for Android test stuff) and sdch (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2013 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/simple/simple_backend_impl.h"
6
7 #include <algorithm>
8 #include <cstdlib>
9 #include <functional>
10
11 #if defined(OS_POSIX)
12 #include <sys/resource.h>
13 #endif
14
15 #include "base/bind.h"
16 #include "base/callback.h"
17 #include "base/files/file_util.h"
18 #include "base/location.h"
19 #include "base/metrics/field_trial.h"
20 #include "base/metrics/histogram.h"
21 #include "base/metrics/sparse_histogram.h"
22 #include "base/single_thread_task_runner.h"
23 #include "base/sys_info.h"
24 #include "base/task_runner_util.h"
25 #include "base/thread_task_runner_handle.h"
26 #include "base/threading/sequenced_worker_pool.h"
27 #include "base/time/time.h"
28 #include "net/base/net_errors.h"
29 #include "net/disk_cache/cache_util.h"
30 #include "net/disk_cache/simple/simple_entry_format.h"
31 #include "net/disk_cache/simple/simple_entry_impl.h"
32 #include "net/disk_cache/simple/simple_histogram_macros.h"
33 #include "net/disk_cache/simple/simple_index.h"
34 #include "net/disk_cache/simple/simple_index_file.h"
35 #include "net/disk_cache/simple/simple_synchronous_entry.h"
36 #include "net/disk_cache/simple/simple_util.h"
37 #include "net/disk_cache/simple/simple_version_upgrade.h"
38
39 using base::Callback;
40 using base::Closure;
41 using base::FilePath;
42 using base::SequencedWorkerPool;
43 using base::Time;
44 using base::DirectoryExists;
45 using base::CreateDirectory;
46
47 namespace disk_cache {
48
49 namespace {
50
51 // Maximum number of concurrent worker pool threads, which also is the limit
52 // on concurrent IO (as we use one thread per IO request).
53 const size_t kMaxWorkerThreads = 5U;
54
55 const char kThreadNamePrefix[] = "SimpleCache";
56
57 // Maximum fraction of the cache that one entry can consume.
58 const int kMaxFileRatio = 8;
59
60 // A global sequenced worker pool to use for launching all tasks.
61 SequencedWorkerPool* g_sequenced_worker_pool = NULL;
62
63 void MaybeCreateSequencedWorkerPool() {
64 if (!g_sequenced_worker_pool) {
65 g_sequenced_worker_pool =
66 new SequencedWorkerPool(kMaxWorkerThreads, kThreadNamePrefix);
67 g_sequenced_worker_pool->AddRef(); // Leak it.
68 }
69 }
70
71 bool g_fd_limit_histogram_has_been_populated = false;
72
73 void MaybeHistogramFdLimit(net::CacheType cache_type) {
74 if (g_fd_limit_histogram_has_been_populated)
75 return;
76
77 // Used in histograms; add new entries at end.
78 enum FdLimitStatus {
79 FD_LIMIT_STATUS_UNSUPPORTED = 0,
80 FD_LIMIT_STATUS_FAILED = 1,
81 FD_LIMIT_STATUS_SUCCEEDED = 2,
82 FD_LIMIT_STATUS_MAX = 3
83 };
84 FdLimitStatus fd_limit_status = FD_LIMIT_STATUS_UNSUPPORTED;
85 int soft_fd_limit = 0;
86 int hard_fd_limit = 0;
87
88 #if defined(OS_POSIX)
89 struct rlimit nofile;
90 if (!getrlimit(RLIMIT_NOFILE, &nofile)) {
91 soft_fd_limit = nofile.rlim_cur;
92 hard_fd_limit = nofile.rlim_max;
93 fd_limit_status = FD_LIMIT_STATUS_SUCCEEDED;
94 } else {
95 fd_limit_status = FD_LIMIT_STATUS_FAILED;
96 }
97 #endif
98
99 SIMPLE_CACHE_UMA(ENUMERATION,
100 "FileDescriptorLimitStatus", cache_type,
101 fd_limit_status, FD_LIMIT_STATUS_MAX);
102 if (fd_limit_status == FD_LIMIT_STATUS_SUCCEEDED) {
103 SIMPLE_CACHE_UMA(SPARSE_SLOWLY,
104 "FileDescriptorLimitSoft", cache_type, soft_fd_limit);
105 SIMPLE_CACHE_UMA(SPARSE_SLOWLY,
106 "FileDescriptorLimitHard", cache_type, hard_fd_limit);
107 }
108
109 g_fd_limit_histogram_has_been_populated = true;
110 }
111
112 // Detects if the files in the cache directory match the current disk cache
113 // backend type and version. If the directory contains no cache, occupies it
114 // with the fresh structure.
115 bool FileStructureConsistent(const base::FilePath& path) {
116 if (!base::PathExists(path) && !base::CreateDirectory(path)) {
117 LOG(ERROR) << "Failed to create directory: " << path.LossyDisplayName();
118 return false;
119 }
120 return disk_cache::UpgradeSimpleCacheOnDisk(path);
121 }
122
123 // A context used by a BarrierCompletionCallback to track state.
124 struct BarrierContext {
125 BarrierContext(int expected)
126 : expected(expected),
127 count(0),
128 had_error(false) {}
129
130 const int expected;
131 int count;
132 bool had_error;
133 };
134
135 void BarrierCompletionCallbackImpl(
136 BarrierContext* context,
137 const net::CompletionCallback& final_callback,
138 int result) {
139 DCHECK_GT(context->expected, context->count);
140 if (context->had_error)
141 return;
142 if (result != net::OK) {
143 context->had_error = true;
144 final_callback.Run(result);
145 return;
146 }
147 ++context->count;
148 if (context->count == context->expected)
149 final_callback.Run(net::OK);
150 }
151
152 // A barrier completion callback is a net::CompletionCallback that waits for
153 // |count| successful results before invoking |final_callback|. In the case of
154 // an error, the first error is passed to |final_callback| and all others
155 // are ignored.
156 net::CompletionCallback MakeBarrierCompletionCallback(
157 int count,
158 const net::CompletionCallback& final_callback) {
159 BarrierContext* context = new BarrierContext(count);
160 return base::Bind(&BarrierCompletionCallbackImpl,
161 base::Owned(context), final_callback);
162 }
163
164 // A short bindable thunk that ensures a completion callback is always called
165 // after running an operation asynchronously.
166 void RunOperationAndCallback(
167 const Callback<int(const net::CompletionCallback&)>& operation,
168 const net::CompletionCallback& operation_callback) {
169 const int operation_result = operation.Run(operation_callback);
170 if (operation_result != net::ERR_IO_PENDING)
171 operation_callback.Run(operation_result);
172 }
173
174 void RecordIndexLoad(net::CacheType cache_type,
175 base::TimeTicks constructed_since,
176 int result) {
177 const base::TimeDelta creation_to_index = base::TimeTicks::Now() -
178 constructed_since;
179 if (result == net::OK) {
180 SIMPLE_CACHE_UMA(TIMES, "CreationToIndex", cache_type, creation_to_index);
181 } else {
182 SIMPLE_CACHE_UMA(TIMES,
183 "CreationToIndexFail", cache_type, creation_to_index);
184 }
185 }
186
187 } // namespace
188
189 class SimpleBackendImpl::ActiveEntryProxy
190 : public SimpleEntryImpl::ActiveEntryProxy {
191 public:
192 ~ActiveEntryProxy() override {
193 if (backend_) {
194 DCHECK_EQ(1U, backend_->active_entries_.count(entry_hash_));
195 backend_->active_entries_.erase(entry_hash_);
196 }
197 }
198
199 static scoped_ptr<SimpleEntryImpl::ActiveEntryProxy> Create(
200 int64 entry_hash,
201 SimpleBackendImpl* backend) {
202 scoped_ptr<SimpleEntryImpl::ActiveEntryProxy>
203 proxy(new ActiveEntryProxy(entry_hash, backend));
204 return proxy.Pass();
205 }
206
207 private:
208 ActiveEntryProxy(uint64 entry_hash,
209 SimpleBackendImpl* backend)
210 : entry_hash_(entry_hash),
211 backend_(backend->AsWeakPtr()) {}
212
213 uint64 entry_hash_;
214 base::WeakPtr<SimpleBackendImpl> backend_;
215 };
216
217 SimpleBackendImpl::SimpleBackendImpl(
218 const FilePath& path,
219 int max_bytes,
220 net::CacheType cache_type,
221 const scoped_refptr<base::SingleThreadTaskRunner>& cache_thread,
222 net::NetLog* net_log)
223 : path_(path),
224 cache_type_(cache_type),
225 cache_thread_(cache_thread),
226 orig_max_size_(max_bytes),
227 entry_operations_mode_(cache_type == net::DISK_CACHE ?
228 SimpleEntryImpl::OPTIMISTIC_OPERATIONS :
229 SimpleEntryImpl::NON_OPTIMISTIC_OPERATIONS),
230 net_log_(net_log) {
231 MaybeHistogramFdLimit(cache_type_);
232 }
233
234 SimpleBackendImpl::~SimpleBackendImpl() {
235 index_->WriteToDisk();
236 }
237
238 int SimpleBackendImpl::Init(const CompletionCallback& completion_callback) {
239 MaybeCreateSequencedWorkerPool();
240
241 worker_pool_ = g_sequenced_worker_pool->GetTaskRunnerWithShutdownBehavior(
242 SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
243
244 index_.reset(new SimpleIndex(
245 base::ThreadTaskRunnerHandle::Get(),
246 this,
247 cache_type_,
248 make_scoped_ptr(new SimpleIndexFile(
249 cache_thread_, worker_pool_.get(), cache_type_, path_))));
250 index_->ExecuteWhenReady(
251 base::Bind(&RecordIndexLoad, cache_type_, base::TimeTicks::Now()));
252
253 PostTaskAndReplyWithResult(
254 cache_thread_.get(),
255 FROM_HERE,
256 base::Bind(
257 &SimpleBackendImpl::InitCacheStructureOnDisk, path_, orig_max_size_),
258 base::Bind(&SimpleBackendImpl::InitializeIndex,
259 AsWeakPtr(),
260 completion_callback));
261 return net::ERR_IO_PENDING;
262 }
263
264 bool SimpleBackendImpl::SetMaxSize(int max_bytes) {
265 if (max_bytes < 0)
266 return false;
267 orig_max_size_ = max_bytes;
268 index_->SetMaxSize(max_bytes);
269 return true;
270 }
271
272 int SimpleBackendImpl::GetMaxFileSize() const {
273 return static_cast<int>(index_->max_size() / kMaxFileRatio);
274 }
275
276 void SimpleBackendImpl::OnDoomStart(uint64 entry_hash) {
277 DCHECK_EQ(0u, entries_pending_doom_.count(entry_hash));
278 entries_pending_doom_.insert(
279 std::make_pair(entry_hash, std::vector<Closure>()));
280 }
281
282 void SimpleBackendImpl::OnDoomComplete(uint64 entry_hash) {
283 DCHECK_EQ(1u, entries_pending_doom_.count(entry_hash));
284 base::hash_map<uint64, std::vector<Closure> >::iterator it =
285 entries_pending_doom_.find(entry_hash);
286 std::vector<Closure> to_run_closures;
287 to_run_closures.swap(it->second);
288 entries_pending_doom_.erase(it);
289
290 std::for_each(to_run_closures.begin(), to_run_closures.end(),
291 std::mem_fun_ref(&Closure::Run));
292 }
293
294 void SimpleBackendImpl::DoomEntries(std::vector<uint64>* entry_hashes,
295 const net::CompletionCallback& callback) {
296 scoped_ptr<std::vector<uint64> >
297 mass_doom_entry_hashes(new std::vector<uint64>());
298 mass_doom_entry_hashes->swap(*entry_hashes);
299
300 std::vector<uint64> to_doom_individually_hashes;
301
302 // For each of the entry hashes, there are two cases:
303 // 1. The entry is either open or pending doom, and so it should be doomed
304 // individually to avoid flakes.
305 // 2. The entry is not in use at all, so we can call
306 // SimpleSynchronousEntry::DoomEntrySet and delete the files en masse.
307 for (int i = mass_doom_entry_hashes->size() - 1; i >= 0; --i) {
308 const uint64 entry_hash = (*mass_doom_entry_hashes)[i];
309 DCHECK(active_entries_.count(entry_hash) == 0 ||
310 entries_pending_doom_.count(entry_hash) == 0);
311 if (!active_entries_.count(entry_hash) &&
312 !entries_pending_doom_.count(entry_hash)) {
313 continue;
314 }
315
316 to_doom_individually_hashes.push_back(entry_hash);
317
318 (*mass_doom_entry_hashes)[i] = mass_doom_entry_hashes->back();
319 mass_doom_entry_hashes->resize(mass_doom_entry_hashes->size() - 1);
320 }
321
322 net::CompletionCallback barrier_callback =
323 MakeBarrierCompletionCallback(to_doom_individually_hashes.size() + 1,
324 callback);
325 for (std::vector<uint64>::const_iterator
326 it = to_doom_individually_hashes.begin(),
327 end = to_doom_individually_hashes.end(); it != end; ++it) {
328 const int doom_result = DoomEntryFromHash(*it, barrier_callback);
329 DCHECK_EQ(net::ERR_IO_PENDING, doom_result);
330 index_->Remove(*it);
331 }
332
333 for (std::vector<uint64>::const_iterator it = mass_doom_entry_hashes->begin(),
334 end = mass_doom_entry_hashes->end();
335 it != end; ++it) {
336 index_->Remove(*it);
337 OnDoomStart(*it);
338 }
339
340 // Taking this pointer here avoids undefined behaviour from calling
341 // base::Passed before mass_doom_entry_hashes.get().
342 std::vector<uint64>* mass_doom_entry_hashes_ptr =
343 mass_doom_entry_hashes.get();
344 PostTaskAndReplyWithResult(worker_pool_.get(),
345 FROM_HERE,
346 base::Bind(&SimpleSynchronousEntry::DoomEntrySet,
347 mass_doom_entry_hashes_ptr,
348 path_),
349 base::Bind(&SimpleBackendImpl::DoomEntriesComplete,
350 AsWeakPtr(),
351 base::Passed(&mass_doom_entry_hashes),
352 barrier_callback));
353 }
354
355 net::CacheType SimpleBackendImpl::GetCacheType() const {
356 return net::DISK_CACHE;
357 }
358
359 int32 SimpleBackendImpl::GetEntryCount() const {
360 // TODO(pasko): Use directory file count when index is not ready.
361 return index_->GetEntryCount();
362 }
363
364 int SimpleBackendImpl::OpenEntry(const std::string& key,
365 Entry** entry,
366 const CompletionCallback& callback) {
367 const uint64 entry_hash = simple_util::GetEntryHashKey(key);
368
369 // TODO(gavinp): Factor out this (not quite completely) repetitive code
370 // block from OpenEntry/CreateEntry/DoomEntry.
371 base::hash_map<uint64, std::vector<Closure> >::iterator it =
372 entries_pending_doom_.find(entry_hash);
373 if (it != entries_pending_doom_.end()) {
374 Callback<int(const net::CompletionCallback&)> operation =
375 base::Bind(&SimpleBackendImpl::OpenEntry,
376 base::Unretained(this), key, entry);
377 it->second.push_back(base::Bind(&RunOperationAndCallback,
378 operation, callback));
379 return net::ERR_IO_PENDING;
380 }
381 scoped_refptr<SimpleEntryImpl> simple_entry =
382 CreateOrFindActiveEntry(entry_hash, key);
383 CompletionCallback backend_callback =
384 base::Bind(&SimpleBackendImpl::OnEntryOpenedFromKey,
385 AsWeakPtr(),
386 key,
387 entry,
388 simple_entry,
389 callback);
390 return simple_entry->OpenEntry(entry, backend_callback);
391 }
392
393 int SimpleBackendImpl::CreateEntry(const std::string& key,
394 Entry** entry,
395 const CompletionCallback& callback) {
396 DCHECK_LT(0u, key.size());
397 const uint64 entry_hash = simple_util::GetEntryHashKey(key);
398
399 base::hash_map<uint64, std::vector<Closure> >::iterator it =
400 entries_pending_doom_.find(entry_hash);
401 if (it != entries_pending_doom_.end()) {
402 Callback<int(const net::CompletionCallback&)> operation =
403 base::Bind(&SimpleBackendImpl::CreateEntry,
404 base::Unretained(this), key, entry);
405 it->second.push_back(base::Bind(&RunOperationAndCallback,
406 operation, callback));
407 return net::ERR_IO_PENDING;
408 }
409 scoped_refptr<SimpleEntryImpl> simple_entry =
410 CreateOrFindActiveEntry(entry_hash, key);
411 return simple_entry->CreateEntry(entry, callback);
412 }
413
414 int SimpleBackendImpl::DoomEntry(const std::string& key,
415 const net::CompletionCallback& callback) {
416 const uint64 entry_hash = simple_util::GetEntryHashKey(key);
417
418 base::hash_map<uint64, std::vector<Closure> >::iterator it =
419 entries_pending_doom_.find(entry_hash);
420 if (it != entries_pending_doom_.end()) {
421 Callback<int(const net::CompletionCallback&)> operation =
422 base::Bind(&SimpleBackendImpl::DoomEntry, base::Unretained(this), key);
423 it->second.push_back(base::Bind(&RunOperationAndCallback,
424 operation, callback));
425 return net::ERR_IO_PENDING;
426 }
427 scoped_refptr<SimpleEntryImpl> simple_entry =
428 CreateOrFindActiveEntry(entry_hash, key);
429 return simple_entry->DoomEntry(callback);
430 }
431
432 int SimpleBackendImpl::DoomAllEntries(const CompletionCallback& callback) {
433 return DoomEntriesBetween(Time(), Time(), callback);
434 }
435
436 void SimpleBackendImpl::IndexReadyForDoom(Time initial_time,
437 Time end_time,
438 const CompletionCallback& callback,
439 int result) {
440 if (result != net::OK) {
441 callback.Run(result);
442 return;
443 }
444 scoped_ptr<std::vector<uint64> > removed_key_hashes(
445 index_->GetEntriesBetween(initial_time, end_time).release());
446 DoomEntries(removed_key_hashes.get(), callback);
447 }
448
449 int SimpleBackendImpl::DoomEntriesBetween(
450 const Time initial_time,
451 const Time end_time,
452 const CompletionCallback& callback) {
453 return index_->ExecuteWhenReady(
454 base::Bind(&SimpleBackendImpl::IndexReadyForDoom, AsWeakPtr(),
455 initial_time, end_time, callback));
456 }
457
458 int SimpleBackendImpl::DoomEntriesSince(
459 const Time initial_time,
460 const CompletionCallback& callback) {
461 return DoomEntriesBetween(initial_time, Time(), callback);
462 }
463
464 class SimpleBackendImpl::SimpleIterator final : public Iterator {
465 public:
466 explicit SimpleIterator(base::WeakPtr<SimpleBackendImpl> backend)
467 : backend_(backend),
468 weak_factory_(this) {
469 }
470
471 // From Backend::Iterator:
472 int OpenNextEntry(Entry** next_entry,
473 const CompletionCallback& callback) override {
474 CompletionCallback open_next_entry_impl =
475 base::Bind(&SimpleIterator::OpenNextEntryImpl,
476 weak_factory_.GetWeakPtr(), next_entry, callback);
477 return backend_->index_->ExecuteWhenReady(open_next_entry_impl);
478 }
479
480 void OpenNextEntryImpl(Entry** next_entry,
481 const CompletionCallback& callback,
482 int index_initialization_error_code) {
483 if (!backend_) {
484 callback.Run(net::ERR_FAILED);
485 return;
486 }
487 if (index_initialization_error_code != net::OK) {
488 callback.Run(index_initialization_error_code);
489 return;
490 }
491 if (!hashes_to_enumerate_)
492 hashes_to_enumerate_ = backend_->index()->GetAllHashes().Pass();
493
494 while (!hashes_to_enumerate_->empty()) {
495 uint64 entry_hash = hashes_to_enumerate_->back();
496 hashes_to_enumerate_->pop_back();
497 if (backend_->index()->Has(entry_hash)) {
498 *next_entry = NULL;
499 CompletionCallback continue_iteration = base::Bind(
500 &SimpleIterator::CheckIterationReturnValue,
501 weak_factory_.GetWeakPtr(),
502 next_entry,
503 callback);
504 int error_code_open = backend_->OpenEntryFromHash(entry_hash,
505 next_entry,
506 continue_iteration);
507 if (error_code_open == net::ERR_IO_PENDING)
508 return;
509 if (error_code_open != net::ERR_FAILED) {
510 callback.Run(error_code_open);
511 return;
512 }
513 }
514 }
515 callback.Run(net::ERR_FAILED);
516 }
517
518 void CheckIterationReturnValue(Entry** entry,
519 const CompletionCallback& callback,
520 int error_code) {
521 if (error_code == net::ERR_FAILED) {
522 OpenNextEntry(entry, callback);
523 return;
524 }
525 callback.Run(error_code);
526 }
527
528 private:
529 base::WeakPtr<SimpleBackendImpl> backend_;
530 scoped_ptr<std::vector<uint64> > hashes_to_enumerate_;
531 base::WeakPtrFactory<SimpleIterator> weak_factory_;
532 };
533
534 scoped_ptr<Backend::Iterator> SimpleBackendImpl::CreateIterator() {
535 return scoped_ptr<Iterator>(new SimpleIterator(AsWeakPtr()));
536 }
537
538 void SimpleBackendImpl::GetStats(
539 std::vector<std::pair<std::string, std::string> >* stats) {
540 std::pair<std::string, std::string> item;
541 item.first = "Cache type";
542 item.second = "Simple Cache";
543 stats->push_back(item);
544 }
545
546 void SimpleBackendImpl::OnExternalCacheHit(const std::string& key) {
547 index_->UseIfExists(simple_util::GetEntryHashKey(key));
548 }
549
550 void SimpleBackendImpl::InitializeIndex(const CompletionCallback& callback,
551 const DiskStatResult& result) {
552 if (result.net_error == net::OK) {
553 index_->SetMaxSize(result.max_size);
554 index_->Initialize(result.cache_dir_mtime);
555 }
556 callback.Run(result.net_error);
557 }
558
559 SimpleBackendImpl::DiskStatResult SimpleBackendImpl::InitCacheStructureOnDisk(
560 const base::FilePath& path,
561 uint64 suggested_max_size) {
562 DiskStatResult result;
563 result.max_size = suggested_max_size;
564 result.net_error = net::OK;
565 if (!FileStructureConsistent(path)) {
566 LOG(ERROR) << "Simple Cache Backend: wrong file structure on disk: "
567 << path.LossyDisplayName();
568 result.net_error = net::ERR_FAILED;
569 } else {
570 bool mtime_result =
571 disk_cache::simple_util::GetMTime(path, &result.cache_dir_mtime);
572 DCHECK(mtime_result);
573 if (!result.max_size) {
574 int64 available = base::SysInfo::AmountOfFreeDiskSpace(path);
575 result.max_size = disk_cache::PreferredCacheSize(available);
576 }
577 DCHECK(result.max_size);
578 }
579 return result;
580 }
581
582 scoped_refptr<SimpleEntryImpl> SimpleBackendImpl::CreateOrFindActiveEntry(
583 const uint64 entry_hash,
584 const std::string& key) {
585 DCHECK_EQ(entry_hash, simple_util::GetEntryHashKey(key));
586 std::pair<EntryMap::iterator, bool> insert_result =
587 active_entries_.insert(EntryMap::value_type(entry_hash, NULL));
588 EntryMap::iterator& it = insert_result.first;
589 const bool did_insert = insert_result.second;
590 if (did_insert) {
591 SimpleEntryImpl* entry = it->second =
592 new SimpleEntryImpl(cache_type_, path_, entry_hash,
593 entry_operations_mode_,this, net_log_);
594 entry->SetKey(key);
595 entry->SetActiveEntryProxy(ActiveEntryProxy::Create(entry_hash, this));
596 }
597 DCHECK(it->second);
598 // It's possible, but unlikely, that we have an entry hash collision with a
599 // currently active entry.
600 if (key != it->second->key()) {
601 it->second->Doom();
602 DCHECK_EQ(0U, active_entries_.count(entry_hash));
603 return CreateOrFindActiveEntry(entry_hash, key);
604 }
605 return make_scoped_refptr(it->second);
606 }
607
608 int SimpleBackendImpl::OpenEntryFromHash(uint64 entry_hash,
609 Entry** entry,
610 const CompletionCallback& callback) {
611 base::hash_map<uint64, std::vector<Closure> >::iterator it =
612 entries_pending_doom_.find(entry_hash);
613 if (it != entries_pending_doom_.end()) {
614 Callback<int(const net::CompletionCallback&)> operation =
615 base::Bind(&SimpleBackendImpl::OpenEntryFromHash,
616 base::Unretained(this), entry_hash, entry);
617 it->second.push_back(base::Bind(&RunOperationAndCallback,
618 operation, callback));
619 return net::ERR_IO_PENDING;
620 }
621
622 EntryMap::iterator has_active = active_entries_.find(entry_hash);
623 if (has_active != active_entries_.end()) {
624 return OpenEntry(has_active->second->key(), entry, callback);
625 }
626
627 scoped_refptr<SimpleEntryImpl> simple_entry = new SimpleEntryImpl(
628 cache_type_, path_, entry_hash, entry_operations_mode_, this, net_log_);
629 CompletionCallback backend_callback =
630 base::Bind(&SimpleBackendImpl::OnEntryOpenedFromHash,
631 AsWeakPtr(), entry_hash, entry, simple_entry, callback);
632 return simple_entry->OpenEntry(entry, backend_callback);
633 }
634
635 int SimpleBackendImpl::DoomEntryFromHash(uint64 entry_hash,
636 const CompletionCallback& callback) {
637 Entry** entry = new Entry*();
638 scoped_ptr<Entry*> scoped_entry(entry);
639
640 base::hash_map<uint64, std::vector<Closure> >::iterator pending_it =
641 entries_pending_doom_.find(entry_hash);
642 if (pending_it != entries_pending_doom_.end()) {
643 Callback<int(const net::CompletionCallback&)> operation =
644 base::Bind(&SimpleBackendImpl::DoomEntryFromHash,
645 base::Unretained(this), entry_hash);
646 pending_it->second.push_back(base::Bind(&RunOperationAndCallback,
647 operation, callback));
648 return net::ERR_IO_PENDING;
649 }
650
651 EntryMap::iterator active_it = active_entries_.find(entry_hash);
652 if (active_it != active_entries_.end())
653 return active_it->second->DoomEntry(callback);
654
655 // There's no pending dooms, nor any open entry. We can make a trivial
656 // call to DoomEntries() to delete this entry.
657 std::vector<uint64> entry_hash_vector;
658 entry_hash_vector.push_back(entry_hash);
659 DoomEntries(&entry_hash_vector, callback);
660 return net::ERR_IO_PENDING;
661 }
662
663 void SimpleBackendImpl::OnEntryOpenedFromHash(
664 uint64 hash,
665 Entry** entry,
666 const scoped_refptr<SimpleEntryImpl>& simple_entry,
667 const CompletionCallback& callback,
668 int error_code) {
669 if (error_code != net::OK) {
670 callback.Run(error_code);
671 return;
672 }
673 DCHECK(*entry);
674 std::pair<EntryMap::iterator, bool> insert_result =
675 active_entries_.insert(EntryMap::value_type(hash, simple_entry.get()));
676 EntryMap::iterator& it = insert_result.first;
677 const bool did_insert = insert_result.second;
678 if (did_insert) {
679 // There was no active entry corresponding to this hash. We've already put
680 // the entry opened from hash in the |active_entries_|. We now provide the
681 // proxy object to the entry.
682 it->second->SetActiveEntryProxy(ActiveEntryProxy::Create(hash, this));
683 callback.Run(net::OK);
684 } else {
685 // The entry was made active while we waiting for the open from hash to
686 // finish. The entry created from hash needs to be closed, and the one
687 // in |active_entries_| can be returned to the caller.
688 simple_entry->Close();
689 it->second->OpenEntry(entry, callback);
690 }
691 }
692
693 void SimpleBackendImpl::OnEntryOpenedFromKey(
694 const std::string key,
695 Entry** entry,
696 const scoped_refptr<SimpleEntryImpl>& simple_entry,
697 const CompletionCallback& callback,
698 int error_code) {
699 int final_code = error_code;
700 if (final_code == net::OK) {
701 bool key_matches = key.compare(simple_entry->key()) == 0;
702 if (!key_matches) {
703 // TODO(clamy): Add a unit test to check this code path.
704 DLOG(WARNING) << "Key mismatch on open.";
705 simple_entry->Doom();
706 simple_entry->Close();
707 final_code = net::ERR_FAILED;
708 } else {
709 DCHECK_EQ(simple_entry->entry_hash(), simple_util::GetEntryHashKey(key));
710 }
711 SIMPLE_CACHE_UMA(BOOLEAN, "KeyMatchedOnOpen", cache_type_, key_matches);
712 }
713 callback.Run(final_code);
714 }
715
716 void SimpleBackendImpl::DoomEntriesComplete(
717 scoped_ptr<std::vector<uint64> > entry_hashes,
718 const net::CompletionCallback& callback,
719 int result) {
720 std::for_each(
721 entry_hashes->begin(), entry_hashes->end(),
722 std::bind1st(std::mem_fun(&SimpleBackendImpl::OnDoomComplete),
723 this));
724 callback.Run(result);
725 }
726
727 void SimpleBackendImpl::FlushWorkerPoolForTesting() {
728 if (g_sequenced_worker_pool)
729 g_sequenced_worker_pool->FlushForTesting();
730 }
731
732 } // namespace disk_cache
OLDNEW
« no previous file with comments | « net/disk_cache/simple/simple_backend_impl.h ('k') | net/disk_cache/simple/simple_backend_version.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698