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. 4 5 #include "storage/common/database/database_connections.h" 6 7 #include "base/auto_reset.h" 8 #include "base/bind.h" 9 #include "base/logging.h" 10 #include "base/message_loop/message_loop.h" 11 #include "base/message_loop/message_loop_proxy.h" 12 13 namespace storage { 14 15 DatabaseConnections::DatabaseConnections() { 16 } 17 18 DatabaseConnections::~DatabaseConnections() { 19 DCHECK(connections_.empty()); 20 } 21 22 bool DatabaseConnections::IsEmpty() const { 23 return connections_.empty(); 24 } 25 26 bool DatabaseConnections::IsDatabaseOpened( 27 const std::string& origin_identifier, 28 const base::string16& database_name) const { 29 OriginConnections::const_iterator origin_it = 30 connections_.find(origin_identifier); 31 if (origin_it == connections_.end()) 32 return false; 33 const DBConnections& origin_connections = origin_it->second; 34 return (origin_connections.find(database_name) != origin_connections.end()); 35 } 36 37 bool DatabaseConnections::IsOriginUsed( 38 const std::string& origin_identifier) const { 39 return (connections_.find(origin_identifier) != connections_.end()); 40 } 41 42 bool DatabaseConnections::AddConnection( 43 const std::string& origin_identifier, 44 const base::string16& database_name) { 45 int& count = connections_[origin_identifier][database_name].first; 46 return ++count == 1; 47 } 48 49 bool DatabaseConnections::RemoveConnection( 50 const std::string& origin_identifier, 51 const base::string16& database_name) { 52 return RemoveConnectionsHelper(origin_identifier, database_name, 1); 53 } 54 55 void DatabaseConnections::RemoveAllConnections() { 56 connections_.clear(); 57 } 58 59 void DatabaseConnections::RemoveConnections( 60 const DatabaseConnections& connections, 61 std::vector<std::pair<std::string, base::string16> >* closed_dbs) { 62 for (OriginConnections::const_iterator origin_it = 63 connections.connections_.begin(); 64 origin_it != connections.connections_.end(); 65 origin_it++) { 66 const DBConnections& db_connections = origin_it->second; 67 for (DBConnections::const_iterator db_it = db_connections.begin(); 68 db_it != db_connections.end(); db_it++) { 69 if (RemoveConnectionsHelper(origin_it->first, db_it->first, 70 db_it->second.first)) 71 closed_dbs->push_back(std::make_pair(origin_it->first, db_it->first)); 72 } 73 } 74 } 75 76 int64 DatabaseConnections::GetOpenDatabaseSize( 77 const std::string& origin_identifier, 78 const base::string16& database_name) const { 79 DCHECK(IsDatabaseOpened(origin_identifier, database_name)); 80 return connections_[origin_identifier][database_name].second; 81 } 82 83 void DatabaseConnections::SetOpenDatabaseSize( 84 const std::string& origin_identifier, 85 const base::string16& database_name, 86 int64 size) { 87 DCHECK(IsDatabaseOpened(origin_identifier, database_name)); 88 connections_[origin_identifier][database_name].second = size; 89 } 90 91 void DatabaseConnections::ListConnections( 92 std::vector<std::pair<std::string, base::string16> > *list) const { 93 for (OriginConnections::const_iterator origin_it = 94 connections_.begin(); 95 origin_it != connections_.end(); 96 origin_it++) { 97 const DBConnections& db_connections = origin_it->second; 98 for (DBConnections::const_iterator db_it = db_connections.begin(); 99 db_it != db_connections.end(); db_it++) { 100 list->push_back(std::make_pair(origin_it->first, db_it->first)); 101 } 102 } 103 } 104 105 bool DatabaseConnections::RemoveConnectionsHelper( 106 const std::string& origin_identifier, 107 const base::string16& database_name, 108 int num_connections) { 109 OriginConnections::iterator origin_iterator = 110 connections_.find(origin_identifier); 111 DCHECK(origin_iterator != connections_.end()); 112 DBConnections& db_connections = origin_iterator->second; 113 int& count = db_connections[database_name].first; 114 DCHECK(count >= num_connections); 115 count -= num_connections; 116 if (count) 117 return false; 118 db_connections.erase(database_name); 119 if (db_connections.empty()) 120 connections_.erase(origin_iterator); 121 return true; 122 } 123 124 DatabaseConnectionsWrapper::DatabaseConnectionsWrapper() 125 : waiting_for_dbs_to_close_(false), 126 main_thread_(base::MessageLoopProxy::current()) { 127 } 128 129 DatabaseConnectionsWrapper::~DatabaseConnectionsWrapper() { 130 } 131 132 void DatabaseConnectionsWrapper::WaitForAllDatabasesToClose() { 133 // We assume that new databases won't be open while we're waiting. 134 DCHECK(main_thread_->BelongsToCurrentThread()); 135 if (HasOpenConnections()) { 136 base::AutoReset<bool> auto_reset(&waiting_for_dbs_to_close_, true); 137 base::MessageLoop::ScopedNestableTaskAllower allow( 138 base::MessageLoop::current()); 139 base::MessageLoop::current()->Run(); 140 } 141 } 142 143 bool DatabaseConnectionsWrapper::HasOpenConnections() { 144 DCHECK(main_thread_->BelongsToCurrentThread()); 145 base::AutoLock auto_lock(open_connections_lock_); 146 return !open_connections_.IsEmpty(); 147 } 148 149 void DatabaseConnectionsWrapper::AddOpenConnection( 150 const std::string& origin_identifier, 151 const base::string16& database_name) { 152 // We add to the collection immediately on any thread. 153 base::AutoLock auto_lock(open_connections_lock_); 154 open_connections_.AddConnection(origin_identifier, database_name); 155 } 156 157 void DatabaseConnectionsWrapper::RemoveOpenConnection( 158 const std::string& origin_identifier, 159 const base::string16& database_name) { 160 // But only remove from the collection on the main thread 161 // so we can handle the waiting_for_dbs_to_close_ case. 162 if (!main_thread_->BelongsToCurrentThread()) { 163 main_thread_->PostTask( 164 FROM_HERE, 165 base::Bind(&DatabaseConnectionsWrapper::RemoveOpenConnection, this, 166 origin_identifier, database_name)); 167 return; 168 } 169 base::AutoLock auto_lock(open_connections_lock_); 170 open_connections_.RemoveConnection(origin_identifier, database_name); 171 if (waiting_for_dbs_to_close_ && open_connections_.IsEmpty()) 172 base::MessageLoop::current()->Quit(); 173 } 174 175 } // namespace storage 176