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 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 "IDBDatabaseBackend.h" 36#include "IDBDatabaseException.h" 37#include "IDBServerConnectionLevelDB.h" 38#include "IDBTransactionBackend.h" 39#include "IDBTransactionCoordinator.h" 40#include "Logging.h" 41#include "SecurityOrigin.h" 42 43#if ENABLE(INDEXED_DATABASE) && USE(LEVELDB) 44 45namespace WebCore { 46 47template<typename K, typename M> 48static void cleanWeakMap(HashMap<K, WeakPtr<M> >& map) 49{ 50 HashMap<K, WeakPtr<M> > other; 51 other.swap(map); 52 53 typename HashMap<K, WeakPtr<M> >::const_iterator iter = other.begin(); 54 while (iter != other.end()) { 55 if (iter->value.get()) 56 map.set(iter->key, iter->value); 57 ++iter; 58 } 59} 60 61static String computeFileIdentifier(const SecurityOrigin& securityOrigin) 62{ 63 static const char levelDBFileSuffix[] = "@1"; 64 return securityOrigin.databaseIdentifier() + levelDBFileSuffix; 65} 66 67static String computeUniqueIdentifier(const String& name, const SecurityOrigin& securityOrigin) 68{ 69 return computeFileIdentifier(securityOrigin) + name; 70} 71 72IDBFactoryBackendLevelDB::IDBFactoryBackendLevelDB(const String& databaseDirectory) 73 : m_databaseDirectory(databaseDirectory) 74{ 75} 76 77IDBFactoryBackendLevelDB::~IDBFactoryBackendLevelDB() 78{ 79} 80 81void IDBFactoryBackendLevelDB::removeIDBDatabaseBackend(const String& uniqueIdentifier) 82{ 83 ASSERT(m_databaseBackendMap.contains(uniqueIdentifier)); 84 m_databaseBackendMap.remove(uniqueIdentifier); 85} 86 87void IDBFactoryBackendLevelDB::getDatabaseNames(PassRefPtr<IDBCallbacks> callbacks, const SecurityOrigin& openingOrigin, const SecurityOrigin&, ScriptExecutionContext*, const String& dataDirectory) 88{ 89 LOG(StorageAPI, "IDBFactoryBackendLevelDB::getDatabaseNames"); 90 RefPtr<IDBBackingStoreLevelDB> backingStore = openBackingStore(openingOrigin, 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 105void IDBFactoryBackendLevelDB::deleteDatabase(const String& name, const SecurityOrigin& openingOrigin, const SecurityOrigin&, PassRefPtr<IDBCallbacks> callbacks, ScriptExecutionContext*, const String& dataDirectory) 106{ 107 LOG(StorageAPI, "IDBFactoryBackendLevelDB::deleteDatabase"); 108 const String uniqueIdentifier = computeUniqueIdentifier(name, openingOrigin); 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(openingOrigin, 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<IDBServerConnection> serverConnection = IDBServerConnectionLevelDB::create(name, backingStore.get()); 126 RefPtr<IDBDatabaseBackend> databaseBackend = IDBDatabaseBackend::create(name, uniqueIdentifier, this, *serverConnection); 127 if (databaseBackend) { 128 m_databaseBackendMap.set(uniqueIdentifier, databaseBackend.get()); 129 databaseBackend->deleteDatabase(callbacks); 130 m_databaseBackendMap.remove(uniqueIdentifier); 131 } else 132 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error creating database backend for indexedDB.deleteDatabase.")); 133} 134 135PassRefPtr<IDBBackingStoreLevelDB> IDBFactoryBackendLevelDB::openBackingStore(const SecurityOrigin& securityOrigin, const String& dataDirectory) 136{ 137 const String fileIdentifier = computeFileIdentifier(securityOrigin); 138 const bool openInMemory = dataDirectory.isEmpty(); 139 140 IDBBackingStoreLevelDBMap::iterator it2 = m_backingStoreMap.find(fileIdentifier); 141 if (it2 != m_backingStoreMap.end() && it2->value.get()) 142 return it2->value.get(); 143 144 RefPtr<IDBBackingStoreLevelDB> backingStore; 145 if (openInMemory) 146 backingStore = IDBBackingStoreLevelDB::openInMemory(fileIdentifier); 147 else 148 backingStore = IDBBackingStoreLevelDB::open(securityOrigin, dataDirectory, fileIdentifier); 149 150 if (backingStore) { 151 cleanWeakMap(m_backingStoreMap); 152 m_backingStoreMap.set(fileIdentifier, backingStore->createWeakPtr()); 153 // If an in-memory database, bind lifetime to this factory instance. 154 if (openInMemory) 155 m_sessionOnlyBackingStores.add(backingStore); 156 157 // All backing stores associated with this factory should be of the same type. 158 ASSERT(m_sessionOnlyBackingStores.isEmpty() || openInMemory); 159 160 return backingStore.release(); 161 } 162 163 return 0; 164} 165 166void IDBFactoryBackendLevelDB::open(const String& name, uint64_t version, int64_t transactionId, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBDatabaseCallbacks> databaseCallbacks, const SecurityOrigin& openingOrigin, const SecurityOrigin&) 167{ 168 LOG(StorageAPI, "IDBFactoryBackendLevelDB::open"); 169 const String uniqueIdentifier = computeUniqueIdentifier(name, openingOrigin); 170 171 RefPtr<IDBDatabaseBackend> databaseBackend; 172 IDBDatabaseBackendMap::iterator it = m_databaseBackendMap.find(uniqueIdentifier); 173 if (it == m_databaseBackendMap.end()) { 174 RefPtr<IDBBackingStoreLevelDB> backingStore = openBackingStore(openingOrigin, m_databaseDirectory); 175 if (!backingStore) { 176 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error opening backing store for indexedDB.open.")); 177 return; 178 } 179 180 RefPtr<IDBServerConnection> serverConnection = IDBServerConnectionLevelDB::create(name, backingStore.get()); 181 databaseBackend = IDBDatabaseBackend::create(name, uniqueIdentifier, this, *serverConnection); 182 if (databaseBackend) 183 m_databaseBackendMap.set(uniqueIdentifier, databaseBackend.get()); 184 else { 185 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error creating database backend for indexeddb.open.")); 186 return; 187 } 188 } else 189 databaseBackend = it->value; 190 191 databaseBackend->openConnection(callbacks, databaseCallbacks, transactionId, version); 192} 193 194} // namespace WebCore 195 196#endif // ENABLE(INDEXED_DATABASE) && USE(LEVELDB) 197