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.
5 #include "webkit/database/database_connections.h"
7 #include "base/auto_reset.h"
9 #include "base/logging.h"
10 #include "base/message_loop.h"
11 #include "base/message_loop_proxy.h"
13 namespace webkit_database
{
15 DatabaseConnections::DatabaseConnections() {
18 DatabaseConnections::~DatabaseConnections() {
19 DCHECK(connections_
.empty());
22 bool DatabaseConnections::IsEmpty() const {
23 return connections_
.empty();
26 bool DatabaseConnections::IsDatabaseOpened(
27 const base::string16
& 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())
33 const DBConnections
& origin_connections
= origin_it
->second
;
34 return (origin_connections
.find(database_name
) != origin_connections
.end());
37 bool DatabaseConnections::IsOriginUsed(
38 const base::string16
& origin_identifier
) const {
39 return (connections_
.find(origin_identifier
) != connections_
.end());
42 bool DatabaseConnections::AddConnection(
43 const base::string16
& origin_identifier
,
44 const base::string16
& database_name
) {
45 int& count
= connections_
[origin_identifier
][database_name
].first
;
49 bool DatabaseConnections::RemoveConnection(
50 const base::string16
& origin_identifier
,
51 const base::string16
& database_name
) {
52 return RemoveConnectionsHelper(origin_identifier
, database_name
, 1);
55 void DatabaseConnections::RemoveAllConnections() {
59 void DatabaseConnections::RemoveConnections(
60 const DatabaseConnections
& connections
,
61 std::vector
<std::pair
<base::string16
, base::string16
> >* closed_dbs
) {
62 for (OriginConnections::const_iterator origin_it
=
63 connections
.connections_
.begin();
64 origin_it
!= connections
.connections_
.end();
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
,
71 closed_dbs
->push_back(std::make_pair(origin_it
->first
, db_it
->first
));
76 int64
DatabaseConnections::GetOpenDatabaseSize(
77 const base::string16
& origin_identifier
,
78 const base::string16
& database_name
) const {
79 DCHECK(IsDatabaseOpened(origin_identifier
, database_name
));
80 return connections_
[origin_identifier
][database_name
].second
;
83 void DatabaseConnections::SetOpenDatabaseSize(
84 const base::string16
& origin_identifier
,
85 const base::string16
& database_name
,
87 DCHECK(IsDatabaseOpened(origin_identifier
, database_name
));
88 connections_
[origin_identifier
][database_name
].second
= size
;
91 void DatabaseConnections::ListConnections(
92 std::vector
<std::pair
<base::string16
, base::string16
> > *list
) const {
93 for (OriginConnections::const_iterator origin_it
=
95 origin_it
!= connections_
.end();
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
));
105 bool DatabaseConnections::RemoveConnectionsHelper(
106 const base::string16
& 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
;
118 db_connections
.erase(database_name
);
119 if (db_connections
.empty())
120 connections_
.erase(origin_iterator
);
124 DatabaseConnectionsWrapper::DatabaseConnectionsWrapper()
125 : waiting_for_dbs_to_close_(false),
126 main_thread_(base::MessageLoopProxy::current()) {
129 DatabaseConnectionsWrapper::~DatabaseConnectionsWrapper() {
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();
143 bool DatabaseConnectionsWrapper::HasOpenConnections() {
144 DCHECK(main_thread_
->BelongsToCurrentThread());
145 base::AutoLock
auto_lock(open_connections_lock_
);
146 return !open_connections_
.IsEmpty();
149 void DatabaseConnectionsWrapper::AddOpenConnection(
150 const base::string16
& 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
);
157 void DatabaseConnectionsWrapper::RemoveOpenConnection(
158 const base::string16
& 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(
165 base::Bind(&DatabaseConnectionsWrapper::RemoveOpenConnection
, this,
166 origin_identifier
, database_name
));
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();
175 } // namespace webkit_database