117fdbeed31d63b64b941803b8eadcd9985ceefc
[WebKit-https.git] / Source / WebCore / Modules / webdatabase / chromium / DatabaseTrackerChromium.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "DatabaseTracker.h"
33
34 #if ENABLE(SQL_DATABASE)
35
36 #include "AbstractDatabase.h"
37 #include "DatabaseObserver.h"
38 #include "QuotaTracker.h"
39 #include "PlatformString.h"
40 #include "ScriptExecutionContext.h"
41 #include "SecurityOrigin.h"
42 #include "SecurityOriginHash.h"
43 #include "SQLiteFileSystem.h"
44 #include <wtf/StdLibExtras.h>
45
46 namespace WebCore {
47
48 DatabaseTracker& DatabaseTracker::tracker()
49 {
50     AtomicallyInitializedStatic(DatabaseTracker&, tracker = *new DatabaseTracker(""));
51     return tracker;
52 }
53
54 DatabaseTracker::DatabaseTracker(const String&)
55 {
56     SQLiteFileSystem::registerSQLiteVFS();
57 }
58
59 bool DatabaseTracker::canEstablishDatabase(ScriptExecutionContext* scriptExecutionContext, const String& name, const String& displayName, unsigned long estimatedSize)
60 {
61     return DatabaseObserver::canEstablishDatabase(scriptExecutionContext, name, displayName, estimatedSize);
62 }
63
64 void DatabaseTracker::setDatabaseDetails(SecurityOrigin*, const String&, const String&, unsigned long)
65 {
66     // Chromium sets the database details when the database is opened
67 }
68
69 String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String& name, bool)
70 {
71     return origin->databaseIdentifier() + "/" + name + "#";
72 }
73
74 void DatabaseTracker::addOpenDatabase(AbstractDatabase* database)
75 {
76     ASSERT(database->scriptExecutionContext()->isContextThread());
77     MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
78     if (!m_openDatabaseMap)
79         m_openDatabaseMap = adoptPtr(new DatabaseOriginMap);
80
81     String originIdentifier = database->securityOrigin()->databaseIdentifier();
82     DatabaseNameMap* nameMap = m_openDatabaseMap->get(originIdentifier);
83     if (!nameMap) {
84         nameMap = new DatabaseNameMap();
85         m_openDatabaseMap->set(originIdentifier, nameMap);
86     }
87
88     String name(database->stringIdentifier());
89     DatabaseSet* databaseSet = nameMap->get(name);
90     if (!databaseSet) {
91         databaseSet = new DatabaseSet();
92         nameMap->set(name, databaseSet);
93     }
94
95     databaseSet->add(database);
96
97     DatabaseObserver::databaseOpened(database);
98 }
99
100 class NotifyDatabaseObserverOnCloseTask : public ScriptExecutionContext::Task {
101 public:
102     static PassOwnPtr<NotifyDatabaseObserverOnCloseTask> create(PassRefPtr<AbstractDatabase> database)
103     {
104         return adoptPtr(new NotifyDatabaseObserverOnCloseTask(database));
105     }
106
107     virtual void performTask(ScriptExecutionContext* context)
108     {
109         DatabaseObserver::databaseClosed(m_database.get());
110     }
111
112     virtual bool isCleanupTask() const
113     {
114         return true;
115     }
116
117 private:
118     NotifyDatabaseObserverOnCloseTask(PassRefPtr<AbstractDatabase> database)
119         : m_database(database)
120     {
121     }
122
123     RefPtr<AbstractDatabase> m_database;
124 };
125
126 void DatabaseTracker::removeOpenDatabase(AbstractDatabase* database)
127 {
128     String originIdentifier = database->securityOrigin()->databaseIdentifier();
129     MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
130     ASSERT(m_openDatabaseMap);
131     DatabaseNameMap* nameMap = m_openDatabaseMap->get(originIdentifier);
132     if (!nameMap)
133         return;
134
135     String name(database->stringIdentifier());
136     DatabaseSet* databaseSet = nameMap->get(name);
137     if (!databaseSet)
138         return;
139
140     DatabaseSet::iterator found = databaseSet->find(database);
141     if (found == databaseSet->end())
142         return;
143
144     databaseSet->remove(found);
145     if (databaseSet->isEmpty()) {
146         nameMap->remove(name);
147         delete databaseSet;
148         if (nameMap->isEmpty()) {
149             m_openDatabaseMap->remove(originIdentifier);
150             delete nameMap;
151         }
152     }
153
154     if (!database->scriptExecutionContext()->isContextThread())
155         database->scriptExecutionContext()->postTask(NotifyDatabaseObserverOnCloseTask::create(database));
156     else
157         DatabaseObserver::databaseClosed(database);
158 }
159
160 unsigned long long DatabaseTracker::getMaxSizeForDatabase(const AbstractDatabase* database)
161 {
162     unsigned long long spaceAvailable = 0;
163     unsigned long long databaseSize = 0;
164     QuotaTracker::instance().getDatabaseSizeAndSpaceAvailableToOrigin(
165         database->securityOrigin()->databaseIdentifier(),
166         database->stringIdentifier(), &databaseSize, &spaceAvailable);
167     return databaseSize + spaceAvailable;
168 }
169
170 void DatabaseTracker::interruptAllDatabasesForContext(const ScriptExecutionContext* context)
171 {
172     MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
173
174     if (!m_openDatabaseMap)
175         return;
176
177     DatabaseNameMap* nameMap = m_openDatabaseMap->get(context->securityOrigin()->databaseIdentifier());
178     if (!nameMap)
179         return;
180
181     DatabaseNameMap::const_iterator dbNameMapEndIt = nameMap->end();
182     for (DatabaseNameMap::const_iterator dbNameMapIt = nameMap->begin(); dbNameMapIt != dbNameMapEndIt; ++dbNameMapIt) {
183         DatabaseSet* databaseSet = dbNameMapIt->second;
184         DatabaseSet::const_iterator end = databaseSet->end();
185         for (DatabaseSet::const_iterator it = databaseSet->begin(); it != end; ++it) {
186             if ((*it)->scriptExecutionContext() == context)
187                 (*it)->interrupt();
188         }
189     }
190 }
191
192 class DatabaseTracker::CloseOneDatabaseImmediatelyTask : public ScriptExecutionContext::Task {
193 public:
194     static PassOwnPtr<CloseOneDatabaseImmediatelyTask> create(const String& originIdentifier, const String& name, AbstractDatabase* database)
195     {
196         return adoptPtr(new CloseOneDatabaseImmediatelyTask(originIdentifier, name, database));
197     }
198
199     virtual void performTask(ScriptExecutionContext* context)
200     {
201         DatabaseTracker::tracker().closeOneDatabaseImmediately(m_originIdentifier, m_name, m_database);
202     }
203
204 private:
205     CloseOneDatabaseImmediatelyTask(const String& originIdentifier, const String& name, AbstractDatabase* database)
206         : m_originIdentifier(originIdentifier.isolatedCopy())
207         , m_name(name.isolatedCopy())
208         , m_database(database)
209     {
210     }
211
212     String m_originIdentifier;
213     String m_name;
214     AbstractDatabase* m_database;  // Intentionally a raw pointer.
215 };
216
217 void DatabaseTracker::closeDatabasesImmediately(const String& originIdentifier, const String& name) {
218     MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
219     if (!m_openDatabaseMap)
220         return;
221
222     DatabaseNameMap* nameMap = m_openDatabaseMap->get(originIdentifier);
223     if (!nameMap)
224         return;
225
226     DatabaseSet* databaseSet = nameMap->get(name);
227     if (!databaseSet)
228         return;
229
230     // We have to call closeImmediately() on the context thread and we cannot safely add a reference to
231     // the database in our collection when not on the context thread (which is always the case given
232     // current usage).
233     for (DatabaseSet::iterator it = databaseSet->begin(); it != databaseSet->end(); ++it)
234         (*it)->scriptExecutionContext()->postTask(CloseOneDatabaseImmediatelyTask::create(originIdentifier, name, *it));
235 }
236
237 void DatabaseTracker::closeOneDatabaseImmediately(const String& originIdentifier, const String& name, AbstractDatabase* database)
238 {
239     // First we have to confirm the 'database' is still in our collection.
240     {
241         MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
242         if (!m_openDatabaseMap)
243             return;
244
245         DatabaseNameMap* nameMap = m_openDatabaseMap->get(originIdentifier);
246         if (!nameMap)
247             return;
248
249         DatabaseSet* databaseSet = nameMap->get(name);
250         if (!databaseSet)
251             return;
252
253         DatabaseSet::iterator found = databaseSet->find(database);
254         if (found == databaseSet->end())
255             return;
256     }
257
258     // And we have to call closeImmediately() without our collection lock being held.
259     database->closeImmediately();
260 }
261
262 }
263
264 #endif // ENABLE(SQL_DATABASE)