📄 sqltransaction.cpp
字号:
// Reset the maximum size here, as it was increased to allow us to retry this statement m_database->m_sqliteDatabase.setMaximumSize(m_database->maximumSize()); } else { // If the current statement has already been run, failed due to quota constraints, and we're not retrying it, // that means it ended in an error. Handle it now if (m_currentStatement && m_currentStatement->lastExecutionFailedDueToQuota()) { handleCurrentStatementError(); break; } // Otherwise, advance to the next statement getNextStatement(); } } while (runCurrentStatement()); // If runCurrentStatement() returned false, that means either there was no current statement to run, // or the current statement requires a callback to complete. In the later case, it also scheduled // the callback or performed any other additional work so we can return if (!m_currentStatement) postflightAndCommit();}void SQLTransaction::getNextStatement(){ m_currentStatement = 0; MutexLocker locker(m_statementMutex); if (!m_statementQueue.isEmpty()) { m_currentStatement = m_statementQueue.first(); m_statementQueue.removeFirst(); }}bool SQLTransaction::runCurrentStatement(){ if (!m_currentStatement) return false; m_database->m_databaseAuthorizer->reset(); if (m_currentStatement->execute(m_database.get())) { if (m_database->m_databaseAuthorizer->lastActionChangedDatabase()) { // Flag this transaction as having changed the database for later delegate notification m_modifiedDatabase = true; // Also dirty the size of this database file for calculating quota usage OriginQuotaManager& manager(DatabaseTracker::tracker().originQuotaManager()); Locker<OriginQuotaManager> locker(manager); manager.markDatabase(m_database.get()); } if (m_currentStatement->hasStatementCallback()) { m_nextStep = &SQLTransaction::deliverStatementCallback; LOG(StorageAPI, "Scheduling deliverStatementCallback for transaction %p\n", this); m_database->scheduleTransactionCallback(this); return false; } return true; } if (m_currentStatement->lastExecutionFailedDueToQuota()) { m_nextStep = &SQLTransaction::deliverQuotaIncreaseCallback; LOG(StorageAPI, "Scheduling deliverQuotaIncreaseCallback for transaction %p\n", this); m_database->scheduleTransactionCallback(this); return false; } handleCurrentStatementError(); return false;}void SQLTransaction::handleCurrentStatementError(){ // Transaction Steps 6.error - Call the statement's error callback, but if there was no error callback, // jump to the transaction error callback if (m_currentStatement->hasStatementErrorCallback()) { m_nextStep = &SQLTransaction::deliverStatementCallback; LOG(StorageAPI, "Scheduling deliverStatementCallback for transaction %p\n", this); m_database->scheduleTransactionCallback(this); } else { m_transactionError = m_currentStatement->sqlError(); if (!m_transactionError) m_transactionError = SQLError::create(1, "the statement failed to execute"); handleTransactionError(false); }}void SQLTransaction::deliverStatementCallback(){ ASSERT(m_currentStatement); // Transaction Step 6.6 and 6.3(error) - If the statement callback went wrong, jump to the transaction error callback // Otherwise, continue to loop through the statement queue m_executeSqlAllowed = true; bool result = m_currentStatement->performCallback(this); m_executeSqlAllowed = false; if (result) { m_transactionError = SQLError::create(0, "the statement callback raised an exception or statement error callback did not return false"); handleTransactionError(true); } else scheduleToRunStatements();}void SQLTransaction::deliverQuotaIncreaseCallback(){ ASSERT(m_currentStatement); ASSERT(!m_shouldRetryCurrentStatement); Page* page = m_database->document()->page(); ASSERT(page); RefPtr<SecurityOrigin> origin = m_database->securityOriginCopy(); unsigned long long currentQuota = DatabaseTracker::tracker().quotaForOrigin(origin.get()); page->chrome()->client()->exceededDatabaseQuota(m_database->document()->frame(), m_database->stringIdentifier()); unsigned long long newQuota = DatabaseTracker::tracker().quotaForOrigin(origin.get()); // If the new quota ended up being larger than the old quota, we will retry the statement. if (newQuota > currentQuota) m_shouldRetryCurrentStatement = true; m_nextStep = &SQLTransaction::runStatements; LOG(StorageAPI, "Scheduling runStatements for transaction %p\n", this); m_database->scheduleTransactionStep(this);}void SQLTransaction::postflightAndCommit(){ // Transaction Step 7 - Peform postflight steps, jumping to the error callback if they fail if (m_wrapper && !m_wrapper->performPostflight(this)) { m_transactionError = m_wrapper->sqlError(); if (!m_transactionError) m_transactionError = SQLError::create(0, "unknown error occured setting up transaction"); handleTransactionError(false); return; } // Transacton Step 8+9 - Commit the transaction, jumping to the error callback if that fails ASSERT(m_sqliteTransaction); m_database->m_databaseAuthorizer->disable(); m_sqliteTransaction->commit(); m_database->m_databaseAuthorizer->enable(); // If the commit failed, the transaction will still be marked as "in progress" if (m_sqliteTransaction->inProgress()) { m_shouldCommitAfterErrorCallback = false; m_transactionError = SQLError::create(0, "failed to commit the transaction"); handleTransactionError(false); return; } // The commit was successful, notify the delegates if the transaction modified this database if (m_modifiedDatabase) DatabaseTracker::tracker().scheduleNotifyDatabaseChanged(m_database->m_securityOrigin.get(), m_database->m_name); // Now release our unneeded callbacks, to break reference cycles. m_callback = 0; m_errorCallback = 0; // Transaction Step 10 - Deliver success callback, if there is one if (m_successCallback) { m_nextStep = &SQLTransaction::deliverSuccessCallback; LOG(StorageAPI, "Scheduling deliverSuccessCallback for transaction %p\n", this); m_database->scheduleTransactionCallback(this); } else cleanupAfterSuccessCallback();}void SQLTransaction::deliverSuccessCallback(){ // Transaction Step 10 - Deliver success callback ASSERT(m_successCallback); m_successCallback->handleEvent(); // Release the last callback to break reference cycle m_successCallback = 0; // Schedule a "post-success callback" step to return control to the database thread in case there // are further transactions queued up for this Database m_nextStep = &SQLTransaction::cleanupAfterSuccessCallback; LOG(StorageAPI, "Scheduling cleanupAfterSuccessCallback for transaction %p\n", this); m_database->scheduleTransactionStep(this);}void SQLTransaction::cleanupAfterSuccessCallback(){ // Transaction Step 11 - End transaction steps // There is no next step LOG(StorageAPI, "Transaction %p is complete\n", this); ASSERT(!m_database->m_sqliteDatabase.transactionInProgress()); m_nextStep = 0;}void SQLTransaction::handleTransactionError(bool inCallback){ if (m_errorCallback) { if (inCallback) deliverTransactionErrorCallback(); else { m_nextStep = &SQLTransaction::deliverTransactionErrorCallback; LOG(StorageAPI, "Scheduling deliverTransactionErrorCallback for transaction %p\n", this); m_database->scheduleTransactionCallback(this); } return; } // Transaction Step 12 - If the callback couldn't be called, then rollback the transaction. m_shouldCommitAfterErrorCallback = false; if (inCallback) { m_nextStep = &SQLTransaction::cleanupAfterTransactionErrorCallback; LOG(StorageAPI, "Scheduling cleanupAfterTransactionErrorCallback for transaction %p\n", this); m_database->scheduleTransactionStep(this); } else { cleanupAfterTransactionErrorCallback(); }}void SQLTransaction::deliverTransactionErrorCallback(){ ASSERT(m_transactionError); // Transaction Step 12 - If the callback didn't return false, then rollback the transaction. // This includes the callback not existing, returning true, or throwing an exception if (!m_errorCallback || m_errorCallback->handleEvent(m_transactionError.get())) m_shouldCommitAfterErrorCallback = false; m_nextStep = &SQLTransaction::cleanupAfterTransactionErrorCallback; LOG(StorageAPI, "Scheduling cleanupAfterTransactionErrorCallback for transaction %p\n", this); m_database->scheduleTransactionStep(this);}void SQLTransaction::cleanupAfterTransactionErrorCallback(){ m_database->m_databaseAuthorizer->disable(); if (m_sqliteTransaction) { // Transaction Step 12 -If the error callback returned false, and the last error wasn't itself a // failure when committing the transaction, then try to commit the transaction if (m_shouldCommitAfterErrorCallback) m_sqliteTransaction->commit(); if (m_sqliteTransaction->inProgress()) { // Transaction Step 12 - If that fails, or if the callback couldn't be called // or if it didn't return false, then rollback the transaction. m_sqliteTransaction->rollback(); } else if (m_modifiedDatabase) { // But if the commit was successful, notify the delegates if the transaction modified this database DatabaseTracker::tracker().scheduleNotifyDatabaseChanged(m_database->m_securityOrigin.get(), m_database->m_name); } ASSERT(!m_database->m_sqliteDatabase.transactionInProgress()); m_sqliteTransaction.clear(); } m_database->m_databaseAuthorizer->enable(); // Transaction Step 12 - Any still-pending statements in the transaction are discarded. { MutexLocker locker(m_statementMutex); m_statementQueue.clear(); } // Transaction is complete! There is no next step LOG(StorageAPI, "Transaction %p is complete with an error\n", this); ASSERT(!m_database->m_sqliteDatabase.transactionInProgress()); m_nextStep = 0; // Now release our callbacks, to break reference cycles. m_callback = 0; m_errorCallback = 0;}} // namespace WebCore
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -