diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-04-10 09:28:39 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-04-10 09:28:39 +0000 |
commit | 32761a6cee1d0dee366b885b7b9c777e67885688 (patch) | |
tree | d6bec92bebfb216f4126356e55518842c2f476a1 /Source/WebCore/Modules/webdatabase/SQLTransactionBackend.cpp | |
parent | a4e969f4965059196ca948db781e52f7cfebf19e (diff) | |
download | WebKitGtk-tarball-32761a6cee1d0dee366b885b7b9c777e67885688.tar.gz |
webkitgtk-2.4.11webkitgtk-2.4.11
Diffstat (limited to 'Source/WebCore/Modules/webdatabase/SQLTransactionBackend.cpp')
-rw-r--r-- | Source/WebCore/Modules/webdatabase/SQLTransactionBackend.cpp | 230 |
1 files changed, 114 insertions, 116 deletions
diff --git a/Source/WebCore/Modules/webdatabase/SQLTransactionBackend.cpp b/Source/WebCore/Modules/webdatabase/SQLTransactionBackend.cpp index 9d086cb0b..244f28566 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 Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Computer, 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,19 +29,20 @@ #include "config.h" #include "SQLTransactionBackend.h" -#include "Database.h" +#if ENABLE(SQL_DATABASE) + +#include "AbstractSQLTransaction.h" +#include "Database.h" // FIXME: Should only be used in the frontend. #include "DatabaseAuthorizer.h" -#include "DatabaseContext.h" +#include "DatabaseBackend.h" +#include "DatabaseBackendContext.h" #include "DatabaseThread.h" #include "DatabaseTracker.h" #include "ExceptionCode.h" #include "Logging.h" #include "OriginLock.h" #include "SQLError.h" -#include "SQLStatement.h" -#include "SQLStatementCallback.h" -#include "SQLStatementErrorCallback.h" -#include "SQLTransaction.h" +#include "SQLStatementBackend.h" #include "SQLTransactionClient.h" #include "SQLTransactionCoordinator.h" #include "SQLValue.h" @@ -259,7 +260,7 @@ // // When executing the transaction (in DatabaseThread::databaseThread()): // ==================================================================== -// std::unique_ptr<DatabaseTask> task; // points to ... +// OwnPtr<DatabaseTask> task; // points to ... // --> DatabaseTransactionTask // RefPtr<SQLTransactionBackend> m_transaction points to ... // --> SQLTransactionBackend // RefPtr<SQLTransaction> m_frontend; // --> SQLTransaction // RefPtr<SQLTransactionBackend> m_backend points to ... @@ -283,7 +284,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 std::unique_ptr. +// task OwnPtr. // // What happens if a transaction is interrupted? // ============================================ @@ -343,12 +344,14 @@ namespace WebCore { -Ref<SQLTransactionBackend> SQLTransactionBackend::create(Database* db, PassRefPtr<SQLTransaction> frontend, PassRefPtr<SQLTransactionWrapper> wrapper, bool readOnly) +PassRefPtr<SQLTransactionBackend> SQLTransactionBackend::create(DatabaseBackend* db, + PassRefPtr<AbstractSQLTransaction> frontend, PassRefPtr<SQLTransactionWrapper> wrapper, bool readOnly) { - return adoptRef(*new SQLTransactionBackend(db, frontend, wrapper, readOnly)); + return adoptRef(new SQLTransactionBackend(db, frontend, wrapper, readOnly)); } -SQLTransactionBackend::SQLTransactionBackend(Database* db, PassRefPtr<SQLTransaction> frontend, PassRefPtr<SQLTransactionWrapper> wrapper, bool readOnly) +SQLTransactionBackend::SQLTransactionBackend(DatabaseBackend* db, + PassRefPtr<AbstractSQLTransaction> frontend, PassRefPtr<SQLTransactionWrapper> wrapper, bool readOnly) : m_frontend(frontend) , m_database(db) , m_wrapper(wrapper) @@ -375,13 +378,13 @@ void SQLTransactionBackend::doCleanup() { if (!m_frontend) return; - m_frontend = nullptr; // Break the reference cycle. See comment about the life-cycle above. + m_frontend = 0; // Break the reference cycle. See comment about the life-cycle above. ASSERT(currentThread() == database()->databaseContext()->databaseThread()->getThreadID()); releaseOriginLockIfNeeded(); - LockHolder locker(m_statementMutex); + MutexLocker locker(m_statementMutex); m_statementQueue.clear(); if (m_sqliteTransaction) { @@ -390,7 +393,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 = nullptr; + m_sqliteTransaction.clear(); } // Release the lock on this database @@ -420,12 +423,12 @@ void SQLTransactionBackend::doCleanup() // SQLTransactionBackend is guaranteed to not destruct until the frontend // is also destructing. - m_wrapper = nullptr; + m_wrapper = 0; } -SQLStatement* SQLTransactionBackend::currentStatement() +AbstractSQLStatement* SQLTransactionBackend::currentStatement() { - return m_currentStatementBackend.get(); + return m_currentStatementBackend->frontend(); } PassRefPtr<SQLError> SQLTransactionBackend::transactionError() @@ -447,14 +450,14 @@ SQLTransactionBackend::StateFunction SQLTransactionBackend::stateFunctionFor(SQL &SQLTransactionBackend::acquireLock, // 2. &SQLTransactionBackend::openTransactionAndPreflight, // 3. &SQLTransactionBackend::runStatements, // 4. - &SQLTransactionBackend::unreachableState, // 5. postflightAndCommit + &SQLTransactionBackend::postflightAndCommit, // 5. &SQLTransactionBackend::cleanupAndTerminate, // 6. &SQLTransactionBackend::cleanupAfterTransactionErrorCallback, // 7. - &SQLTransactionBackend::unreachableState, // 8. deliverTransactionCallback - &SQLTransactionBackend::unreachableState, // 9. deliverTransactionErrorCallback - &SQLTransactionBackend::unreachableState, // 10. deliverStatementCallback - &SQLTransactionBackend::unreachableState, // 11. deliverQuotaIncreaseCallback - &SQLTransactionBackend::unreachableState // 12. deliverSuccessCallback + &SQLTransactionBackend::sendToFrontendState, // 8. deliverTransactionCallback + &SQLTransactionBackend::sendToFrontendState, // 9. deliverTransactionErrorCallback + &SQLTransactionBackend::sendToFrontendState, // 10. deliverStatementCallback + &SQLTransactionBackend::sendToFrontendState, // 11. deliverQuotaIncreaseCallback + &SQLTransactionBackend::sendToFrontendState // 12. deliverSuccessCallback }; ASSERT(WTF_ARRAY_LENGTH(stateFunctions) == static_cast<int>(SQLTransactionState::NumberOfStates)); @@ -463,17 +466,17 @@ SQLTransactionBackend::StateFunction SQLTransactionBackend::stateFunctionFor(SQL return stateFunctions[static_cast<int>(state)]; } -void SQLTransactionBackend::enqueueStatementBackend(std::unique_ptr<SQLStatement> statementBackend) +void SQLTransactionBackend::enqueueStatementBackend(PassRefPtr<SQLStatementBackend> statementBackend) { - LockHolder locker(m_statementMutex); - m_statementQueue.append(WTFMove(statementBackend)); + MutexLocker locker(m_statementMutex); + m_statementQueue.append(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()) { + if (m_database->opened() && !m_database->isInterrupted()) { setStateToRequestedState(); ASSERT(m_nextState == SQLTransactionState::AcquireLock || m_nextState == SQLTransactionState::OpenTransactionAndPreflight @@ -497,7 +500,7 @@ void SQLTransactionBackend::computeNextStateAndCleanupIfNeeded() // The current SQLite transaction should be stopped, as well if (m_sqliteTransaction) { m_sqliteTransaction->stop(); - m_sqliteTransaction = nullptr; + m_sqliteTransaction.clear(); } // Terminate the frontend state machine. This also gets the frontend to @@ -515,12 +518,24 @@ void SQLTransactionBackend::performNextStep() runStateMachine(); } -void SQLTransactionBackend::executeSQL(std::unique_ptr<SQLStatement> statementBackend) +#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) { - if (m_database->deleted()) + RefPtr<SQLStatementBackend> statementBackend; + statementBackend = SQLStatementBackend::create(statement, sqlStatement, arguments, permissions); + + if (Database::from(m_database.get())->deleted()) statementBackend->setDatabaseDeletedError(); - enqueueStatementBackend(WTFMove(statementBackend)); + enqueueStatementBackend(statementBackend); } void SQLTransactionBackend::notifyDatabaseThreadIsShuttingDown() @@ -535,21 +550,19 @@ void SQLTransactionBackend::notifyDatabaseThreadIsShuttingDown() doCleanup(); } -void SQLTransactionBackend::acquireLock() +SQLTransactionState SQLTransactionBackend::acquireLock() { m_database->transactionCoordinator()->acquireLock(this); + return SQLTransactionState::Idle; } void SQLTransactionBackend::lockAcquired() { m_lockAcquired = true; - - m_requestedState = SQLTransactionState::OpenTransactionAndPreflight; - ASSERT(m_requestedState != SQLTransactionState::End); - m_database->scheduleTransactionStep(this); + requestTransitToState(SQLTransactionState::OpenTransactionAndPreflight); } -void SQLTransactionBackend::openTransactionAndPreflight() +SQLTransactionState SQLTransactionBackend::openTransactionAndPreflight() { ASSERT(!m_database->sqliteDatabase().transactionInProgress()); ASSERT(m_lockAcquired); @@ -557,11 +570,9 @@ void SQLTransactionBackend::openTransactionAndPreflight() LOG(StorageAPI, "Opening and preflighting transaction %p", this); // If the database was deleted, jump to the error callback - if (m_database->deleted()) { + if (Database::from(m_database.get())->deleted()) { m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "unable to open a transaction, because the user deleted the database"); - - handleTransactionError(); - return; + return nextStateForTransactionError(); } // Set the maximum usage for this transaction if this transactions is not read-only @@ -571,7 +582,7 @@ void SQLTransactionBackend::openTransactionAndPreflight() } ASSERT(!m_sqliteTransaction); - m_sqliteTransaction = std::make_unique<SQLiteTransaction>(m_database->sqliteDatabase(), m_readOnly); + m_sqliteTransaction = adoptPtr(new SQLiteTransaction(m_database->sqliteDatabase(), m_readOnly)); m_database->resetDeletes(); m_database->disableAuthorizer(); @@ -583,10 +594,8 @@ void 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 = nullptr; - - handleTransactionError(); - return; + m_sqliteTransaction.clear(); + return nextStateForTransactionError(); } // Note: We intentionally retrieve the actual version even with an empty expected version. @@ -597,41 +606,35 @@ void 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 = nullptr; + m_sqliteTransaction.clear(); m_database->enableAuthorizer(); - - handleTransactionError(); - return; + return nextStateForTransactionError(); } - 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 = nullptr; + m_sqliteTransaction.clear(); m_database->enableAuthorizer(); m_transactionError = m_wrapper->sqlError(); if (!m_transactionError) m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "unknown error occurred during transaction preflight"); - - handleTransactionError(); - return; + return nextStateForTransactionError(); } // Spec 4.3.2.4: Invoke the transaction callback with the new SQLTransaction object - if (m_hasCallback) { - m_frontend->requestTransitToState(SQLTransactionState::DeliverTransactionCallback); - return; - } + if (m_hasCallback) + return SQLTransactionState::DeliverTransactionCallback; // If we have no callback to make, skip pass to the state after: - runStatements(); + return SQLTransactionState::RunStatements; } -void SQLTransactionBackend::runStatements() +SQLTransactionState 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 @@ -650,36 +653,32 @@ void 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()) { - handleCurrentStatementError(); - break; + return nextStateForCurrentStatementError(); } // Otherwise, advance to the next statement getNextStatement(); } - } while (runCurrentStatement()); + nextState = runCurrentStatementAndGetNextState(); + } while (nextState == SQLTransactionState::RunStatements); - // 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(); + return nextState; } void SQLTransactionBackend::getNextStatement() { - m_currentStatementBackend = nullptr; + m_currentStatementBackend = 0; - LockHolder locker(m_statementMutex); + MutexLocker locker(m_statementMutex); if (!m_statementQueue.isEmpty()) m_currentStatementBackend = m_statementQueue.takeFirst(); } -bool SQLTransactionBackend::runCurrentStatement() +SQLTransactionState SQLTransactionBackend::runCurrentStatementAndGetNextState() { if (!m_currentStatementBackend) { // No more statements to run. So move on to the next state. - return false; + return SQLTransactionState::PostflightAndCommit; } m_database->resetAuthorizer(); @@ -687,61 +686,42 @@ bool SQLTransactionBackend::runCurrentStatement() if (m_hasVersionMismatch) m_currentStatementBackend->setVersionMismatchedError(); - if (m_currentStatementBackend->execute(*m_database)) { + if (m_currentStatementBackend->execute(m_database.get())) { if (m_database->lastActionChangedDatabase()) { // Flag this transaction as having changed the database for later delegate notification m_modifiedDatabase = true; } if (m_currentStatementBackend->hasStatementCallback()) { - m_frontend->requestTransitToState(SQLTransactionState::DeliverStatementCallback); - return false; + return SQLTransactionState::DeliverStatementCallback; } // 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 true; + return SQLTransactionState::RunStatements; } if (m_currentStatementBackend->lastExecutionFailedDueToQuota()) { - m_frontend->requestTransitToState(SQLTransactionState::DeliverQuotaIncreaseCallback); - return false; + return SQLTransactionState::DeliverQuotaIncreaseCallback; } - handleCurrentStatementError(); - return false; + return nextStateForCurrentStatementError(); } -void SQLTransactionBackend::handleCurrentStatementError() +SQLTransactionState SQLTransactionBackend::nextStateForCurrentStatementError() { // 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()) { - m_frontend->requestTransitToState(SQLTransactionState::DeliverStatementCallback); - return; - } + if (m_currentStatementBackend->hasStatementErrorCallback() && !m_sqliteTransaction->wasRolledBackBySqlite()) + return SQLTransactionState::DeliverStatementCallback; m_transactionError = m_currentStatementBackend->sqlError(); if (!m_transactionError) m_transactionError = SQLError::create(SQLError::DATABASE_ERR, "the statement failed to execute"); - - 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(); + return nextStateForTransactionError(); } -void SQLTransactionBackend::postflightAndCommit() +SQLTransactionState SQLTransactionBackend::postflightAndCommit() { ASSERT(m_lockAcquired); @@ -750,9 +730,7 @@ void SQLTransactionBackend::postflightAndCommit() m_transactionError = m_wrapper->sqlError(); if (!m_transactionError) m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "unknown error occurred during transaction postflight"); - - handleTransactionError(); - return; + return nextStateForTransactionError(); } // Spec 4.3.2.7: Commit the transaction, jumping to the error callback if that fails. @@ -770,9 +748,7 @@ void 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()); - - handleTransactionError(); - return; + return nextStateForTransactionError(); } // Vacuum the database if anything was deleted. @@ -784,10 +760,10 @@ void SQLTransactionBackend::postflightAndCommit() m_database->transactionClient()->didCommitWriteTransaction(database()); // Spec 4.3.2.8: Deliver success callback, if there is one. - m_frontend->requestTransitToState(SQLTransactionState::DeliverSuccessCallback); + return SQLTransactionState::DeliverSuccessCallback; } -void SQLTransactionBackend::cleanupAndTerminate() +SQLTransactionState SQLTransactionBackend::cleanupAndTerminate() { ASSERT(m_lockAcquired); @@ -798,9 +774,21 @@ void SQLTransactionBackend::cleanupAndTerminate() // Phase 5 cleanup. See comment on the SQLTransaction life-cycle above. doCleanup(); m_database->inProgressTransactionCompleted(); + return SQLTransactionState::End; } -void SQLTransactionBackend::cleanupAfterTransactionErrorCallback() +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() { ASSERT(m_lockAcquired); @@ -811,7 +799,7 @@ void SQLTransactionBackend::cleanupAfterTransactionErrorCallback() m_sqliteTransaction->rollback(); ASSERT(!m_database->sqliteDatabase().transactionInProgress()); - m_sqliteTransaction = nullptr; + m_sqliteTransaction.clear(); } m_database->enableAuthorizer(); @@ -819,7 +807,7 @@ void SQLTransactionBackend::cleanupAfterTransactionErrorCallback() ASSERT(!m_database->sqliteDatabase().transactionInProgress()); - cleanupAndTerminate(); + return SQLTransactionState::CleanupAndTerminate; } // requestTransitToState() can be called from the frontend. Hence, it should @@ -836,9 +824,17 @@ 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. -void SQLTransactionBackend::unreachableState() +SQLTransactionState 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() @@ -852,8 +848,10 @@ void SQLTransactionBackend::releaseOriginLockIfNeeded() { if (m_originLock) { m_originLock->unlock(); - m_originLock = nullptr; + m_originLock.clear(); } } } // namespace WebCore + +#endif // ENABLE(SQL_DATABASE) |