1/* 2 * Copyright (C) 2013 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "IDBBackingStoreCursorLevelDB.h" 28 29#if ENABLE(INDEXED_DATABASE) && USE(LEVELDB) 30 31#include "IDBBackingStoreLevelDB.h" 32#include "LevelDBTransaction.h" 33 34namespace WebCore { 35 36IDBBackingStoreCursorLevelDB::IDBBackingStoreCursorLevelDB(const IDBBackingStoreCursorLevelDB* other) 37 : m_transaction(other->m_transaction) 38 , m_cursorOptions(other->m_cursorOptions) 39 , m_currentKey(other->m_currentKey) 40 , m_recordIdentifier(IDBRecordIdentifier::create()) 41{ 42 if (other->m_iterator) { 43 m_iterator = m_transaction->createIterator(); 44 45 if (other->m_iterator->isValid()) { 46 m_iterator->seek(other->m_iterator->key()); 47 ASSERT(m_iterator->isValid()); 48 } 49 } 50 51 m_recordIdentifier->reset(other->m_recordIdentifier->encodedPrimaryKey(), other->m_recordIdentifier->version()); 52} 53 54bool IDBBackingStoreCursorLevelDB::firstSeek() 55{ 56 m_iterator = m_transaction->createIterator(); 57 if (m_cursorOptions.forward) 58 m_iterator->seek(m_cursorOptions.lowKey); 59 else 60 m_iterator->seek(m_cursorOptions.highKey); 61 62 return continueFunction(0, Ready); 63} 64 65bool IDBBackingStoreCursorLevelDB::advance(unsigned long count) 66{ 67 while (count--) { 68 if (!continueFunction()) 69 return false; 70 } 71 return true; 72} 73 74bool IDBBackingStoreCursorLevelDB::continueFunction(const IDBKey* key, IteratorState nextState) 75{ 76 RefPtr<IDBKey> previousKey = m_currentKey; 77 78 bool firstIteration = true; 79 80 // When iterating with PrevNoDuplicate, spec requires that the 81 // value we yield for each key is the first duplicate in forwards 82 // order. 83 RefPtr<IDBKey> lastDuplicateKey; 84 85 bool forward = m_cursorOptions.forward; 86 87 for (;;) { 88 if (nextState == Seek) { 89 // FIXME: Optimize seeking for reverse cursors as well. 90 if (firstIteration && key && forward) { 91 m_iterator->seek(encodeKey(*key)); 92 firstIteration = false; 93 } else if (forward) 94 m_iterator->next(); 95 else 96 m_iterator->prev(); 97 } else 98 nextState = Seek; // for subsequent iterations 99 100 if (!m_iterator->isValid()) { 101 if (!forward && lastDuplicateKey.get()) { 102 // We need to walk forward because we hit the end of 103 // the data. 104 forward = true; 105 continue; 106 } 107 108 return false; 109 } 110 111 if (isPastBounds()) { 112 if (!forward && lastDuplicateKey.get()) { 113 // We need to walk forward because now we're beyond the 114 // bounds defined by the cursor. 115 forward = true; 116 continue; 117 } 118 119 return false; 120 } 121 122 if (!haveEnteredRange()) 123 continue; 124 125 // The row may not load because there's a stale entry in the 126 // index. This is not fatal. 127 if (!loadCurrentRow()) 128 continue; 129 130 if (key) { 131 if (forward) { 132 if (m_currentKey->isLessThan(key)) 133 continue; 134 } else { 135 if (key->isLessThan(m_currentKey.get())) 136 continue; 137 } 138 } 139 140 if (m_cursorOptions.unique) { 141 142 if (m_currentKey->isEqual(previousKey.get())) { 143 // We should never be able to walk forward all the way 144 // to the previous key. 145 ASSERT(!lastDuplicateKey.get()); 146 continue; 147 } 148 149 if (!forward) { 150 if (!lastDuplicateKey.get()) { 151 lastDuplicateKey = m_currentKey; 152 continue; 153 } 154 155 // We need to walk forward because we hit the boundary 156 // between key ranges. 157 if (!lastDuplicateKey->isEqual(m_currentKey.get())) { 158 forward = true; 159 continue; 160 } 161 162 continue; 163 } 164 } 165 break; 166 } 167 168 ASSERT(!lastDuplicateKey.get() || (forward && lastDuplicateKey->isEqual(m_currentKey.get()))); 169 return true; 170} 171 172bool IDBBackingStoreCursorLevelDB::haveEnteredRange() const 173{ 174 if (m_cursorOptions.forward) { 175 if (m_cursorOptions.lowOpen) 176 return IDBBackingStoreLevelDB::compareIndexKeys(m_iterator->key(), m_cursorOptions.lowKey) > 0; 177 178 return IDBBackingStoreLevelDB::compareIndexKeys(m_iterator->key(), m_cursorOptions.lowKey) >= 0; 179 } 180 if (m_cursorOptions.highOpen) 181 return IDBBackingStoreLevelDB::compareIndexKeys(m_iterator->key(), m_cursorOptions.highKey) < 0; 182 183 return IDBBackingStoreLevelDB::compareIndexKeys(m_iterator->key(), m_cursorOptions.highKey) <= 0; 184} 185 186bool IDBBackingStoreCursorLevelDB::isPastBounds() const 187{ 188 if (m_cursorOptions.forward) { 189 if (m_cursorOptions.highOpen) 190 return IDBBackingStoreLevelDB::compareIndexKeys(m_iterator->key(), m_cursorOptions.highKey) >= 0; 191 return IDBBackingStoreLevelDB::compareIndexKeys(m_iterator->key(), m_cursorOptions.highKey) > 0; 192 } 193 194 if (m_cursorOptions.lowOpen) 195 return IDBBackingStoreLevelDB::compareIndexKeys(m_iterator->key(), m_cursorOptions.lowKey) <= 0; 196 return IDBBackingStoreLevelDB::compareIndexKeys(m_iterator->key(), m_cursorOptions.lowKey) < 0; 197} 198 199} // namespace WebCore 200 201#endif // ENABLE(INDEXED_DATABASE) && USE(LEVELDB) 202 203