diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-05-24 08:28:08 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-05-24 08:28:08 +0000 |
commit | a4e969f4965059196ca948db781e52f7cfebf19e (patch) | |
tree | 6ca352808c8fdc52006a0f33f6ae3c593b23867d /Source/WebCore/Modules/webdatabase/SQLTransactionBackend.cpp | |
parent | 41386e9cb918eed93b3f13648cbef387e371e451 (diff) | |
download | WebKitGtk-tarball-a4e969f4965059196ca948db781e52f7cfebf19e.tar.gz |
webkitgtk-2.12.3webkitgtk-2.12.3
Diffstat (limited to 'Source/WebCore/Modules/webdatabase/SQLTransactionBackend.cpp')
-rw-r--r-- | Source/WebCore/Modules/webdatabase/SQLTransactionBackend.cpp | 230 |
1 files changed, 116 insertions, 114 deletions
diff --git a/Source/WebCore/Modules/webdatabase/SQLTransactionBackend.cpp b/Source/WebCore/Modules/webdatabase/SQLTransactionBackend.cpp index 244f28566..9d086cb0b 100644 --- a/Source/WebCore/Modules/webdatabase/SQLTransactionBackend.cpp +++ b/Source/WebCore/Modules/webdatabase/SQLTransactionBackend.cpp @@ -10,7 +10,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -29,20 +29,19 @@ #include "config.h" #include "SQLTransactionBackend.h" -#if ENABLE(SQL_DATABASE) - -#include "AbstractSQLTransaction.h" -#include "Database.h" // FIXME: Should only be used in the frontend. +#include "Database.h" #include "DatabaseAuthorizer.h" -#include "DatabaseBackend.h" -#include "DatabaseBackendContext.h" +#include "DatabaseContext.h" #include "DatabaseThread.h" #include "DatabaseTracker.h" #include "ExceptionCode.h" #include "Logging.h" #include "OriginLock.h" #include "SQLError.h" -#include "SQLStatementBackend.h" +#include "SQLStatement.h" +#include "SQLStatementCallback.h" +#include "SQLStatementErrorCallback.h" +#include "SQLTransaction.h" #include "SQLTransactionClient.h" #include "SQLTransactionCoordinator.h" #include "SQLValue.h" @@ -260,7 +259,7 @@ // // When executing the transaction (in DatabaseThread::databaseThread()): // ==================================================================== -// OwnPtr<DatabaseTask> task; // points to ... +// std::unique_ptr<DatabaseTask> task; // points to ... // --> DatabaseTransactionTask // RefPtr<SQLTransactionBackend> m_transaction points to ... // --> SQLTransactionBackend // RefPtr<SQLTransaction> m_frontend; // --> SQLTransaction // RefPtr<SQLTransactionBackend> m_backend points to ... @@ -284,7 +283,7 @@ // However, there will still be a DatabaseTask pointing to the SQLTransactionBackend (see // the "When executing the transaction" chain above). This will keep the // SQLTransactionBackend alive until DatabaseThread::databaseThread() releases its -// task OwnPtr. +// task std::unique_ptr. // // What happens if a transaction is interrupted? // ============================================ @@ -344,14 +343,12 @@ namespace WebCore { -PassRefPtr<SQLTransactionBackend> SQLTransactionBackend::create(DatabaseBackend* db, - PassRefPtr<AbstractSQLTransaction> frontend, PassRefPtr<SQLTransactionWrapper> wrapper, bool readOnly) +Ref<SQLTransactionBackend> SQLTransactionBackend::create(Database* db, PassRefPtr<SQLTransaction> frontend, PassRefPtr<SQLTransactionWrapper> wrapper, bool readOnly) { - return adoptRef(new SQLTransactionBackend(db, frontend, wrapper, readOnly)); + return adoptRef(*new SQLTransactionBackend(db, frontend, wrapper, readOnly)); } -SQLTransactionBackend::SQLTransactionBackend(DatabaseBackend* db, - PassRefPtr<AbstractSQLTransaction> frontend, PassRefPtr<SQLTransactionWrapper> wrapper, bool readOnly) +SQLTransactionBackend::SQLTransactionBackend(Database* db, PassRefPtr<SQLTransaction> frontend, PassRefPtr<SQLTransactionWrapper> wrapper, bool readOnly) : m_frontend(frontend) , m_database(db) , m_wrapper(wrapper) @@ -378,13 +375,13 @@ void SQLTransactionBackend::doCleanup() { if (!m_frontend) return; - m_frontend = 0; // Break the reference cycle. See comment about the life-cycle above. + m_frontend = nullptr; // Break the reference cycle. See comment about the life-cycle above. ASSERT(currentThread() == database()->databaseContext()->databaseThread()->getThreadID()); releaseOriginLockIfNeeded(); - MutexLocker locker(m_statementMutex); + LockHolder locker(m_statementMutex); m_statementQueue.clear(); if (m_sqliteTransaction) { @@ -393,7 +390,7 @@ void SQLTransactionBackend::doCleanup() // m_sqliteTransaction invokes SQLiteTransaction's destructor which does // just that. We might as well do this unconditionally and free up its // resources because we're already terminating. - m_sqliteTransaction.clear(); + m_sqliteTransaction = nullptr; } // Release the lock on this database @@ -423,12 +420,12 @@ void SQLTransactionBackend::doCleanup() // SQLTransactionBackend is guaranteed to not destruct until the frontend // is also destructing. - m_wrapper = 0; + m_wrapper = nullptr; } -AbstractSQLStatement* SQLTransactionBackend::currentStatement() +SQLStatement* SQLTransactionBackend::currentStatement() { - return m_currentStatementBackend->frontend(); + return m_currentStatementBackend.get(); } PassRefPtr<SQLError> SQLTransactionBackend::transactionError() @@ -450,14 +447,14 @@ SQLTransactionBackend::StateFunction SQLTransactionBackend::stateFunctionFor(SQL &SQLTransactionBackend::acquireLock, // 2. &SQLTransactionBackend::openTransactionAndPreflight, // 3. &SQLTransactionBackend::runStatements, // 4. - &SQLTransactionBackend::postflightAndCommit, // 5. + &SQLTransactionBackend::unreachableState, // 5. postflightAndCommit &SQLTransactionBackend::cleanupAndTerminate, // 6. &SQLTransactionBackend::cleanupAfterTransactionErrorCallback, // 7. - &SQLTransactionBackend::sendToFrontendState, // 8. deliverTransactionCallback - &SQLTransactionBackend::sendToFrontendState, // 9. deliverTransactionErrorCallback - &SQLTransactionBackend::sendToFrontendState, // 10. deliverStatementCallback - &SQLTransactionBackend::sendToFrontendState, // 11. deliverQuotaIncreaseCallback - &SQLTransactionBackend::sendToFrontendState // 12. deliverSuccessCallback + &SQLTransactionBackend::unreachableState, // 8. deliverTransactionCallback + &SQLTransactionBackend::unreachableState, // 9. deliverTransactionErrorCallback + &SQLTransactionBackend::unreachableState, // 10. deliverStatementCallback + &SQLTransactionBackend::unreachableState, // 11. deliverQuotaIncreaseCallback + &SQLTransactionBackend::unreachableState // 12. deliverSuccessCallback }; ASSERT(WTF_ARRAY_LENGTH(stateFunctions) == static_cast<int>(SQLTransactionState::NumberOfStates)); @@ -466,17 +463,17 @@ SQLTransactionBackend::StateFunction SQLTransactionBackend::stateFunctionFor(SQL return stateFunctions[static_cast<int>(state)]; } -void SQLTransactionBackend::enqueueStatementBackend(PassRefPtr<SQLStatementBackend> statementBackend) +void SQLTransactionBackend::enqueueStatementBackend(std::unique_ptr<SQLStatement> statementBackend) { - MutexLocker locker(m_statementMutex); - m_statementQueue.append(statementBackend); + LockHolder locker(m_statementMutex); + m_statementQueue.append(WTFMove(statementBackend)); } void SQLTransactionBackend::computeNextStateAndCleanupIfNeeded() { // Only honor the requested state transition if we're not supposed to be // cleaning up and shutting down: - if (m_database->opened() && !m_database->isInterrupted()) { + if (m_database->opened()) { setStateToRequestedState(); ASSERT(m_nextState == SQLTransactionState::AcquireLock || m_nextState == SQLTransactionState::OpenTransactionAndPreflight @@ -500,7 +497,7 @@ void SQLTransactionBackend::computeNextStateAndCleanupIfNeeded() // The current SQLite transaction should be stopped, as well if (m_sqliteTransaction) { m_sqliteTransaction->stop(); - m_sqliteTransaction.clear(); + m_sqliteTransaction = nullptr; } // Terminate the frontend state machine. This also gets the frontend to @@ -518,24 +515,12 @@ void SQLTransactionBackend::performNextStep() runStateMachine(); } -#if PLATFORM(IOS) -bool SQLTransactionBackend::shouldPerformWhilePaused() const -{ - // SQLTransactions should only run-while-paused if they have progressed passed the first transaction step. - return m_nextState != SQLTransactionState::AcquireLock; -} -#endif - -void SQLTransactionBackend::executeSQL(PassOwnPtr<AbstractSQLStatement> statement, - const String& sqlStatement, const Vector<SQLValue>& arguments, int permissions) +void SQLTransactionBackend::executeSQL(std::unique_ptr<SQLStatement> statementBackend) { - RefPtr<SQLStatementBackend> statementBackend; - statementBackend = SQLStatementBackend::create(statement, sqlStatement, arguments, permissions); - - if (Database::from(m_database.get())->deleted()) + if (m_database->deleted()) statementBackend->setDatabaseDeletedError(); - enqueueStatementBackend(statementBackend); + enqueueStatementBackend(WTFMove(statementBackend)); } void SQLTransactionBackend::notifyDatabaseThreadIsShuttingDown() @@ -550,19 +535,21 @@ void SQLTransactionBackend::notifyDatabaseThreadIsShuttingDown() doCleanup(); } -SQLTransactionState SQLTransactionBackend::acquireLock() +void SQLTransactionBackend::acquireLock() { m_database->transactionCoordinator()->acquireLock(this); - return SQLTransactionState::Idle; } void SQLTransactionBackend::lockAcquired() { m_lockAcquired = true; - requestTransitToState(SQLTransactionState::OpenTransactionAndPreflight); + + m_requestedState = SQLTransactionState::OpenTransactionAndPreflight; + ASSERT(m_requestedState != SQLTransactionState::End); + m_database->scheduleTransactionStep(this); } -SQLTransactionState SQLTransactionBackend::openTransactionAndPreflight() +void SQLTransactionBackend::openTransactionAndPreflight() { ASSERT(!m_database->sqliteDatabase().transactionInProgress()); ASSERT(m_lockAcquired); @@ -570,9 +557,11 @@ SQLTransactionState SQLTransactionBackend::openTransactionAndPreflight() LOG(StorageAPI, "Opening and preflighting transaction %p", this); // If the database was deleted, jump to the error callback - if (Database::from(m_database.get())->deleted()) { + if (m_database->deleted()) { m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "unable to open a transaction, because the user deleted the database"); - return nextStateForTransactionError(); + + handleTransactionError(); + return; } // Set the maximum usage for this transaction if this transactions is not read-only @@ -582,7 +571,7 @@ SQLTransactionState SQLTransactionBackend::openTransactionAndPreflight() } ASSERT(!m_sqliteTransaction); - m_sqliteTransaction = adoptPtr(new SQLiteTransaction(m_database->sqliteDatabase(), m_readOnly)); + m_sqliteTransaction = std::make_unique<SQLiteTransaction>(m_database->sqliteDatabase(), m_readOnly); m_database->resetDeletes(); m_database->disableAuthorizer(); @@ -594,8 +583,10 @@ SQLTransactionState SQLTransactionBackend::openTransactionAndPreflight() ASSERT(!m_database->sqliteDatabase().transactionInProgress()); m_transactionError = SQLError::create(SQLError::DATABASE_ERR, "unable to begin transaction", m_database->sqliteDatabase().lastError(), m_database->sqliteDatabase().lastErrorMsg()); - m_sqliteTransaction.clear(); - return nextStateForTransactionError(); + m_sqliteTransaction = nullptr; + + handleTransactionError(); + return; } // Note: We intentionally retrieve the actual version even with an empty expected version. @@ -606,35 +597,41 @@ SQLTransactionState SQLTransactionBackend::openTransactionAndPreflight() m_transactionError = SQLError::create(SQLError::DATABASE_ERR, "unable to read version", m_database->sqliteDatabase().lastError(), m_database->sqliteDatabase().lastErrorMsg()); m_database->disableAuthorizer(); - m_sqliteTransaction.clear(); + m_sqliteTransaction = nullptr; m_database->enableAuthorizer(); - return nextStateForTransactionError(); + + handleTransactionError(); + return; } + m_hasVersionMismatch = !m_database->expectedVersion().isEmpty() && (m_database->expectedVersion() != actualVersion); // Spec 4.3.2.3: Perform preflight steps, jumping to the error callback if they fail if (m_wrapper && !m_wrapper->performPreflight(this)) { m_database->disableAuthorizer(); - m_sqliteTransaction.clear(); + m_sqliteTransaction = nullptr; m_database->enableAuthorizer(); m_transactionError = m_wrapper->sqlError(); if (!m_transactionError) m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "unknown error occurred during transaction preflight"); - return nextStateForTransactionError(); + + handleTransactionError(); + return; } // Spec 4.3.2.4: Invoke the transaction callback with the new SQLTransaction object - if (m_hasCallback) - return SQLTransactionState::DeliverTransactionCallback; + if (m_hasCallback) { + m_frontend->requestTransitToState(SQLTransactionState::DeliverTransactionCallback); + return; + } // If we have no callback to make, skip pass to the state after: - return SQLTransactionState::RunStatements; + runStatements(); } -SQLTransactionState SQLTransactionBackend::runStatements() +void SQLTransactionBackend::runStatements() { ASSERT(m_lockAcquired); - SQLTransactionState nextState; // If there is a series of statements queued up that are all successful and have no associated // SQLStatementCallback objects, then we can burn through the queue @@ -653,32 +650,36 @@ SQLTransactionState SQLTransactionBackend::runStatements() // 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_currentStatementBackend && m_currentStatementBackend->lastExecutionFailedDueToQuota()) { - return nextStateForCurrentStatementError(); + handleCurrentStatementError(); + break; } // Otherwise, advance to the next statement getNextStatement(); } - nextState = runCurrentStatementAndGetNextState(); - } while (nextState == SQLTransactionState::RunStatements); + } while (runCurrentStatement()); - return nextState; + // 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_currentStatementBackend) + postflightAndCommit(); } void SQLTransactionBackend::getNextStatement() { - m_currentStatementBackend = 0; + m_currentStatementBackend = nullptr; - MutexLocker locker(m_statementMutex); + LockHolder locker(m_statementMutex); if (!m_statementQueue.isEmpty()) m_currentStatementBackend = m_statementQueue.takeFirst(); } -SQLTransactionState SQLTransactionBackend::runCurrentStatementAndGetNextState() +bool SQLTransactionBackend::runCurrentStatement() { if (!m_currentStatementBackend) { // No more statements to run. So move on to the next state. - return SQLTransactionState::PostflightAndCommit; + return false; } m_database->resetAuthorizer(); @@ -686,42 +687,61 @@ SQLTransactionState SQLTransactionBackend::runCurrentStatementAndGetNextState() if (m_hasVersionMismatch) m_currentStatementBackend->setVersionMismatchedError(); - if (m_currentStatementBackend->execute(m_database.get())) { + if (m_currentStatementBackend->execute(*m_database)) { if (m_database->lastActionChangedDatabase()) { // Flag this transaction as having changed the database for later delegate notification m_modifiedDatabase = true; } if (m_currentStatementBackend->hasStatementCallback()) { - return SQLTransactionState::DeliverStatementCallback; + m_frontend->requestTransitToState(SQLTransactionState::DeliverStatementCallback); + return false; } // If we get here, then the statement doesn't have a callback to invoke. // We can move on to the next statement. Hence, stay in this state. - return SQLTransactionState::RunStatements; + return true; } if (m_currentStatementBackend->lastExecutionFailedDueToQuota()) { - return SQLTransactionState::DeliverQuotaIncreaseCallback; + m_frontend->requestTransitToState(SQLTransactionState::DeliverQuotaIncreaseCallback); + return false; } - return nextStateForCurrentStatementError(); + handleCurrentStatementError(); + return false; } -SQLTransactionState SQLTransactionBackend::nextStateForCurrentStatementError() +void SQLTransactionBackend::handleCurrentStatementError() { // Spec 4.3.2.6.6: error - Call the statement's error callback, but if there was no error callback, // or the transaction was rolled back, jump to the transaction error callback - if (m_currentStatementBackend->hasStatementErrorCallback() && !m_sqliteTransaction->wasRolledBackBySqlite()) - return SQLTransactionState::DeliverStatementCallback; + if (m_currentStatementBackend->hasStatementErrorCallback() && !m_sqliteTransaction->wasRolledBackBySqlite()) { + m_frontend->requestTransitToState(SQLTransactionState::DeliverStatementCallback); + return; + } m_transactionError = m_currentStatementBackend->sqlError(); if (!m_transactionError) m_transactionError = SQLError::create(SQLError::DATABASE_ERR, "the statement failed to execute"); - return nextStateForTransactionError(); + + handleTransactionError(); +} + +void SQLTransactionBackend::handleTransactionError() +{ + ASSERT(m_transactionError); + if (m_hasErrorCallback) { + m_frontend->requestTransitToState(SQLTransactionState::DeliverTransactionErrorCallback); + return; + } + + // No error callback, so fast-forward to the next state and rollback the + // transaction. + cleanupAfterTransactionErrorCallback(); } -SQLTransactionState SQLTransactionBackend::postflightAndCommit() +void SQLTransactionBackend::postflightAndCommit() { ASSERT(m_lockAcquired); @@ -730,7 +750,9 @@ SQLTransactionState SQLTransactionBackend::postflightAndCommit() m_transactionError = m_wrapper->sqlError(); if (!m_transactionError) m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "unknown error occurred during transaction postflight"); - return nextStateForTransactionError(); + + handleTransactionError(); + return; } // Spec 4.3.2.7: Commit the transaction, jumping to the error callback if that fails. @@ -748,7 +770,9 @@ SQLTransactionState SQLTransactionBackend::postflightAndCommit() m_wrapper->handleCommitFailedAfterPostflight(this); m_transactionError = SQLError::create(SQLError::DATABASE_ERR, "unable to commit transaction", m_database->sqliteDatabase().lastError(), m_database->sqliteDatabase().lastErrorMsg()); - return nextStateForTransactionError(); + + handleTransactionError(); + return; } // Vacuum the database if anything was deleted. @@ -760,10 +784,10 @@ SQLTransactionState SQLTransactionBackend::postflightAndCommit() m_database->transactionClient()->didCommitWriteTransaction(database()); // Spec 4.3.2.8: Deliver success callback, if there is one. - return SQLTransactionState::DeliverSuccessCallback; + m_frontend->requestTransitToState(SQLTransactionState::DeliverSuccessCallback); } -SQLTransactionState SQLTransactionBackend::cleanupAndTerminate() +void SQLTransactionBackend::cleanupAndTerminate() { ASSERT(m_lockAcquired); @@ -774,21 +798,9 @@ SQLTransactionState SQLTransactionBackend::cleanupAndTerminate() // Phase 5 cleanup. See comment on the SQLTransaction life-cycle above. doCleanup(); m_database->inProgressTransactionCompleted(); - return SQLTransactionState::End; } -SQLTransactionState SQLTransactionBackend::nextStateForTransactionError() -{ - ASSERT(m_transactionError); - if (m_hasErrorCallback) - return SQLTransactionState::DeliverTransactionErrorCallback; - - // No error callback, so fast-forward to the next state and rollback the - // transaction. - return SQLTransactionState::CleanupAfterTransactionErrorCallback; -} - -SQLTransactionState SQLTransactionBackend::cleanupAfterTransactionErrorCallback() +void SQLTransactionBackend::cleanupAfterTransactionErrorCallback() { ASSERT(m_lockAcquired); @@ -799,7 +811,7 @@ SQLTransactionState SQLTransactionBackend::cleanupAfterTransactionErrorCallback( m_sqliteTransaction->rollback(); ASSERT(!m_database->sqliteDatabase().transactionInProgress()); - m_sqliteTransaction.clear(); + m_sqliteTransaction = nullptr; } m_database->enableAuthorizer(); @@ -807,7 +819,7 @@ SQLTransactionState SQLTransactionBackend::cleanupAfterTransactionErrorCallback( ASSERT(!m_database->sqliteDatabase().transactionInProgress()); - return SQLTransactionState::CleanupAndTerminate; + cleanupAndTerminate(); } // requestTransitToState() can be called from the frontend. Hence, it should @@ -824,17 +836,9 @@ void SQLTransactionBackend::requestTransitToState(SQLTransactionState nextState) // This state function is used as a stub function to plug unimplemented states // in the state dispatch table. They are unimplemented because they should // never be reached in the course of correct execution. -SQLTransactionState SQLTransactionBackend::unreachableState() +void SQLTransactionBackend::unreachableState() { ASSERT_NOT_REACHED(); - return SQLTransactionState::End; -} - -SQLTransactionState SQLTransactionBackend::sendToFrontendState() -{ - ASSERT(m_nextState != SQLTransactionState::Idle); - m_frontend->requestTransitToState(m_nextState); - return SQLTransactionState::Idle; } void SQLTransactionBackend::acquireOriginLock() @@ -848,10 +852,8 @@ void SQLTransactionBackend::releaseOriginLockIfNeeded() { if (m_originLock) { m_originLock->unlock(); - m_originLock.clear(); + m_originLock = nullptr; } } } // namespace WebCore - -#endif // ENABLE(SQL_DATABASE) |