2011-05-25 Hans Wennborg <hans@chromium.org>
authorhans@chromium.org <hans@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 26 May 2011 08:48:09 +0000 (08:48 +0000)
committerhans@chromium.org <hans@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 26 May 2011 08:48:09 +0000 (08:48 +0000)
        Reviewed by Steve Block.

        IndexedDB: Support LevelDB transactions.
        https://bugs.webkit.org/show_bug.cgi?id=61270

        Introduce LevelDBTransaction, which implements in-memory transaction
        support on top of LevelDB, and hook this up for IndexedDB to use.

        This is all covered by existing tests.

        * CMakeLists.txt:
        * GNUmakefile.list.am:
        * WebCore.gypi:
        * WebCore.pro:
        * WebCore.xcodeproj/project.pbxproj:
        * platform/leveldb/LevelDBDatabase.cpp:
        (WebCore::LevelDBDatabase::open):
        (WebCore::LevelDBDatabase::put):
        (WebCore::LevelDBDatabase::remove):
        (WebCore::LevelDBDatabase::write):
        (WebCore::IteratorImpl::IteratorImpl):
        (WebCore::IteratorImpl::isValid):
        (WebCore::IteratorImpl::seekToLast):
        (WebCore::IteratorImpl::seek):
        (WebCore::IteratorImpl::next):
        (WebCore::IteratorImpl::prev):
        (WebCore::IteratorImpl::key):
        (WebCore::IteratorImpl::value):
        (WebCore::LevelDBDatabase::createIterator):
        (WebCore::LevelDBDatabase::comparator):
        * platform/leveldb/LevelDBDatabase.h:
        * platform/leveldb/LevelDBIterator.h:
        (WebCore::LevelDBIterator::~LevelDBIterator):
        * platform/leveldb/LevelDBTransaction.cpp: Added.
        (WebCore::LevelDBTransaction::create):
        (WebCore::LevelDBTransaction::LevelDBTransaction):
        (WebCore::LevelDBTransaction::clearTree):
        (WebCore::LevelDBTransaction::~LevelDBTransaction):
        (WebCore::makeVector):
        (WebCore::LevelDBTransaction::set):
        (WebCore::LevelDBTransaction::put):
        (WebCore::LevelDBTransaction::remove):
        (WebCore::LevelDBTransaction::get):
        (WebCore::LevelDBTransaction::commit):
        (WebCore::LevelDBTransaction::rollback):
        (WebCore::LevelDBTransaction::createIterator):
        (WebCore::LevelDBTransaction::TreeIterator::create):
        (WebCore::LevelDBTransaction::TreeIterator::isValid):
        (WebCore::LevelDBTransaction::TreeIterator::seekToLast):
        (WebCore::LevelDBTransaction::TreeIterator::seek):
        (WebCore::LevelDBTransaction::TreeIterator::next):
        (WebCore::LevelDBTransaction::TreeIterator::prev):
        (WebCore::LevelDBTransaction::TreeIterator::key):
        (WebCore::LevelDBTransaction::TreeIterator::value):
        (WebCore::LevelDBTransaction::TreeIterator::isDeleted):
        (WebCore::LevelDBTransaction::TreeIterator::reset):
        (WebCore::LevelDBTransaction::TreeIterator::~TreeIterator):
        (WebCore::LevelDBTransaction::TreeIterator::TreeIterator):
        (WebCore::LevelDBTransaction::TransactionIterator::create):
        (WebCore::LevelDBTransaction::TransactionIterator::TransactionIterator):
        (WebCore::LevelDBTransaction::TransactionIterator::isValid):
        (WebCore::LevelDBTransaction::TransactionIterator::seekToLast):
        (WebCore::LevelDBTransaction::TransactionIterator::seek):
        (WebCore::LevelDBTransaction::TransactionIterator::next):
        (WebCore::LevelDBTransaction::TransactionIterator::prev):
        (WebCore::LevelDBTransaction::TransactionIterator::key):
        (WebCore::LevelDBTransaction::TransactionIterator::value):
        (WebCore::LevelDBTransaction::TransactionIterator::handleConflictsAndDeletes):
        (WebCore::LevelDBTransaction::TransactionIterator::setCurrentIteratorToSmallestKey):
        (WebCore::LevelDBTransaction::TransactionIterator::setCurrentIteratorToLargestKey):
        (WebCore::LevelDBTransaction::registerIterator):
        (WebCore::LevelDBTransaction::unregisterIterator):
        (WebCore::LevelDBTransaction::resetIterators):
        * platform/leveldb/LevelDBTransaction.h: Added.
        (WebCore::LevelDBTransaction::AVLTreeAbstractor::get_less):
        (WebCore::LevelDBTransaction::AVLTreeAbstractor::set_less):
        (WebCore::LevelDBTransaction::AVLTreeAbstractor::get_greater):
        (WebCore::LevelDBTransaction::AVLTreeAbstractor::set_greater):
        (WebCore::LevelDBTransaction::AVLTreeAbstractor::get_balance_factor):
        (WebCore::LevelDBTransaction::AVLTreeAbstractor::set_balance_factor):
        (WebCore::LevelDBTransaction::AVLTreeAbstractor::compare_key_key):
        (WebCore::LevelDBTransaction::AVLTreeAbstractor::compare_key_node):
        (WebCore::LevelDBTransaction::AVLTreeAbstractor::compare_node_node):
        (WebCore::LevelDBTransaction::AVLTreeAbstractor::null):
        (WebCore::LevelDBTransaction::TransactionIterator::~TransactionIterator):
        * platform/leveldb/LevelDBWriteBatch.cpp:
        (WebCore::LevelDBWriteBatch::create):
        (WebCore::LevelDBWriteBatch::LevelDBWriteBatch):
        (WebCore::LevelDBWriteBatch::~LevelDBWriteBatch):
        (WebCore::makeSlice):
        (WebCore::LevelDBWriteBatch::put):
        (WebCore::LevelDBWriteBatch::remove):
        (WebCore::LevelDBWriteBatch::clear):
        * storage/IDBLevelDBBackingStore.cpp:
        (WebCore::getInt):
        (WebCore::putInt):
        (WebCore::getString):
        (WebCore::putString):
        (WebCore::getNewObjectStoreId):
        (WebCore::IDBLevelDBBackingStore::createObjectStore):
        (WebCore::deleteRange):
        (WebCore::IDBLevelDBBackingStore::deleteObjectStore):
        (WebCore::IDBLevelDBBackingStore::getObjectStoreRecord):
        (WebCore::getNewVersionNumber):
        (WebCore::IDBLevelDBBackingStore::putObjectStoreRecord):
        (WebCore::IDBLevelDBBackingStore::clearObjectStore):
        (WebCore::IDBLevelDBBackingStore::deleteObjectStoreRecord):
        (WebCore::IDBLevelDBBackingStore::nextAutoIncrementNumber):
        (WebCore::IDBLevelDBBackingStore::keyExistsInObjectStore):
        (WebCore::IDBLevelDBBackingStore::forEachObjectStoreRecord):
        (WebCore::getNewIndexId):
        (WebCore::IDBLevelDBBackingStore::createIndex):
        (WebCore::IDBLevelDBBackingStore::putIndexDataForRecord):
        (WebCore::findGreatestKeyLessThan):
        (WebCore::versionExists):
        (WebCore::IDBLevelDBBackingStore::getPrimaryKeyViaIndex):
        (WebCore::IDBLevelDBBackingStore::keyExistsInIndex):
        (WebCore::findLastIndexKeyEqualTo):
        (WebCore::IDBLevelDBBackingStore::openObjectStoreCursor):
        (WebCore::IDBLevelDBBackingStore::openIndexKeyCursor):
        (WebCore::IDBLevelDBBackingStore::openIndexCursor):
        (WebCore::IDBLevelDBBackingStore::createTransaction):
        (WebCore::IDBLevelDBBackingStore::Transaction::create):
        (WebCore::IDBLevelDBBackingStore::Transaction::Transaction):
        (WebCore::IDBLevelDBBackingStore::Transaction::begin):
        (WebCore::IDBLevelDBBackingStore::Transaction::commit):
        (WebCore::IDBLevelDBBackingStore::Transaction::rollback):
        * storage/IDBLevelDBBackingStore.h:
        * storage/IDBTransactionBackendImpl.cpp:
        (WebCore::IDBTransactionBackendImpl::abort):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@87370 268f45cc-cd09-0410-ab3c-d52691b4dbfc

16 files changed:
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/GNUmakefile.list.am
Source/WebCore/WebCore.gypi
Source/WebCore/WebCore.pro
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/platform/leveldb/LevelDBDatabase.cpp
Source/WebCore/platform/leveldb/LevelDBDatabase.h
Source/WebCore/platform/leveldb/LevelDBIterator.h
Source/WebCore/platform/leveldb/LevelDBTransaction.cpp [new file with mode: 0644]
Source/WebCore/platform/leveldb/LevelDBTransaction.h [new file with mode: 0644]
Source/WebCore/platform/leveldb/LevelDBWriteBatch.cpp [moved from Source/WebCore/platform/leveldb/LevelDBIterator.cpp with 57% similarity]
Source/WebCore/platform/leveldb/LevelDBWriteBatch.h [new file with mode: 0644]
Source/WebCore/storage/IDBLevelDBBackingStore.cpp
Source/WebCore/storage/IDBLevelDBBackingStore.h
Source/WebCore/storage/IDBTransactionBackendImpl.cpp

index 5233cfd..c874b94 100644 (file)
@@ -1469,7 +1469,8 @@ ENDIF ()
 IF (ENABLE_LEVELDB)
     LIST(APPEND WebCore_SOURCES
         platform/leveldb/LevelDBDatabase.cpp
-        platform/leveldb/LevelDBIterator.cpp
+        platform/leveldb/LevelDBTransaction.cpp
+        platform/leveldb/LevelDBWriteBatch.cpp
     )
 ENDIF ()
 
