DatabaseBackend.cpp [plain text]
#include "config.h"
#include "DatabaseBackend.h"
#if ENABLE(SQL_DATABASE)
#include "ChangeVersionData.h"
#include "ChangeVersionWrapper.h"
#include "DatabaseBackendContext.h"
#include "DatabaseTask.h"
#include "DatabaseThread.h"
#include "DatabaseTracker.h"
#include "Logging.h"
#include "SQLTransaction.h"
#include "SQLTransactionBackend.h"
#include "SQLTransactionClient.h"
#include "SQLTransactionCoordinator.h"
namespace WebCore {
DatabaseBackend::DatabaseBackend(PassRefPtr<DatabaseBackendContext> databaseContext, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize)
: DatabaseBackendBase(databaseContext, name, expectedVersion, displayName, estimatedSize, DatabaseType::Async)
, m_transactionInProgress(false)
, m_isTransactionQueueEnabled(true)
{
}
bool DatabaseBackend::openAndVerifyVersion(bool setVersionInNewDatabase, DatabaseError& error, String& errorMessage)
{
DatabaseTaskSynchronizer synchronizer;
if (!databaseContext()->databaseThread() || databaseContext()->databaseThread()->terminationRequested(&synchronizer))
return false;
bool success = false;
auto task = DatabaseOpenTask::create(this, setVersionInNewDatabase, &synchronizer, error, errorMessage, success);
databaseContext()->databaseThread()->scheduleImmediateTask(WTF::move(task));
synchronizer.waitForTaskCompletion();
return success;
}
bool DatabaseBackend::performOpenAndVerify(bool setVersionInNewDatabase, DatabaseError& error, String& errorMessage)
{
if (DatabaseBackendBase::performOpenAndVerify(setVersionInNewDatabase, error, errorMessage)) {
if (databaseContext()->databaseThread())
databaseContext()->databaseThread()->recordDatabaseOpen(this);
return true;
}
return false;
}
void DatabaseBackend::close()
{
ASSERT(databaseContext()->databaseThread());
ASSERT(currentThread() == databaseContext()->databaseThread()->getThreadID());
{
MutexLocker locker(m_transactionInProgressMutex);
RefPtr<SQLTransactionBackend> transaction;
while (!m_transactionQueue.isEmpty()) {
transaction = m_transactionQueue.takeFirst();
transaction->notifyDatabaseThreadIsShuttingDown();
}
m_isTransactionQueueEnabled = false;
m_transactionInProgress = false;
}
closeDatabase();
Ref<DatabaseBackend> protect(*this);
databaseContext()->databaseThread()->recordDatabaseClosed(this);
databaseContext()->databaseThread()->unscheduleDatabaseTasks(this);
}
PassRefPtr<SQLTransactionBackend> DatabaseBackend::runTransaction(PassRefPtr<SQLTransaction> transaction,
bool readOnly, const ChangeVersionData* data)
{
MutexLocker locker(m_transactionInProgressMutex);
if (!m_isTransactionQueueEnabled)
return 0;
RefPtr<SQLTransactionWrapper> wrapper;
if (data)
wrapper = ChangeVersionWrapper::create(data->oldVersion(), data->newVersion());
RefPtr<SQLTransactionBackend> transactionBackend = SQLTransactionBackend::create(this, transaction, wrapper, readOnly);
m_transactionQueue.append(transactionBackend);
if (!m_transactionInProgress)
scheduleTransaction();
return transactionBackend;
}
void DatabaseBackend::inProgressTransactionCompleted()
{
MutexLocker locker(m_transactionInProgressMutex);
m_transactionInProgress = false;
scheduleTransaction();
}
void DatabaseBackend::scheduleTransaction()
{
ASSERT(!m_transactionInProgressMutex.tryLock()); RefPtr<SQLTransactionBackend> transaction;
if (m_isTransactionQueueEnabled && !m_transactionQueue.isEmpty())
transaction = m_transactionQueue.takeFirst();
if (transaction && databaseContext()->databaseThread()) {
auto task = DatabaseTransactionTask::create(transaction);
LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for transaction %p\n", task.get(), task->transaction());
m_transactionInProgress = true;
databaseContext()->databaseThread()->scheduleTask(WTF::move(task));
} else
m_transactionInProgress = false;
}
void DatabaseBackend::scheduleTransactionStep(SQLTransactionBackend* transaction)
{
if (!databaseContext()->databaseThread())
return;
auto task = DatabaseTransactionTask::create(transaction);
LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for the transaction step\n", task.get());
databaseContext()->databaseThread()->scheduleTask(WTF::move(task));
}
SQLTransactionClient* DatabaseBackend::transactionClient() const
{
return databaseContext()->databaseThread()->transactionClient();
}
SQLTransactionCoordinator* DatabaseBackend::transactionCoordinator() const
{
return databaseContext()->databaseThread()->transactionCoordinator();
}
}
#endif // ENABLE(SQL_DATABASE)