2 * Copyright (C) 2011 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
30 #include "IDBFactoryBackendLevelDB.h"
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"
40 #include "SecurityOrigin.h"
42 #if ENABLE(INDEXED_DATABASE) && USE(LEVELDB)
46 template<typename K, typename M>
47 static void cleanWeakMap(HashMap<K, WeakPtr<M> >& map)
49 HashMap<K, WeakPtr<M> > other;
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);
60 static String computeFileIdentifier(const SecurityOrigin& securityOrigin)
62 static const char levelDBFileSuffix[] = "@1";
63 return securityOrigin.databaseIdentifier() + levelDBFileSuffix;
66 static String computeUniqueIdentifier(const String& name, const SecurityOrigin& securityOrigin)
68 return computeFileIdentifier(securityOrigin) + name;
71 IDBFactoryBackendLevelDB::IDBFactoryBackendLevelDB(const String& databaseDirectory)
72 : m_databaseDirectory(databaseDirectory)
76 IDBFactoryBackendLevelDB::~IDBFactoryBackendLevelDB()
80 void IDBFactoryBackendLevelDB::removeIDBDatabaseBackend(const String& uniqueIdentifier)
82 ASSERT(m_databaseBackendMap.contains(uniqueIdentifier));
83 m_databaseBackendMap.remove(uniqueIdentifier);
86 void IDBFactoryBackendLevelDB::getDatabaseNames(PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<SecurityOrigin> securityOrigin, ScriptExecutionContext*, const String& dataDirectory)
88 ASSERT(securityOrigin);
89 LOG(StorageAPI, "IDBFactoryBackendLevelDB::getDatabaseNames");
90 RefPtr<IDBBackingStoreLevelDB> backingStore = openBackingStore(*securityOrigin, dataDirectory);
92 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error opening backing store for indexedDB.webkitGetDatabaseNames."));
96 RefPtr<DOMStringList> databaseNames = DOMStringList::create();
98 Vector<String> foundNames = backingStore->getDatabaseNames();
99 for (Vector<String>::const_iterator it = foundNames.begin(); it != foundNames.end(); ++it)
100 databaseNames->append(*it);
102 callbacks->onSuccess(databaseNames.release());
105 void IDBFactoryBackendLevelDB::deleteDatabase(const String& name, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<SecurityOrigin> securityOrigin, ScriptExecutionContext*, const String& dataDirectory)
107 LOG(StorageAPI, "IDBFactoryBackendLevelDB::deleteDatabase");
108 const String uniqueIdentifier = computeUniqueIdentifier(name, *securityOrigin);
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
114 it->value->deleteDatabase(callbacks);
118 // FIXME: Everything from now on should be done on another thread.
119 RefPtr<IDBBackingStoreLevelDB> backingStore = openBackingStore(*securityOrigin, dataDirectory);
121 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error opening backing store for indexedDB.deleteDatabase."));
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);
131 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error creating database backend for indexedDB.deleteDatabase."));
134 PassRefPtr<IDBBackingStoreLevelDB> IDBFactoryBackendLevelDB::openBackingStore(const SecurityOrigin& securityOrigin, const String& dataDirectory)
136 const String fileIdentifier = computeFileIdentifier(securityOrigin);
137 const bool openInMemory = dataDirectory.isEmpty();
139 IDBBackingStoreLevelDBMap::iterator it2 = m_backingStoreMap.find(fileIdentifier);
140 if (it2 != m_backingStoreMap.end() && it2->value.get())
141 return it2->value.get();
143 RefPtr<IDBBackingStoreLevelDB> backingStore;
145 backingStore = IDBBackingStoreLevelDB::openInMemory(fileIdentifier);
147 backingStore = IDBBackingStoreLevelDB::open(securityOrigin, dataDirectory, fileIdentifier);
150 cleanWeakMap(m_backingStoreMap);
151 m_backingStoreMap.set(fileIdentifier, backingStore->createWeakPtr());
152 // If an in-memory database, bind lifetime to this factory instance.
154 m_sessionOnlyBackingStores.add(backingStore);
156 // All backing stores associated with this factory should be of the same type.
157 ASSERT(m_sessionOnlyBackingStores.isEmpty() || openInMemory);
159 return backingStore.release();
165 void IDBFactoryBackendLevelDB::open(const String& name, uint64_t version, int64_t transactionId, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBDatabaseCallbacks> databaseCallbacks, const SecurityOrigin& openingOrigin, const SecurityOrigin&)
167 LOG(StorageAPI, "IDBFactoryBackendLevelDB::open");
168 const String uniqueIdentifier = computeUniqueIdentifier(name, openingOrigin);
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);
175 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error opening backing store for indexedDB.open."));
179 databaseBackend = IDBDatabaseBackendImpl::create(name, backingStore.get(), this, uniqueIdentifier);
181 m_databaseBackendMap.set(uniqueIdentifier, databaseBackend.get());
183 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error creating database backend for indexeddb.open."));
187 databaseBackend = it->value;
189 databaseBackend->openConnection(callbacks, databaseCallbacks, transactionId, version);
192 PassRefPtr<IDBTransactionBackend> IDBFactoryBackendLevelDB::maybeCreateTransactionBackend(IDBDatabaseBackendInterface* backend, int64_t transactionId, PassRefPtr<IDBDatabaseCallbacks> databaseCallbacks, const Vector<int64_t>& objectStoreIds, IndexedDB::TransactionMode mode)
194 if (!backend->isIDBDatabaseBackendImpl())
197 return IDBTransactionBackend::create(static_cast<IDBDatabaseBackendImpl*>(backend), transactionId, databaseCallbacks, objectStoreIds, mode);
200 PassRefPtr<IDBCursorBackend> IDBFactoryBackendLevelDB::createCursorBackend(IDBTransactionBackend& transactionBackend, IDBBackingStoreCursorInterface& backingStoreCursor, IndexedDB::CursorType cursorType, IDBDatabaseBackendInterface::TaskType taskType, int64_t objectStoreId)
202 return IDBCursorBackend::create(&backingStoreCursor, cursorType, taskType, &transactionBackend, objectStoreId);
206 } // namespace WebCore
208 #endif // ENABLE(INDEXED_DATABASE) && USE(LEVELDB)