index ec825e8..926a499 100644 (file)
@@ -1,3 +1,136 @@
+2011-05-25  Hans Wennborg  <hans@chromium.org>
+
+        Reviewed by Steve Block.
+
+        IndexedDB: Support LevelDB transactions.
+        https://bugs.webkit.org/show_bug.cgi?id=61270
+
+        Introduce LevelDBTransaction, which implements in-memory transaction
+        support on top of LevelDB, and hook this up for IndexedDB to use.
+
+        This is all covered by existing tests.
+
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * WebCore.gypi:
+        * WebCore.pro:
+        * WebCore.xcodeproj/project.pbxproj:
+        * platform/leveldb/LevelDBDatabase.cpp:
+        (WebCore::LevelDBDatabase::open):
+        (WebCore::LevelDBDatabase::put):
+        (WebCore::LevelDBDatabase::remove):
+        (WebCore::LevelDBDatabase::write):
+        (WebCore::IteratorImpl::IteratorImpl):
+        (WebCore::IteratorImpl::isValid):
+        (WebCore::IteratorImpl::seekToLast):
+        (WebCore::IteratorImpl::seek):
+        (WebCore::IteratorImpl::next):
+        (WebCore::IteratorImpl::prev):
+        (WebCore::IteratorImpl::key):
+        (WebCore::IteratorImpl::value):
+        (WebCore::LevelDBDatabase::createIterator):
+        (WebCore::LevelDBDatabase::comparator):
+        * platform/leveldb/LevelDBDatabase.h:
+        * platform/leveldb/LevelDBIterator.h:
+        (WebCore::LevelDBIterator::~LevelDBIterator):
+        * platform/leveldb/LevelDBTransaction.cpp: Added.
+        (WebCore::LevelDBTransaction::create):
+        (WebCore::LevelDBTransaction::LevelDBTransaction):
+        (WebCore::LevelDBTransaction::clearTree):
+        (WebCore::LevelDBTransaction::~LevelDBTransaction):
+        (WebCore::makeVector):
+        (WebCore::LevelDBTransaction::set):
+        (WebCore::LevelDBTransaction::put):
+        (WebCore::LevelDBTransaction::remove):
+        (WebCore::LevelDBTransaction::get):
+        (WebCore::LevelDBTransaction::commit):
+        (WebCore::LevelDBTransaction::rollback):
+        (WebCore::LevelDBTransaction::createIterator):
+        (WebCore::LevelDBTransaction::TreeIterator::create):
+        (WebCore::LevelDBTransaction::TreeIterator::isValid):
+        (WebCore::LevelDBTransaction::TreeIterator::seekToLast):
+        (WebCore::LevelDBTransaction::TreeIterator::seek):
+        (WebCore::LevelDBTransaction::TreeIterator::next):
+        (WebCore::LevelDBTransaction::TreeIterator::prev):
+        (WebCore::LevelDBTransaction::TreeIterator::key):
+        (WebCore::LevelDBTransaction::TreeIterator::value):
+        (WebCore::LevelDBTransaction::TreeIterator::isDeleted):
+        (WebCore::LevelDBTransaction::TreeIterator::reset):
+        (WebCore::LevelDBTransaction::TreeIterator::~TreeIterator):
+        (WebCore::LevelDBTransaction::TreeIterator::TreeIterator):
+        (WebCore::LevelDBTransaction::TransactionIterator::create):
+        (WebCore::LevelDBTransaction::TransactionIterator::TransactionIterator):
+        (WebCore::LevelDBTransaction::TransactionIterator::isValid):
+        (WebCore::LevelDBTransaction::TransactionIterator::seekToLast):
+        (WebCore::LevelDBTransaction::TransactionIterator::seek):
+        (WebCore::LevelDBTransaction::TransactionIterator::next):
+        (WebCore::LevelDBTransaction::TransactionIterator::prev):
+        (WebCore::LevelDBTransaction::TransactionIterator::key):
+        (WebCore::LevelDBTransaction::TransactionIterator::value):
+        (WebCore::LevelDBTransaction::TransactionIterator::handleConflictsAndDeletes):
+        (WebCore::LevelDBTransaction::TransactionIterator::setCurrentIteratorToSmallestKey):
+        (WebCore::LevelDBTransaction::TransactionIterator::setCurrentIteratorToLargestKey):
+        (WebCore::LevelDBTransaction::registerIterator):
+        (WebCore::LevelDBTransaction::unregisterIterator):
+        (WebCore::LevelDBTransaction::resetIterators):
+        * platform/leveldb/LevelDBTransaction.h: Added.
+        (WebCore::LevelDBTransaction::AVLTreeAbstractor::get_less):
+        (WebCore::LevelDBTransaction::AVLTreeAbstractor::set_less):
+        (WebCore::LevelDBTransaction::AVLTreeAbstractor::get_greater):
+        (WebCore::LevelDBTransaction::AVLTreeAbstractor::set_greater):
+        (WebCore::LevelDBTransaction::AVLTreeAbstractor::get_balance_factor):
+        (WebCore::LevelDBTransaction::AVLTreeAbstractor::set_balance_factor):
+        (WebCore::LevelDBTransaction::AVLTreeAbstractor::compare_key_key):
+        (WebCore::LevelDBTransaction::AVLTreeAbstractor::compare_key_node):
+        (WebCore::LevelDBTransaction::AVLTreeAbstractor::compare_node_node):
+        (WebCore::LevelDBTransaction::AVLTreeAbstractor::null):
+        (WebCore::LevelDBTransaction::TransactionIterator::~TransactionIterator):
+        * platform/leveldb/LevelDBWriteBatch.cpp:
+        (WebCore::LevelDBWriteBatch::create):
+        (WebCore::LevelDBWriteBatch::LevelDBWriteBatch):
+        (WebCore::LevelDBWriteBatch::~LevelDBWriteBatch):
+        (WebCore::makeSlice):
+        (WebCore::LevelDBWriteBatch::put):
+        (WebCore::LevelDBWriteBatch::remove):
+        (WebCore::LevelDBWriteBatch::clear):
+        * storage/IDBLevelDBBackingStore.cpp:
+        (WebCore::getInt):
+        (WebCore::putInt):
+        (WebCore::getString):
+        (WebCore::putString):
+        (WebCore::getNewObjectStoreId):
+        (WebCore::IDBLevelDBBackingStore::createObjectStore):
+        (WebCore::deleteRange):
+        (WebCore::IDBLevelDBBackingStore::deleteObjectStore):
+        (WebCore::IDBLevelDBBackingStore::getObjectStoreRecord):
+        (WebCore::getNewVersionNumber):
+        (WebCore::IDBLevelDBBackingStore::putObjectStoreRecord):
+        (WebCore::IDBLevelDBBackingStore::clearObjectStore):
+        (WebCore::IDBLevelDBBackingStore::deleteObjectStoreRecord):
+        (WebCore::IDBLevelDBBackingStore::nextAutoIncrementNumber):
+        (WebCore::IDBLevelDBBackingStore::keyExistsInObjectStore):
+        (WebCore::IDBLevelDBBackingStore::forEachObjectStoreRecord):
+        (WebCore::getNewIndexId):
+        (WebCore::IDBLevelDBBackingStore::createIndex):
+        (WebCore::IDBLevelDBBackingStore::putIndexDataForRecord):
+        (WebCore::findGreatestKeyLessThan):
+        (WebCore::versionExists):
+        (WebCore::IDBLevelDBBackingStore::getPrimaryKeyViaIndex):
+        (WebCore::IDBLevelDBBackingStore::keyExistsInIndex):
+        (WebCore::findLastIndexKeyEqualTo):
+        (WebCore::IDBLevelDBBackingStore::openObjectStoreCursor):
+        (WebCore::IDBLevelDBBackingStore::openIndexKeyCursor):
+        (WebCore::IDBLevelDBBackingStore::openIndexCursor):
+        (WebCore::IDBLevelDBBackingStore::createTransaction):
+        (WebCore::IDBLevelDBBackingStore::Transaction::create):
+        (WebCore::IDBLevelDBBackingStore::Transaction::Transaction):
+        (WebCore::IDBLevelDBBackingStore::Transaction::begin):
+        (WebCore::IDBLevelDBBackingStore::Transaction::commit):
+        (WebCore::IDBLevelDBBackingStore::Transaction::rollback):
+        * storage/IDBLevelDBBackingStore.h:
+        * storage/IDBTransactionBackendImpl.cpp:
+        (WebCore::IDBTransactionBackendImpl::abort):
+
 2011-05-26  Shane Stephens  <shanestephens@google.com>
 
         Reviewed by James Robinson.
index 0b06b3a..99f9f3e 100644 (file)
@@ -2543,9 +2543,12 @@ webcore_sources += \
        Source/WebCore/platform/leveldb/LevelDBComparator.h \
        Source/WebCore/platform/leveldb/LevelDBDatabase.cpp \
        Source/WebCore/platform/leveldb/LevelDBDatabase.h \
-       Source/WebCore/platform/leveldb/LevelDBIterator.cpp \
        Source/WebCore/platform/leveldb/LevelDBIterator.h \
        Source/WebCore/platform/leveldb/LevelDBSlice.h \
+       Source/WebCore/platform/leveldb/LevelDBTransaction.h \
+       Source/WebCore/platform/leveldb/LevelDBTransaction.cpp \
+       Source/WebCore/platform/leveldb/LevelDBWriteBatch.h \
+       Source/WebCore/platform/leveldb/LevelDBWriteBatch.cpp \
        Source/WebCore/platform/LinkHash.cpp \
        Source/WebCore/platform/LinkHash.h \
        Source/WebCore/platform/LocalizedStrings.h \
index ff447ce..56e32bb 100644 (file)
             'platform/leveldb/LevelDBComparator.h',
             'platform/leveldb/LevelDBDatabase.cpp',
             'platform/leveldb/LevelDBDatabase.h',
-            'platform/leveldb/LevelDBIterator.cpp',
             'platform/leveldb/LevelDBIterator.h',
             'platform/leveldb/LevelDBSlice.h',
+            'platform/leveldb/LevelDBTransaction.cpp',
+            'platform/leveldb/LevelDBTransaction.h',
+            'platform/leveldb/LevelDBWriteBatch.cpp',
+            'platform/leveldb/LevelDBWriteBatch.h',
             'platform/mac/BlockExceptions.h',
             'platform/mac/ClipboardMac.h',
             'platform/mac/EmptyProtocolDefinitions.h',
index 30dd6c5..7780d68 100644 (file)
@@ -1017,12 +1017,9 @@ SOURCES += \
     platform/Language.cpp \
     platform/Length.cpp \
     platform/text/LineEnding.cpp \
-    platform/leveldb/LevelDBComparator.h \
     platform/leveldb/LevelDBDatabase.cpp \
-    platform/leveldb/LevelDBDatabase.h \
-    platform/leveldb/LevelDBIterator.cpp \
-    platform/leveldb/LevelDBIterator.h \
-    platform/leveldb/LevelDBSlice.h \
+    platform/leveldb/LevelDBTransaction.cpp \
+    platform/leveldb/LevelDBWriteBatch.cpp \
     platform/LinkHash.cpp \
     platform/Logging.cpp \
     platform/MemoryPressureHandler.cpp \
@@ -1998,6 +1995,12 @@ HEADERS += \
     platform/KillRing.h \
     platform/KURL.h \
     platform/Length.h \
+    platform/leveldb/LevelDBComparator.h \
+    platform/leveldb/LevelDBDatabase.h \
+    platform/leveldb/LevelDBIterator.h \
+    platform/leveldb/LevelDBSlice.h \
+    platform/leveldb/LevelDBTransaction.h \
+    platform/leveldb/LevelDBWriteBatch.h \
     platform/text/BidiRunList.h \
     platform/text/LineEnding.h \
     platform/text/TextCheckerClient.h \
index cf295d0..f077eac 100644 (file)
                8AF4E55611DC5A36000ED3DE /* PerformanceNavigation.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AF4E55311DC5A36000ED3DE /* PerformanceNavigation.h */; };
                8AF4E55B11DC5A63000ED3DE /* PerformanceTiming.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8AF4E55811DC5A63000ED3DE /* PerformanceTiming.cpp */; };
                8AF4E55C11DC5A63000ED3DE /* PerformanceTiming.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AF4E55911DC5A63000ED3DE /* PerformanceTiming.h */; };
+               8C0E334C138A92C7008DA94F /* LevelDBTransaction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C0E3348138A92C7008DA94F /* LevelDBTransaction.cpp */; };
+               8C0E334D138A92C7008DA94F /* LevelDBTransaction.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C0E3349138A92C7008DA94F /* LevelDBTransaction.h */; };
+               8C0E334E138A92C7008DA94F /* LevelDBWriteBatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C0E334A138A92C7008DA94F /* LevelDBWriteBatch.cpp */; };
+               8C0E334F138A92C7008DA94F /* LevelDBWriteBatch.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C0E334B138A92C7008DA94F /* LevelDBWriteBatch.h */; };
                8C6EA61911EF7E0400FD8EE3 /* RuntimeEnabledFeatures.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C6EA61711EF7E0400FD8EE3 /* RuntimeEnabledFeatures.cpp */; };
                8C6EA61A11EF7E0400FD8EE3 /* RuntimeEnabledFeatures.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C6EA61811EF7E0400FD8EE3 /* RuntimeEnabledFeatures.h */; };
                8CADF2A9135C7B36009EF43F /* LevelDBComparator.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CADF2A3135C7B36009EF43F /* LevelDBComparator.h */; };
                8CADF2AA135C7B36009EF43F /* LevelDBDatabase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CADF2A4135C7B36009EF43F /* LevelDBDatabase.cpp */; };
                8CADF2AB135C7B36009EF43F /* LevelDBDatabase.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CADF2A5135C7B36009EF43F /* LevelDBDatabase.h */; };
