Merge IDBTransactionBackendInterface and IDBTransactionBackendImpl
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / IDBCursorBackend.cpp
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "IDBCursorBackend.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
31 #include "IDBBackingStoreInterface.h"
32 #include "IDBCallbacks.h"
33 #include "IDBDatabaseBackendImpl.h"
34 #include "IDBDatabaseCallbacks.h"
35 #include "IDBDatabaseError.h"
36 #include "IDBDatabaseException.h"
37 #include "IDBKeyRange.h"
38 #include "IDBOperation.h"
39 #include "Logging.h"
40 #include "SharedBuffer.h"
41
42 namespace WebCore {
43
44 class IDBCursorBackend::CursorIterationOperation : public IDBOperation {
45 public:
46     static PassOwnPtr<IDBOperation> create(PassRefPtr<IDBCursorBackend> cursor, PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks)
47     {
48         return adoptPtr(new CursorIterationOperation(cursor, key, callbacks));
49     }
50     virtual void perform() OVERRIDE FINAL;
51 private:
52     CursorIterationOperation(PassRefPtr<IDBCursorBackend> cursor, PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks)
53         : m_cursor(cursor)
54         , m_key(key)
55         , m_callbacks(callbacks)
56     {
57     }
58
59     RefPtr<IDBCursorBackend> m_cursor;
60     RefPtr<IDBKey> m_key;
61     RefPtr<IDBCallbacks> m_callbacks;
62 };
63
64 class IDBCursorBackend::CursorAdvanceOperation : public IDBOperation {
65 public:
66     static PassOwnPtr<IDBOperation> create(PassRefPtr<IDBCursorBackend> cursor, unsigned long count, PassRefPtr<IDBCallbacks> callbacks)
67     {
68         return adoptPtr(new CursorAdvanceOperation(cursor, count, callbacks));
69     }
70     virtual void perform() OVERRIDE FINAL;
71 private:
72     CursorAdvanceOperation(PassRefPtr<IDBCursorBackend> cursor, unsigned long count, PassRefPtr<IDBCallbacks> callbacks)
73         : m_cursor(cursor)
74         , m_count(count)
75         , m_callbacks(callbacks)
76     {
77     }
78
79     RefPtr<IDBCursorBackend> m_cursor;
80     unsigned long m_count;
81     RefPtr<IDBCallbacks> m_callbacks;
82 };
83
84 class IDBCursorBackend::CursorPrefetchIterationOperation : public IDBOperation {
85 public:
86     static PassOwnPtr<IDBOperation> create(PassRefPtr<IDBCursorBackend> cursor, int numberToFetch, PassRefPtr<IDBCallbacks> callbacks)
87     {
88         return adoptPtr(new CursorPrefetchIterationOperation(cursor, numberToFetch, callbacks));
89     }
90     virtual void perform() OVERRIDE FINAL;
91 private:
92     CursorPrefetchIterationOperation(PassRefPtr<IDBCursorBackend> cursor, int numberToFetch, PassRefPtr<IDBCallbacks> callbacks)
93         : m_cursor(cursor)
94         , m_numberToFetch(numberToFetch)
95         , m_callbacks(callbacks)
96     {
97     }
98
99     RefPtr<IDBCursorBackend> m_cursor;
100     int m_numberToFetch;
101     RefPtr<IDBCallbacks> m_callbacks;
102 };
103
104 IDBCursorBackend::IDBCursorBackend(PassRefPtr<IDBBackingStoreCursorInterface> cursor, IndexedDB::CursorType cursorType, IDBDatabaseBackendInterface::TaskType taskType, IDBTransactionBackend* transaction, int64_t objectStoreId)
105     : m_taskType(taskType)
106     , m_cursorType(cursorType)
107     , m_database(&(transaction->database()))
108     , m_transaction(transaction)
109     , m_objectStoreId(objectStoreId)
110     , m_cursor(cursor)
111     , m_closed(false)
112 {
113     m_transaction->registerOpenCursor(this);
114 }
115
116 IDBCursorBackend::~IDBCursorBackend()
117 {
118     m_transaction->unregisterOpenCursor(this);
119 }
120
121
122 void IDBCursorBackend::continueFunction(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode&)
123 {
124     LOG(StorageAPI, "IDBCursorBackend::continue");
125     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
126     m_transaction->scheduleTask(m_taskType, CursorIterationOperation::create(this, key, callbacks));
127 }
128
129 void IDBCursorBackend::advance(unsigned long count, PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode&)
130 {
131     LOG(StorageAPI, "IDBCursorBackend::advance");
132     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
133     m_transaction->scheduleTask(CursorAdvanceOperation::create(this, count, callbacks));
134 }
135
136 void IDBCursorBackend::CursorAdvanceOperation::perform()
137 {
138     LOG(StorageAPI, "CursorAdvanceOperation");
139     if (!m_cursor->m_cursor || !m_cursor->m_cursor->advance(m_count)) {
140         m_cursor->m_cursor = 0;
141         m_callbacks->onSuccess(static_cast<SharedBuffer*>(0));
142         return;
143     }
144
145     m_callbacks->onSuccess(m_cursor->key(), m_cursor->primaryKey(), m_cursor->value());
146 }
147
148 void IDBCursorBackend::CursorIterationOperation::perform()
149 {
150     LOG(StorageAPI, "CursorIterationOperation");
151     if (!m_cursor->m_cursor || !m_cursor->m_cursor->continueFunction(m_key.get())) {
152         m_cursor->m_cursor = 0;
153         m_callbacks->onSuccess(static_cast<SharedBuffer*>(0));
154         return;
155     }
156
157     m_callbacks->onSuccess(m_cursor->key(), m_cursor->primaryKey(), m_cursor->value());
158 }
159
160 void IDBCursorBackend::deleteFunction(PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode&)
161 {
162     LOG(StorageAPI, "IDBCursorBackend::delete");
163     ASSERT(m_transaction->mode() != IndexedDB::TransactionReadOnly);
164     RefPtr<IDBKeyRange> keyRange = IDBKeyRange::create(m_cursor->primaryKey());
165     m_database->deleteRange(m_transaction.get()->id(), m_objectStoreId, keyRange.release(), prpCallbacks);
166 }
167
168 void IDBCursorBackend::prefetchContinue(int numberToFetch, PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode&)
169 {
170     LOG(StorageAPI, "IDBCursorBackend::prefetchContinue");
171     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
172     m_transaction->scheduleTask(m_taskType, CursorPrefetchIterationOperation::create(this, numberToFetch, callbacks));
173 }
174
175 void IDBCursorBackend::CursorPrefetchIterationOperation::perform()
176 {
177     LOG(StorageAPI, "CursorPrefetchIterationOperation");
178
179     Vector<RefPtr<IDBKey>> foundKeys;
180     Vector<RefPtr<IDBKey>> foundPrimaryKeys;
181     Vector<RefPtr<SharedBuffer>> foundValues;
182
183     if (m_cursor->m_cursor)
184         m_cursor->m_savedCursor = m_cursor->m_cursor->clone();
185
186     const size_t maxSizeEstimate = 10 * 1024 * 1024;
187     size_t sizeEstimate = 0;
188
189     for (int i = 0; i < m_numberToFetch; ++i) {
190         if (!m_cursor->m_cursor || !m_cursor->m_cursor->continueFunction(0)) {
191             m_cursor->m_cursor = 0;
192             break;
193         }
194
195         foundKeys.append(m_cursor->m_cursor->key());
196         foundPrimaryKeys.append(m_cursor->m_cursor->primaryKey());
197
198         switch (m_cursor->m_cursorType) {
199         case IndexedDB::CursorKeyOnly:
200             foundValues.append(SharedBuffer::create());
201             break;
202         case IndexedDB::CursorKeyAndValue:
203             sizeEstimate += m_cursor->m_cursor->value()->size();
204             foundValues.append(m_cursor->m_cursor->value());
205             break;
206         default:
207             ASSERT_NOT_REACHED();
208         }
209         sizeEstimate += m_cursor->m_cursor->key()->sizeEstimate();
210         sizeEstimate += m_cursor->m_cursor->primaryKey()->sizeEstimate();
211
212         if (sizeEstimate > maxSizeEstimate)
213             break;
214     }
215
216     if (!foundKeys.size()) {
217         m_callbacks->onSuccess(static_cast<SharedBuffer*>(0));
218         return;
219     }
220
221     m_callbacks->onSuccessWithPrefetch(foundKeys, foundPrimaryKeys, foundValues);
222 }
223
224 void IDBCursorBackend::prefetchReset(int usedPrefetches, int)
225 {
226     LOG(StorageAPI, "IDBCursorBackend::prefetchReset");
227     m_cursor = m_savedCursor;
228     m_savedCursor = 0;
229
230     if (m_closed)
231         return;
232     if (m_cursor) {
233         for (int i = 0; i < usedPrefetches; ++i) {
234             bool ok = m_cursor->continueFunction();
235             ASSERT_UNUSED(ok, ok);
236         }
237     }
238 }
239
240 void IDBCursorBackend::close()
241 {
242     LOG(StorageAPI, "IDBCursorBackend::close");
243     m_closed = true;
244     m_cursor.clear();
245     m_savedCursor.clear();
246 }
247
248 } // namespace WebCore
249
250 #endif // ENABLE(INDEXED_DATABASE)