Merge IDBTransactionBackendInterface and IDBTransactionBackendImpl
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / leveldb / IDBFactoryBackendLevelDB.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 "IDBFactoryBackendLevelDB.h"
31
32 #include "DOMStringList.h"
33 #include "IDBBackingStoreLevelDB.h"
34 #include "IDBCursorBackend.h"
35 #include "IDBDatabaseBackendImpl.h"
36 #include "IDBDatabaseException.h"
37 #include "IDBTransactionBackend.h"
38 #include "IDBTransactionCoordinator.h"
39 #include "Logging.h"
40 #include "SecurityOrigin.h"
41
42 #if ENABLE(INDEXED_DATABASE) && USE(LEVELDB)
43
44 namespace WebCore {
45
46 template<typename K, typename M>
47 static void cleanWeakMap(HashMap<K, WeakPtr<M> >& map)
48 {
49     HashMap<K, WeakPtr<M> > other;
50     other.swap(map);
51
52     typename HashMap<K, WeakPtr<M> >::const_iterator iter = other.begin();
53     while (iter != other.end()) {
54         if (iter->value.get())
55             map.set(iter->key, iter->value);
56         ++iter;
57     }
58 }
59
60 static String computeFileIdentifier(const SecurityOrigin& securityOrigin)
61 {
62     static const char levelDBFileSuffix[] = "@1";
63     return securityOrigin.databaseIdentifier() + levelDBFileSuffix;
64 }
65
66 static String computeUniqueIdentifier(const String& name, const SecurityOrigin& securityOrigin)
67 {
68     return computeFileIdentifier(securityOrigin) + name;
69 }
70
71 IDBFactoryBackendLevelDB::IDBFactoryBackendLevelDB(const String& databaseDirectory)
72     : m_databaseDirectory(databaseDirectory)
73 {
74 }
75
76 IDBFactoryBackendLevelDB::~IDBFactoryBackendLevelDB()
77 {
78 }
79
80 void IDBFactoryBackendLevelDB::removeIDBDatabaseBackend(const String& uniqueIdentifier)
81 {
82     ASSERT(m_databaseBackendMap.contains(uniqueIdentifier));
83     m_databaseBackendMap.remove(uniqueIdentifier);
84 }
85
86 void IDBFactoryBackendLevelDB::getDatabaseNames(PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<SecurityOrigin> securityOrigin, ScriptExecutionContext*, const String& dataDirectory)
87 {
88     ASSERT(securityOrigin);
89     LOG(StorageAPI, "IDBFactoryBackendLevelDB::getDatabaseNames");
90     RefPtr<IDBBackingStoreLevelDB> backingStore = openBackingStore(*securityOrigin, dataDirectory);
91     if (!backingStore) {
92         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error opening backing store for indexedDB.webkitGetDatabaseNames."));
93         return;
94     }
95
96     RefPtr<DOMStringList> databaseNames = DOMStringList::create();
97
98     Vector<String> foundNames = backingStore->getDatabaseNames();
99     for (Vector<String>::const_iterator it = foundNames.begin(); it != foundNames.end(); ++it)
100         databaseNames->append(*it);
101
102     callbacks->onSuccess(databaseNames.release());
103 }
104
105 void IDBFactoryBackendLevelDB::deleteDatabase(const String& name, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<SecurityOrigin> securityOrigin, ScriptExecutionContext*, const String& dataDirectory)
106 {
107     LOG(StorageAPI, "IDBFactoryBackendLevelDB::deleteDatabase");
108     const String uniqueIdentifier = computeUniqueIdentifier(name, *securityOrigin);
109
110     IDBDatabaseBackendMap::iterator it = m_databaseBackendMap.find(uniqueIdentifier);
111     if (it != m_databaseBackendMap.end()) {
112         // If there are any connections to the database, directly delete the
113         // database.
114         it->value->deleteDatabase(callbacks);
115         return;
116     }
117
118     // FIXME: Everything from now on should be done on another thread.
119     RefPtr<IDBBackingStoreLevelDB> backingStore = openBackingStore(*securityOrigin, dataDirectory);
120     if (!backingStore) {
121         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error opening backing store for indexedDB.deleteDatabase."));
122         return;
123     }
124
125     RefPtr<IDBDatabaseBackendImpl> databaseBackend = IDBDatabaseBackendImpl::create(name, backingStore.get(), this, uniqueIdentifier);
126     if (databaseBackend) {
127         m_databaseBackendMap.set(uniqueIdentifier, databaseBackend.get());
128         databaseBackend->deleteDatabase(callbacks);
129         m_databaseBackendMap.remove(uniqueIdentifier);
130     } else
131         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error creating database backend for indexedDB.deleteDatabase."));
132 }
133
134 PassRefPtr<IDBBackingStoreLevelDB> IDBFactoryBackendLevelDB::openBackingStore(const SecurityOrigin& securityOrigin, const String& dataDirectory)
135 {
136     const String fileIdentifier = computeFileIdentifier(securityOrigin);
137     const bool openInMemory = dataDirectory.isEmpty();
138
139     IDBBackingStoreLevelDBMap::iterator it2 = m_backingStoreMap.find(fileIdentifier);
140     if (it2 != m_backingStoreMap.end() && it2->value.get())
141         return it2->value.get();
142
143     RefPtr<IDBBackingStoreLevelDB> backingStore;
144     if (openInMemory)
145         backingStore = IDBBackingStoreLevelDB::openInMemory(fileIdentifier);
146     else
147         backingStore = IDBBackingStoreLevelDB::open(securityOrigin, dataDirectory, fileIdentifier);
148
149     if (backingStore) {
150         cleanWeakMap(m_backingStoreMap);
151         m_backingStoreMap.set(fileIdentifier, backingStore->createWeakPtr());
152         // If an in-memory database, bind lifetime to this factory instance.
153         if (openInMemory)
154             m_sessionOnlyBackingStores.add(backingStore);
155
156         // All backing stores associated with this factory should be of the same type.
157         ASSERT(m_sessionOnlyBackingStores.isEmpty() || openInMemory);
158
159         return backingStore.release();
160     }
161
162     return 0;
163 }
164
165 void IDBFactoryBackendLevelDB::open(const String& name, uint64_t version, int64_t transactionId, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBDatabaseCallbacks> databaseCallbacks, const SecurityOrigin& openingOrigin, const SecurityOrigin&)
166 {
167     LOG(StorageAPI, "IDBFactoryBackendLevelDB::open");
168     const String uniqueIdentifier = computeUniqueIdentifier(name, openingOrigin);
169
170     RefPtr<IDBDatabaseBackendImpl> databaseBackend;
171     IDBDatabaseBackendMap::iterator it = m_databaseBackendMap.find(uniqueIdentifier);
172     if (it == m_databaseBackendMap.end()) {
173         RefPtr<IDBBackingStoreLevelDB> backingStore = openBackingStore(openingOrigin, m_databaseDirectory);
174         if (!backingStore) {
175             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error opening backing store for indexedDB.open."));
176             return;
177         }
178
179         databaseBackend = IDBDatabaseBackendImpl::create(name, backingStore.get(), this, uniqueIdentifier);
180         if (databaseBackend)
181             m_databaseBackendMap.set(uniqueIdentifier, databaseBackend.get());
182         else {
183             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error creating database backend for indexeddb.open."));
184             return;
185         }
186     } else
187         databaseBackend = it->value;
188
189     databaseBackend->openConnection(callbacks, databaseCallbacks, transactionId, version);
190 }
191
192 PassRefPtr<IDBTransactionBackend> IDBFactoryBackendLevelDB::maybeCreateTransactionBackend(IDBDatabaseBackendInterface* backend, int64_t transactionId, PassRefPtr<IDBDatabaseCallbacks> databaseCallbacks, const Vector<int64_t>& objectStoreIds, IndexedDB::TransactionMode mode)
193 {
194     if (!backend->isIDBDatabaseBackendImpl())
195         return 0;
196
197     return IDBTransactionBackend::create(static_cast<IDBDatabaseBackendImpl*>(backend), transactionId, databaseCallbacks, objectStoreIds, mode);
198 }
199
200 PassRefPtr<IDBCursorBackend> IDBFactoryBackendLevelDB::createCursorBackend(IDBTransactionBackend& transactionBackend, IDBBackingStoreCursorInterface& backingStoreCursor, IndexedDB::CursorType cursorType, IDBDatabaseBackendInterface::TaskType taskType, int64_t objectStoreId)
201 {
202     return IDBCursorBackend::create(&backingStoreCursor, cursorType, taskType, &transactionBackend, objectStoreId);
203 }
204
205
206 } // namespace WebCore
207
208 #endif // ENABLE(INDEXED_DATABASE) && USE(LEVELDB)