-               8CADF2AC135C7B36009EF43F /* LevelDBIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CADF2A6135C7B36009EF43F /* LevelDBIterator.cpp */; };
                8CADF2AD135C7B36009EF43F /* LevelDBIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CADF2A7135C7B36009EF43F /* LevelDBIterator.h */; };
                8CADF2AE135C7B36009EF43F /* LevelDBSlice.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CADF2A8135C7B36009EF43F /* LevelDBSlice.h */; };
                8F67561B1288B17B0047ACA3 /* EventQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 8F6756191288B17B0047ACA3 /* EventQueue.h */; };
                8AF4E55811DC5A63000ED3DE /* PerformanceTiming.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PerformanceTiming.cpp; sourceTree = "<group>"; };
                8AF4E55911DC5A63000ED3DE /* PerformanceTiming.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PerformanceTiming.h; sourceTree = "<group>"; };
                8AF4E55A11DC5A63000ED3DE /* PerformanceTiming.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = PerformanceTiming.idl; sourceTree = "<group>"; };
+               8C0E3348138A92C7008DA94F /* LevelDBTransaction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LevelDBTransaction.cpp; sourceTree = "<group>"; };
+               8C0E3349138A92C7008DA94F /* LevelDBTransaction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LevelDBTransaction.h; sourceTree = "<group>"; };
+               8C0E334A138A92C7008DA94F /* LevelDBWriteBatch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LevelDBWriteBatch.cpp; sourceTree = "<group>"; };
+               8C0E334B138A92C7008DA94F /* LevelDBWriteBatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LevelDBWriteBatch.h; sourceTree = "<group>"; };
                8C6EA61711EF7E0400FD8EE3 /* RuntimeEnabledFeatures.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RuntimeEnabledFeatures.cpp; path = generic/RuntimeEnabledFeatures.cpp; sourceTree = "<group>"; };
                8C6EA61811EF7E0400FD8EE3 /* RuntimeEnabledFeatures.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RuntimeEnabledFeatures.h; path = generic/RuntimeEnabledFeatures.h; sourceTree = "<group>"; };
                8CADF2A3135C7B36009EF43F /* LevelDBComparator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LevelDBComparator.h; sourceTree = "<group>"; };
                8CADF2A4135C7B36009EF43F /* LevelDBDatabase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LevelDBDatabase.cpp; sourceTree = "<group>"; };
                8CADF2A5135C7B36009EF43F /* LevelDBDatabase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LevelDBDatabase.h; sourceTree = "<group>"; };
-               8CADF2A6135C7B36009EF43F /* LevelDBIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LevelDBIterator.cpp; sourceTree = "<group>"; };
                8CADF2A7135C7B36009EF43F /* LevelDBIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LevelDBIterator.h; sourceTree = "<group>"; };
                8CADF2A8135C7B36009EF43F /* LevelDBSlice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LevelDBSlice.h; sourceTree = "<group>"; };
                8F6756191288B17B0047ACA3 /* EventQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EventQueue.h; sourceTree = "<group>"; };
                                8CADF2A3135C7B36009EF43F /* LevelDBComparator.h */,
                                8CADF2A4135C7B36009EF43F /* LevelDBDatabase.cpp */,
                                8CADF2A5135C7B36009EF43F /* LevelDBDatabase.h */,
-                               8CADF2A6135C7B36009EF43F /* LevelDBIterator.cpp */,
                                8CADF2A7135C7B36009EF43F /* LevelDBIterator.h */,
                                8CADF2A8135C7B36009EF43F /* LevelDBSlice.h */,
+                               8C0E3348138A92C7008DA94F /* LevelDBTransaction.cpp */,
+                               8C0E3349138A92C7008DA94F /* LevelDBTransaction.h */,
+                               8C0E334A138A92C7008DA94F /* LevelDBWriteBatch.cpp */,
+                               8C0E334B138A92C7008DA94F /* LevelDBWriteBatch.h */,
                        );
                        path = leveldb;
                        sourceTree = "<group>";
                                B12D236613560330002A28D4 /* JSTrackList.h in Headers */,
                                B12D236A1356033F002A28D4 /* JSExclusiveTrackList.h in Headers */,
                                B12D236E1356034D002A28D4 /* JSMultipleTrackList.h in Headers */,
+                               8C0E334D138A92C7008DA94F /* LevelDBTransaction.h in Headers */,
+                               8C0E334F138A92C7008DA94F /* LevelDBWriteBatch.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                51B2417B0D931F3F00E83F5C /* LegacyWebArchiveMac.mm in Sources */,
                                BCE65BEA0EACDF16007E4533 /* Length.cpp in Sources */,
                                8CADF2AA135C7B36009EF43F /* LevelDBDatabase.cpp in Sources */,
-                               8CADF2AC135C7B36009EF43F /* LevelDBIterator.cpp in Sources */,
                                84730D901248F0B300D3A9C9 /* LightSource.cpp in Sources */,
                                89B5EAA111E8003D00F2367E /* LineEnding.cpp in Sources */,
                                A7AD2F870EC89D07008AB002 /* LinkHash.cpp in Sources */,
                                B12D236513560330002A28D4 /* JSTrackList.cpp in Sources */,
                                B12D23691356033F002A28D4 /* JSExclusiveTrackList.cpp in Sources */,
                                B12D236D1356034D002A28D4 /* JSMultipleTrackList.cpp in Sources */,
