1 // Copyright 2014 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/bind.h"
6 #include "base/location.h"
7 #include "base/stl_util.h"
8 #include "base/task_runner.h"
9 #include "content/browser/indexed_db/indexed_db_active_blob_registry.h"
10 #include "content/browser/indexed_db/indexed_db_backing_store.h"
11 #include "content/browser/indexed_db/indexed_db_factory.h"
12 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h"
13
14 namespace content {
15
IndexedDBActiveBlobRegistry(IndexedDBBackingStore * backing_store)16 IndexedDBActiveBlobRegistry::IndexedDBActiveBlobRegistry(
17 IndexedDBBackingStore* backing_store)
18 : backing_store_(backing_store), weak_factory_(this) {}
19
~IndexedDBActiveBlobRegistry()20 IndexedDBActiveBlobRegistry::~IndexedDBActiveBlobRegistry() {
21 }
22
AddBlobRef(int64 database_id,int64 blob_key)23 void IndexedDBActiveBlobRegistry::AddBlobRef(int64 database_id,
24 int64 blob_key) {
25 DCHECK(backing_store_);
26 DCHECK(backing_store_->task_runner()->RunsTasksOnCurrentThread());
27 DCHECK(KeyPrefix::IsValidDatabaseId(database_id));
28 DCHECK(DatabaseMetaDataKey::IsValidBlobKey(blob_key));
29 DCHECK(!ContainsKey(deleted_dbs_, database_id));
30 bool need_ref = use_tracker_.empty();
31 SingleDBMap& single_db_map = use_tracker_[database_id];
32 SingleDBMap::iterator iter = single_db_map.find(blob_key);
33 if (iter == single_db_map.end()) {
34 single_db_map[blob_key] = false;
35 if (need_ref) {
36 backing_store_->factory()->ReportOutstandingBlobs(
37 backing_store_->origin_url(), true);
38 }
39 } else {
40 DCHECK(!need_ref);
41 DCHECK(!iter->second); // You can't add a reference once it's been deleted.
42 }
43 }
44
ReleaseBlobRef(int64 database_id,int64 blob_key)45 void IndexedDBActiveBlobRegistry::ReleaseBlobRef(int64 database_id,
46 int64 blob_key) {
47 DCHECK(backing_store_);
48 DCHECK(backing_store_->task_runner()->RunsTasksOnCurrentThread());
49 DCHECK(KeyPrefix::IsValidDatabaseId(database_id));
50 DCHECK(DatabaseMetaDataKey::IsValidBlobKey(blob_key));
51 AllDBsMap::iterator db_pair = use_tracker_.find(database_id);
52 if (db_pair == use_tracker_.end()) {
53 NOTREACHED();
54 return;
55 }
56 SingleDBMap& single_db = db_pair->second;
57 SingleDBMap::iterator blob_pair = single_db.find(blob_key);
58 if (blob_pair == single_db.end()) {
59 NOTREACHED();
60 return;
61 }
62 bool delete_in_backend = false;
63 DeletedDBSet::iterator db_to_delete = deleted_dbs_.find(database_id);
64 bool db_marked_for_deletion = db_to_delete != deleted_dbs_.end();
65 // Don't bother deleting the file if we're going to delete its whole
66 // database directory soon.
67 delete_in_backend = blob_pair->second && !db_marked_for_deletion;
68 single_db.erase(blob_pair);
69 if (single_db.empty()) {
70 use_tracker_.erase(db_pair);
71 if (db_marked_for_deletion) {
72 delete_in_backend = true;
73 blob_key = DatabaseMetaDataKey::kAllBlobsKey;
74 deleted_dbs_.erase(db_to_delete);
75 }
76 }
77 if (delete_in_backend)
78 backing_store_->ReportBlobUnused(database_id, blob_key);
79 if (use_tracker_.empty()) {
80 backing_store_->factory()->ReportOutstandingBlobs(
81 backing_store_->origin_url(), false);
82 }
83 }
84
MarkDeletedCheckIfUsed(int64 database_id,int64 blob_key)85 bool IndexedDBActiveBlobRegistry::MarkDeletedCheckIfUsed(int64 database_id,
86 int64 blob_key) {
87 DCHECK(backing_store_);
88 DCHECK(backing_store_->task_runner()->RunsTasksOnCurrentThread());
89 DCHECK(KeyPrefix::IsValidDatabaseId(database_id));
90 AllDBsMap::iterator db_pair = use_tracker_.find(database_id);
91 if (db_pair == use_tracker_.end())
92 return false;
93
94 if (blob_key == DatabaseMetaDataKey::kAllBlobsKey) {
95 deleted_dbs_.insert(database_id);
96 return true;
97 }
98
99 SingleDBMap& single_db = db_pair->second;
100 SingleDBMap::iterator iter = single_db.find(blob_key);
101 if (iter == single_db.end())
102 return false;
103
104 iter->second = true;
105 return true;
106 }
107
ReleaseBlobRefThreadSafe(scoped_refptr<base::TaskRunner> task_runner,base::WeakPtr<IndexedDBActiveBlobRegistry> weak_ptr,int64 database_id,int64 blob_key,const base::FilePath & unused)108 void IndexedDBActiveBlobRegistry::ReleaseBlobRefThreadSafe(
109 scoped_refptr<base::TaskRunner> task_runner,
110 base::WeakPtr<IndexedDBActiveBlobRegistry> weak_ptr,
111 int64 database_id,
112 int64 blob_key,
113 const base::FilePath& unused) {
114 task_runner->PostTask(FROM_HERE,
115 base::Bind(&IndexedDBActiveBlobRegistry::ReleaseBlobRef,
116 weak_ptr,
117 database_id,
118 blob_key));
119 }
120
121 storage::ShareableFileReference::FinalReleaseCallback
GetFinalReleaseCallback(int64 database_id,int64 blob_key)122 IndexedDBActiveBlobRegistry::GetFinalReleaseCallback(int64 database_id,
123 int64 blob_key) {
124 return base::Bind(
125 &IndexedDBActiveBlobRegistry::ReleaseBlobRefThreadSafe,
126 scoped_refptr<base::TaskRunner>(backing_store_->task_runner()),
127 weak_factory_.GetWeakPtr(),
128 database_id,
129 blob_key);
130 }
131
GetAddBlobRefCallback(int64 database_id,int64 blob_key)132 base::Closure IndexedDBActiveBlobRegistry::GetAddBlobRefCallback(
133 int64 database_id,
134 int64 blob_key) {
135 return base::Bind(&IndexedDBActiveBlobRegistry::AddBlobRef,
136 weak_factory_.GetWeakPtr(),
137 database_id,
138 blob_key);
139 }
140
ForceShutdown()141 void IndexedDBActiveBlobRegistry::ForceShutdown() {
142 weak_factory_.InvalidateWeakPtrs();
143 use_tracker_.clear();
144 backing_store_ = NULL;
145 }
146
147 } // namespace content
148