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 "IDBServerConnectionLevelDB.h"
28
29#if ENABLE(INDEXED_DATABASE)
30#if USE(LEVELDB)
31
32#include "IDBBackingStoreCursorLevelDB.h"
33#include "IDBBackingStoreLevelDB.h"
34#include "IDBBackingStoreTransactionLevelDB.h"
35#include "IDBCursorBackend.h"
36#include "IDBFactoryBackendLevelDB.h"
37#include "IDBIndexWriterLevelDB.h"
38#include <wtf/MainThread.h>
39
40#define ASYNC_COMPLETION_CALLBACK_WITH_ARG(callback, arg) \
41    callOnMainThread([callback, arg]() { \
42        callback(arg); \
43    });
44
45#define ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(callback, arg1, arg2) \
46    callOnMainThread([callback]() { \
47        callback(arg1, arg2); \
48    });
49
50#define ASYNC_COMPLETION_CALLBACK_WITH_NULL_ARG(callback) \
51    callOnMainThread([callback]() { \
52        callback(0); \
53    });
54
55#define EMPTY_ASYNC_COMPLETION_CALLBACK(callback) \
56    callOnMainThread([callback]() { \
57        callback(); \
58    });
59
60
61namespace WebCore {
62
63IDBServerConnectionLevelDB::IDBServerConnectionLevelDB(const String& databaseName, IDBBackingStoreLevelDB* backingStore)
64    : m_backingStore(backingStore)
65    , m_nextCursorID(1)
66    , m_closed(false)
67    , m_databaseName(databaseName)
68{
69}
70
71IDBServerConnectionLevelDB::~IDBServerConnectionLevelDB()
72{
73}
74
75bool IDBServerConnectionLevelDB::isClosed()
76{
77    return m_closed;
78}
79
80void IDBServerConnectionLevelDB::getOrEstablishIDBDatabaseMetadata(GetIDBDatabaseMetadataFunction callback)
81{
82    RefPtr<IDBServerConnection> self(this);
83    m_backingStore->getOrEstablishIDBDatabaseMetadata(m_databaseName, [self, this, callback](const IDBDatabaseMetadata& metadata, bool success) {
84        callback(metadata, success);
85    });
86}
87
88void IDBServerConnectionLevelDB::deleteDatabase(const String& name, BoolCallbackFunction successCallback)
89{
90    RefPtr<IDBServerConnection> self(this);
91    m_backingStore->deleteDatabase(name, [self, this, successCallback](bool success) {
92        successCallback(success);
93    });
94}
95
96void IDBServerConnectionLevelDB::close()
97{
98    m_backingStore.clear();
99    m_closed = true;
100}
101
102void IDBServerConnectionLevelDB::openTransaction(int64_t transactionID, const HashSet<int64_t>&, IndexedDB::TransactionMode, BoolCallbackFunction successCallback)
103{
104    if (!m_backingStore) {
105        callOnMainThread([successCallback]() {
106            successCallback(false);
107        });
108        return;
109    }
110
111    m_backingStore->establishBackingStoreTransaction(transactionID);
112    callOnMainThread([successCallback]() {
113        successCallback(true);
114    });
115}
116
117void IDBServerConnectionLevelDB::beginTransaction(int64_t transactionID, std::function<void()> completionCallback)
118{
119    RefPtr<IDBBackingStoreTransactionLevelDB> transaction = m_backingStoreTransactions.get(transactionID);
120    ASSERT(transaction);
121
122    transaction->begin();
123    callOnMainThread(completionCallback);
124}
125
126void IDBServerConnectionLevelDB::commitTransaction(int64_t transactionID, BoolCallbackFunction successCallback)
127{
128    RefPtr<IDBBackingStoreTransactionLevelDB> transaction = m_backingStoreTransactions.get(transactionID);
129    ASSERT(transaction);
130
131    bool result = transaction->commit();
132    callOnMainThread([successCallback, result]() {
133        successCallback(result);
134    });
135}
136
137void IDBServerConnectionLevelDB::resetTransaction(int64_t transactionID, std::function<void()> completionCallback)
138{
139    RefPtr<IDBBackingStoreTransactionLevelDB> transaction = m_backingStoreTransactions.get(transactionID);
140    ASSERT(transaction);
141
142    transaction->resetTransaction();
143    callOnMainThread(completionCallback);
144}
145
146void IDBServerConnectionLevelDB::rollbackTransaction(int64_t transactionID, std::function<void()> completionCallback)
147{
148    RefPtr<IDBBackingStoreTransactionLevelDB> transaction = m_backingStoreTransactions.get(transactionID);
149    ASSERT(transaction);
150
151    transaction->rollback();
152    callOnMainThread(completionCallback);
153}
154
155void IDBServerConnectionLevelDB::setIndexKeys(int64_t transactionID, int64_t databaseID, int64_t objectStoreID, const IDBObjectStoreMetadata& objectStoreMetadata, IDBKey& primaryKey, const Vector<int64_t>& indexIDs, const Vector<Vector<RefPtr<IDBKey>>>& indexKeys, std::function<void(PassRefPtr<IDBDatabaseError>)> completionCallback)
156{
157    RefPtr<IDBBackingStoreTransactionLevelDB> backingStoreTransaction = m_backingStoreTransactions.get(transactionID);
158    ASSERT(backingStoreTransaction);
159
160    RefPtr<IDBRecordIdentifier> recordIdentifier;
161    bool ok = m_backingStore->keyExistsInObjectStore(*backingStoreTransaction, databaseID, objectStoreID, primaryKey, recordIdentifier);
162    if (!ok) {
163        callOnMainThread([completionCallback]() {
164            completionCallback(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error: setting index keys."));
165        });
166        return;
167    }
168    if (!recordIdentifier) {
169        callOnMainThread([completionCallback]() {
170            completionCallback(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error: setting index keys for object store."));
171        });
172        return;
173    }
174
175    Vector<RefPtr<IDBIndexWriterLevelDB>> indexWriters;
176    String errorMessage;
177    bool obeysConstraints = false;
178
179    bool backingStoreSuccess = m_backingStore->makeIndexWriters(transactionID, databaseID, objectStoreMetadata, primaryKey, false, indexIDs, indexKeys, indexWriters, &errorMessage, obeysConstraints);
180    if (!backingStoreSuccess) {
181        callOnMainThread([completionCallback]() {
182            completionCallback(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error: backing store error updating index keys."));
183        });
184        return;
185    }
186    if (!obeysConstraints) {
187        callOnMainThread([completionCallback, errorMessage]() {
188            completionCallback(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, errorMessage));
189        });
190        return;
191    }
192
193    for (size_t i = 0; i < indexWriters.size(); ++i) {
194        IDBIndexWriterLevelDB* indexWriter = indexWriters[i].get();
195        indexWriter->writeIndexKeys(recordIdentifier.get(), *m_backingStore, *backingStoreTransaction, databaseID, objectStoreID);
196    }
197
198    ASYNC_COMPLETION_CALLBACK_WITH_NULL_ARG(completionCallback);
199}
200
201void IDBServerConnectionLevelDB::createObjectStore(IDBTransactionBackend& transaction, const CreateObjectStoreOperation& operation, std::function<void(PassRefPtr<IDBDatabaseError>)> completionCallback)
202{
203    IDBBackingStoreTransactionLevelDB* backingStoreTransaction = m_backingStoreTransactions.get(transaction.id());
204    ASSERT(backingStoreTransaction);
205
206    String objectStoreName = operation.objectStoreMetadata().name;
207
208    if (!m_backingStore->createObjectStore(*backingStoreTransaction, transaction.database().id(), operation.objectStoreMetadata().id, objectStoreName, operation.objectStoreMetadata().keyPath, operation.objectStoreMetadata().autoIncrement)) {
209        callOnMainThread([completionCallback, objectStoreName]() {
210            completionCallback(IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error creating object store '%s'.", objectStoreName.utf8().data())));
211        });
212        return;
213    }
214    ASYNC_COMPLETION_CALLBACK_WITH_NULL_ARG(completionCallback);
215}
216
217void IDBServerConnectionLevelDB::createIndex(IDBTransactionBackend& transaction, const CreateIndexOperation& operation, std::function<void(PassRefPtr<IDBDatabaseError>)> completionCallback)
218{
219    IDBBackingStoreTransactionLevelDB* backingStoreTransaction = m_backingStoreTransactions.get(transaction.id());
220    ASSERT(backingStoreTransaction);
221
222    const IDBIndexMetadata& indexMetadata = operation.idbIndexMetadata();
223    if (!m_backingStore->createIndex(*backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), indexMetadata.id, indexMetadata.name, indexMetadata.keyPath, indexMetadata.unique, indexMetadata.multiEntry)) {
224        callOnMainThread([completionCallback, indexMetadata]() {
225            completionCallback(IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error when trying to create index '%s'.", indexMetadata.name.utf8().data())));
226        });
227        return;
228    }
229    ASYNC_COMPLETION_CALLBACK_WITH_NULL_ARG(completionCallback);
230}
231
232void IDBServerConnectionLevelDB::deleteIndex(IDBTransactionBackend& transaction, const DeleteIndexOperation& operation, std::function<void(PassRefPtr<IDBDatabaseError>)> completionCallback)
233{
234    IDBBackingStoreTransactionLevelDB* backingStoreTransaction = m_backingStoreTransactions.get(transaction.id());
235    ASSERT(backingStoreTransaction);
236
237    const IDBIndexMetadata& indexMetadata = operation.idbIndexMetadata();
238    if (!m_backingStore->deleteIndex(*backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), indexMetadata.id)) {
239        callOnMainThread([completionCallback, indexMetadata]() {
240            completionCallback(IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error deleting index '%s'.", indexMetadata.name.utf8().data())));
241        });
242        return;
243    }
244    ASYNC_COMPLETION_CALLBACK_WITH_NULL_ARG(completionCallback);
245}
246
247void IDBServerConnectionLevelDB::get(IDBTransactionBackend& transaction, const GetOperation& operation, std::function<void(const IDBGetResult&, PassRefPtr<IDBDatabaseError>)> completionCallback)
248{
249    IDBBackingStoreTransactionLevelDB* backingStoreTransaction = m_backingStoreTransactions.get(transaction.id());
250    ASSERT(backingStoreTransaction);
251
252    RefPtr<IDBKey> key;
253
254    if (operation.keyRange()->isOnlyKey())
255        key = operation.keyRange()->lower();
256    else {
257        RefPtr<IDBBackingStoreCursorLevelDB> backingStoreCursor;
258        int64_t cursorID = m_nextCursorID++;
259
260        if (operation.indexID() == IDBIndexMetadata::InvalidId) {
261            ASSERT(operation.cursorType() != IndexedDB::CursorType::KeyOnly);
262            // ObjectStore Retrieval Operation
263            backingStoreCursor = m_backingStore->openObjectStoreCursor(cursorID, *backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), operation.keyRange(), IndexedDB::CursorDirection::Next);
264        } else {
265            if (operation.cursorType() == IndexedDB::CursorType::KeyOnly) {
266                // Index Value Retrieval Operation
267                backingStoreCursor = m_backingStore->openIndexKeyCursor(cursorID, *backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), operation.indexID(), operation.keyRange(), IndexedDB::CursorDirection::Next);
268            } else {
269                // Index Referenced Value Retrieval Operation
270                backingStoreCursor = m_backingStore->openIndexCursor(cursorID, *backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), operation.indexID(), operation.keyRange(), IndexedDB::CursorDirection::Next);
271            }
272        }
273
274        if (!backingStoreCursor) {
275            ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(completionCallback, IDBGetResult(), nullptr);
276            return;
277        }
278
279        key = backingStoreCursor->key();
280    }
281
282    RefPtr<IDBKey> primaryKey;
283    bool ok;
284    if (operation.indexID() == IDBIndexMetadata::InvalidId) {
285        // Object Store Retrieval Operation
286        Vector<char> value;
287        ok = m_backingStore->getRecord(*backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), *key, value);
288        if (!ok) {
289            ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(completionCallback, IDBGetResult(), IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error in getRecord."));
290            return;
291        }
292
293        if (value.isEmpty()) {
294            ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(completionCallback, IDBGetResult(), nullptr);
295            return;
296        }
297
298        IDBGetResult result;
299
300        if (operation.autoIncrement() && !operation.keyPath().isNull())
301            result = IDBGetResult(SharedBuffer::adoptVector(value), key, operation.keyPath());
302        else
303            result = IDBGetResult(SharedBuffer::adoptVector(value));
304
305        callOnMainThread([completionCallback, result]() {
306            completionCallback(result, nullptr);
307        });
308        return;
309    }
310
311    // From here we are dealing only with indexes.
312    ok = m_backingStore->getPrimaryKeyViaIndex(*backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), operation.indexID(), *key, primaryKey);
313    if (!ok) {
314        ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(completionCallback, IDBGetResult(), IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error in getPrimaryKeyViaIndex."));
315        return;
316    }
317    if (!primaryKey) {
318        ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(completionCallback, IDBGetResult(), nullptr);
319        return;
320    }
321    if (operation.cursorType() == IndexedDB::CursorType::KeyOnly) {
322        // Index Value Retrieval Operation
323        IDBGetResult result(primaryKey.release());
324        callOnMainThread([completionCallback, result]() {
325            completionCallback(result, nullptr);
326        });
327        return;
328    }
329
330    // Index Referenced Value Retrieval Operation
331    Vector<char> value;
332    ok = m_backingStore->getRecord(*backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), *primaryKey, value);
333    if (!ok) {
334        ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(completionCallback, IDBGetResult(), IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error in getRecord."));
335        return;
336    }
337
338    if (value.isEmpty()) {
339        ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(completionCallback, IDBGetResult(), nullptr);
340        return;
341    }
342    if (operation.autoIncrement() && !operation.keyPath().isNull()) {
343        IDBGetResult result(SharedBuffer::adoptVector(value), key, operation.keyPath());
344        callOnMainThread([completionCallback, result]() {
345            completionCallback(result, nullptr);
346        });
347
348        return;
349    }
350
351    IDBGetResult result(SharedBuffer::adoptVector(value));
352    callOnMainThread([completionCallback, result]() {
353        completionCallback(result, nullptr);
354    });
355}
356
357void IDBServerConnectionLevelDB::put(IDBTransactionBackend& transaction, const PutOperation& operation, std::function<void(PassRefPtr<IDBKey>, PassRefPtr<IDBDatabaseError>)> completionCallback)
358{
359    IDBBackingStoreTransactionLevelDB* backingStoreTransaction = m_backingStoreTransactions.get(transaction.id());
360    ASSERT(backingStoreTransaction);
361
362    bool keyWasGenerated = false;
363
364    RefPtr<IDBKey> key;
365    if (operation.putMode() != IDBDatabaseBackend::CursorUpdate && operation.objectStore().autoIncrement && !operation.key()) {
366        RefPtr<IDBKey> autoIncKey = m_backingStore->generateKey(transaction, transaction.database().id(), operation.objectStore().id);
367        keyWasGenerated = true;
368        if (!autoIncKey->isValid()) {
369            ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(completionCallback, nullptr, IDBDatabaseError::create(IDBDatabaseException::ConstraintError, "Maximum key generator value reached."));
370            return;
371        }
372        key = autoIncKey;
373    } else
374        key = operation.key();
375
376    ASSERT(key);
377    ASSERT(key->isValid());
378
379    RefPtr<IDBRecordIdentifier> recordIdentifier;
380    if (operation.putMode() == IDBDatabaseBackend::AddOnly) {
381        bool ok = m_backingStore->keyExistsInObjectStore(*backingStoreTransaction, transaction.database().id(), operation.objectStore().id, *key, recordIdentifier);
382        if (!ok) {
383            ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(completionCallback, nullptr, IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error checking key existence."));
384            return;
385        }
386        if (recordIdentifier) {
387            ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(completionCallback, nullptr, IDBDatabaseError::create(IDBDatabaseException::ConstraintError, "Key already exists in the object store."));
388            return;
389        }
390    }
391
392    Vector<RefPtr<IDBIndexWriterLevelDB>> indexWriters;
393    String errorMessage;
394    bool obeysConstraints = false;
395    bool backingStoreSuccess = m_backingStore->makeIndexWriters(transaction.id(), transaction.database().id(), operation.objectStore(), *key, keyWasGenerated, operation.indexIDs(), operation.indexKeys(), indexWriters, &errorMessage, obeysConstraints);
396    if (!backingStoreSuccess) {
397        ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(completionCallback, nullptr, IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error: backing store error updating index keys."));
398        return;
399    }
400    if (!obeysConstraints) {
401        callOnMainThread([completionCallback, errorMessage]() { \
402            completionCallback(nullptr, IDBDatabaseError::create(IDBDatabaseException::ConstraintError, errorMessage)); \
403        });
404        return;
405    }
406
407    // Before this point, don't do any mutation. After this point, rollback the transaction in case of error.
408    backingStoreSuccess = m_backingStore->putRecord(*backingStoreTransaction, transaction.database().id(), operation.objectStore().id, *key, operation.value(), recordIdentifier.get());
409    if (!backingStoreSuccess) {
410        ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(completionCallback, nullptr, IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error: backing store error performing put/add."));
411        return;
412    }
413
414    for (size_t i = 0; i < indexWriters.size(); ++i) {
415        IDBIndexWriterLevelDB* indexWriter = indexWriters[i].get();
416        indexWriter->writeIndexKeys(recordIdentifier.get(), *m_backingStore, *backingStoreTransaction, transaction.database().id(), operation.objectStore().id);
417    }
418
419    if (operation.objectStore().autoIncrement && operation.putMode() != IDBDatabaseBackend::CursorUpdate && key->type() == IDBKey::NumberType) {
420        bool ok = m_backingStore->updateKeyGenerator(transaction, transaction.database().id(), operation.objectStore().id, *key, !keyWasGenerated);
421        if (!ok) {
422            ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(completionCallback, nullptr, IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error updating key generator."));
423            return;
424        }
425    }
426
427    callOnMainThread([completionCallback, key]() { \
428        completionCallback(key.get(), nullptr); \
429    });
430}
431
432void IDBServerConnectionLevelDB::openCursor(IDBTransactionBackend& transaction, const OpenCursorOperation& operation, std::function<void(int64_t, PassRefPtr<IDBKey>, PassRefPtr<IDBKey>, PassRefPtr<SharedBuffer>, PassRefPtr<IDBDatabaseError>)> completionCallback)
433{
434    IDBBackingStoreTransactionLevelDB* backingStoreTransaction = m_backingStoreTransactions.get(transaction.id());
435    ASSERT(backingStoreTransaction);
436
437    // The frontend has begun indexing, so this pauses the transaction
438    // until the indexing is complete. This can't happen any earlier
439    // because we don't want to switch to early mode in case multiple
440    // indexes are being created in a row, with put()'s in between.
441    if (operation.taskType() == IDBDatabaseBackend::PreemptiveTask)
442        transaction.addPreemptiveEvent();
443
444    int64_t cursorID = m_nextCursorID++;
445
446    RefPtr<IDBBackingStoreCursorLevelDB> backingStoreCursor;
447    if (operation.indexID() == IDBIndexMetadata::InvalidId) {
448        ASSERT(operation.cursorType() != IndexedDB::CursorType::KeyOnly);
449        backingStoreCursor = m_backingStore->openObjectStoreCursor(cursorID, *backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), operation.keyRange(), operation.direction());
450    } else {
451        ASSERT(operation.taskType() == IDBDatabaseBackend::NormalTask);
452        if (operation.cursorType() == IndexedDB::CursorType::KeyOnly)
453            backingStoreCursor = m_backingStore->openIndexKeyCursor(cursorID, *backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), operation.indexID(), operation.keyRange(), operation.direction());
454        else
455            backingStoreCursor = m_backingStore->openIndexCursor(cursorID, *backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), operation.indexID(), operation.keyRange(), operation.direction());
456    }
457
458    if (!backingStoreCursor) {
459        // FIXME: Should it be an error to not have a backing store cursor?
460        cursorID = 0;
461    }
462
463    callOnMainThread([completionCallback, cursorID]() {
464        // FIXME: Need to actually pass the initial key, primaryKey, and value to the callback.
465        completionCallback(cursorID, nullptr, nullptr, nullptr, nullptr);
466    });
467}
468
469void IDBServerConnectionLevelDB::count(IDBTransactionBackend& transaction, const CountOperation& operation, std::function<void(int64_t, PassRefPtr<IDBDatabaseError>)> completionCallback)
470{
471    IDBBackingStoreTransactionLevelDB* backingStoreTransaction = m_backingStoreTransactions.get(transaction.id());
472    ASSERT(backingStoreTransaction);
473
474    uint32_t count = 0;
475    RefPtr<IDBBackingStoreCursorLevelDB> backingStoreCursor;
476
477    int64_t cursorID = m_nextCursorID++;
478
479    if (operation.indexID() == IDBIndexMetadata::InvalidId)
480        backingStoreCursor = m_backingStore->openObjectStoreKeyCursor(cursorID, *backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), operation.keyRange(), IndexedDB::CursorDirection::Next);
481    else
482        backingStoreCursor = m_backingStore->openIndexKeyCursor(cursorID, *backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), operation.indexID(), operation.keyRange(), IndexedDB::CursorDirection::Next);
483    if (!backingStoreCursor) {
484        // FIXME: Is this an error case?
485        callOnMainThread([completionCallback, count]() {
486            completionCallback(count, nullptr);
487        });
488        return;
489    }
490
491    do {
492        ++count;
493    } while (backingStoreCursor->continueFunction(0));
494
495    callOnMainThread([completionCallback, count]() {
496        completionCallback(count, nullptr);
497    });
498}
499
500void IDBServerConnectionLevelDB::deleteRange(IDBTransactionBackend& transaction, const DeleteRangeOperation& operation, std::function<void(PassRefPtr<IDBDatabaseError>)> completionCallback)
501{
502    IDBBackingStoreTransactionLevelDB* backingStoreTransaction = m_backingStoreTransactions.get(transaction.id());
503    ASSERT(backingStoreTransaction);
504
505    int64_t cursorID = m_nextCursorID++;
506
507    RefPtr<IDBBackingStoreCursorLevelDB> backingStoreCursor = m_backingStore->openObjectStoreCursor(cursorID, *backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), operation.keyRange(), IndexedDB::CursorDirection::Next);
508    if (backingStoreCursor) {
509        do {
510            if (!m_backingStore->deleteRecord(*backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), backingStoreCursor->recordIdentifier())) {
511                callOnMainThread([completionCallback]() {
512                    completionCallback(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Error deleting data in range"));
513                });
514                return;
515            }
516        } while (backingStoreCursor->continueFunction(0));
517    }
518
519    callOnMainThread([completionCallback]() {
520        completionCallback(nullptr);
521    });
522}
523
524void IDBServerConnectionLevelDB::clearObjectStore(IDBTransactionBackend& transaction, const ClearObjectStoreOperation& operation, std::function<void(PassRefPtr<IDBDatabaseError>)> completionCallback)
525{
526    IDBBackingStoreTransactionLevelDB* backingStoreTransaction = m_backingStoreTransactions.get(transaction.id());
527    ASSERT(backingStoreTransaction);
528
529    if (!m_backingStore->clearObjectStore(*backingStoreTransaction, transaction.database().id(), operation.objectStoreID())) {
530        callOnMainThread([completionCallback]() {
531            completionCallback(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Error clearing object store"));
532        });
533        return;
534    }
535
536    ASYNC_COMPLETION_CALLBACK_WITH_NULL_ARG(completionCallback);
537}
538
539void IDBServerConnectionLevelDB::deleteObjectStore(IDBTransactionBackend& transaction, const DeleteObjectStoreOperation& operation, std::function<void(PassRefPtr<IDBDatabaseError>)> completionCallback)
540{
541    IDBBackingStoreTransactionLevelDB* backingStoreTransaction = m_backingStoreTransactions.get(transaction.id());
542    ASSERT(backingStoreTransaction);
543
544    const IDBObjectStoreMetadata& objectStoreMetadata = operation.objectStoreMetadata();
545
546    if (!m_backingStore->deleteObjectStore(*backingStoreTransaction, transaction.database().id(), objectStoreMetadata.id)) {
547        callOnMainThread([completionCallback, objectStoreMetadata]() {
548            completionCallback(IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error deleting object store '%s'.", objectStoreMetadata.name.utf8().data())));
549        });
550        return;
551    }
552    ASYNC_COMPLETION_CALLBACK_WITH_NULL_ARG(completionCallback);
553}
554
555void IDBServerConnectionLevelDB::changeDatabaseVersion(IDBTransactionBackend& transaction, const IDBDatabaseBackend::VersionChangeOperation&, std::function<void(PassRefPtr<IDBDatabaseError>)> completionCallback)
556{
557    IDBBackingStoreTransactionLevelDB* backingStoreTransaction = m_backingStoreTransactions.get(transaction.id());
558    ASSERT(backingStoreTransaction);
559
560    IDBDatabaseBackend& database = transaction.database();
561    int64_t databaseId = database.id();
562
563    if (!m_backingStore->updateIDBDatabaseVersion(*backingStoreTransaction, databaseId, database.metadata().version)) {
564        RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Error writing data to stable storage when updating version.");
565        ASYNC_COMPLETION_CALLBACK_WITH_ARG(completionCallback, error);
566        return;
567    }
568
569    ASYNC_COMPLETION_CALLBACK_WITH_NULL_ARG(completionCallback);
570}
571
572void IDBServerConnectionLevelDB::cursorAdvance(IDBCursorBackend& cursor, const CursorAdvanceOperation& operation, std::function<void(PassRefPtr<IDBKey>, PassRefPtr<IDBKey>, PassRefPtr<SharedBuffer>, PassRefPtr<IDBDatabaseError>)> completionCallback)
573{
574    IDBBackingStoreCursorLevelDB* backingStoreCursor = cursor.id() ? m_backingStoreCursors.get(cursor.id()) : 0;
575#ifndef NDEBUG
576    if (cursor.id())
577        ASSERT(backingStoreCursor);
578#endif
579
580    if (!backingStoreCursor || !backingStoreCursor->advance(operation.count())) {
581        m_backingStoreCursors.remove(cursor.id());
582
583        callOnMainThread([completionCallback]() {
584            completionCallback(nullptr, nullptr, nullptr, IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Unknown error advancing cursor"));
585        });
586
587        return;
588    }
589
590    RefPtr<IDBKey> key = backingStoreCursor->key(), primaryKey = backingStoreCursor->primaryKey();
591    RefPtr<SharedBuffer> value = backingStoreCursor->value();
592
593    callOnMainThread([completionCallback, key, primaryKey, value]() {
594        completionCallback(key, primaryKey, value, IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Unknown error advancing cursor"));
595    });
596}
597
598void IDBServerConnectionLevelDB::cursorIterate(IDBCursorBackend& cursor, const CursorIterationOperation& operation, std::function<void(PassRefPtr<IDBKey>, PassRefPtr<IDBKey>, PassRefPtr<SharedBuffer>, PassRefPtr<IDBDatabaseError>)> completionCallback)
599{
600    IDBBackingStoreCursorLevelDB* backingStoreCursor = cursor.id() ? m_backingStoreCursors.get(cursor.id()) : 0;
601#ifndef NDEBUG
602    if (cursor.id())
603        ASSERT(backingStoreCursor);
604#endif
605
606    if (!backingStoreCursor || !backingStoreCursor->continueFunction(operation.key())) {
607        m_backingStoreCursors.remove(cursor.id());
608
609        callOnMainThread([completionCallback]() {
610            completionCallback(nullptr, nullptr, nullptr, IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Unknown error advancing cursor"));
611        });
612
613        return;
614    }
615
616    RefPtr<IDBKey> key = backingStoreCursor->key(), primaryKey = backingStoreCursor->primaryKey();
617    RefPtr<SharedBuffer> value = backingStoreCursor->value();
618
619    callOnMainThread([completionCallback, key, primaryKey, value]() {
620        completionCallback(key, primaryKey, value, IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Unknown error advancing cursor"));
621    });
622}
623
624} // namespace WebCore
625
626#endif // USE(LEVELDB)
627#endif // ENABLE(INDEXED_DATABASE)
628