+                               8C0E334C138A92C7008DA94F /* LevelDBTransaction.cpp in Sources */,
+                               8C0E334E138A92C7008DA94F /* LevelDBWriteBatch.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index d56f26c..386f5dd 100644 (file)
@@ -31,6 +31,7 @@
 #include "LevelDBComparator.h"
 #include "LevelDBIterator.h"
 #include "LevelDBSlice.h"
+#include "LevelDBWriteBatch.h"
 #include <leveldb/comparator.h>
 #include <leveldb/db.h>
 #include <leveldb/slice.h>
@@ -110,15 +111,15 @@ PassOwnPtr<LevelDBDatabase> LevelDBDatabase::open(const String& fileName, const
 
     result->m_db = adoptPtr(db);
     result->m_comparatorAdapter = comparatorAdapter.release();
+    result->m_comparator = comparator;
 
     return result.release();
 }
 
-
 bool LevelDBDatabase::put(const LevelDBSlice& key, const Vector<char>& value)
 {
     leveldb::WriteOptions writeOptions;
-    writeOptions.sync = false;
+    writeOptions.sync = true;
 
     return m_db->Put(writeOptions, makeSlice(key), makeSlice(value)).ok();
 }
@@ -126,7 +127,7 @@ bool LevelDBDatabase::put(const LevelDBSlice& key, const Vector<char>& value)
 bool LevelDBDatabase::remove(const LevelDBSlice& key)
 {
     leveldb::WriteOptions writeOptions;
-    writeOptions.sync = false;
+    writeOptions.sync = true;
 
     return m_db->Delete(writeOptions, makeSlice(key)).ok();
 }
@@ -141,12 +142,90 @@ bool LevelDBDatabase::get(const LevelDBSlice& key, Vector<char>& value)
     return true;
 }
 
+bool LevelDBDatabase::write(LevelDBWriteBatch& writeBatch)
+{
+    leveldb::WriteOptions writeOptions;
+    writeOptions.sync = true;
+
+    return m_db->Write(writeOptions, writeBatch.m_writeBatch.get()).ok();
+}
+
+namespace {
+class IteratorImpl : public LevelDBIterator {
+public:
+    ~IteratorImpl() { };
+
+    virtual bool isValid() const;
+    virtual void seekToLast();
+    virtual void seek(const LevelDBSlice& target);
+    virtual void next();
+    virtual void prev();
+    virtual LevelDBSlice key() const;
+    virtual LevelDBSlice value() const;
+
+private:
+    friend class WebCore::LevelDBDatabase;
+    IteratorImpl(PassOwnPtr<leveldb::Iterator>);
+
+    OwnPtr<leveldb::Iterator> m_iterator;
+};
+}
+
+IteratorImpl::IteratorImpl(PassOwnPtr<leveldb::Iterator> it)
+    : m_iterator(it)
+{
+}
+
+bool IteratorImpl::isValid() const
+{
+    return m_iterator->Valid();
+}
+
+void IteratorImpl::seekToLast()
+{
+    m_iterator->SeekToLast();
+}
+
+void IteratorImpl::seek(const LevelDBSlice& target)
+{
+    m_iterator->Seek(makeSlice(target));
+}
+
+void IteratorImpl::next()
+{
+    ASSERT(isValid());
+    m_iterator->Next();
+}
+
+void IteratorImpl::prev()
+{
+    ASSERT(isValid());
+    m_iterator->Prev();
+}
+
+LevelDBSlice IteratorImpl::key() const
+{
+    ASSERT(isValid());
+    return makeLevelDBSlice(m_iterator->key());
+}
+
+LevelDBSlice IteratorImpl::value() const
+{
+    ASSERT(isValid());
+    return makeLevelDBSlice(m_iterator->value());
+}
+
 PassOwnPtr<LevelDBIterator> LevelDBDatabase::createIterator()
 {
     OwnPtr<leveldb::Iterator> i = adoptPtr(m_db->NewIterator(leveldb::ReadOptions()));
     if (!i) // FIXME: Double check if we actually need to check this.
         return nullptr;
-    return adoptPtr(new LevelDBIterator(i.release()));
+    return adoptPtr(new IteratorImpl(i.release()));
+}
+
+const LevelDBComparator* LevelDBDatabase::comparator() const
+{
+    return m_comparator;
 }
 
 }
index 526d0b8..cbc28f6 100644 (file)
@@ -43,6 +43,7 @@ namespace WebCore {
 class LevelDBComparator;
 class LevelDBIterator;
 class LevelDBSlice;
+class LevelDBWriteBatch;
 
 class LevelDBDatabase {
 public:
@@ -52,12 +53,15 @@ public:
     bool put(const LevelDBSlice& key, const Vector<char>& value);
     bool remove(const LevelDBSlice& key);
     bool get(const LevelDBSlice& key, Vector<char>& value);
+    bool write(LevelDBWriteBatch&);
     PassOwnPtr<LevelDBIterator> createIterator();
+    const LevelDBComparator* comparator() const;
 
 private:
     LevelDBDatabase();
 
     OwnPtr<leveldb::DB> m_db;
+    const LevelDBComparator* m_comparator;
     OwnPtr<leveldb::Comparator> m_comparatorAdapter;
 };
 
index 768a1b4..15255d6 100644 (file)
 #if ENABLE(LEVELDB)
 
 #include "LevelDBSlice.h"
-#include "PlatformString.h"
-#include <OwnPtr.h>
-#include <Vector.h>
-
-namespace leveldb {
-class Iterator;
-}
 
 namespace WebCore {
 
 class LevelDBIterator {
 public:
-    ~LevelDBIterator();
-
-    bool isValid() const;
-    void seekToLast();
-    void seek(const Vector<char>& target);
-    void next();
-    void prev();
-    LevelDBSlice key() const;
-    LevelDBSlice value() const;
-
-private:
-    LevelDBIterator(PassOwnPtr<leveldb::Iterator>);
-    friend class LevelDBDatabase;
-
-    OwnPtr<leveldb::Iterator> m_iterator;
+    virtual ~LevelDBIterator() { };
+    virtual bool isValid() const = 0;
+    virtual void seekToLast() = 0;
+    virtual void seek(const LevelDBSlice& target) = 0;
+    virtual void next() = 0;
+    virtual void prev() = 0;
+    virtual LevelDBSlice key() const = 0;
+    virtual LevelDBSlice value() const = 0;
 };
 
-
 } // namespace WebCore
 
 #endif // ENABLE(LEVELDB)
diff --git a/Source/WebCore/platform/leveldb/LevelDBTransaction.cpp b/Source/WebCore/platform/leveldb/LevelDBTransaction.cpp
new file mode 100644 (file)
index 0000000..efc416e
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "LevelDBTransaction.h"
+
+#include "LevelDBDatabase.h"
+#include "LevelDBSlice.h"
+#include "LevelDBWriteBatch.h"
+
+#if ENABLE(INDEXED_DATABASE)
+#if ENABLE(LEVELDB)
+
+namespace WebCore {
+
+PassRefPtr<LevelDBTransaction> LevelDBTransaction::create(LevelDBDatabase* db)
+{
+    return adoptRef(new LevelDBTransaction(db));
+}
+
+LevelDBTransaction::LevelDBTransaction(LevelDBDatabase* db)
+    : m_db(db)
+    , m_comparator(db->comparator())
+    , m_finished(false)
+{
+    m_tree.abstractor().m_comparator = m_comparator;
+}
+
+void LevelDBTransaction::clearTree()
+{
+    TreeType::Iterator iterator;
+    iterator.start_iter_least(m_tree);
+
+    while (*iterator) {
+        delete *iterator;
+        ++iterator;
+    }
+    m_tree.purge();
+}
+
+LevelDBTransaction::~LevelDBTransaction()
+{
+    clearTree();
+}
+
+static void initVector(const LevelDBSlice& slice, Vector<char>* vector)
+{
+    vector->clear();
+    vector->append(slice.begin(), slice.end() - slice.begin());
+}
+
+bool LevelDBTransaction::set(const LevelDBSlice& key, const Vector<char>& value, bool deleted)
+{
+    ASSERT(!m_finished);
+    bool newNode = false;
+    AVLTreeNode* node = m_tree.search(key);
+
+    if (!node) {
+        node = new AVLTreeNode;
+        initVector(key, &node->key);
+        m_tree.insert(node);
+        newNode = true;
+    }
+    node->value = value;
+    node->deleted = deleted;
+
+    if (newNode)
+        resetIterators();
+    return true;
+}
+
+bool LevelDBTransaction::put(const LevelDBSlice& key, const Vector<char>& value)
+{
+    return set(key, value, false);
+}
+
+bool LevelDBTransaction::remove(const LevelDBSlice& key)
+{
+    return set(key, Vector<char>(), true);
+}
+
+bool LevelDBTransaction::get(const LevelDBSlice& key, Vector<char>& value)
+{
+    ASSERT(!m_finished);
+    AVLTreeNode* node = m_tree.search(key);
+
+    if (node) {
+        if (node->deleted)
+            return false;
+
+        value = node->value;
+        return true;
+    }
+
+    return m_db->get(key, value);
+}
+
+bool LevelDBTransaction::commit()
+{
+    ASSERT(!m_finished);
+    OwnPtr<LevelDBWriteBatch> writeBatch = LevelDBWriteBatch::create();
+
+    TreeType::Iterator iterator;
+    iterator.start_iter_least(m_tree);
+
+    while (*iterator) {
+        AVLTreeNode* node = *iterator;
+        if (!node->deleted)
+            writeBatch->put(node->key, node->value);
+        else
+            writeBatch->remove(node->key);
+        ++iterator;
+    }
+
+    if (!m_db->write(*writeBatch))
+        return false;
+
+    clearTree();
+    m_finished = true;
+    return true;
+}
+
+void LevelDBTransaction::rollback()
+{
+    ASSERT(!m_finished);
+    m_finished = true;
+    clearTree();
+}
+
+PassOwnPtr<LevelDBIterator> LevelDBTransaction::createIterator()
+{
+    return TransactionIterator::create(this);
+}
+
+PassOwnPtr<LevelDBTransaction::TreeIterator> LevelDBTransaction::TreeIterator::create(LevelDBTransaction* transaction)
+{
+    return adoptPtr(new TreeIterator(transaction));
+}
+
+bool LevelDBTransaction::TreeIterator::isValid() const
+{
+    return *m_iterator;
+}
+
+void LevelDBTransaction::TreeIterator::seekToLast()
+{
+    m_iterator.start_iter_greatest(*m_tree);
+    if (isValid())
+        m_key = (*m_iterator)->key;
+}
+
+void LevelDBTransaction::TreeIterator::seek(const LevelDBSlice& target)
+{
+    m_iterator.start_iter(*m_tree, target, TreeType::EQUAL);
+    if (!isValid())
+        m_iterator.start_iter(*m_tree, target, TreeType::GREATER);
+
+    if (isValid())
+        m_key = (*m_iterator)->key;
+}
+
+void LevelDBTransaction::TreeIterator::next()
+{
+    ASSERT(isValid());
+    ++m_iterator;
+    if (isValid()) {
+        ASSERT(m_transaction->m_comparator->compare((*m_iterator)->key, m_key) > 0);
+        m_key = (*m_iterator)->key;
+    }
+}
+
+void LevelDBTransaction::TreeIterator::prev()
+{
+    ASSERT(isValid());
+    --m_iterator;
+    if (isValid()) {
+        ASSERT(m_tree->abstractor().m_comparator->compare((*m_iterator)->key, m_key) < 0);
+        m_key = (*m_iterator)->key;
+    }
+}
+
+LevelDBSlice LevelDBTransaction::TreeIterator::key() const
+{
+    ASSERT(isValid());
+    return m_key;
+}
+
+LevelDBSlice LevelDBTransaction::TreeIterator::value() const
+{
+    ASSERT(isValid());
+    ASSERT(!isDeleted());
+    return (*m_iterator)->value;
+}
+
+bool LevelDBTransaction::TreeIterator::isDeleted() const
+{
+    ASSERT(isValid());
+    return (*m_iterator)->deleted;
+}
+
+void LevelDBTransaction::TreeIterator::reset()
+{
+    // FIXME: Be lazy: set a flag and do the actual reset next time we use the iterator.
+    if (isValid()) {
+        m_iterator.start_iter(*m_tree, m_key, TreeType::EQUAL);
+        ASSERT(isValid());
+    }
+}
+
+LevelDBTransaction::TreeIterator::~TreeIterator()
+{
+    m_transaction->unregisterIterator(this);
+}
+
+LevelDBTransaction::TreeIterator::TreeIterator(LevelDBTransaction* transaction)
+    : m_tree(&transaction->m_tree)
+    , m_transaction(transaction)
+{
+    transaction->registerIterator(this);
+}
+
+PassOwnPtr<LevelDBTransaction::TransactionIterator> LevelDBTransaction::TransactionIterator::create(PassRefPtr<LevelDBTransaction> transaction)
+{
+    return adoptPtr(new TransactionIterator(transaction));
+}
+
+LevelDBTransaction::TransactionIterator::TransactionIterator(PassRefPtr<LevelDBTransaction> transaction)
+    : m_transaction(transaction)
+    , m_comparator(m_transaction->m_comparator)
+    , m_treeIterator(TreeIterator::create(m_transaction.get()))
+    , m_dbIterator(m_transaction->m_db->createIterator())
+    , m_current(0)
+    , m_direction(kForward)
+{
+}
+
+bool LevelDBTransaction::TransactionIterator::isValid() const
+{
+    return m_current;
+}
+
+void LevelDBTransaction::TransactionIterator::seekToLast()
+{
+    m_treeIterator->seekToLast();
+    m_dbIterator->seekToLast();
+    m_direction = kReverse;
+
+    handleConflictsAndDeletes();
+    setCurrentIteratorToLargestKey();
+}
+
+void LevelDBTransaction::TransactionIterator::seek(const LevelDBSlice& target)
+{
+    m_treeIterator->seek(target);
+    m_dbIterator->seek(target);
+    m_direction = kForward;
+
+    handleConflictsAndDeletes();
+    setCurrentIteratorToSmallestKey();
+}
+
+void LevelDBTransaction::TransactionIterator::next()
+{
+    ASSERT(isValid());
+
+    if (m_direction != kForward) {
+        // Ensure the non-current iterator is positioned after key().
+
+        LevelDBIterator* nonCurrent = (m_current == m_dbIterator.get()) ? m_treeIterator.get() : m_dbIterator.get();
+
+        nonCurrent->seek(key());
+        if (nonCurrent->isValid() && !m_comparator->compare(nonCurrent->key(), key()))
+            nonCurrent->next(); // Take an extra step so the non-current key is strictly greater than key().
+
+        ASSERT(!nonCurrent->isValid() || m_comparator->compare(nonCurrent->key(), key()) > 0);
+
+        m_direction = kForward;
+    }
+
+    m_current->next();
+    handleConflictsAndDeletes();
+    setCurrentIteratorToSmallestKey();
+}
+
+void LevelDBTransaction::TransactionIterator::prev()
+{
+    ASSERT(isValid());
+
+    if (m_direction != kReverse) {
+        // Ensure the non-current iterator is positioned before key().
+
+        LevelDBIterator* nonCurrent = (m_current == m_dbIterator.get()) ? m_treeIterator.get() : m_dbIterator.get();
+
+        nonCurrent->seek(key());
+        if (nonCurrent->isValid()) {
+            // Iterator is at first entry >= key().
+            // Step back once to entry < key.
+            // This is why we don't check for the keys being the same before
+            // stepping, like we do in next() above.
+            nonCurrent->prev();
+        } else
+            nonCurrent->seekToLast(); // Iterator has no entries >= key(). Position at last entry.
+
+        ASSERT(!nonCurrent->isValid() || m_comparator->compare(nonCurrent->key(), key()) < 0);
+
+        m_direction = kReverse;
+    }
+
+    m_current->prev();
+    handleConflictsAndDeletes();
+    setCurrentIteratorToLargestKey();
+}
+
+LevelDBSlice LevelDBTransaction::TransactionIterator::key() const
+{
+    ASSERT(isValid());
+    return m_current->key();
+}
+
+LevelDBSlice LevelDBTransaction::TransactionIterator::value() const
+{
+    ASSERT(isValid());
+    return m_current->value();
+}
+
+void LevelDBTransaction::TransactionIterator::handleConflictsAndDeletes()
+{
+    bool loop = true;
+
+    while (loop) {
+        loop = false;
+
+        if (m_treeIterator->isValid() && m_dbIterator->isValid() && !m_comparator->compare(m_treeIterator->key(), m_dbIterator->key())) {
+            // For equal keys, the tree iterator takes precedence, so move the database iterator another step.
+            if (m_direction == kForward)
+                m_dbIterator->next();
+            else
+                m_dbIterator->prev();
+        }
+
+        if (m_treeIterator->isValid() && m_treeIterator->isDeleted()) {
+            // If the tree iterator is on a delete marker, take another step.
+            if (m_direction == kForward)
+                m_treeIterator->next();
+            else
+                m_treeIterator->prev();
+
+            loop = true;
+        }
+    }
+}
+
+void LevelDBTransaction::TransactionIterator::setCurrentIteratorToSmallestKey()
+{
+    LevelDBIterator* smallest = 0;
+
+    if (m_treeIterator->isValid())
+        smallest = m_treeIterator.get();
+
+    if (m_dbIterator->isValid()) {
+        if (!smallest || m_comparator->compare(m_dbIterator->key(), smallest->key()) < 0)
+            smallest = m_dbIterator.get();
+    }
+
+    m_current = smallest;
+}
+
+void LevelDBTransaction::TransactionIterator::setCurrentIteratorToLargestKey()
+{
+    LevelDBIterator* largest = 0;
+
+    if (m_treeIterator->isValid())
+        largest = m_treeIterator.get();
+
+    if (m_dbIterator->isValid()) {
+        if (!largest || m_comparator->compare(m_dbIterator->key(), largest->key()) > 0)
+            largest = m_dbIterator.get();
+    }
+
+    m_current = largest;
+}
+
+void LevelDBTransaction::registerIterator(TreeIterator* iterator)
+{
+    ASSERT(!m_treeIterators.contains(iterator));
+    m_treeIterators.add(iterator);
+}
+
+void LevelDBTransaction::unregisterIterator(TreeIterator* iterator)
+{
+    ASSERT(m_treeIterators.contains(iterator));
+    m_treeIterators.remove(iterator);
+}
+
+void LevelDBTransaction::resetIterators()
+{
+    for (HashSet<TreeIterator*>::iterator i = m_treeIterators.begin(); i != m_treeIterators.end(); ++i) {
+        TreeIterator* treeIterator = *i;
+        treeIterator->reset();
+    }
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(LEVELDB)
+#endif // ENABLE(INDEXED_DATABASE)
diff --git a/Source/WebCore/platform/leveldb/LevelDBTransaction.h b/Source/WebCore/platform/leveldb/LevelDBTransaction.h
new file mode 100644 (file)
index 0000000..72e862b
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LevelDBTransaction_h
+#define LevelDBTransaction_h
+
+#if ENABLE(INDEXED_DATABASE)
+#if ENABLE(LEVELDB)
+
+#include "LevelDBComparator.h"
+#include "LevelDBIterator.h"
+#include "LevelDBSlice.h"
+#include <wtf/AVLTree.h>
+#include <wtf/HashSet.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class LevelDBDatabase;
+
+using WTF::AVLTree;
+
+class LevelDBTransaction : public RefCounted<LevelDBTransaction> {
+public:
+    static PassRefPtr<LevelDBTransaction> create(LevelDBDatabase*);
+
+    ~LevelDBTransaction();
+    bool put(const LevelDBSlice& key, const Vector<char>& value);
+    bool remove(const LevelDBSlice& key);
+    bool get(const LevelDBSlice& key, Vector<char>& value);
+    bool commit();
+    void rollback();
+
+    PassOwnPtr<LevelDBIterator> createIterator();
+
+private:
+    LevelDBTransaction(LevelDBDatabase*);
+
+    struct AVLTreeNode {
+        Vector<char> key;
+        Vector<char> value;
+        bool deleted;
+
+        AVLTreeNode* less;
+        AVLTreeNode* greater;
+        int balanceFactor;
+    };
+
+    struct AVLTreeAbstractor {
+        typedef AVLTreeNode* handle;
+        typedef size_t size;
+        typedef LevelDBSlice key;
+
+        handle get_less(handle h) { return h->less; }
+        void set_less(handle h, handle less) { h->less = less; }
+        handle get_greater(handle h) { return h->greater; }
+        void set_greater(handle h, handle greater) { h->greater = greater; }
+
+        int get_balance_factor(handle h) { return h->balanceFactor; }
+        void set_balance_factor(handle h, int bf) { h->balanceFactor = bf; }
+
+        int compare_key_key(const key& ka, const key& kb) { return m_comparator->compare(ka, kb); }
+        int compare_key_node(const key& k, handle h) { return compare_key_key(k, h->key); }
+        int compare_node_node(handle ha, handle hb) { return compare_key_key(ha->key, hb->key); }
+
+        static handle null() { return 0; }
+
+        const LevelDBComparator* m_comparator;
+    };
+
+    typedef AVLTree<AVLTreeAbstractor> TreeType;
+
+    class TreeIterator : public LevelDBIterator {
+    public:
+        static PassOwnPtr<TreeIterator> create(LevelDBTransaction*);
+        ~TreeIterator();
+
+        virtual bool isValid() const;
+        virtual void seekToLast();
+        virtual void seek(const LevelDBSlice&);
+        virtual void next();
+        virtual void prev();
+        virtual LevelDBSlice key() const;
+        virtual LevelDBSlice value() const;
+        bool isDeleted() const;
+        void reset();
+
+    private:
+        TreeIterator(LevelDBTransaction*);
+        mutable TreeType::Iterator m_iterator; // Dereferencing this is non-const.
+        TreeType* m_tree;
+        LevelDBTransaction* m_transaction;
+        Vector<char> m_key;
+    };
+
+    class TransactionIterator : public LevelDBIterator {
+    public:
+        ~TransactionIterator() { };
+        static PassOwnPtr<TransactionIterator> create(PassRefPtr<LevelDBTransaction>);
+
+        virtual bool isValid() const;
+        virtual void seekToLast();
+        virtual void seek(const LevelDBSlice& target);
+        virtual void next();
+        virtual void prev();
+        virtual LevelDBSlice key() const;
+        virtual LevelDBSlice value() const;
+
+    private:
+        TransactionIterator(PassRefPtr<LevelDBTransaction>);
+        void handleConflictsAndDeletes();
+        void setCurrentIteratorToSmallestKey();
+        void setCurrentIteratorToLargestKey();
+
+        RefPtr<LevelDBTransaction> m_transaction;
+        const LevelDBComparator* m_comparator;
+        OwnPtr<TreeIterator> m_treeIterator;
+        OwnPtr<LevelDBIterator> m_dbIterator;
+        LevelDBIterator* m_current;
+
+        enum Direction {
+            kForward,
+            kReverse
+        };
+        Direction m_direction;
+    };
+
+    bool set(const LevelDBSlice& key, const Vector<char>& value, bool deleted);
+    void clearTree();
+    void registerIterator(TreeIterator*);
+    void unregisterIterator(TreeIterator*);
+    void resetIterators();
+
+    LevelDBDatabase* m_db;
+    const LevelDBComparator* m_comparator;
+    TreeType m_tree;
+    bool m_finished;
+    HashSet<TreeIterator*> m_treeIterators;
+};
+
+}
+
+#endif // ENABLE(LEVELDB)
+#endif // ENABLE(INDEXED_DATABASE)
+
+#endif // LevelDBTransaction_h
  */
 
 #include "config.h"
