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 "webkit/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 webkit_database {
14
DatabaseConnections()15 DatabaseConnections::DatabaseConnections() {
16 }
17
~DatabaseConnections()18 DatabaseConnections::~DatabaseConnections() {
19 DCHECK(connections_.empty());
20 }
21
IsEmpty() const22 bool DatabaseConnections::IsEmpty() const {
23 return connections_.empty();
24 }
25
IsDatabaseOpened(const std::string & origin_identifier,const base::string16 & database_name) const26 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
IsOriginUsed(const std::string & origin_identifier) const37 bool DatabaseConnections::IsOriginUsed(
38 const std::string& origin_identifier) const {
39 return (connections_.find(origin_identifier) != connections_.end());
40 }
41
AddConnection(const std::string & origin_identifier,const base::string16 & database_name)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
RemoveConnection(const std::string & origin_identifier,const base::string16 & database_name)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
RemoveAllConnections()55 void DatabaseConnections::RemoveAllConnections() {
56 connections_.clear();
57 }
58
RemoveConnections(const DatabaseConnections & connections,std::vector<std::pair<std::string,base::string16>> * closed_dbs)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
GetOpenDatabaseSize(const std::string & origin_identifier,const base::string16 & database_name) const76 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
SetOpenDatabaseSize(const std::string & origin_identifier,const base::string16 & database_name,int64 size)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
ListConnections(std::vector<std::pair<std::string,base::string16>> * list) const91 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
RemoveConnectionsHelper(const std::string & origin_identifier,const base::string16 & database_name,int num_connections)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
DatabaseConnectionsWrapper()124 DatabaseConnectionsWrapper::DatabaseConnectionsWrapper()
125 : waiting_for_dbs_to_close_(false),
126 main_thread_(base::MessageLoopProxy::current()) {
127 }
128
~DatabaseConnectionsWrapper()129 DatabaseConnectionsWrapper::~DatabaseConnectionsWrapper() {
130 }
131
WaitForAllDatabasesToClose()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
HasOpenConnections()143 bool DatabaseConnectionsWrapper::HasOpenConnections() {
144 DCHECK(main_thread_->BelongsToCurrentThread());
145 base::AutoLock auto_lock(open_connections_lock_);
146 return !open_connections_.IsEmpty();
147 }
148
AddOpenConnection(const std::string & origin_identifier,const base::string16 & database_name)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
RemoveOpenConnection(const std::string & origin_identifier,const base::string16 & database_name)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 webkit_database
176