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.
14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "IDBLevelDBBackingStore.h"
29 #if ENABLE(INDEXED_DATABASE)
32 #include <wtf/Assertions.h>
33 #include "FileSystem.h"
34 #include "IDBFactoryBackendImpl.h"
35 #include "IDBKeyRange.h"
36 #include "IDBLevelDBCoding.h"
37 #include "LevelDBComparator.h"
38 #include "LevelDBDatabase.h"
39 #include "LevelDBIterator.h"
40 #include "LevelDBSlice.h"
41 #include "LevelDBTransaction.h"
42 #include "SecurityOrigin.h"
46 using namespace IDBLevelDBCoding;
48 template <typename DBOrTransaction>
49 static bool getBool(DBOrTransaction* db, const Vector<char>& key, bool& foundBool)
52 if (!db->get(key, result))
55 foundBool = decodeBool(result.begin(), result.end());
59 template <typename DBOrTransaction>
60 static bool putBool(DBOrTransaction* db, const Vector<char>& key, bool value)
62 return db->put(key, encodeBool(value));
65 template <typename DBOrTransaction>
66 static bool getInt(DBOrTransaction* db, const Vector<char>& key, int64_t& foundInt)
69 if (!db->get(key, result))
72 foundInt = decodeInt(result.begin(), result.end());
76 template <typename DBOrTransaction>
77 static bool putInt(DBOrTransaction* db, const Vector<char>& key, int64_t value)
79 return db->put(key, encodeInt(value));
82 template <typename DBOrTransaction>
83 static bool getString(DBOrTransaction* db, const Vector<char>& key, String& foundString)
86 if (!db->get(key, result))
89 foundString = decodeString(result.begin(), result.end());
93 template <typename DBOrTransaction>
94 static bool putString(DBOrTransaction* db, const Vector<char> key, const String& value)
96 if (!db->put(key, encodeString(value)))
101 static int compareKeys(const LevelDBSlice& a, const LevelDBSlice& b)
103 return compare(a, b);
106 static int compareIndexKeys(const LevelDBSlice& a, const LevelDBSlice& b)
108 return compare(a, b, true);
111 class Comparator : public LevelDBComparator {
113 virtual int compare(const LevelDBSlice& a, const LevelDBSlice& b) const { return IDBLevelDBCoding::compare(a, b); }
114 virtual const char* name() const { return "idb_cmp1"; }
117 static bool setUpMetadata(LevelDBDatabase* db)
119 const Vector<char> metaDataKey = SchemaVersionKey::encode();
121 int64_t schemaVersion = 0;
122 if (!getInt(db, metaDataKey, schemaVersion)) {
124 if (!putInt(db, metaDataKey, schemaVersion))
128 // FIXME: Eventually, we'll need to be able to transition between schemas.
130 return false; // Don't know what to do with this version.
135 IDBLevelDBBackingStore::IDBLevelDBBackingStore(const String& identifier, IDBFactoryBackendImpl* factory, PassOwnPtr<LevelDBDatabase> db)
136 : m_identifier(identifier)
140 m_factory->addIDBBackingStore(identifier, this);
143 IDBLevelDBBackingStore::~IDBLevelDBBackingStore()
145 m_factory->removeIDBBackingStore(m_identifier);
147 // m_db's destructor uses m_comparator. The order of destruction is important.
149 m_comparator.clear();
152 PassRefPtr<IDBBackingStore> IDBLevelDBBackingStore::open(SecurityOrigin* securityOrigin, const String& pathBaseArg, const String& fileIdentifier, IDBFactoryBackendImpl* factory)
154 String pathBase = pathBaseArg;
156 OwnPtr<LevelDBComparator> comparator = adoptPtr(new Comparator());
157 OwnPtr<LevelDBDatabase> db;
159 if (pathBase.isEmpty())
160 db = LevelDBDatabase::openInMemory(comparator.get());
162 if (!makeAllDirectories(pathBase)) {
163 LOG_ERROR("Unable to create IndexedDB database path %s", pathBase.utf8().data());
164 return PassRefPtr<IDBBackingStore>();
166 // FIXME: We should eventually use the same LevelDB database for all origins.
167 String path = pathByAppendingComponent(pathBase, securityOrigin->databaseIdentifier() + ".indexeddb.leveldb");
169 db = LevelDBDatabase::open(path, comparator.get());
172 LOG_ERROR("IndexedDB backing store open failed, attempting cleanup");
173 bool success = LevelDBDatabase::destroy(path);
175 LOG_ERROR("IndexedDB backing store cleanup failed");
176 return PassRefPtr<IDBBackingStore>();
179 LOG_ERROR("IndexedDB backing store cleanup succeeded, reopening");
180 db = LevelDBDatabase::open(path, comparator.get());
182 LOG_ERROR("IndexedDB backing store reopen after recovery failed");
183 return PassRefPtr<IDBBackingStore>();
189 return PassRefPtr<IDBBackingStore>();
191 // FIXME: Handle comparator name changes.
193 RefPtr<IDBLevelDBBackingStore> backingStore(adoptRef(new IDBLevelDBBackingStore(fileIdentifier, factory, db.release())));
194 backingStore->m_comparator = comparator.release();
196 if (!setUpMetadata(backingStore->m_db.get()))
197 return PassRefPtr<IDBBackingStore>();
199 return backingStore.release();
202 void IDBLevelDBBackingStore::getDatabaseNames(Vector<String>& foundNames)
204 const Vector<char> startKey = DatabaseNameKey::encodeMinKeyForOrigin(m_identifier);
205 const Vector<char> stopKey = DatabaseNameKey::encodeStopKeyForOrigin(m_identifier);
207 ASSERT(foundNames.isEmpty());
209 OwnPtr<LevelDBIterator> it = m_db->createIterator();
210 for (it->seek(startKey); it->isValid() && compareKeys(it->key(), stopKey) < 0; it->next()) {
211 const char *p = it->key().begin();
212 const char *limit = it->key().end();
214 DatabaseNameKey databaseNameKey;
215 p = DatabaseNameKey::decode(p, limit, &databaseNameKey);
218 foundNames.append(databaseNameKey.databaseName());
222 bool IDBLevelDBBackingStore::getIDBDatabaseMetaData(const String& name, String& foundVersion, int64_t& foundId)
224 const Vector<char> key = DatabaseNameKey::encode(m_identifier, name);
226 bool ok = getInt(m_db.get(), key, foundId);
230 ok = getString(m_db.get(), DatabaseMetaDataKey::encode(foundId, DatabaseMetaDataKey::kUserVersion), foundVersion);
237 static int64_t getNewDatabaseId(LevelDBDatabase* db)
239 int64_t maxDatabaseId = -1;
240 if (!getInt(db, MaxDatabaseIdKey::encode(), maxDatabaseId))
243 ASSERT(maxDatabaseId >= 0);
245 int64_t databaseId = maxDatabaseId + 1;
246 if (!putInt(db, MaxDatabaseIdKey::encode(), databaseId))
252 bool IDBLevelDBBackingStore::createIDBDatabaseMetaData(const String& name, const String& version, int64_t& rowId)
254 rowId = getNewDatabaseId(m_db.get());
258 const Vector<char> key = DatabaseNameKey::encode(m_identifier, name);
259 if (!putInt(m_db.get(), key, rowId))
261 if (!putString(m_db.get(), DatabaseMetaDataKey::encode(rowId, DatabaseMetaDataKey::kUserVersion), version))
266 bool IDBLevelDBBackingStore::updateIDBDatabaseMetaData(int64_t rowId, const String& version)
268 ASSERT(m_currentTransaction);
269 if (!putString(m_currentTransaction.get(), DatabaseMetaDataKey::encode(rowId, DatabaseMetaDataKey::kUserVersion), version))
275 static bool deleteRange(LevelDBTransaction* transaction, const Vector<char>& begin, const Vector<char>& end)
277 OwnPtr<LevelDBIterator> it = transaction->createIterator();
278 for (it->seek(begin); it->isValid() && compareKeys(it->key(), end) < 0; it->next()) {
279 if (!transaction->remove(it->key()))
287 bool IDBLevelDBBackingStore::deleteDatabase(const String& name)
289 if (m_currentTransaction)
292 RefPtr<IDBLevelDBBackingStore::Transaction> transaction = IDBLevelDBBackingStore::Transaction::create(this);
293 transaction->begin();
297 if (!getIDBDatabaseMetaData(name, version, databaseId)) {
298 transaction->rollback();
302 const Vector<char> startKey = DatabaseMetaDataKey::encode(databaseId, DatabaseMetaDataKey::kOriginName);
303 const Vector<char> stopKey = DatabaseMetaDataKey::encode(databaseId + 1, DatabaseMetaDataKey::kOriginName);
304 if (!deleteRange(m_currentTransaction.get(), startKey, stopKey)) {
305 transaction->rollback();
309 const Vector<char> key = DatabaseNameKey::encode(m_identifier, name);
310 m_currentTransaction->remove(key);
312 return transaction->commit();
315 static bool checkObjectStoreAndMetaDataType(const LevelDBIterator* it, const Vector<char>& stopKey, int64_t objectStoreId, int64_t metaDataType)
317 if (!it->isValid() || compareKeys(it->key(), stopKey) >= 0)
320 ObjectStoreMetaDataKey metaDataKey;
321 const char* p = ObjectStoreMetaDataKey::decode(it->key().begin(), it->key().end(), &metaDataKey);
323 if (metaDataKey.objectStoreId() != objectStoreId)
325 if (metaDataKey.metaDataType() != metaDataType)
330 void IDBLevelDBBackingStore::getObjectStores(int64_t databaseId, Vector<int64_t>& foundIds, Vector<String>& foundNames, Vector<String>& foundKeyPaths, Vector<bool>& foundAutoIncrementFlags)
332 const Vector<char> startKey = ObjectStoreMetaDataKey::encode(databaseId, 1, 0);
333 const Vector<char> stopKey = ObjectStoreMetaDataKey::encodeMaxKey(databaseId);
335 ASSERT(foundIds.isEmpty());
336 ASSERT(foundNames.isEmpty());
337 ASSERT(foundKeyPaths.isEmpty());
338 ASSERT(foundAutoIncrementFlags.isEmpty());
340 OwnPtr<LevelDBIterator> it = m_db->createIterator();
342 while (it->isValid() && compareKeys(it->key(), stopKey) < 0) {
343 const char *p = it->key().begin();
344 const char *limit = it->key().end();
346 ObjectStoreMetaDataKey metaDataKey;
347 p = ObjectStoreMetaDataKey::decode(p, limit, &metaDataKey);
349 if (metaDataKey.metaDataType() != ObjectStoreMetaDataKey::kName) {
350 LOG_ERROR("Internal Indexed DB error.");
351 // Possible stale metadata, but don't fail the load.
356 int64_t objectStoreId = metaDataKey.objectStoreId();
358 // FIXME: Do this by direct key lookup rather than iteration, to simplify.
359 String objectStoreName = decodeString(it->value().begin(), it->value().end());
362 if (!checkObjectStoreAndMetaDataType(it.get(), stopKey, objectStoreId, ObjectStoreMetaDataKey::kKeyPath)) {
363 LOG_ERROR("Internal Indexed DB error.");
366 String keyPath = decodeString(it->value().begin(), it->value().end());
367 bool hasKeyPath = true;
370 if (!checkObjectStoreAndMetaDataType(it.get(), stopKey, objectStoreId, ObjectStoreMetaDataKey::kAutoIncrement)) {
371 LOG_ERROR("Internal Indexed DB error.");
374 bool autoIncrement = decodeBool(it->value().begin(), it->value().end());
376 it->next(); // Is evicatble.
377 if (!checkObjectStoreAndMetaDataType(it.get(), stopKey, objectStoreId, ObjectStoreMetaDataKey::kEvictable)) {
378 LOG_ERROR("Internal Indexed DB error.");
382 it->next(); // Last version.
383 if (!checkObjectStoreAndMetaDataType(it.get(), stopKey, objectStoreId, ObjectStoreMetaDataKey::kLastVersion)) {
384 LOG_ERROR("Internal Indexed DB error.");
388 it->next(); // Maximum index id allocated.
389 if (!checkObjectStoreAndMetaDataType(it.get(), stopKey, objectStoreId, ObjectStoreMetaDataKey::kMaxIndexId)) {
390 LOG_ERROR("Internal Indexed DB error.");
394 it->next(); // [optional] has key path (is not null)
395 if (checkObjectStoreAndMetaDataType(it.get(), stopKey, objectStoreId, ObjectStoreMetaDataKey::kHasKeyPath)) {
396 hasKeyPath = decodeBool(it->value().begin(), it->value().end());
397 if (!hasKeyPath && !keyPath.isEmpty()) {
398 LOG_ERROR("Internal Indexed DB error.");
404 foundIds.append(objectStoreId);
405 foundNames.append(objectStoreName);
406 foundKeyPaths.append(hasKeyPath ? keyPath : String());
407 foundAutoIncrementFlags.append(autoIncrement);
411 static int64_t getNewObjectStoreId(LevelDBTransaction* transaction, int64_t databaseId)
413 int64_t maxObjectStoreId = -1;
414 const Vector<char> maxObjectStoreIdKey = DatabaseMetaDataKey::encode(databaseId, DatabaseMetaDataKey::kMaxObjectStoreId);
415 if (!getInt(transaction, maxObjectStoreIdKey, maxObjectStoreId))
416 maxObjectStoreId = 0;
418 ASSERT(maxObjectStoreId >= 0);
420 int64_t objectStoreId = maxObjectStoreId + 1;
421 if (!putInt(transaction, maxObjectStoreIdKey, objectStoreId))
424 return objectStoreId;
427 bool IDBLevelDBBackingStore::createObjectStore(int64_t databaseId, const String& name, const String& keyPath, bool autoIncrement, int64_t& assignedObjectStoreId)
429 ASSERT(m_currentTransaction);
430 int64_t objectStoreId = getNewObjectStoreId(m_currentTransaction.get(), databaseId);
431 if (objectStoreId < 0)
434 const Vector<char> nameKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, ObjectStoreMetaDataKey::kName);
435 const Vector<char> keyPathKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, ObjectStoreMetaDataKey::kKeyPath);
436 const Vector<char> autoIncrementKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, ObjectStoreMetaDataKey::kAutoIncrement);
437 const Vector<char> evictableKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, ObjectStoreMetaDataKey::kEvictable);
438 const Vector<char> lastVersionKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, ObjectStoreMetaDataKey::kLastVersion);
439 const Vector<char> maxIndexIdKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, ObjectStoreMetaDataKey::kMaxIndexId);
440 const Vector<char> hasKeyPathKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, ObjectStoreMetaDataKey::kHasKeyPath);
441 const Vector<char> namesKey = ObjectStoreNamesKey::encode(databaseId, name);
443 bool ok = putString(m_currentTransaction.get(), nameKey, name);
445 LOG_ERROR("Internal Indexed DB error.");
449 ok = putString(m_currentTransaction.get(), keyPathKey, keyPath);
451 LOG_ERROR("Internal Indexed DB error.");
455 ok = putInt(m_currentTransaction.get(), autoIncrementKey, autoIncrement);
457 LOG_ERROR("Internal Indexed DB error.");
461 ok = putInt(m_currentTransaction.get(), evictableKey, false);
463 LOG_ERROR("Internal Indexed DB error.");
467 ok = putInt(m_currentTransaction.get(), lastVersionKey, 1);
469 LOG_ERROR("Internal Indexed DB error.");
473 ok = putInt(m_currentTransaction.get(), maxIndexIdKey, kMinimumIndexId);
475 LOG_ERROR("Internal Indexed DB error.");
479 ok = putBool(m_currentTransaction.get(), hasKeyPathKey, !keyPath.isNull());
481 LOG_ERROR("Internal Indexed DB error.");
485 ok = putInt(m_currentTransaction.get(), namesKey, objectStoreId);
487 LOG_ERROR("Internal Indexed DB error.");
491 assignedObjectStoreId = objectStoreId;
496 void IDBLevelDBBackingStore::deleteObjectStore(int64_t databaseId, int64_t objectStoreId)
498 ASSERT(m_currentTransaction);
500 String objectStoreName;
501 getString(m_currentTransaction.get(), ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, ObjectStoreMetaDataKey::kName), objectStoreName);
503 if (!deleteRange(m_currentTransaction.get(), ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, 0), ObjectStoreMetaDataKey::encodeMaxKey(databaseId, objectStoreId)))
504 return; // FIXME: Report error.
506 m_currentTransaction->remove(ObjectStoreNamesKey::encode(databaseId, objectStoreName));
508 if (!deleteRange(m_currentTransaction.get(), IndexFreeListKey::encode(databaseId, objectStoreId, 0), IndexFreeListKey::encodeMaxKey(databaseId, objectStoreId)))
509 return; // FIXME: Report error.
510 if (!deleteRange(m_currentTransaction.get(), IndexMetaDataKey::encode(databaseId, objectStoreId, 0, 0), IndexMetaDataKey::encodeMaxKey(databaseId, objectStoreId)))
511 return; // FIXME: Report error.
513 clearObjectStore(databaseId, objectStoreId);
516 String IDBLevelDBBackingStore::getObjectStoreRecord(int64_t databaseId, int64_t objectStoreId, const IDBKey& key)
518 const Vector<char> leveldbKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, key);
521 ASSERT(m_currentTransaction);
522 if (!m_currentTransaction->get(leveldbKey, data))
526 const char* p = decodeVarInt(data.begin(), data.end(), version);
531 return decodeString(p, data.end());
535 class LevelDBRecordIdentifier : public IDBBackingStore::ObjectStoreRecordIdentifier {
537 static PassRefPtr<LevelDBRecordIdentifier> create(const Vector<char>& primaryKey, int64_t version) { return adoptRef(new LevelDBRecordIdentifier(primaryKey, version)); }
538 static PassRefPtr<LevelDBRecordIdentifier> create() { return adoptRef(new LevelDBRecordIdentifier()); }
540 virtual bool isValid() const { return m_primaryKey.isEmpty(); }
541 Vector<char> primaryKey() const { return m_primaryKey; }
542 void setPrimaryKey(const Vector<char>& primaryKey) { m_primaryKey = primaryKey; }
543 int64_t version() const { return m_version; }
544 void setVersion(int64_t version) { m_version = version; }
547 LevelDBRecordIdentifier(const Vector<char>& primaryKey, int64_t version) : m_primaryKey(primaryKey), m_version(version) { ASSERT(!primaryKey.isEmpty()); }
548 LevelDBRecordIdentifier() : m_primaryKey(), m_version(-1) {}
550 Vector<char> m_primaryKey; // FIXME: Make it more clear that this is the *encoded* version of the key.
555 static int64_t getNewVersionNumber(LevelDBTransaction* transaction, int64_t databaseId, int64_t objectStoreId)
557 const Vector<char> lastVersionKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, ObjectStoreMetaDataKey::kLastVersion);
559 int64_t lastVersion = -1;
560 if (!getInt(transaction, lastVersionKey, lastVersion))
563 ASSERT(lastVersion >= 0);
565 int64_t version = lastVersion + 1;
566 bool ok = putInt(transaction, lastVersionKey, version);
567 ASSERT_UNUSED(ok, ok);
569 ASSERT(version > lastVersion); // FIXME: Think about how we want to handle the overflow scenario.
574 bool IDBLevelDBBackingStore::putObjectStoreRecord(int64_t databaseId, int64_t objectStoreId, const IDBKey& key, const String& value, ObjectStoreRecordIdentifier* recordIdentifier)
576 ASSERT(m_currentTransaction);
577 int64_t version = getNewVersionNumber(m_currentTransaction.get(), databaseId, objectStoreId);
578 const Vector<char> objectStoredataKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, key);
581 v.append(encodeVarInt(version));
582 v.append(encodeString(value));
584 if (!m_currentTransaction->put(objectStoredataKey, v))
587 const Vector<char> existsEntryKey = ExistsEntryKey::encode(databaseId, objectStoreId, key);
588 if (!m_currentTransaction->put(existsEntryKey, encodeInt(version)))
591 LevelDBRecordIdentifier* levelDBRecordIdentifier = static_cast<LevelDBRecordIdentifier*>(recordIdentifier);
592 levelDBRecordIdentifier->setPrimaryKey(encodeIDBKey(key));
593 levelDBRecordIdentifier->setVersion(version);
597 void IDBLevelDBBackingStore::clearObjectStore(int64_t databaseId, int64_t objectStoreId)
599 ASSERT(m_currentTransaction);
600 const Vector<char> startKey = KeyPrefix(databaseId, objectStoreId, 0).encode();
601 const Vector<char> stopKey = KeyPrefix(databaseId, objectStoreId + 1, 0).encode();
603 deleteRange(m_currentTransaction.get(), startKey, stopKey);
606 PassRefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> IDBLevelDBBackingStore::createInvalidRecordIdentifier()
608 return LevelDBRecordIdentifier::create();
611 void IDBLevelDBBackingStore::deleteObjectStoreRecord(int64_t databaseId, int64_t objectStoreId, const ObjectStoreRecordIdentifier* recordIdentifier)
613 ASSERT(m_currentTransaction);
614 const LevelDBRecordIdentifier* levelDBRecordIdentifier = static_cast<const LevelDBRecordIdentifier*>(recordIdentifier);
616 const Vector<char> objectStoreDataKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, levelDBRecordIdentifier->primaryKey());
617 m_currentTransaction->remove(objectStoreDataKey);
619 const Vector<char> existsEntryKey = ExistsEntryKey::encode(databaseId, objectStoreId, levelDBRecordIdentifier->primaryKey());
620 m_currentTransaction->remove(existsEntryKey);
623 int64_t IDBLevelDBBackingStore::nextAutoIncrementNumber(int64_t databaseId, int64_t objectStoreId)
625 ASSERT(m_currentTransaction);
626 const Vector<char> startKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, minIDBKey());
627 const Vector<char> stopKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, maxIDBKey());
629 OwnPtr<LevelDBIterator> it = m_currentTransaction->createIterator();
631 int64_t maxNumericKey = 0;
633 // FIXME: This does a forward scan over all keys. Improve it.
634 // Since all dates > all numbers, create Date(-Infinity) and seek backwards.
636 for (it->seek(startKey); it->isValid() && compareKeys(it->key(), stopKey) < 0; it->next()) {
637 const char *p = it->key().begin();
638 const char *limit = it->key().end();
640 ObjectStoreDataKey dataKey;
641 p = ObjectStoreDataKey::decode(p, limit, &dataKey);
644 if (dataKey.userKey()->type() == IDBKey::NumberType) {
645 int64_t n = static_cast<int64_t>(dataKey.userKey()->number());
646 if (n > maxNumericKey)
651 return maxNumericKey + 1;
654 bool IDBLevelDBBackingStore::keyExistsInObjectStore(int64_t databaseId, int64_t objectStoreId, const IDBKey& key, ObjectStoreRecordIdentifier* foundRecordIdentifier)
656 ASSERT(m_currentTransaction);
657 const Vector<char> leveldbKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, key);
660 if (!m_currentTransaction->get(leveldbKey, data))
664 if (!decodeVarInt(data.begin(), data.end(), version))
667 LevelDBRecordIdentifier* levelDBRecordIdentifier = static_cast<LevelDBRecordIdentifier*>(foundRecordIdentifier);
668 levelDBRecordIdentifier->setPrimaryKey(encodeIDBKey(key));
669 levelDBRecordIdentifier->setVersion(version);
673 bool IDBLevelDBBackingStore::forEachObjectStoreRecord(int64_t databaseId, int64_t objectStoreId, ObjectStoreRecordCallback& callback)
675 ASSERT(m_currentTransaction);
676 const Vector<char> startKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, minIDBKey());
677 const Vector<char> stopKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, maxIDBKey());
679 OwnPtr<LevelDBIterator> it = m_currentTransaction->createIterator();
680 for (it->seek(startKey); it->isValid() && compareKeys(it->key(), stopKey) < 0; it->next()) {
681 const char *p = it->key().begin();
682 const char *limit = it->key().end();
683 ObjectStoreDataKey dataKey;
684 p = ObjectStoreDataKey::decode(p, limit, &dataKey);
687 RefPtr<IDBKey> primaryKey = dataKey.userKey();
690 const char* q = decodeVarInt(it->value().begin(), it->value().end(), version);
694 RefPtr<LevelDBRecordIdentifier> ri = LevelDBRecordIdentifier::create(encodeIDBKey(*primaryKey), version);
695 String idbValue = decodeString(q, it->value().end());
697 if (!callback.callback(ri.get(), idbValue))
704 static bool checkIndexAndMetaDataKey(const LevelDBIterator* it, const Vector<char>& stopKey, int64_t indexId, unsigned char metaDataType)
706 if (!it->isValid() || compareKeys(it->key(), stopKey) >= 0)
709 IndexMetaDataKey metaDataKey;
710 const char* p = IndexMetaDataKey::decode(it->key().begin(), it->key().end(), &metaDataKey);
712 if (metaDataKey.indexId() != indexId)
714 if (metaDataKey.metaDataType() != metaDataType)
720 void IDBLevelDBBackingStore::getIndexes(int64_t databaseId, int64_t objectStoreId, Vector<int64_t>& foundIds, Vector<String>& foundNames, Vector<String>& foundKeyPaths, Vector<bool>& foundUniqueFlags, Vector<bool>& foundMultiEntryFlags)
722 const Vector<char> startKey = IndexMetaDataKey::encode(databaseId, objectStoreId, 0, 0);
723 const Vector<char> stopKey = IndexMetaDataKey::encode(databaseId, objectStoreId + 1, 0, 0);
725 ASSERT(foundIds.isEmpty());
726 ASSERT(foundNames.isEmpty());
727 ASSERT(foundKeyPaths.isEmpty());
728 ASSERT(foundUniqueFlags.isEmpty());
729 ASSERT(foundMultiEntryFlags.isEmpty());
731 OwnPtr<LevelDBIterator> it = m_db->createIterator();
733 while (it->isValid() && compareKeys(it->key(), stopKey) < 0) {
734 const char* p = it->key().begin();
735 const char* limit = it->key().end();
737 IndexMetaDataKey metaDataKey;
738 p = IndexMetaDataKey::decode(p, limit, &metaDataKey);
740 if (metaDataKey.metaDataType() != IndexMetaDataKey::kName) {
741 LOG_ERROR("Internal Indexed DB error.");
742 // Possible stale metadata due to http://webkit.org/b/85557 but don't fail the load.
747 // FIXME: Do this by direct key lookup rather than iteration, to simplify.
748 int64_t indexId = metaDataKey.indexId();
749 String indexName = decodeString(it->value().begin(), it->value().end());
751 it->next(); // unique flag
752 if (!checkIndexAndMetaDataKey(it.get(), stopKey, indexId, IndexMetaDataKey::kUnique)) {
753 LOG_ERROR("Internal Indexed DB error.");
756 bool indexUnique = decodeBool(it->value().begin(), it->value().end());
758 it->next(); // keyPath
759 if (!checkIndexAndMetaDataKey(it.get(), stopKey, indexId, IndexMetaDataKey::kKeyPath)) {
760 LOG_ERROR("Internal Indexed DB error.");
763 String keyPath = decodeString(it->value().begin(), it->value().end());
765 it->next(); // [optional] multiEntry flag
766 bool indexMultiEntry = false;
767 if (checkIndexAndMetaDataKey(it.get(), stopKey, indexId, IndexMetaDataKey::kMultiEntry)) {
768 indexMultiEntry = decodeBool(it->value().begin(), it->value().end());
772 foundIds.append(indexId);
773 foundNames.append(indexName);
774 foundKeyPaths.append(keyPath);
775 foundUniqueFlags.append(indexUnique);
776 foundMultiEntryFlags.append(indexMultiEntry);
780 static int64_t getNewIndexId(LevelDBTransaction* transaction, int64_t databaseId, int64_t objectStoreId)
782 int64_t maxIndexId = -1;
783 const Vector<char> maxIndexIdKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, ObjectStoreMetaDataKey::kMaxIndexId);
784 if (!getInt(transaction, maxIndexIdKey, maxIndexId))
785 maxIndexId = kMinimumIndexId;
787 ASSERT(maxIndexId >= 0);
789 int64_t indexId = maxIndexId + 1;
790 if (!putInt(transaction, maxIndexIdKey, indexId))
796 bool IDBLevelDBBackingStore::createIndex(int64_t databaseId, int64_t objectStoreId, const String& name, const String& keyPath, bool isUnique, bool isMultiEntry, int64_t& indexId)
798 ASSERT(m_currentTransaction);
799 indexId = getNewIndexId(m_currentTransaction.get(), databaseId, objectStoreId);
803 const Vector<char> nameKey = IndexMetaDataKey::encode(databaseId, objectStoreId, indexId, IndexMetaDataKey::kName);
804 const Vector<char> uniqueKey = IndexMetaDataKey::encode(databaseId, objectStoreId, indexId, IndexMetaDataKey::kUnique);
805 const Vector<char> keyPathKey = IndexMetaDataKey::encode(databaseId, objectStoreId, indexId, IndexMetaDataKey::kKeyPath);
806 const Vector<char> multiEntryKey = IndexMetaDataKey::encode(databaseId, objectStoreId, indexId, IndexMetaDataKey::kMultiEntry);
808 bool ok = putString(m_currentTransaction.get(), nameKey, name);
810 LOG_ERROR("Internal Indexed DB error.");
814 ok = putBool(m_currentTransaction.get(), uniqueKey, isUnique);
816 LOG_ERROR("Internal Indexed DB error.");
820 ok = putString(m_currentTransaction.get(), keyPathKey, keyPath);
822 LOG_ERROR("Internal Indexed DB error.");
826 ok = putBool(m_currentTransaction.get(), multiEntryKey, isMultiEntry);
828 LOG_ERROR("Internal Indexed DB error.");
835 void IDBLevelDBBackingStore::deleteIndex(int64_t databaseId, int64_t objectStoreId, int64_t indexId)
837 ASSERT(m_currentTransaction);
839 const Vector<char> indexMetaDataStart = IndexMetaDataKey::encode(databaseId, objectStoreId, indexId, 0);
840 const Vector<char> indexMetaDataEnd = IndexMetaDataKey::encodeMaxKey(databaseId, objectStoreId, indexId);
842 if (!deleteRange(m_currentTransaction.get(), indexMetaDataStart, indexMetaDataEnd)) {
843 LOG_ERROR("Internal Indexed DB error.");
847 const Vector<char> indexDataStart = IndexDataKey::encodeMinKey(databaseId, objectStoreId, indexId);
848 const Vector<char> indexDataEnd = IndexDataKey::encodeMaxKey(databaseId, objectStoreId, indexId);
850 if (!deleteRange(m_currentTransaction.get(), indexDataStart, indexDataEnd)) {
851 LOG_ERROR("Internal Indexed DB error.");
856 bool IDBLevelDBBackingStore::putIndexDataForRecord(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey& key, const ObjectStoreRecordIdentifier* recordIdentifier)
858 ASSERT(indexId >= kMinimumIndexId);
859 const LevelDBRecordIdentifier* levelDBRecordIdentifier = static_cast<const LevelDBRecordIdentifier*>(recordIdentifier);
861 ASSERT(m_currentTransaction);
862 const Vector<char> indexDataKey = IndexDataKey::encode(databaseId, objectStoreId, indexId, encodeIDBKey(key), levelDBRecordIdentifier->primaryKey());
865 data.append(encodeVarInt(levelDBRecordIdentifier->version()));
866 data.append(levelDBRecordIdentifier->primaryKey());
868 return m_currentTransaction->put(indexDataKey, data);
871 static bool findGreatestKeyLessThanOrEqual(LevelDBTransaction* transaction, const Vector<char>& target, Vector<char>& foundKey)
873 OwnPtr<LevelDBIterator> it = transaction->createIterator();
876 if (!it->isValid()) {
882 while (compareIndexKeys(it->key(), target) > 0) {
890 foundKey.append(it->key().begin(), it->key().end() - it->key().begin());
892 // There can be several index keys that compare equal. We want the last one.
894 } while (it->isValid() && !compareIndexKeys(it->key(), target));
899 bool IDBLevelDBBackingStore::deleteIndexDataForRecord(int64_t, int64_t, int64_t, const ObjectStoreRecordIdentifier*)
901 // FIXME: This isn't needed since we invalidate index data via the version number mechanism.
905 String IDBLevelDBBackingStore::getObjectViaIndex(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey& key)
907 RefPtr<IDBKey> primaryKey = getPrimaryKeyViaIndex(databaseId, objectStoreId, indexId, key);
911 return getObjectStoreRecord(databaseId, objectStoreId, *primaryKey);
914 static bool versionExists(LevelDBTransaction* transaction, int64_t databaseId, int64_t objectStoreId, int64_t version, const Vector<char>& encodedPrimaryKey)
916 const Vector<char> key = ExistsEntryKey::encode(databaseId, objectStoreId, encodedPrimaryKey);
919 if (!transaction->get(key, data))
922 return decodeInt(data.begin(), data.end()) == version;
925 static bool findKeyInIndex(LevelDBTransaction* transaction, int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey& key, Vector<char>& foundEncodedPrimaryKey)
927 ASSERT(foundEncodedPrimaryKey.isEmpty());
929 const Vector<char> leveldbKey = IndexDataKey::encode(databaseId, objectStoreId, indexId, key);
930 OwnPtr<LevelDBIterator> it = transaction->createIterator();
931 it->seek(leveldbKey);
936 if (compareIndexKeys(it->key(), leveldbKey) > 0)
940 const char* p = decodeVarInt(it->value().begin(), it->value().end(), version);
943 foundEncodedPrimaryKey.append(p, it->value().end() - p);
945 if (!versionExists(transaction, databaseId, objectStoreId, version, foundEncodedPrimaryKey)) {
946 // Delete stale index data entry and continue.
947 transaction->remove(it->key());
956 PassRefPtr<IDBKey> IDBLevelDBBackingStore::getPrimaryKeyViaIndex(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey& key)
958 ASSERT(m_currentTransaction);
960 Vector<char> foundEncodedPrimaryKey;
961 if (findKeyInIndex(m_currentTransaction.get(), databaseId, objectStoreId, indexId, key, foundEncodedPrimaryKey)) {
962 RefPtr<IDBKey> primaryKey;
963 decodeIDBKey(foundEncodedPrimaryKey.begin(), foundEncodedPrimaryKey.end(), primaryKey);
964 return primaryKey.release();
970 bool IDBLevelDBBackingStore::keyExistsInIndex(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey& indexKey, RefPtr<IDBKey>& foundPrimaryKey)
972 ASSERT(m_currentTransaction);
974 Vector<char> foundEncodedPrimaryKey;
975 if (!findKeyInIndex(m_currentTransaction.get(), databaseId, objectStoreId, indexId, indexKey, foundEncodedPrimaryKey))
978 decodeIDBKey(foundEncodedPrimaryKey.begin(), foundEncodedPrimaryKey.end(), foundPrimaryKey);
984 struct CursorOptions {
987 Vector<char> highKey;
993 class CursorImplCommon : public IDBBackingStore::Cursor {
995 // IDBBackingStore::Cursor
996 virtual bool advance(unsigned long);
997 virtual bool continueFunction(const IDBKey* = 0, IteratorState = Seek);
998 virtual PassRefPtr<IDBKey> key() { return m_currentKey; }
999 virtual PassRefPtr<IDBKey> primaryKey() { return m_currentKey; }
1000 virtual String value() = 0;
1001 virtual PassRefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> objectStoreRecordIdentifier() = 0;
1002 virtual int64_t indexDataId() = 0;
1003 virtual void close() { }
1005 virtual bool loadCurrentRow() = 0;
1009 CursorImplCommon(LevelDBTransaction* transaction, const CursorOptions& cursorOptions)
1010 : m_transaction(transaction)
1011 , m_cursorOptions(cursorOptions)
1015 CursorImplCommon(const CursorImplCommon* other)
1016 : m_transaction(other->m_transaction)
1017 , m_cursorOptions(other->m_cursorOptions)
1018 , m_currentKey(other->m_currentKey)
1020 if (other->m_iterator) {
1021 m_iterator = m_transaction->createIterator();
1023 if (other->m_iterator->isValid()) {
1024 m_iterator->seek(other->m_iterator->key());
1025 ASSERT(m_iterator->isValid());
1030 virtual ~CursorImplCommon() {}
1032 bool isPastBounds() const;
1033 bool haveEnteredRange() const;
1035 LevelDBTransaction* m_transaction;
1036 CursorOptions m_cursorOptions;
1037 OwnPtr<LevelDBIterator> m_iterator;
1038 RefPtr<IDBKey> m_currentKey;
1041 bool CursorImplCommon::firstSeek()
1043 m_iterator = m_transaction->createIterator();
1044 if (m_cursorOptions.forward)
1045 m_iterator->seek(m_cursorOptions.lowKey);
1047 m_iterator->seek(m_cursorOptions.highKey);
1049 return continueFunction(0, Ready);
1052 bool CursorImplCommon::advance(unsigned long count)
1055 if (!continueFunction())
1061 bool CursorImplCommon::continueFunction(const IDBKey* key, IteratorState nextState)
1063 RefPtr<IDBKey> previousKey = m_currentKey;
1065 // When iterating with PREV_NO_DUPLICATE, spec requires that the
1066 // value we yield for each key is the first duplicate in forwards
1068 RefPtr<IDBKey> lastDuplicateKey;
1070 bool forward = m_cursorOptions.forward;
1073 if (nextState == Seek) {
1079 nextState = Seek; // for subsequent iterations
1081 if (!m_iterator->isValid()) {
1082 if (!forward && lastDuplicateKey.get()) {
1083 // We need to walk forward because we hit the end of
1092 if (isPastBounds()) {
1093 if (!forward && lastDuplicateKey.get()) {
1094 // We need to walk forward because now we're beyond the
1095 // bounds defined by the cursor.
1103 if (!haveEnteredRange())
1106 // The row may not load because there's a stale entry in the
1107 // index. This is not fatal.
1108 if (!loadCurrentRow())
1113 if (m_currentKey->isLessThan(key))
1116 if (key->isLessThan(m_currentKey.get()))
1121 if (m_cursorOptions.unique) {
1123 if (m_currentKey->isEqual(previousKey.get())) {
1124 // We should never be able to walk forward all the way
1125 // to the previous key.
1126 ASSERT(!lastDuplicateKey.get());
1131 if (!lastDuplicateKey.get()) {
1132 lastDuplicateKey = m_currentKey;
1136 // We need to walk forward because we hit the boundary
1137 // between key ranges.
1138 if (!lastDuplicateKey->isEqual(m_currentKey.get())) {
1149 ASSERT(!lastDuplicateKey.get() || (forward && lastDuplicateKey->isEqual(m_currentKey.get())));
1153 bool CursorImplCommon::haveEnteredRange() const
1155 if (m_cursorOptions.forward) {
1156 if (m_cursorOptions.lowOpen)
1157 return compareIndexKeys(m_iterator->key(), m_cursorOptions.lowKey) > 0;
1159 return compareIndexKeys(m_iterator->key(), m_cursorOptions.lowKey) >= 0;
1161 if (m_cursorOptions.highOpen)
1162 return compareIndexKeys(m_iterator->key(), m_cursorOptions.highKey) < 0;
1164 return compareIndexKeys(m_iterator->key(), m_cursorOptions.highKey) <= 0;
1167 bool CursorImplCommon::isPastBounds() const
1169 if (m_cursorOptions.forward) {
1170 if (m_cursorOptions.highOpen)
1171 return compareIndexKeys(m_iterator->key(), m_cursorOptions.highKey) >= 0;
1172 return compareIndexKeys(m_iterator->key(), m_cursorOptions.highKey) > 0;
1175 if (m_cursorOptions.lowOpen)
1176 return compareIndexKeys(m_iterator->key(), m_cursorOptions.lowKey) <= 0;
1177 return compareIndexKeys(m_iterator->key(), m_cursorOptions.lowKey) < 0;
1180 class ObjectStoreCursorImpl : public CursorImplCommon {
1182 static PassRefPtr<ObjectStoreCursorImpl> create(LevelDBTransaction* transaction, const CursorOptions& cursorOptions)
1184 return adoptRef(new ObjectStoreCursorImpl(transaction, cursorOptions));
1187 virtual PassRefPtr<IDBBackingStore::Cursor> clone()
1189 return adoptRef(new ObjectStoreCursorImpl(this));
1193 virtual String value() { return m_currentValue; }
1194 virtual PassRefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> objectStoreRecordIdentifier() OVERRIDE
1196 return m_identifier;
1198 virtual int64_t indexDataId() { ASSERT_NOT_REACHED(); return 0; }
1199 virtual bool loadCurrentRow();
1202 ObjectStoreCursorImpl(LevelDBTransaction* transaction, const CursorOptions& cursorOptions)
1203 : CursorImplCommon(transaction, cursorOptions)
1207 ObjectStoreCursorImpl(const ObjectStoreCursorImpl* other)
1208 : CursorImplCommon(other)
1209 , m_currentValue(other->m_currentValue)
1213 String m_currentValue;
1214 RefPtr<LevelDBRecordIdentifier> m_identifier;
1217 bool ObjectStoreCursorImpl::loadCurrentRow()
1219 const char* p = m_iterator->key().begin();
1220 const char* keyLimit = m_iterator->key().end();
1222 ObjectStoreDataKey objectStoreDataKey;
1223 p = ObjectStoreDataKey::decode(p, keyLimit, &objectStoreDataKey);
1228 m_currentKey = objectStoreDataKey.userKey();
1231 const char* q = decodeVarInt(m_iterator->value().begin(), m_iterator->value().end(), version);
1236 // FIXME: This re-encodes what was just decoded; try and optimize.
1237 m_identifier = LevelDBRecordIdentifier::create(encodeIDBKey(*m_currentKey), version);
1239 m_currentValue = decodeString(q, m_iterator->value().end());
1244 class IndexKeyCursorImpl : public CursorImplCommon {
1246 static PassRefPtr<IndexKeyCursorImpl> create(LevelDBTransaction* transaction, const CursorOptions& cursorOptions)
1248 return adoptRef(new IndexKeyCursorImpl(transaction, cursorOptions));
1251 virtual PassRefPtr<IDBBackingStore::Cursor> clone()
1253 return adoptRef(new IndexKeyCursorImpl(this));
1257 virtual String value() { ASSERT_NOT_REACHED(); return String(); }
1258 virtual PassRefPtr<IDBKey> primaryKey() { return m_primaryKey; }
1259 virtual PassRefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> objectStoreRecordIdentifier() { ASSERT_NOT_REACHED(); return 0; }
1260 virtual int64_t indexDataId() { ASSERT_NOT_REACHED(); return 0; }
1261 virtual bool loadCurrentRow();
1264 IndexKeyCursorImpl(LevelDBTransaction* transaction, const CursorOptions& cursorOptions)
1265 : CursorImplCommon(transaction, cursorOptions)
1269 IndexKeyCursorImpl(const IndexKeyCursorImpl* other)
1270 : CursorImplCommon(other)
1271 , m_primaryKey(other->m_primaryKey)
1275 RefPtr<IDBKey> m_primaryKey;
1278 bool IndexKeyCursorImpl::loadCurrentRow()
1280 const char* p = m_iterator->key().begin();
1281 const char* keyLimit = m_iterator->key().end();
1282 IndexDataKey indexDataKey;
1283 p = IndexDataKey::decode(p, keyLimit, &indexDataKey);
1285 m_currentKey = indexDataKey.userKey();
1287 int64_t indexDataVersion;
1288 const char* q = decodeVarInt(m_iterator->value().begin(), m_iterator->value().end(), indexDataVersion);
1293 q = decodeIDBKey(q, m_iterator->value().end(), m_primaryKey);
1298 Vector<char> primaryLevelDBKey = ObjectStoreDataKey::encode(indexDataKey.databaseId(), indexDataKey.objectStoreId(), *m_primaryKey);
1300 Vector<char> result;
1301 if (!m_transaction->get(primaryLevelDBKey, result)) {
1302 m_transaction->remove(m_iterator->key());
1306 int64_t objectStoreDataVersion;
1307 const char* t = decodeVarInt(result.begin(), result.end(), objectStoreDataVersion);
1312 if (objectStoreDataVersion != indexDataVersion) {
1313 m_transaction->remove(m_iterator->key());
1320 class IndexCursorImpl : public CursorImplCommon {
1322 static PassRefPtr<IndexCursorImpl> create(LevelDBTransaction* transaction, const CursorOptions& cursorOptions)
1324 return adoptRef(new IndexCursorImpl(transaction, cursorOptions));
1327 virtual PassRefPtr<IDBBackingStore::Cursor> clone()
1329 return adoptRef(new IndexCursorImpl(this));
1333 virtual String value() { return m_value; }
1334 virtual PassRefPtr<IDBKey> primaryKey() { return m_primaryKey; }
1335 virtual PassRefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> objectStoreRecordIdentifier() { ASSERT_NOT_REACHED(); return 0; }
1336 virtual int64_t indexDataId() { ASSERT_NOT_REACHED(); return 0; }
1337 bool loadCurrentRow();
1340 IndexCursorImpl(LevelDBTransaction* transaction, const CursorOptions& cursorOptions)
1341 : CursorImplCommon(transaction, cursorOptions)
1345 IndexCursorImpl(const IndexCursorImpl* other)
1346 : CursorImplCommon(other)
1347 , m_primaryKey(other->m_primaryKey)
1348 , m_value(other->m_value)
1349 , m_primaryLevelDBKey(other->m_primaryLevelDBKey)
1353 RefPtr<IDBKey> m_primaryKey;
1355 Vector<char> m_primaryLevelDBKey;
1358 bool IndexCursorImpl::loadCurrentRow()
1360 const char *p = m_iterator->key().begin();
1361 const char *limit = m_iterator->key().end();
1363 IndexDataKey indexDataKey;
1364 p = IndexDataKey::decode(p, limit, &indexDataKey);
1366 m_currentKey = indexDataKey.userKey();
1368 const char *q = m_iterator->value().begin();
1369 const char *valueLimit = m_iterator->value().end();
1371 int64_t indexDataVersion;
1372 q = decodeVarInt(q, valueLimit, indexDataVersion);
1376 q = decodeIDBKey(q, valueLimit, m_primaryKey);
1381 m_primaryLevelDBKey = ObjectStoreDataKey::encode(indexDataKey.databaseId(), indexDataKey.objectStoreId(), *m_primaryKey);
1383 Vector<char> result;
1384 if (!m_transaction->get(m_primaryLevelDBKey, result)) {
1385 m_transaction->remove(m_iterator->key());
1389 int64_t objectStoreDataVersion;
1390 const char* t = decodeVarInt(result.begin(), result.end(), objectStoreDataVersion);
1395 if (objectStoreDataVersion != indexDataVersion) {
1396 m_transaction->remove(m_iterator->key());
1400 m_value = decodeString(t, result.end());
1406 PassRefPtr<IDBBackingStore::Cursor> IDBLevelDBBackingStore::openObjectStoreCursor(int64_t databaseId, int64_t objectStoreId, const IDBKeyRange* range, IDBCursor::Direction direction)
1408 ASSERT(m_currentTransaction);
1409 CursorOptions cursorOptions;
1411 bool lowerBound = range && range->lower();
1412 bool upperBound = range && range->upper();
1413 cursorOptions.forward = (direction == IDBCursor::NEXT_NO_DUPLICATE || direction == IDBCursor::NEXT);
1414 cursorOptions.unique = (direction == IDBCursor::NEXT_NO_DUPLICATE || direction == IDBCursor::PREV_NO_DUPLICATE);
1417 cursorOptions.lowKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, minIDBKey());
1418 cursorOptions.lowOpen = true; // Not included.
1420 cursorOptions.lowKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, *range->lower());
1421 cursorOptions.lowOpen = range->lowerOpen();
1425 cursorOptions.highKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, maxIDBKey());
1427 if (cursorOptions.forward)
1428 cursorOptions.highOpen = true; // Not included.
1430 // We need a key that exists.
1431 if (!findGreatestKeyLessThanOrEqual(m_currentTransaction.get(), cursorOptions.highKey, cursorOptions.highKey))
1433 cursorOptions.highOpen = false;
1436 cursorOptions.highKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, *range->upper());
1437 cursorOptions.highOpen = range->upperOpen();
1439 if (!cursorOptions.forward) {
1440 // For reverse cursors, we need a key that exists.
1441 Vector<char> foundHighKey;
1442 if (!findGreatestKeyLessThanOrEqual(m_currentTransaction.get(), cursorOptions.highKey, foundHighKey))
1445 // If the target key should not be included, but we end up with a smaller key, we should include that.
1446 if (cursorOptions.highOpen && compareIndexKeys(foundHighKey, cursorOptions.highKey) < 0)
1447 cursorOptions.highOpen = false;
1449 cursorOptions.highKey = foundHighKey;
1453 RefPtr<ObjectStoreCursorImpl> cursor = ObjectStoreCursorImpl::create(m_currentTransaction.get(), cursorOptions);
1454 if (!cursor->firstSeek())
1457 return cursor.release();
1460 PassRefPtr<IDBBackingStore::Cursor> IDBLevelDBBackingStore::openIndexKeyCursor(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKeyRange* range, IDBCursor::Direction direction)
1462 ASSERT(m_currentTransaction);
1463 CursorOptions cursorOptions;
1464 bool lowerBound = range && range->lower();
1465 bool upperBound = range && range->upper();
1466 cursorOptions.forward = (direction == IDBCursor::NEXT_NO_DUPLICATE || direction == IDBCursor::NEXT);
1467 cursorOptions.unique = (direction == IDBCursor::NEXT_NO_DUPLICATE || direction == IDBCursor::PREV_NO_DUPLICATE);
1470 cursorOptions.lowKey = IndexDataKey::encodeMinKey(databaseId, objectStoreId, indexId);
1471 cursorOptions.lowOpen = false; // Included.
1473 cursorOptions.lowKey = IndexDataKey::encode(databaseId, objectStoreId, indexId, *range->lower());
1474 cursorOptions.lowOpen = range->lowerOpen();
1478 cursorOptions.highKey = IndexDataKey::encodeMaxKey(databaseId, objectStoreId, indexId);
1479 cursorOptions.highOpen = false; // Included.
1481 if (!cursorOptions.forward) { // We need a key that exists.
1482 if (!findGreatestKeyLessThanOrEqual(m_currentTransaction.get(), cursorOptions.highKey, cursorOptions.highKey))
1484 cursorOptions.highOpen = false;
1487 cursorOptions.highKey = IndexDataKey::encode(databaseId, objectStoreId, indexId, *range->upper());
1488 cursorOptions.highOpen = range->upperOpen();
1490 Vector<char> foundHighKey;
1491 if (!findGreatestKeyLessThanOrEqual(m_currentTransaction.get(), cursorOptions.highKey, foundHighKey)) // Seek to the *last* key in the set of non-unique keys.
1494 // If the target key should not be included, but we end up with a smaller key, we should include that.
1495 if (cursorOptions.highOpen && compareIndexKeys(foundHighKey, cursorOptions.highKey) < 0)
1496 cursorOptions.highOpen = false;
1498 cursorOptions.highKey = foundHighKey;
1501 RefPtr<IndexKeyCursorImpl> cursor = IndexKeyCursorImpl::create(m_currentTransaction.get(), cursorOptions);
1502 if (!cursor->firstSeek())
1505 return cursor.release();
1508 PassRefPtr<IDBBackingStore::Cursor> IDBLevelDBBackingStore::openIndexCursor(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKeyRange* range, IDBCursor::Direction direction)
1510 ASSERT(m_currentTransaction);
1511 CursorOptions cursorOptions;
1512 bool lowerBound = range && range->lower();
1513 bool upperBound = range && range->upper();
1514 cursorOptions.forward = (direction == IDBCursor::NEXT_NO_DUPLICATE || direction == IDBCursor::NEXT);
1515 cursorOptions.unique = (direction == IDBCursor::NEXT_NO_DUPLICATE || direction == IDBCursor::PREV_NO_DUPLICATE);
1518 cursorOptions.lowKey = IndexDataKey::encodeMinKey(databaseId, objectStoreId, indexId);
1519 cursorOptions.lowOpen = false; // Included.
1521 cursorOptions.lowKey = IndexDataKey::encode(databaseId, objectStoreId, indexId, *range->lower());
1522 cursorOptions.lowOpen = range->lowerOpen();
1526 cursorOptions.highKey = IndexDataKey::encodeMaxKey(databaseId, objectStoreId, indexId);
1527 cursorOptions.highOpen = false; // Included.
1529 if (!cursorOptions.forward) { // We need a key that exists.
1530 if (!findGreatestKeyLessThanOrEqual(m_currentTransaction.get(), cursorOptions.highKey, cursorOptions.highKey))
1532 cursorOptions.highOpen = false;
1535 cursorOptions.highKey = IndexDataKey::encode(databaseId, objectStoreId, indexId, *range->upper());
1536 cursorOptions.highOpen = range->upperOpen();
1538 Vector<char> foundHighKey;
1539 if (!findGreatestKeyLessThanOrEqual(m_currentTransaction.get(), cursorOptions.highKey, foundHighKey)) // Seek to the *last* key in the set of non-unique keys.
1542 // If the target key should not be included, but we end up with a smaller key, we should include that.
1543 if (cursorOptions.highOpen && compareIndexKeys(foundHighKey, cursorOptions.highKey) < 0)
1544 cursorOptions.highOpen = false;
1546 cursorOptions.highKey = foundHighKey;
1549 RefPtr<IndexCursorImpl> cursor = IndexCursorImpl::create(m_currentTransaction.get(), cursorOptions);
1550 if (!cursor->firstSeek())
1553 return cursor.release();
1556 PassRefPtr<IDBBackingStore::Transaction> IDBLevelDBBackingStore::createTransaction()
1558 return Transaction::create(this);
1561 PassRefPtr<IDBLevelDBBackingStore::Transaction> IDBLevelDBBackingStore::Transaction::create(IDBLevelDBBackingStore* backingStore)
1563 return adoptRef(new Transaction(backingStore));
1566 IDBLevelDBBackingStore::Transaction::Transaction(IDBLevelDBBackingStore* backingStore)
1567 : m_backingStore(backingStore)
1571 void IDBLevelDBBackingStore::Transaction::begin()
1573 ASSERT(!m_backingStore->m_currentTransaction);
1574 m_backingStore->m_currentTransaction = LevelDBTransaction::create(m_backingStore->m_db.get());
1577 bool IDBLevelDBBackingStore::Transaction::commit()
1579 ASSERT(m_backingStore->m_currentTransaction);
1580 bool result = m_backingStore->m_currentTransaction->commit();
1581 m_backingStore->m_currentTransaction.clear();
1585 void IDBLevelDBBackingStore::Transaction::rollback()
1587 ASSERT(m_backingStore->m_currentTransaction);
1588 m_backingStore->m_currentTransaction->rollback();
1589 m_backingStore->m_currentTransaction.clear();
1592 bool IDBLevelDBBackingStore::backingStoreExists(SecurityOrigin* securityOrigin, const String&, const String& pathBaseArg)
1594 String pathBase = pathBaseArg;
1596 if (pathBase.isEmpty())
1599 // FIXME: We should eventually use the same LevelDB database for all origins.
1600 String path = pathByAppendingComponent(pathBase, securityOrigin->databaseIdentifier() + ".indexeddb.leveldb");
1602 // FIXME: this is checking for presence of the domain, not the database itself
1603 return fileExists(path+"/CURRENT");
1606 } // namespace WebCore
1608 #endif // USE(LEVELDB)
1609 #endif // ENABLE(INDEXED_DATABASE)