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 16 IndexedDBActiveBlobRegistry::IndexedDBActiveBlobRegistry( 17 IndexedDBBackingStore* backing_store) 18 : backing_store_(backing_store), weak_factory_(this) {} 19 20 IndexedDBActiveBlobRegistry::~IndexedDBActiveBlobRegistry() { 21 } 22 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 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 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 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 webkit_blob::ShareableFileReference::FinalReleaseCallback 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 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 141 void IndexedDBActiveBlobRegistry::ForceShutdown() { 142 weak_factory_.InvalidateWeakPtrs(); 143 use_tracker_.clear(); 144 backing_store_ = NULL; 145 } 146 147 } // namespace content 148