Home | History | Annotate | Download | only in webdatabase
      1 /*
      2  * Copyright (C) 2013 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "modules/webdatabase/DatabaseBackend.h"
     28 
     29 #include "core/platform/Logging.h"
     30 #include "modules/webdatabase/ChangeVersionData.h"
     31 #include "modules/webdatabase/ChangeVersionWrapper.h"
     32 #include "modules/webdatabase/DatabaseBackendContext.h"
     33 #include "modules/webdatabase/DatabaseTask.h"
     34 #include "modules/webdatabase/DatabaseThread.h"
     35 #include "modules/webdatabase/DatabaseTracker.h"
     36 #include "modules/webdatabase/SQLTransaction.h"
     37 #include "modules/webdatabase/SQLTransactionBackend.h"
     38 #include "modules/webdatabase/SQLTransactionClient.h"
     39 #include "modules/webdatabase/SQLTransactionCoordinator.h"
     40 
     41 namespace WebCore {
     42 
     43 DatabaseBackend::DatabaseBackend(PassRefPtr<DatabaseBackendContext> databaseContext, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize)
     44     : DatabaseBackendBase(databaseContext, name, expectedVersion, displayName, estimatedSize, DatabaseType::Async)
     45     , m_transactionInProgress(false)
     46     , m_isTransactionQueueEnabled(true)
     47 {
     48 }
     49 
     50 bool DatabaseBackend::openAndVerifyVersion(bool setVersionInNewDatabase, DatabaseError& error, String& errorMessage)
     51 {
     52     DatabaseTaskSynchronizer synchronizer;
     53     if (!databaseContext()->databaseThread() || databaseContext()->databaseThread()->terminationRequested(&synchronizer))
     54         return false;
     55 
     56     DatabaseTracker::tracker().prepareToOpenDatabase(this);
     57     bool success = false;
     58     OwnPtr<DatabaseOpenTask> task = DatabaseOpenTask::create(this, setVersionInNewDatabase, &synchronizer, error, errorMessage, success);
     59     databaseContext()->databaseThread()->scheduleImmediateTask(task.release());
     60     synchronizer.waitForTaskCompletion();
     61 
     62     return success;
     63 }
     64 
     65 bool DatabaseBackend::performOpenAndVerify(bool setVersionInNewDatabase, DatabaseError& error, String& errorMessage)
     66 {
     67     if (DatabaseBackendBase::performOpenAndVerify(setVersionInNewDatabase, error, errorMessage)) {
     68         if (databaseContext()->databaseThread())
     69             databaseContext()->databaseThread()->recordDatabaseOpen(this);
     70 
     71         return true;
     72     }
     73 
     74     return false;
     75 }
     76 
     77 void DatabaseBackend::close()
     78 {
     79     ASSERT(databaseContext()->databaseThread());
     80     ASSERT(currentThread() == databaseContext()->databaseThread()->getThreadID());
     81 
     82     {
     83         MutexLocker locker(m_transactionInProgressMutex);
     84 
     85         // Clean up transactions that have not been scheduled yet:
     86         // Transaction phase 1 cleanup. See comment on "What happens if a
     87         // transaction is interrupted?" at the top of SQLTransactionBackend.cpp.
     88         RefPtr<SQLTransactionBackend> transaction;
     89         while (!m_transactionQueue.isEmpty()) {
     90             transaction = m_transactionQueue.takeFirst();
     91             transaction->notifyDatabaseThreadIsShuttingDown();
     92         }
     93 
     94         m_isTransactionQueueEnabled = false;
     95         m_transactionInProgress = false;
     96     }
     97 
     98     closeDatabase();
     99 
    100     // DatabaseThread keeps databases alive by referencing them in its
    101     // m_openDatabaseSet. DatabaseThread::recordDatabaseClose() will remove
    102     // this database from that set (which effectively deref's it). We hold on
    103     // to it with a local pointer here for a liitle longer, so that we can
    104     // unschedule any DatabaseTasks that refer to it before the database gets
    105     // deleted.
    106     RefPtr<DatabaseBackend> protect = this;
    107     databaseContext()->databaseThread()->recordDatabaseClosed(this);
    108     databaseContext()->databaseThread()->unscheduleDatabaseTasks(this);
    109 }
    110 
    111 PassRefPtr<SQLTransactionBackend> DatabaseBackend::runTransaction(PassRefPtr<SQLTransaction> transaction,
    112     bool readOnly, const ChangeVersionData* data)
    113 {
    114     MutexLocker locker(m_transactionInProgressMutex);
    115     if (!m_isTransactionQueueEnabled)
    116         return 0;
    117 
    118     RefPtr<SQLTransactionWrapper> wrapper;
    119     if (data)
    120         wrapper = ChangeVersionWrapper::create(data->oldVersion(), data->newVersion());
    121 
    122     RefPtr<SQLTransactionBackend> transactionBackend = SQLTransactionBackend::create(this, transaction, wrapper, readOnly);
    123     m_transactionQueue.append(transactionBackend);
    124     if (!m_transactionInProgress)
    125         scheduleTransaction();
    126 
    127     return transactionBackend;
    128 }
    129 
    130 void DatabaseBackend::inProgressTransactionCompleted()
    131 {
    132     MutexLocker locker(m_transactionInProgressMutex);
    133     m_transactionInProgress = false;
    134     scheduleTransaction();
    135 }
    136 
    137 void DatabaseBackend::scheduleTransaction()
    138 {
    139     ASSERT(!m_transactionInProgressMutex.tryLock()); // Locked by caller.
    140     RefPtr<SQLTransactionBackend> transaction;
    141 
    142     if (m_isTransactionQueueEnabled && !m_transactionQueue.isEmpty())
    143         transaction = m_transactionQueue.takeFirst();
    144 
    145     if (transaction && databaseContext()->databaseThread()) {
    146         OwnPtr<DatabaseTransactionTask> task = DatabaseTransactionTask::create(transaction);
    147         LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for transaction %p\n", task.get(), task->transaction());
    148         m_transactionInProgress = true;
    149         databaseContext()->databaseThread()->scheduleTask(task.release());
    150     } else
    151         m_transactionInProgress = false;
    152 }
    153 
    154 void DatabaseBackend::scheduleTransactionStep(SQLTransactionBackend* transaction)
    155 {
    156     if (!databaseContext()->databaseThread())
    157         return;
    158 
    159     OwnPtr<DatabaseTransactionTask> task = DatabaseTransactionTask::create(transaction);
    160     LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for the transaction step\n", task.get());
    161     databaseContext()->databaseThread()->scheduleTask(task.release());
    162 }
    163 
    164 SQLTransactionClient* DatabaseBackend::transactionClient() const
    165 {
    166     return databaseContext()->databaseThread()->transactionClient();
    167 }
    168 
    169 SQLTransactionCoordinator* DatabaseBackend::transactionCoordinator() const
    170 {
    171     return databaseContext()->databaseThread()->transactionCoordinator();
    172 }
    173 
    174 } // namespace WebCore
    175