-#include "LevelDBIterator.h"
+#include "LevelDBWriteBatch.h"
 
 #if ENABLE(LEVELDB)
 
-#include <leveldb/iterator.h>
+#include "LevelDBSlice.h"
 #include <leveldb/slice.h>
-#include <wtf/PassOwnPtr.h>
-#include <wtf/text/CString.h>
-#include <wtf/text/WTFString.h>
+#include <leveldb/write_batch.h>
 
 namespace WebCore {
 
-LevelDBIterator::~LevelDBIterator()
+PassOwnPtr<LevelDBWriteBatch> LevelDBWriteBatch::create()
 {
+    return adoptPtr(new LevelDBWriteBatch);
 }
 
-LevelDBIterator::LevelDBIterator(PassOwnPtr<leveldb::Iterator> it)
-    : m_iterator(it)
+LevelDBWriteBatch::LevelDBWriteBatch()
+    : m_writeBatch(adoptPtr(new leveldb::WriteBatch))
 {
 }
 
-static leveldb::Slice makeSlice(const Vector<char>& value)
+LevelDBWriteBatch::~LevelDBWriteBatch()
 {
-    return leveldb::Slice(value.data(), value.size());
 }
 
-static LevelDBSlice makeLevelDBSlice(leveldb::Slice s)
+static leveldb::Slice makeSlice(const LevelDBSlice& s)
 {
-    return LevelDBSlice(s.data(), s.data() + s.size());
+    return leveldb::Slice(s.begin(), s.end() - s.begin());
 }
 
-bool LevelDBIterator::isValid() const
+void LevelDBWriteBatch::put(const LevelDBSlice& key, const LevelDBSlice& value)
 {
-    return m_iterator->Valid();
+    m_writeBatch->Put(makeSlice(key), makeSlice(value));
 }
 
-void LevelDBIterator::seekToLast()
+void LevelDBWriteBatch::remove(const LevelDBSlice& key)
 {
-    m_iterator->SeekToLast();
+    m_writeBatch->Delete(makeSlice(key));
 }
 
-void LevelDBIterator::seek(const Vector<char>& target)
+void LevelDBWriteBatch::clear()
 {
-    m_iterator->Seek(makeSlice(target));
+    m_writeBatch->Clear();
 }
 
-void LevelDBIterator::next()
-{
-    m_iterator->Next();
-}
-
-void LevelDBIterator::prev()
-{
-    m_iterator->Prev();
 }
 
-LevelDBSlice LevelDBIterator::key() const
-{
-    return makeLevelDBSlice(m_iterator->key());
-}
-
-LevelDBSlice LevelDBIterator::value() const
-{
-    return makeLevelDBSlice(m_iterator->value());
-}
-
-} // namespace WebCore
-
-#endif // ENABLE(LEVELDB)
+#endif
diff --git a/Source/WebCore/platform/leveldb/LevelDBWriteBatch.h b/Source/WebCore/platform/leveldb/LevelDBWriteBatch.h
new file mode 100644 (file)
index 0000000..af8e0c4
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LevelDBWriteBatch_h
+#define LevelDBWriteBatch_h
+
+#if ENABLE(LEVELDB)
+
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace leveldb {
+class WriteBatch;
+}
+
+namespace WebCore {
+
+class LevelDBSlice;
+
+// Wrapper around leveldb::WriteBatch.
+// This class holds a collection of updates to apply atomically to a database.
+class LevelDBWriteBatch {
+public:
+    static PassOwnPtr<LevelDBWriteBatch> create();
+    ~LevelDBWriteBatch();
+
+    void put(const LevelDBSlice& key, const LevelDBSlice& value);
+    void remove(const LevelDBSlice& key); // Add remove operation to the batch.
+    void clear();
+
+private:
+    friend class LevelDBDatabase;
+    LevelDBWriteBatch();
+
+    OwnPtr<leveldb::WriteBatch> m_writeBatch;
+};
+
+}
+
+#endif // ENABLE(LEVELDB)
+#endif // LevelDBWriteBatch_h
index 3b0dd33..04b57e7 100644 (file)
@@ -38,6 +38,7 @@
 #include "LevelDBDatabase.h"
 #include "LevelDBIterator.h"
 #include "LevelDBSlice.h"
+#include "LevelDBTransaction.h"
 #include "SecurityOrigin.h"
 
 #ifndef INT64_MAX
