Merge IDBTransactionBackendInterface and IDBTransactionBackendImpl
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / leveldb / IDBBackingStoreCursorLevelDB.cpp
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
34 namespace WebCore {
35
36 IDBBackingStoreCursorLevelDB::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
54 bool 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
65 bool IDBBackingStoreCursorLevelDB::advance(unsigned long count)
66 {
67     while (count--) {
68         if (!continueFunction())
69             return false;
70     }
71     return true;
72 }
73
74 bool 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
172 bool 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
186 bool 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