summaryrefslogtreecommitdiff
path: root/Source/WebCore/Modules/webdatabase/SQLTransactionBackend.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2016-04-10 09:28:39 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2016-04-10 09:28:39 +0000
commit32761a6cee1d0dee366b885b7b9c777e67885688 (patch)
treed6bec92bebfb216f4126356e55518842c2f476a1 /Source/WebCore/Modules/webdatabase/SQLTransactionBackend.cpp
parenta4e969f4965059196ca948db781e52f7cfebf19e (diff)
downloadWebKitGtk-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.cpp230
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)