summaryrefslogtreecommitdiff
path: root/Source/WebCore/Modules/webdatabase/SQLTransactionBackend.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2016-05-24 08:28:08 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2016-05-24 08:28:08 +0000
commita4e969f4965059196ca948db781e52f7cfebf19e (patch)
tree6ca352808c8fdc52006a0f33f6ae3c593b23867d /Source/WebCore/Modules/webdatabase/SQLTransactionBackend.cpp
parent41386e9cb918eed93b3f13648cbef387e371e451 (diff)
downloadWebKitGtk-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.cpp230
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)