@@ -49,7 +50,8 @@ namespace WebCore {
 
 using namespace IDBLevelDBCoding;
 
-static bool getInt(LevelDBDatabase* db, const Vector<char>& key, int64_t& foundInt)
+template <typename DBOrTransaction>
+static bool getInt(DBOrTransaction* db, const Vector<char>& key, int64_t& foundInt)
 {
     Vector<char> result;
     if (!db->get(key, result))
@@ -59,12 +61,14 @@ static bool getInt(LevelDBDatabase* db, const Vector<char>& key, int64_t& foundI
     return true;
 }
 
-static bool putInt(LevelDBDatabase* db, const Vector<char>& key, int64_t value)
+template <typename DBOrTransaction>
+static bool putInt(DBOrTransaction* db, const Vector<char>& key, int64_t value)
 {
     return db->put(key, encodeInt(value));
 }
 
-static bool getString(LevelDBDatabase* db, const Vector<char>& key, String& foundString)
+template <typename DBOrTransaction>
+static bool getString(DBOrTransaction* db, const Vector<char>& key, String& foundString)
 {
     Vector<char> result;
     if (!db->get(key, result))
@@ -74,7 +78,8 @@ static bool getString(LevelDBDatabase* db, const Vector<char>& key, String& foun
     return true;
 }
 
-static bool putString(LevelDBDatabase* db, const Vector<char> key, const String& value)
+template <typename DBOrTransaction>
+static bool putString(DBOrTransaction* db, const Vector<char> key, const String& value)
 {
     if (!db->put(key, encodeString(value)))
         return false;
@@ -283,12 +288,12 @@ void IDBLevelDBBackingStore::getObjectStores(int64_t databaseId, Vector<int64_t>
     }
 }
 
-static int64_t getNewObjectStoreId(LevelDBDatabase* db, int64_t databaseId)
+static int64_t getNewObjectStoreId(LevelDBTransaction* transaction, int64_t databaseId)
 {
     const Vector<char> freeListStartKey = ObjectStoreFreeListKey::encode(databaseId, 0);
     const Vector<char> freeListStopKey = ObjectStoreFreeListKey::encode(databaseId, INT64_MAX);
 
-    OwnPtr<LevelDBIterator> it = db->createIterator();
+    OwnPtr<LevelDBIterator> it = transaction->createIterator();
     for (it->seek(freeListStartKey); it->isValid() && compareKeys(it->key(), freeListStopKey) < 0; it->next()) {
         const char* p = it->key().begin();
         const char* limit = it->key().end();
@@ -297,7 +302,7 @@ static int64_t getNewObjectStoreId(LevelDBDatabase* db, int64_t databaseId)
         p = ObjectStoreFreeListKey::decode(p, limit, &freeListKey);
         ASSERT(p);
 
-        bool ok = db->remove(it->key());
+        bool ok = transaction->remove(it->key());
         ASSERT_UNUSED(ok, ok);
 
         return freeListKey.objectStoreId();
@@ -305,13 +310,13 @@ static int64_t getNewObjectStoreId(LevelDBDatabase* db, int64_t databaseId)
 
     int64_t maxObjectStoreId = -1;
     const Vector<char> maxObjectStoreIdKey = DatabaseMetaDataKey::encode(databaseId, DatabaseMetaDataKey::kMaxObjectStoreId);
-    if (!getInt(db, maxObjectStoreIdKey, maxObjectStoreId))
+    if (!getInt(transaction, maxObjectStoreIdKey, maxObjectStoreId))
         maxObjectStoreId = 0;
 
     ASSERT(maxObjectStoreId >= 0);
 
     int64_t objectStoreId = maxObjectStoreId + 1;
-    bool ok = putInt(db, maxObjectStoreIdKey, objectStoreId);
+    bool ok = putInt(transaction, maxObjectStoreIdKey, objectStoreId);
     ASSERT_UNUSED(ok, ok);
 
     return objectStoreId;
@@ -319,7 +324,8 @@ static int64_t getNewObjectStoreId(LevelDBDatabase* db, int64_t databaseId)
 
 bool IDBLevelDBBackingStore::createObjectStore(int64_t databaseId, const String& name, const String& keyPath, bool autoIncrement, int64_t& assignedObjectStoreId)
 {
-    int64_t objectStoreId = getNewObjectStoreId(m_db.get(), databaseId);
+    ASSERT(m_currentTransaction);
+    int64_t objectStoreId = getNewObjectStoreId(m_currentTransaction.get(), databaseId);
 
     const Vector<char> nameKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, 0);
     const Vector<char> keyPathKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, 1);
@@ -329,43 +335,43 @@ bool IDBLevelDBBackingStore::createObjectStore(int64_t databaseId, const String&
     const Vector<char> maxIndexIdKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, 5);
     const Vector<char> namesKey = ObjectStoreNamesKey::encode(databaseId, name);
 
-    bool ok = putString(m_db.get(), nameKey, name);
+    bool ok = putString(m_currentTransaction.get(), nameKey, name);
     if (!ok) {
         LOG_ERROR("Internal Indexed DB error.");
         return false;
     }
 
-    ok = putString(m_db.get(), keyPathKey, keyPath);
+    ok = putString(m_currentTransaction.get(), keyPathKey, keyPath);
     if (!ok) {
         LOG_ERROR("Internal Indexed DB error.");
         return false;
     }
 
-    ok = putInt(m_db.get(), autoIncrementKey, autoIncrement);
+    ok = putInt(m_currentTransaction.get(), autoIncrementKey, autoIncrement);
     if (!ok) {
         LOG_ERROR("Internal Indexed DB error.");
         return false;
     }
 
-    ok = putInt(m_db.get(), evictableKey, false);
+    ok = putInt(m_currentTransaction.get(), evictableKey, false);
     if (!ok) {
         LOG_ERROR("Internal Indexed DB error.");
         return false;
     }
 
-    ok = putInt(m_db.get(), lastVersionKey, 1);
+    ok = putInt(m_currentTransaction.get(), lastVersionKey, 1);
     if (!ok) {
         LOG_ERROR("Internal Indexed DB error.");
         return false;
     }
 
-    ok = putInt(m_db.get(), maxIndexIdKey, kMinimumIndexId);
+    ok = putInt(m_currentTransaction.get(), maxIndexIdKey, kMinimumIndexId);
     if (!ok) {
         LOG_ERROR("Internal Indexed DB error.");
         return false;
     }
 
-    ok = putInt(m_db.get(), namesKey, objectStoreId);
+    ok = putInt(m_currentTransaction.get(), namesKey, objectStoreId);
     if (!ok) {
         LOG_ERROR("Internal Indexed DB error.");
         return false;
@@ -376,12 +382,11 @@ bool IDBLevelDBBackingStore::createObjectStore(int64_t databaseId, const String&
     return true;
 }
 
-static bool deleteRange(LevelDBDatabase* db, const Vector<char>& begin, const Vector<char>& end)
+static bool deleteRange(LevelDBTransaction* transaction, const Vector<char>& begin, const Vector<char>& end)
 {
-    // FIXME: LevelDB may be able to provide a bulk operation that we can do first.
-    OwnPtr<LevelDBIterator> it = db->createIterator();
+    OwnPtr<LevelDBIterator> it = transaction->createIterator();
     for (it->seek(begin); it->isValid() && compareKeys(it->key(), end) < 0; it->next()) {
-        if (!db->remove(it->key()))
+        if (!transaction->remove(it->key()))
             return false;
     }
 
@@ -390,18 +395,20 @@ static bool deleteRange(LevelDBDatabase* db, const Vector<char>& begin, const Ve
 
 void IDBLevelDBBackingStore::deleteObjectStore(int64_t databaseId, int64_t objectStoreId)
 {
+    ASSERT(m_currentTransaction);
+
     String objectStoreName;
-    getString(m_db.get(), ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, 0), objectStoreName);
+    getString(m_currentTransaction.get(), ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, 0), objectStoreName);
 
-    if (!deleteRange(m_db.get(), ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, 0), ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, 6)))
+    if (!deleteRange(m_currentTransaction.get(), ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, 0), ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, 6)))
         return; // FIXME: Report error.
 
-    putString(m_db.get(), ObjectStoreFreeListKey::encode(databaseId, objectStoreId), "");
-    m_db->remove(ObjectStoreNamesKey::encode(databaseId, objectStoreName));
+    putString(m_currentTransaction.get(), ObjectStoreFreeListKey::encode(databaseId, objectStoreId), "");
+    m_currentTransaction->remove(ObjectStoreNamesKey::encode(databaseId, objectStoreName));
 
-    if (!deleteRange(m_db.get(), IndexFreeListKey::encode(databaseId, objectStoreId, 0), IndexFreeListKey::encode(databaseId, objectStoreId, INT64_MAX)))
+    if (!deleteRange(m_currentTransaction.get(), IndexFreeListKey::encode(databaseId, objectStoreId, 0), IndexFreeListKey::encode(databaseId, objectStoreId, INT64_MAX)))
         return; // FIXME: Report error.
-    if (!deleteRange(m_db.get(), IndexMetaDataKey::encode(databaseId, objectStoreId, 0, 0), IndexMetaDataKey::encode(databaseId, objectStoreId, INT64_MAX, 0)))
+    if (!deleteRange(m_currentTransaction.get(), IndexMetaDataKey::encode(databaseId, objectStoreId, 0, 0), IndexMetaDataKey::encode(databaseId, objectStoreId, INT64_MAX, 0)))
         return; // FIXME: Report error.
 
     clearObjectStore(databaseId, objectStoreId);
@@ -412,7 +419,8 @@ String IDBLevelDBBackingStore::getObjectStoreRecord(int64_t databaseId, int64_t
     const Vector<char> leveldbKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, key);
     Vector<char> data;
 
-    if (!m_db->get(leveldbKey, data))
+    ASSERT(m_currentTransaction);
+    if (!m_currentTransaction->get(leveldbKey, data))
         return String();
 
     int64_t version;
@@ -445,18 +453,18 @@ private:
 };
 }
 
-static int64_t getNewVersionNumber(LevelDBDatabase* db, int64_t databaseId, int64_t objectStoreId)
+static int64_t getNewVersionNumber(LevelDBTransaction* transaction, int64_t databaseId, int64_t objectStoreId)
 {
     const Vector<char> lastVersionKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, 4);
 
     int64_t lastVersion = -1;
-    if (!getInt(db, lastVersionKey, lastVersion))
+    if (!getInt(transaction, lastVersionKey, lastVersion))
         lastVersion = 0;
 
     ASSERT(lastVersion >= 0);
 
     int64_t version = lastVersion + 1;
-    bool ok = putInt(db, lastVersionKey, version);
+    bool ok = putInt(transaction, lastVersionKey, version);
     ASSERT_UNUSED(ok, ok);
 
     ASSERT(version > lastVersion); // FIXME: Think about how we want to handle the overflow scenario.
