IndexedDB: Use WeakPtr for Factory-to-BackingStore reference
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / IDBFactoryBackendImpl.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
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "IDBFactoryBackendImpl.h"
31
32 #include "DOMStringList.h"
33 #include "IDBBackingStore.h"
34 #include "IDBDatabaseBackendImpl.h"
35 #include "IDBDatabaseException.h"
36 #include "IDBTransactionCoordinator.h"
37 #include "SecurityOrigin.h"
38 #include <wtf/UnusedParam.h>
39
40 #if ENABLE(INDEXED_DATABASE)
41
42 namespace WebCore {
43
44 template<typename K, typename M>
45 static void cleanWeakMap(HashMap<K, WeakPtr<M> >& map)
46 {
47     HashMap<K, WeakPtr<M> > other;
48     other.swap(map);
49
50     typename HashMap<K, WeakPtr<M> >::const_iterator iter = other.begin();
51     while (iter != other.end()) {
52         if (iter->value.get())
53             map.set(iter->key, iter->value);
54         ++iter;
55     }
56 }
57
58 static String computeFileIdentifier(SecurityOrigin* securityOrigin)
59 {
60     static const char levelDBFileSuffix[] = "@1";
61     return securityOrigin->databaseIdentifier() + levelDBFileSuffix;
62 }
63
64 static String computeUniqueIdentifier(const String& name, SecurityOrigin* securityOrigin)
65 {
66     return computeFileIdentifier(securityOrigin) + name;
67 }
68
69 IDBFactoryBackendImpl::IDBFactoryBackendImpl()
70 {
71 }
72
73 IDBFactoryBackendImpl::~IDBFactoryBackendImpl()
74 {
75 }
76
77 void IDBFactoryBackendImpl::removeIDBDatabaseBackend(const String& uniqueIdentifier)
78 {
79     ASSERT(m_databaseBackendMap.contains(uniqueIdentifier));
80     m_databaseBackendMap.remove(uniqueIdentifier);
81 }
82
83 void IDBFactoryBackendImpl::getDatabaseNames(PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<SecurityOrigin> securityOrigin, ScriptExecutionContext*, const String& dataDirectory)
84 {
85     RefPtr<IDBBackingStore> backingStore = openBackingStore(securityOrigin, dataDirectory);
86     if (!backingStore) {
87         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error opening backing store for indexedDB.webkitGetDatabaseNames."));
88         return;
89     }
90
91     RefPtr<DOMStringList> databaseNames = DOMStringList::create();
92
93     Vector<String> foundNames = backingStore->getDatabaseNames();
94     for (Vector<String>::const_iterator it = foundNames.begin(); it != foundNames.end(); ++it)
95         databaseNames->append(*it);
96
97     callbacks->onSuccess(databaseNames.release());
98 }
99
100 void IDBFactoryBackendImpl::deleteDatabase(const String& name, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<SecurityOrigin> securityOrigin, ScriptExecutionContext*, const String& dataDirectory)
101 {
102     const String uniqueIdentifier = computeUniqueIdentifier(name, securityOrigin.get());
103
104     IDBDatabaseBackendMap::iterator it = m_databaseBackendMap.find(uniqueIdentifier);
105     if (it != m_databaseBackendMap.end()) {
106         // If there are any connections to the database, directly delete the
107         // database.
108         it->value->deleteDatabase(callbacks);
109         return;
110     }
111
112     // FIXME: Everything from now on should be done on another thread.
113     RefPtr<IDBBackingStore> backingStore = openBackingStore(securityOrigin, dataDirectory);
114     if (!backingStore) {
115         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error opening backing store for indexedDB.deleteDatabase."));
116         return;
117     }
118
119     RefPtr<IDBDatabaseBackendImpl> databaseBackend = IDBDatabaseBackendImpl::create(name, backingStore.get(), this, uniqueIdentifier);
120     if (databaseBackend) {
121         m_databaseBackendMap.set(uniqueIdentifier, databaseBackend.get());
122         databaseBackend->deleteDatabase(callbacks);
123         m_databaseBackendMap.remove(uniqueIdentifier);
124     } else
125         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error creating database backend for indexedDB.deleteDatabase."));
126 }
127
128 PassRefPtr<IDBBackingStore> IDBFactoryBackendImpl::openBackingStore(PassRefPtr<SecurityOrigin> securityOrigin, const String& dataDirectory)
129 {
130     const String fileIdentifier = computeFileIdentifier(securityOrigin.get());
131
132     IDBBackingStoreMap::iterator it2 = m_backingStoreMap.find(fileIdentifier);
133     if (it2 != m_backingStoreMap.end()) {
134         if (it2->value.get())
135             return it2->value.get();
136     }
137
138     RefPtr<IDBBackingStore> backingStore = IDBBackingStore::open(securityOrigin.get(), dataDirectory, fileIdentifier);
139     if (backingStore) {
140         cleanWeakMap(m_backingStoreMap);
141         m_backingStoreMap.set(fileIdentifier, backingStore->createWeakPtr());
142         return backingStore.release();
143     }
144
145     return 0;
146 }
147
148 void IDBFactoryBackendImpl::open(const String& name, int64_t version, int64_t transactionId, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBDatabaseCallbacks> databaseCallbacks, PassRefPtr<SecurityOrigin> prpSecurityOrigin, ScriptExecutionContext*, const String& dataDirectory)
149 {
150     RefPtr<SecurityOrigin> securityOrigin = prpSecurityOrigin;
151     const String uniqueIdentifier = computeUniqueIdentifier(name, securityOrigin.get());
152
153     RefPtr<IDBDatabaseBackendImpl> databaseBackend;
154     IDBDatabaseBackendMap::iterator it = m_databaseBackendMap.find(uniqueIdentifier);
155     if (it == m_databaseBackendMap.end()) {
156         RefPtr<IDBBackingStore> backingStore = openBackingStore(securityOrigin, dataDirectory);
157         if (!backingStore) {
158             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error opening backing store for indexedDB.open."));
159             return;
160         }
161
162         databaseBackend = IDBDatabaseBackendImpl::create(name, backingStore.get(), this, uniqueIdentifier);
163         if (databaseBackend)
164             m_databaseBackendMap.set(uniqueIdentifier, databaseBackend.get());
165         else {
166             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error creating database backend for indexeddb.open."));
167             return;
168         }
169     } else
170         databaseBackend = it->value;
171
172     databaseBackend->openConnection(callbacks, databaseCallbacks, transactionId, version);
173 }
174
175 } // namespace WebCore
176
177 #endif // ENABLE(INDEXED_DATABASE)