668466b0fc45957165438d03c308f695cd23a702
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / IDBCursorBackendImpl.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 "IDBCursorBackendImpl.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
31 #include "CrossThreadTask.h"
32 #include "IDBBackingStore.h"
33 #include "IDBCallbacks.h"
34 #include "IDBDatabaseError.h"
35 #include "IDBDatabaseException.h"
36 #include "IDBKeyRange.h"
37 #include "IDBObjectStoreBackendImpl.h"
38 #include "IDBRequest.h"
39 #include "IDBTracing.h"
40 #include "IDBTransactionBackendImpl.h"
41 #include "SerializedScriptValue.h"
42
43 namespace WebCore {
44
45 IDBCursorBackendImpl::IDBCursorBackendImpl(PassRefPtr<IDBBackingStore::Cursor> cursor, CursorType cursorType, IDBTransactionBackendInterface::TaskType taskType, IDBTransactionBackendImpl* transaction, IDBObjectStoreBackendImpl* objectStore)
46     : m_cursor(cursor)
47     , m_taskType(taskType)
48     , m_cursorType(cursorType)
49     , m_transaction(transaction)
50     , m_objectStore(objectStore)
51     , m_closed(false)
52 {
53     m_transaction->registerOpenCursor(this);
54 }
55
56 IDBCursorBackendImpl::~IDBCursorBackendImpl()
57 {
58     m_transaction->unregisterOpenCursor(this);
59     // Order is important, the cursors have to be destructed before the objectStore.
60     m_cursor.clear();
61     m_savedCursor.clear();
62
63     m_objectStore.clear();
64 }
65
66 void IDBCursorBackendImpl::continueFunction(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode&)
67 {
68     IDB_TRACE("IDBCursorBackendImpl::continue");
69     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
70
71     if (!m_transaction->scheduleTask(m_taskType, createCallbackTask(&IDBCursorBackendImpl::continueFunctionInternal, this, prpKey, callbacks)))
72         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR));
73 }
74
75 void IDBCursorBackendImpl::advance(unsigned long count, PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode&)
76 {
77     IDB_TRACE("IDBCursorBackendImpl::advance");
78     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
79
80     if (!m_transaction->scheduleTask(createCallbackTask(&IDBCursorBackendImpl::advanceInternal, this, count, callbacks)))
81         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR));
82 }
83
84 void IDBCursorBackendImpl::advanceInternal(ScriptExecutionContext*, PassRefPtr<IDBCursorBackendImpl> prpCursor, unsigned long count, PassRefPtr<IDBCallbacks> callbacks)
85 {
86     IDB_TRACE("IDBCursorBackendImpl::advanceInternal");
87     RefPtr<IDBCursorBackendImpl> cursor = prpCursor;
88     if (!cursor->m_cursor || !cursor->m_cursor->advance(count)) {
89         cursor->m_cursor = 0;
90         callbacks->onSuccess(SerializedScriptValue::nullValue());
91         return;
92     }
93
94     callbacks->onSuccess(cursor->key(), cursor->primaryKey(), cursor->value());
95 }
96
97 void IDBCursorBackendImpl::continueFunctionInternal(ScriptExecutionContext*, PassRefPtr<IDBCursorBackendImpl> prpCursor, PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> callbacks)
98 {
99     IDB_TRACE("IDBCursorBackendImpl::continueInternal");
100     RefPtr<IDBCursorBackendImpl> cursor = prpCursor;
101     RefPtr<IDBKey> key = prpKey;
102
103     if (!cursor->m_cursor || !cursor->m_cursor->continueFunction(key.get())) {
104         cursor->m_cursor = 0;
105         callbacks->onSuccess(SerializedScriptValue::nullValue());
106         return;
107     }
108
109     callbacks->onSuccess(cursor->key(), cursor->primaryKey(), cursor->value());
110 }
111
112 void IDBCursorBackendImpl::deleteFunction(PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode&)
113 {
114     IDB_TRACE("IDBCursorBackendImpl::delete");
115     ASSERT(m_transaction->mode() != IDBTransaction::READ_ONLY);
116
117     ExceptionCode ec = 0;
118     RefPtr<IDBKeyRange> keyRange = IDBKeyRange::only(m_cursor->primaryKey(), ec);
119     ASSERT(!ec);
120
121     m_objectStore->deleteFunction(keyRange.release(), prpCallbacks, m_transaction.get(), ec);
122     ASSERT(!ec);
123 }
124
125 void IDBCursorBackendImpl::prefetchContinue(int numberToFetch, PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode&)
126 {
127     IDB_TRACE("IDBCursorBackendImpl::prefetchContinue");
128     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
129     if (!m_transaction->scheduleTask(m_taskType, createCallbackTask(&IDBCursorBackendImpl::prefetchContinueInternal, this, numberToFetch, callbacks)))
130         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR));
131 }
132
133 void IDBCursorBackendImpl::prefetchContinueInternal(ScriptExecutionContext*, PassRefPtr<IDBCursorBackendImpl> prpCursor, int numberToFetch, PassRefPtr<IDBCallbacks> callbacks)
134 {
135     IDB_TRACE("IDBCursorBackendImpl::prefetchContinueInternal");
136     RefPtr<IDBCursorBackendImpl> cursor = prpCursor;
137
138     Vector<RefPtr<IDBKey> > foundKeys;
139     Vector<RefPtr<IDBKey> > foundPrimaryKeys;
140     Vector<RefPtr<SerializedScriptValue> > foundValues;
141
142     if (cursor->m_cursor)
143         cursor->m_savedCursor = cursor->m_cursor->clone();
144
145     const size_t maxSizeEstimate = 10 * 1024 * 1024;
146     size_t sizeEstimate = 0;
147
148     for (int i = 0; i < numberToFetch; ++i) {
149         if (!cursor->m_cursor || !cursor->m_cursor->continueFunction(0)) {
150             cursor->m_cursor = 0;
151             break;
152         }
153
154         foundKeys.append(cursor->m_cursor->key());
155         foundPrimaryKeys.append(cursor->m_cursor->primaryKey());
156
157         if (cursor->m_cursorType != IDBCursorBackendInterface::IndexKeyCursor)
158             foundValues.append(SerializedScriptValue::createFromWire(cursor->m_cursor->value()));
159         else
160             foundValues.append(SerializedScriptValue::create());
161
162         sizeEstimate += cursor->m_cursor->key()->sizeEstimate();
163         sizeEstimate += cursor->m_cursor->primaryKey()->sizeEstimate();
164         if (cursor->m_cursorType != IDBCursorBackendInterface::IndexKeyCursor)
165             sizeEstimate += cursor->m_cursor->value().length() * sizeof(UChar);
166
167         if (sizeEstimate > maxSizeEstimate)
168             break;
169     }
170
171     if (!foundKeys.size()) {
172         callbacks->onSuccess(SerializedScriptValue::nullValue());
173         return;
174     }
175
176     cursor->m_transaction->addPendingEvents(foundKeys.size() - 1);
177     callbacks->onSuccessWithPrefetch(foundKeys, foundPrimaryKeys, foundValues);
178 }
179
180 void IDBCursorBackendImpl::prefetchReset(int usedPrefetches, int unusedPrefetches)
181 {
182     IDB_TRACE("IDBCursorBackendImpl::prefetchReset");
183     m_transaction->addPendingEvents(-unusedPrefetches);
184     m_cursor = m_savedCursor;
185     m_savedCursor = 0;
186
187     if (m_closed)
188         return;
189     if (m_cursor) {
190         for (int i = 0; i < usedPrefetches; ++i) {
191             bool ok = m_cursor->continueFunction();
192             ASSERT_UNUSED(ok, ok);
193         }
194     }
195 }
196
197 void IDBCursorBackendImpl::close()
198 {
199     IDB_TRACE("IDBCursorBackendImpl::close");
200     m_closed = true;
201     if (m_cursor)
202         m_cursor->close();
203     m_cursor.clear();
204     m_savedCursor.clear();
205 }
206
207 } // namespace WebCore
208
209 #endif // ENABLE(INDEXED_DATABASE)