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