@@ -466,18 +474,19 @@ static int64_t getNewVersionNumber(LevelDBDatabase* db, int64_t databaseId, int6
 
 bool IDBLevelDBBackingStore::putObjectStoreRecord(int64_t databaseId, int64_t objectStoreId, const IDBKey& key, const String& value, ObjectStoreRecordIdentifier* recordIdentifier)
 {
-    int64_t version = getNewVersionNumber(m_db.get(), databaseId, objectStoreId);
+    ASSERT(m_currentTransaction);
+    int64_t version = getNewVersionNumber(m_currentTransaction.get(), databaseId, objectStoreId);
     const Vector<char> objectStoredataKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, key);
 
     Vector<char> v;
     v.append(encodeVarInt(version));
     v.append(encodeString(value));
 
-    if (!m_db->put(objectStoredataKey, v))
+    if (!m_currentTransaction->put(objectStoredataKey, v))
         return false;
 
     const Vector<char> existsEntryKey = ExistsEntryKey::encode(databaseId, objectStoreId, key);
-    if (!m_db->put(existsEntryKey, encodeInt(version)))
+    if (!m_currentTransaction->put(existsEntryKey, encodeInt(version)))
         return false;
 
     LevelDBRecordIdentifier* levelDBRecordIdentifier = static_cast<LevelDBRecordIdentifier*>(recordIdentifier);
@@ -488,10 +497,11 @@ bool IDBLevelDBBackingStore::putObjectStoreRecord(int64_t databaseId, int64_t ob
 
 void IDBLevelDBBackingStore::clearObjectStore(int64_t databaseId, int64_t objectStoreId)
 {
+    ASSERT(m_currentTransaction);
     const Vector<char> startKey = KeyPrefix(databaseId, objectStoreId, 0).encode();
     const Vector<char> stopKey = KeyPrefix(databaseId, objectStoreId + 1, 0).encode();
 
-    deleteRange(m_db.get(), startKey, stopKey);
+    deleteRange(m_currentTransaction.get(), startKey, stopKey);
 }
 
 PassRefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> IDBLevelDBBackingStore::createInvalidRecordIdentifier()
@@ -501,17 +511,19 @@ PassRefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> IDBLevelDBBackingStore:
 
 void IDBLevelDBBackingStore::deleteObjectStoreRecord(int64_t databaseId, int64_t objectStoreId, const ObjectStoreRecordIdentifier* recordIdentifier)
 {
+    ASSERT(m_currentTransaction);
     const LevelDBRecordIdentifier* levelDBRecordIdentifier = static_cast<const LevelDBRecordIdentifier*>(recordIdentifier);
     const Vector<char> key = ObjectStoreDataKey::encode(databaseId, objectStoreId, levelDBRecordIdentifier->primaryKey());
-    m_db->remove(key);
+    m_currentTransaction->remove(key);
 }
 
 double IDBLevelDBBackingStore::nextAutoIncrementNumber(int64_t databaseId, int64_t objectStoreId)
 {
+    ASSERT(m_currentTransaction);
     const Vector<char> startKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, minIDBKey());
     const Vector<char> stopKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, maxIDBKey());
 
-    OwnPtr<LevelDBIterator> it = m_db->createIterator();
+    OwnPtr<LevelDBIterator> it = m_currentTransaction->createIterator();
 
     int maxNumericKey = 0;
 
@@ -537,10 +549,11 @@ double IDBLevelDBBackingStore::nextAutoIncrementNumber(int64_t databaseId, int64
 
 bool IDBLevelDBBackingStore::keyExistsInObjectStore(int64_t databaseId, int64_t objectStoreId, const IDBKey& key, ObjectStoreRecordIdentifier* foundRecordIdentifier)
 {
+    ASSERT(m_currentTransaction);
     const Vector<char> leveldbKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, key);
     Vector<char> data;
 
-    if (!m_db->get(leveldbKey, data))
+    if (!m_currentTransaction->get(leveldbKey, data))
         return false;
 
     int64_t version;
@@ -555,10 +568,11 @@ bool IDBLevelDBBackingStore::keyExistsInObjectStore(int64_t databaseId, int64_t
 
 bool IDBLevelDBBackingStore::forEachObjectStoreRecord(int64_t databaseId, int64_t objectStoreId, ObjectStoreRecordCallback& callback)
 {
+    ASSERT(m_currentTransaction);
     const Vector<char> startKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, minIDBKey());
     const Vector<char> stopKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, maxIDBKey());
 
-    OwnPtr<LevelDBIterator> it = m_db->createIterator();
+    OwnPtr<LevelDBIterator> it = m_currentTransaction->createIterator();
     for (it->seek(startKey); it->isValid() && compareKeys(it->key(), stopKey) < 0; it->next()) {
         const char *p = it->key().begin();
         const char *limit = it->key().end();
@@ -622,12 +636,12 @@ void IDBLevelDBBackingStore::getIndexes(int64_t databaseId, int64_t objectStoreI
     }
 }
 
-static int64_t getNewIndexId(LevelDBDatabase* db, int64_t databaseId, int64_t objectStoreId)
+static int64_t getNewIndexId(LevelDBTransaction* transaction, int64_t databaseId, int64_t objectStoreId)
 {
     const Vector<char> startKey = IndexFreeListKey::encode(databaseId, objectStoreId, 0);
     const Vector<char> stopKey = IndexFreeListKey::encode(databaseId, objectStoreId, INT64_MAX);
 
-    OwnPtr<LevelDBIterator> it = db->createIterator();
+    OwnPtr<LevelDBIterator> it = transaction->createIterator();
     for (it->seek(startKey); it->isValid() && compareKeys(it->key(), stopKey) < 0; it->next()) {
         const char* p = it->key().begin();
         const char* limit = it->key().end();
@@ -636,7 +650,7 @@ static int64_t getNewIndexId(LevelDBDatabase* db, int64_t databaseId, int64_t ob
         p = IndexFreeListKey::decode(p, limit, &freeListKey);
         ASSERT(p);
 
-        bool ok = db->remove(it->key());
+        bool ok = transaction->remove(it->key());
         ASSERT_UNUSED(ok, ok);
 
         ASSERT(freeListKey.indexId() >= kMinimumIndexId);
@@ -645,13 +659,13 @@ static int64_t getNewIndexId(LevelDBDatabase* db, int64_t databaseId, int64_t ob
 
     int64_t maxIndexId = -1;
     const Vector<char> maxIndexIdKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, 5);
-    if (!getInt(db, maxIndexIdKey, maxIndexId))
+    if (!getInt(transaction, maxIndexIdKey, maxIndexId))
         maxIndexId = kMinimumIndexId;
 
     ASSERT(maxIndexId >= 0);
 
     int64_t indexId = maxIndexId + 1;
-    bool ok = putInt(db, maxIndexIdKey, indexId);
+    bool ok = putInt(transaction, maxIndexIdKey, indexId);
     if (!ok)
         return false;
 
@@ -660,25 +674,26 @@ static int64_t getNewIndexId(LevelDBDatabase* db, int64_t databaseId, int64_t ob
 
 bool IDBLevelDBBackingStore::createIndex(int64_t databaseId, int64_t objectStoreId, const String& name, const String& keyPath, bool isUnique, int64_t& indexId)
 {
-    indexId = getNewIndexId(m_db.get(), databaseId, objectStoreId);
+    ASSERT(m_currentTransaction);
+    indexId = getNewIndexId(m_currentTransaction.get(), databaseId, objectStoreId);
 
     const Vector<char> nameKey = IndexMetaDataKey::encode(databaseId, objectStoreId, indexId, 0);
     const Vector<char> uniqueKey = IndexMetaDataKey::encode(databaseId, objectStoreId, indexId, 1);
     const Vector<char> keyPathKey = IndexMetaDataKey::encode(databaseId, objectStoreId, indexId, 2);
 
-    bool ok = putString(m_db.get(), nameKey, name);
+    bool ok = putString(m_currentTransaction.get(), nameKey, name);
     if (!ok) {
         LOG_ERROR("Internal Indexed DB error.");
         return false;
     }
 
-    ok = putInt(m_db.get(), uniqueKey, isUnique);
+    ok = putInt(m_currentTransaction.get(), uniqueKey, isUnique);
     if (!ok) {
         LOG_ERROR("Internal Indexed DB error.");
         return false;
     }
 
-    ok = putString(m_db.get(), keyPathKey, keyPath);
+    ok = putString(m_currentTransaction.get(), keyPathKey, keyPath);
     if (!ok) {
         LOG_ERROR("Internal Indexed DB error.");
         return false;
@@ -698,19 +713,20 @@ bool IDBLevelDBBackingStore::putIndexDataForRecord(int64_t databaseId, int64_t o
     ASSERT(indexId >= kMinimumIndexId);
     const LevelDBRecordIdentifier* levelDBRecordIdentifier = static_cast<const LevelDBRecordIdentifier*>(recordIdentifier);
 
-    const int64_t globalSequenceNumber = getNewVersionNumber(m_db.get(), databaseId, objectStoreId);
+    ASSERT(m_currentTransaction);
+    const int64_t globalSequenceNumber = getNewVersionNumber(m_currentTransaction.get(), databaseId, objectStoreId);
     const Vector<char> indexDataKey = IndexDataKey::encode(databaseId, objectStoreId, indexId, key, globalSequenceNumber);
 
     Vector<char> data;
     data.append(encodeVarInt(levelDBRecordIdentifier->version()));
     data.append(levelDBRecordIdentifier->primaryKey());
 
-    return m_db->put(indexDataKey, data);
+    return m_currentTransaction->put(indexDataKey, data);
 }
 
-static bool findGreatestKeyLessThan(LevelDBDatabase* db, const Vector<char>& target, Vector<char>& foundKey)
+static bool findGreatestKeyLessThan(LevelDBTransaction* transaction, const Vector<char>& target, Vector<char>& foundKey)
 {
-    OwnPtr<LevelDBIterator> it = db->createIterator();
+    OwnPtr<LevelDBIterator> it = transaction->createIterator();
     it->seek(target);
 
     if (!it->isValid()) {
@@ -745,12 +761,12 @@ String IDBLevelDBBackingStore::getObjectViaIndex(int64_t databaseId, int64_t obj
     return getObjectStoreRecord(databaseId, objectStoreId, *primaryKey);
 }
 
-static bool versionExists(LevelDBDatabase* db, int64_t databaseId, int64_t objectStoreId, int64_t version, const Vector<char>& encodedPrimaryKey)
+static bool versionExists(LevelDBTransaction* transaction, int64_t databaseId, int64_t objectStoreId, int64_t version, const Vector<char>& encodedPrimaryKey)
 {
     const Vector<char> key = ExistsEntryKey::encode(databaseId, objectStoreId, encodedPrimaryKey);
     Vector<char> data;
 
-    if (!db->get(key, data))
+    if (!transaction->get(key, data))
         return false;
 
     return decodeInt(data.begin(), data.end()) == version;
@@ -758,8 +774,9 @@ static bool versionExists(LevelDBDatabase* db, int64_t databaseId, int64_t objec
 
 PassRefPtr<IDBKey> IDBLevelDBBackingStore::getPrimaryKeyViaIndex(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey& key)
 {
+    ASSERT(m_currentTransaction);
     const Vector<char> leveldbKey = IndexDataKey::encode(databaseId, objectStoreId, indexId, key, 0);
-    OwnPtr<LevelDBIterator> it = m_db->createIterator();
+    OwnPtr<LevelDBIterator> it = m_currentTransaction->createIterator();
     it->seek(leveldbKey);
 
     for (;;) {
@@ -775,9 +792,9 @@ PassRefPtr<IDBKey> IDBLevelDBBackingStore::getPrimaryKeyViaIndex(int64_t databas
         Vector<char> encodedPrimaryKey;
         encodedPrimaryKey.append(p, it->value().end() - p);
 
-        if (!versionExists(m_db.get(), databaseId, objectStoreId, version, encodedPrimaryKey)) {
+        if (!versionExists(m_currentTransaction.get(), databaseId, objectStoreId, version, encodedPrimaryKey)) {
             // Delete stale index data entry and continue.
-            m_db->remove(it->key());
+            m_currentTransaction->remove(it->key());
             it->next();
             continue;
         }
@@ -790,8 +807,9 @@ PassRefPtr<IDBKey> IDBLevelDBBackingStore::getPrimaryKeyViaIndex(int64_t databas
 
 bool IDBLevelDBBackingStore::keyExistsInIndex(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey& key)
 {
+    ASSERT(m_currentTransaction);
     const Vector<char> levelDBKey = IndexDataKey::encode(databaseId, objectStoreId, indexId, key, 0);
-    OwnPtr<LevelDBIterator> it = m_db->createIterator();
+    OwnPtr<LevelDBIterator> it = m_currentTransaction->createIterator();
 
     bool found = false;
 
@@ -818,8 +836,8 @@ public:
     bool firstSeek();
 
 protected:
-    CursorImplCommon(LevelDBDatabase* db, const Vector<char>& lowKey, bool lowOpen, const Vector<char>& highKey, bool highOpen, bool forward)
-        : m_db(db)
+    CursorImplCommon(LevelDBTransaction* transaction, const Vector<char>& lowKey, bool lowOpen, const Vector<char>& highKey, bool highOpen, bool forward)
+        : m_transaction(transaction)
         , m_lowKey(lowKey)
         , m_lowOpen(lowOpen)
         , m_highKey(highKey)
@@ -829,7 +847,7 @@ protected:
     }
     virtual ~CursorImplCommon() {}
 
-    LevelDBDatabase* m_db;
+    LevelDBTransaction* m_transaction;
     OwnPtr<LevelDBIterator> m_iterator;
     Vector<char> m_lowKey;
     bool m_lowOpen;
@@ -841,7 +859,7 @@ protected:
 
 bool CursorImplCommon::firstSeek()
 {
-    m_iterator = m_db->createIterator();
+    m_iterator = m_transaction->createIterator();
 
     if (m_forward)
         m_iterator->seek(m_lowKey);
@@ -902,7 +920,7 @@ bool CursorImplCommon::continueFunction(const IDBKey* key)
             return false;
 
         Vector<char> trash;
-        if (!m_db->get(m_iterator->key(), trash))
+        if (!m_transaction->get(m_iterator->key(), trash))
              continue;
 
         if (m_forward && m_highOpen && compareIndexKeys(m_iterator->key(), m_highKey) >= 0) // high key not included in range
@@ -937,9 +955,9 @@ bool CursorImplCommon::continueFunction(const IDBKey* key)
 
 class ObjectStoreCursorImpl : public CursorImplCommon {
 public:
-    static PassRefPtr<ObjectStoreCursorImpl> create(LevelDBDatabase* db, const Vector<char>& lowKey, bool lowOpen, const Vector<char>& highKey, bool highOpen, bool forward)
+    static PassRefPtr<ObjectStoreCursorImpl> create(LevelDBTransaction* transaction, const Vector<char>& lowKey, bool lowOpen, const Vector<char>& highKey, bool highOpen, bool forward)
     {
-        return adoptRef(new ObjectStoreCursorImpl(db, lowKey, lowOpen, highKey, highOpen, forward));
+        return adoptRef(new ObjectStoreCursorImpl(transaction, lowKey, lowOpen, highKey, highOpen, forward));
     }
 
     // CursorImplCommon
@@ -949,8 +967,8 @@ public:
     virtual bool loadCurrentRow();
 
 private:
-    ObjectStoreCursorImpl(LevelDBDatabase* db, const Vector<char>& lowKey, bool lowOpen, const Vector<char>& highKey, bool highOpen, bool forward)
-        : CursorImplCommon(db, lowKey, lowOpen, highKey, highOpen, forward)
+    ObjectStoreCursorImpl(LevelDBTransaction* transaction, const Vector<char>& lowKey, bool lowOpen, const Vector<char>& highKey, bool highOpen, bool forward)
+        : CursorImplCommon(transaction, lowKey, lowOpen, highKey, highOpen, forward)
     {
     }
 
@@ -984,9 +1002,9 @@ bool ObjectStoreCursorImpl::loadCurrentRow()
 
 class IndexKeyCursorImpl : public CursorImplCommon {
 public:
-    static PassRefPtr<IndexKeyCursorImpl> create(LevelDBDatabase* db, const Vector<char>& lowKey, bool lowOpen, const Vector<char>& highKey, bool highOpen, bool forward)
+    static PassRefPtr<IndexKeyCursorImpl> create(LevelDBTransaction* transaction, const Vector<char>& lowKey, bool lowOpen, const Vector<char>& highKey, bool highOpen, bool forward)
     {
-        return adoptRef(new IndexKeyCursorImpl(db, lowKey, lowOpen, highKey, highOpen, forward));
+        return adoptRef(new IndexKeyCursorImpl(transaction, lowKey, lowOpen, highKey, highOpen, forward));
     }
 
     // CursorImplCommon
@@ -997,8 +1015,8 @@ public:
     virtual bool loadCurrentRow();
 
 private:
-    IndexKeyCursorImpl(LevelDBDatabase* db, const Vector<char>& lowKey, bool lowOpen, const Vector<char>& highKey, bool highOpen, bool forward)
-        : CursorImplCommon(db, lowKey, lowOpen, highKey, highOpen, forward)
+    IndexKeyCursorImpl(LevelDBTransaction* transaction, const Vector<char>& lowKey, bool lowOpen, const Vector<char>& highKey, bool highOpen, bool forward)
+        : CursorImplCommon(transaction, lowKey, lowOpen, highKey, highOpen, forward)
     {
     }
 
@@ -1028,7 +1046,7 @@ bool IndexKeyCursorImpl::loadCurrentRow()
     Vector<char> primaryLevelDBKey = ObjectStoreDataKey::encode(indexDataKey.databaseId(), indexDataKey.objectStoreId(), *m_primaryKey);
 
     Vector<char> result;
-    if (!m_db->get(primaryLevelDBKey, result))
+    if (!m_transaction->get(primaryLevelDBKey, result))
         return false;
 
     int64_t objectStoreDataVersion;
@@ -1038,7 +1056,7 @@ bool IndexKeyCursorImpl::loadCurrentRow()
         return false;
 
     if (objectStoreDataVersion != indexDataVersion) { // FIXME: This is probably not very well covered by the layout tests.
-        m_db->remove(m_iterator->key());
+        m_transaction->remove(m_iterator->key());
         return false;
     }
 
@@ -1047,9 +1065,9 @@ bool IndexKeyCursorImpl::loadCurrentRow()
 
 class IndexCursorImpl : public CursorImplCommon {
 public:
-    static PassRefPtr<IndexCursorImpl> create(LevelDBDatabase* db, const Vector<char>& lowKey, bool lowOpen, const Vector<char>& highKey, bool highOpen, bool forward)
+    static PassRefPtr<IndexCursorImpl> create(LevelDBTransaction* transaction, const Vector<char>& lowKey, bool lowOpen, const Vector<char>& highKey, bool highOpen, bool forward)
     {
-        return adoptRef(new IndexCursorImpl(db, lowKey, lowOpen, highKey, highOpen, forward));
+        return adoptRef(new IndexCursorImpl(transaction, lowKey, lowOpen, highKey, highOpen, forward));
     }
 
     // CursorImplCommon
@@ -1060,8 +1078,8 @@ public:
     bool loadCurrentRow();
 
 private:
-    IndexCursorImpl(LevelDBDatabase* db, const Vector<char>& lowKey, bool lowOpen, const Vector<char>& highKey, bool highOpen, bool forward)
-        : CursorImplCommon(db, lowKey, lowOpen, highKey, highOpen, forward)
+    IndexCursorImpl(LevelDBTransaction* transaction, const Vector<char>& lowKey, bool lowOpen, const Vector<char>& highKey, bool highOpen, bool forward)
+        : CursorImplCommon(transaction, lowKey, lowOpen, highKey, highOpen, forward)
     {
     }
 
@@ -1096,7 +1114,7 @@ bool IndexCursorImpl::loadCurrentRow()
     m_primaryLevelDBKey = ObjectStoreDataKey::encode(indexDataKey.databaseId(), indexDataKey.objectStoreId(), *m_primaryKey);
 
     Vector<char> result;
-    if (!m_db->get(m_primaryLevelDBKey, result))
+    if (!m_transaction->get(m_primaryLevelDBKey, result))
         return false;
 
     int64_t objectStoreDataVersion;
@@ -1106,7 +1124,7 @@ bool IndexCursorImpl::loadCurrentRow()
         return false;
 
     if (objectStoreDataVersion != indexDataVersion) {
-        m_db->remove(m_iterator->key());
+        m_transaction->remove(m_iterator->key());
         return false;
     }
 
@@ -1116,9 +1134,9 @@ bool IndexCursorImpl::loadCurrentRow()
 
 }
 
-static bool findLastIndexKeyEqualTo(LevelDBDatabase* db, const Vector<char>& target, Vector<char>& foundKey)
+static bool findLastIndexKeyEqualTo(LevelDBTransaction* transaction, const Vector<char>& target, Vector<char>& foundKey)
 {
-    OwnPtr<LevelDBIterator> it = db->createIterator();
+    OwnPtr<LevelDBIterator> it = transaction->createIterator();
     it->seek(target);
 
     if (!it->isValid())
@@ -1135,6 +1153,7 @@ static bool findLastIndexKeyEqualTo(LevelDBDatabase* db, const Vector<char>& tar
 
 PassRefPtr<IDBBackingStore::Cursor> IDBLevelDBBackingStore::openObjectStoreCursor(int64_t databaseId, int64_t objectStoreId, const IDBKeyRange* range, IDBCursor::Direction direction)
 {
+    ASSERT(m_currentTransaction);
     bool lowerBound = range && range->lower();
     bool upperBound = range && range->upper();
     bool forward = (direction == IDBCursor::NEXT_NO_DUPLICATE || direction == IDBCursor::NEXT);
@@ -1155,7 +1174,7 @@ PassRefPtr<IDBBackingStore::Cursor> IDBLevelDBBackingStore::openObjectStoreCurso
         upperOpen = true; // Not included.
 
         if (!forward) { // We need a key that exists.
-            if (!findGreatestKeyLessThan(m_db.get(), stopKey, stopKey))
+            if (!findGreatestKeyLessThan(m_currentTransaction.get(), stopKey, stopKey))
                 return 0;
             upperOpen = false;
         }
@@ -1164,7 +1183,7 @@ PassRefPtr<IDBBackingStore::Cursor> IDBLevelDBBackingStore::openObjectStoreCurso
         upperOpen = range->upperOpen();
     }
 
-    RefPtr<ObjectStoreCursorImpl> cursor = ObjectStoreCursorImpl::create(m_db.get(), startKey, lowerOpen, stopKey, upperOpen, forward);
+    RefPtr<ObjectStoreCursorImpl> cursor = ObjectStoreCursorImpl::create(m_currentTransaction.get(), startKey, lowerOpen, stopKey, upperOpen, forward);
     if (!cursor->firstSeek())
         return 0;
 
@@ -1173,6 +1192,7 @@ PassRefPtr<IDBBackingStore::Cursor> IDBLevelDBBackingStore::openObjectStoreCurso
 
 PassRefPtr<IDBBackingStore::Cursor> IDBLevelDBBackingStore::openIndexKeyCursor(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKeyRange* range, IDBCursor::Direction direction)
 {
+    ASSERT(m_currentTransaction);
     bool lowerBound = range && range->lower();
     bool upperBound = range && range->upper();
     bool forward = (direction == IDBCursor::NEXT_NO_DUPLICATE || direction == IDBCursor::NEXT);
@@ -1193,18 +1213,18 @@ PassRefPtr<IDBBackingStore::Cursor> IDBLevelDBBackingStore::openIndexKeyCursor(i
         upperOpen = false; // Included.
 
         if (!forward) { // We need a key that exists.
-            if (!findGreatestKeyLessThan(m_db.get(), stopKey, stopKey))
+            if (!findGreatestKeyLessThan(m_currentTransaction.get(), stopKey, stopKey))
                 return 0;
             upperOpen = false;
         }
     } else {
         stopKey = IndexDataKey::encode(databaseId, objectStoreId, indexId, *range->upper(), 0);
-        if (!findLastIndexKeyEqualTo(m_db.get(), stopKey, stopKey)) // Seek to the *last* key in the set of non-unique keys.
+        if (!findLastIndexKeyEqualTo(m_currentTransaction.get(), stopKey, stopKey)) // Seek to the *last* key in the set of non-unique keys.
             return 0;
         upperOpen = range->upperOpen();
     }
 
-    RefPtr<IndexKeyCursorImpl> cursor = IndexKeyCursorImpl::create(m_db.get(), startKey, lowerOpen, stopKey, upperOpen, forward);
+    RefPtr<IndexKeyCursorImpl> cursor = IndexKeyCursorImpl::create(m_currentTransaction.get(), startKey, lowerOpen, stopKey, upperOpen, forward);
     if (!cursor->firstSeek())
         return 0;
 
@@ -1213,6 +1233,7 @@ PassRefPtr<IDBBackingStore::Cursor> IDBLevelDBBackingStore::openIndexKeyCursor(i
 
 PassRefPtr<IDBBackingStore::Cursor> IDBLevelDBBackingStore::openIndexCursor(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKeyRange* range, IDBCursor::Direction direction)
 {
+    ASSERT(m_currentTransaction);
     bool lowerBound = range && range->lower();
     bool upperBound = range && range->upper();
     bool forward = (direction == IDBCursor::NEXT_NO_DUPLICATE || direction == IDBCursor::NEXT);
@@ -1233,37 +1254,57 @@ PassRefPtr<IDBBackingStore::Cursor> IDBLevelDBBackingStore::openIndexCursor(int6
         upperOpen = false; // Included.
 
         if (!forward) { // We need a key that exists.
-            if (!findGreatestKeyLessThan(m_db.get(), stopKey, stopKey))
+            if (!findGreatestKeyLessThan(m_currentTransaction.get(), stopKey, stopKey))
                 return 0;
             upperOpen = false;
         }
     } else {
         stopKey = IndexDataKey::encode(databaseId, objectStoreId, indexId, *range->upper(), 0);
-        if (!findLastIndexKeyEqualTo(m_db.get(), stopKey, stopKey)) // Seek to the *last* key in the set of non-unique keys.
+        if (!findLastIndexKeyEqualTo(m_currentTransaction.get(), stopKey, stopKey)) // Seek to the *last* key in the set of non-unique keys.
             return 0;
         upperOpen = range->upperOpen();
     }
 
-    RefPtr<IndexCursorImpl> cursor = IndexCursorImpl::create(m_db.get(), startKey, lowerOpen, stopKey, upperOpen, forward);
+    RefPtr<IndexCursorImpl> cursor = IndexCursorImpl::create(m_currentTransaction.get(), startKey, lowerOpen, stopKey, upperOpen, forward);
     if (!cursor->firstSeek())
         return 0;
 
     return cursor.release();
 }
 
-namespace {
-class DummyTransaction : public IDBBackingStore::Transaction {
-public:
-    virtual void begin() {}
-    virtual void commit() {}
-    virtual void rollback() {}
-};
+PassRefPtr<IDBBackingStore::Transaction> IDBLevelDBBackingStore::createTransaction()
+{
+    return Transaction::create(this);
 }
 
-PassRefPtr<IDBBackingStore::Transaction> IDBLevelDBBackingStore::createTransaction()
+PassRefPtr<IDBLevelDBBackingStore::Transaction> IDBLevelDBBackingStore::Transaction::create(IDBLevelDBBackingStore* backingStore)
+{
+    return adoptRef(new Transaction(backingStore));
+}
+
+IDBLevelDBBackingStore::Transaction::Transaction(IDBLevelDBBackingStore* backingStore)
+    : m_backingStore(backingStore)
+{
+}
+
+void IDBLevelDBBackingStore::Transaction::begin()
+{
+    ASSERT(!m_backingStore->m_currentTransaction);
+    m_backingStore->m_currentTransaction = LevelDBTransaction::create(m_backingStore->m_db.get());
+}
+
+void IDBLevelDBBackingStore::Transaction::commit()
+{
+    ASSERT(m_backingStore->m_currentTransaction);
+    m_backingStore->m_currentTransaction->commit();
+    m_backingStore->m_currentTransaction.clear();
+}
+
+void IDBLevelDBBackingStore::Transaction::rollback()
 {
-    // FIXME: We need to implement a transaction abstraction that allows for roll-backs, and write tests for it.
-    return adoptRef(new DummyTransaction());
+    ASSERT(m_backingStore->m_currentTransaction);
+    m_backingStore->m_currentTransaction->rollback();
+    m_backingStore->m_currentTransaction.clear();
 }
 
 // FIXME: deleteDatabase should be part of IDBBackingStore.
index 60f621a..98f5ea2 100644 (file)
@@ -36,6 +36,7 @@ namespace WebCore {
 
 class LevelDBComparator;
 class LevelDBDatabase;
+class LevelDBTransaction;
 
 class IDBLevelDBBackingStore : public IDBBackingStore {
 public:
@@ -80,6 +81,19 @@ private:
     RefPtr<IDBFactoryBackendImpl> m_factory;
     OwnPtr<LevelDBDatabase> m_db;
     OwnPtr<LevelDBComparator> m_comparator;
+    RefPtr<LevelDBTransaction> m_currentTransaction;
+
+    class Transaction : public IDBBackingStore::Transaction {
+    public:
+        static PassRefPtr<Transaction> create(IDBLevelDBBackingStore*);
+        virtual void begin();
+        virtual void commit();
+        virtual void rollback();
+
+    private:
+        Transaction(IDBLevelDBBackingStore*);
+        IDBLevelDBBackingStore* m_backingStore;
+    };
 };
 
 } // namespace WebCore
index d736758..156cb89 100644 (file)
@@ -106,6 +106,8 @@ void IDBTransactionBackendImpl::abort()
     if (m_state == Finished)
         return;
 
+    bool wasRunning = m_state == Running;
+
     // The last reference to this object may be released while performing the
     // abort steps below. We therefore take a self reference to keep ourselves
     // alive while executing this method.
@@ -116,7 +118,8 @@ void IDBTransactionBackendImpl::abort()
     m_taskEventTimer.stop();
 
     closeOpenCursors();
-    m_transaction->rollback();
+    if (wasRunning)
+        m_transaction->rollback();
 
     // Run the abort tasks, if any.
     while (!m_abortTaskQueue.isEmpty()) {