IDBError MemoryObjectStore::updateIndexesForPutRecord(const IDBKeyData& key, const ThreadSafeDataBuffer& value) { JSLockHolder locker(UniqueIDBDatabase::databaseThreadVM()); auto jsValue = idbValueDataToJSValue(UniqueIDBDatabase::databaseThreadExecState(), value); if (jsValue.isUndefinedOrNull()) return { }; IDBError error; Vector<std::pair<MemoryIndex*, IndexKey>> changedIndexRecords; for (auto* index : m_indexesByName.values()) { IndexKey indexKey; generateIndexKeyForValue(UniqueIDBDatabase::databaseThreadExecState(), index->info(), jsValue, indexKey); if (indexKey.isNull()) continue; error = index->putIndexKey(key, indexKey); if (!error.isNull()) break; changedIndexRecords.append(std::make_pair(index, indexKey)); } // If any of the index puts failed, revert all of the ones that went through. if (!error.isNull()) { for (auto& record : changedIndexRecords) record.first->removeRecord(key, record.second); } return error; }
void UniqueIDBDatabase::performPutOrAdd(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData& keyData, const ThreadSafeDataBuffer& valueData, IndexedDB::ObjectStoreOverwriteMode overwriteMode) { ASSERT(!isMainThread()); LOG(IndexedDB, "(db) UniqueIDBDatabase::performPutOrAdd"); ASSERT(m_backingStore); ASSERT(objectStoreIdentifier); IDBKeyData usedKey; IDBError error; auto objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier); if (!objectStoreInfo) { error = IDBError(IDBExceptionCode::InvalidStateError, ASCIILiteral("Object store cannot be found in the backing store")); m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey)); return; } if (objectStoreInfo->autoIncrement() && !keyData.isValid()) { uint64_t keyNumber; error = m_backingStore->generateKeyNumber(transactionIdentifier, objectStoreIdentifier, keyNumber); if (!error.isNull()) { m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey)); return; } usedKey.setNumberValue(keyNumber); } else usedKey = keyData; if (overwriteMode == IndexedDB::ObjectStoreOverwriteMode::NoOverwrite) { bool keyExists; error = m_backingStore->keyExistsInObjectStore(transactionIdentifier, objectStoreIdentifier, usedKey, keyExists); if (error.isNull() && keyExists) error = IDBError(IDBExceptionCode::ConstraintError, ASCIILiteral("Key already exists in the object store")); if (!error.isNull()) { m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey)); return; } } // 3.4.1 Object Store Storage Operation // ...If a record already exists in store ... // then remove the record from store using the steps for deleting records from an object store... // This is important because formally deleting it from from the object store also removes it from the appropriate indexes. error = m_backingStore->deleteRange(transactionIdentifier, objectStoreIdentifier, usedKey); if (!error.isNull()) { m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey)); return; } error = m_backingStore->addRecord(transactionIdentifier, objectStoreIdentifier, usedKey, valueData); m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey)); }
IDBError MemoryObjectStore::populateIndexWithExistingRecords(MemoryIndex& index) { if (!m_keyValueStore) return { }; JSLockHolder locker(UniqueIDBDatabase::databaseThreadVM()); for (auto iterator : *m_keyValueStore) { auto jsValue = idbValueDataToJSValue(UniqueIDBDatabase::databaseThreadExecState(), iterator.value); if (jsValue.isUndefinedOrNull()) return { }; IndexKey indexKey; generateIndexKeyForValue(UniqueIDBDatabase::databaseThreadExecState(), index.info(), jsValue, indexKey); if (indexKey.isNull()) continue; IDBError error = index.putIndexKey(iterator.key, indexKey); if (!error.isNull()) return error; } return { }; }
void UniqueIDBDatabase::didPerformDeleteObjectStore(uint64_t callbackIdentifier, const IDBError& error, const String& objectStoreName) { ASSERT(isMainThread()); LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformDeleteObjectStore"); if (error.isNull()) m_databaseInfo->deleteObjectStore(objectStoreName); performErrorCallback(callbackIdentifier, error); }
void UniqueIDBDatabase::didPerformCreateObjectStore(uint64_t callbackIdentifier, const IDBError& error, const IDBObjectStoreInfo& info) { ASSERT(isMainThread()); LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformCreateObjectStore"); if (error.isNull()) m_databaseInfo->addExistingObjectStore(info); performErrorCallback(callbackIdentifier, error); }
void UniqueIDBDatabase::didPerformCreateIndex(uint64_t callbackIdentifier, const IDBError& error, const IDBIndexInfo& info) { ASSERT(isMainThread()); LOG(IndexedDB, "(main) UniqueIDBDatabase::didPerformCreateIndex"); if (error.isNull()) { ASSERT(m_databaseInfo); auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(info.objectStoreIdentifier()); ASSERT(objectStoreInfo); objectStoreInfo->addExistingIndex(info); } performErrorCallback(callbackIdentifier, error); }
void IDBTransaction::didCommit(const IDBError& error) { LOG(IndexedDB, "IDBTransaction::didCommit"); ASSERT(m_state == IndexedDB::TransactionState::Committing); if (error.isNull()) { m_database->didCommitTransaction(*this); fireOnComplete(); } else { m_database->willAbortTransaction(*this); notifyDidAbort(error); } finishAbortOrCommit(); }
void IDBTransaction::didStart(const IDBError& error) { LOG(IndexedDB, "IDBTransaction::didStart"); m_database->didStartTransaction(*this); m_startedOnServer = true; // It's possible the transaction failed to start on the server. // That equates to an abort. if (!error.isNull()) { didAbort(error); return; } scheduleOperationTimer(); }