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