Home | History | Annotate | Download | only in webdatabase
      1 /*
      2  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
      3  * Copyright (C) 2011 Google, Inc. All Rights Reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  *
     26  */
     27 
     28 #include "config.h"
     29 #include "modules/webdatabase/DatabaseContext.h"
     30 
     31 #include "core/dom/Document.h"
     32 #include "core/dom/ExecutionContext.h"
     33 #include "modules/webdatabase/Database.h"
     34 #include "modules/webdatabase/DatabaseManager.h"
     35 #include "modules/webdatabase/DatabaseTask.h"
     36 #include "modules/webdatabase/DatabaseThread.h"
     37 #include "platform/weborigin/SchemeRegistry.h"
     38 #include "platform/weborigin/SecurityOrigin.h"
     39 #include "wtf/Assertions.h"
     40 
     41 namespace WebCore {
     42 
     43 // How the DatabaseContext Life-Cycle works?
     44 // ========================================
     45 // ... in other words, who's keeping the DatabaseContext alive and how long does
     46 // it need to stay alive?
     47 //
     48 // The DatabaseContext is referenced from RefPtrs in:
     49 // 1. ExecutionContext
     50 // 2. Database
     51 //
     52 // At Birth:
     53 // ========
     54 // We create a DatabaseContext only when there is a need i.e. the script tries to
     55 // open a Database via DatabaseManager::openDatabase().
     56 //
     57 // The DatabaseContext constructor will call ref(). This lets DatabaseContext keep itself alive.
     58 // Note that paired deref() is called from contextDestroyed().
     59 //
     60 // Once a DatabaseContext is associated with a ExecutionContext, it will
     61 // live until after the ExecutionContext destructs. This is true even if
     62 // we don't succeed in opening any Databases for that context. When we do
     63 // succeed in opening Databases for this ExecutionContext, the Database
     64 // will re-use the same DatabaseContext.
     65 //
     66 // At Shutdown:
     67 // ===========
     68 // During shutdown, the DatabaseContext needs to:
     69 // 1. "outlive" the ExecutionContext.
     70 //    - This is needed because the DatabaseContext needs to remove itself from the
     71 //      ExecutionContext's ActiveDOMObject list and ContextLifecycleObserver
     72 //      list. This removal needs to be executed on the script's thread. Hence, we
     73 //      rely on the ExecutionContext's shutdown process to call
     74 //      stop() and contextDestroyed() to give us a chance to clean these up from
     75 //      the script thread.
     76 //
     77 // 2. "outlive" the Databases.
     78 //    - This is because they may make use of the DatabaseContext to execute a close
     79 //      task and shutdown in an orderly manner. When the Databases are destructed,
     80 //      they will deref the DatabaseContext from the DatabaseThread.
     81 //
     82 // During shutdown, the ExecutionContext is shutting down on the script thread
     83 // while the Databases are shutting down on the DatabaseThread. Hence, there can be
     84 // a race condition as to whether the ExecutionContext or the Databases
     85 // destruct first.
     86 //
     87 // The RefPtrs in the Databases and ExecutionContext will ensure that the
     88 // DatabaseContext will outlive both regardless of which of the 2 destructs first.
     89 
     90 PassRefPtrWillBeRawPtr<DatabaseContext> DatabaseContext::create(ExecutionContext* context)
     91 {
     92     RefPtrWillBeRawPtr<DatabaseContext> self = adoptRefWillBeNoop(new DatabaseContext(context));
     93     DatabaseManager::manager().registerDatabaseContext(self.get());
     94     return self.release();
     95 }
     96 
     97 DatabaseContext::DatabaseContext(ExecutionContext* context)
     98     : ActiveDOMObject(context)
     99     , m_hasOpenDatabases(false)
    100     , m_hasRequestedTermination(false)
    101 {
    102     // ActiveDOMObject expects this to be called to set internal flags.
    103     suspendIfNeeded();
    104 
    105     // For debug accounting only. We must do this before we register the
    106     // instance. The assertions assume this.
    107     DatabaseManager::manager().didConstructDatabaseContext();
    108     if (context->isWorkerGlobalScope())
    109         toWorkerGlobalScope(context)->registerTerminationObserver(this);
    110 }
    111 
    112 DatabaseContext::~DatabaseContext()
    113 {
    114     // For debug accounting only. We must call this last. The assertions assume
    115     // this.
    116     DatabaseManager::manager().didDestructDatabaseContext();
    117 }
    118 
    119 void DatabaseContext::trace(Visitor* visitor)
    120 {
    121     visitor->trace(m_databaseThread);
    122     visitor->trace(m_openSyncDatabases);
    123 }
    124 
    125 // This is called if the associated ExecutionContext is destructing while
    126 // we're still associated with it. That's our cue to disassociate and shutdown.
    127 // To do this, we stop the database and let everything shutdown naturally
    128 // because the database closing process may still make use of this context.
    129 // It is not safe to just delete the context here.
    130 void DatabaseContext::contextDestroyed()
    131 {
    132     RefPtrWillBeRawPtr<DatabaseContext> protector(this);
    133     stopDatabases();
    134     if (executionContext()->isWorkerGlobalScope())
    135         toWorkerGlobalScope(executionContext())->unregisterTerminationObserver(this);
    136     DatabaseManager::manager().unregisterDatabaseContext(this);
    137     ActiveDOMObject::contextDestroyed();
    138 }
    139 
    140 void DatabaseContext::wasRequestedToTerminate()
    141 {
    142     DatabaseManager::manager().interruptAllDatabasesForContext(this);
    143 }
    144 
    145 // stop() is from stopActiveDOMObjects() which indicates that the owner LocalFrame
    146 // or WorkerThread is shutting down. Initiate the orderly shutdown by stopping
    147 // the associated databases.
    148 void DatabaseContext::stop()
    149 {
    150     stopDatabases();
    151 }
    152 
    153 DatabaseContext* DatabaseContext::backend()
    154 {
    155     return this;
    156 }
    157 
    158 DatabaseThread* DatabaseContext::databaseThread()
    159 {
    160     if (!m_databaseThread && !m_hasOpenDatabases) {
    161         // It's OK to ask for the m_databaseThread after we've requested
    162         // termination because we're still using it to execute the closing
    163         // of the database. However, it is NOT OK to create a new thread
    164         // after we've requested termination.
    165         ASSERT(!m_hasRequestedTermination);
    166 
    167         // Create the database thread on first request - but not if at least one database was already opened,
    168         // because in that case we already had a database thread and terminated it and should not create another.
    169         m_databaseThread = DatabaseThread::create();
    170         m_databaseThread->start();
    171     }
    172 
    173     return m_databaseThread.get();
    174 }
    175 
    176 void DatabaseContext::didOpenDatabase(DatabaseBackendBase& database)
    177 {
    178     if (!database.isSyncDatabase())
    179         return;
    180     ASSERT(isContextThread());
    181 #if ENABLE(OILPAN)
    182     m_openSyncDatabases.add(&database, adoptPtr(new DatabaseCloser(database)));
    183 #else
    184     m_openSyncDatabases.add(&database);
    185 #endif
    186 }
    187 
    188 void DatabaseContext::didCloseDatabase(DatabaseBackendBase& database)
    189 {
    190 #if !ENABLE(OILPAN)
    191     if (!database.isSyncDatabase())
    192         return;
    193     ASSERT(isContextThread());
    194     m_openSyncDatabases.remove(&database);
    195 #endif
    196 }
    197 
    198 #if ENABLE(OILPAN)
    199 DatabaseContext::DatabaseCloser::~DatabaseCloser()
    200 {
    201     m_database.closeImmediately();
    202 }
    203 #endif
    204 
    205 void DatabaseContext::stopSyncDatabases()
    206 {
    207     // SQLite is "multi-thread safe", but each database handle can only be used
    208     // on a single thread at a time.
    209     //
    210     // For DatabaseBackendSync, we open the SQLite database on the script
    211     // context thread. And hence we should also close it on that same
    212     // thread. This means that the SQLite database need to be closed here in the
    213     // destructor.
    214     ASSERT(isContextThread());
    215 #if ENABLE(OILPAN)
    216     m_openSyncDatabases.clear();
    217 #else
    218     Vector<DatabaseBackendBase*> syncDatabases;
    219     copyToVector(m_openSyncDatabases, syncDatabases);
    220     m_openSyncDatabases.clear();
    221     for (size_t i = 0; i < syncDatabases.size(); ++i)
    222         syncDatabases[i]->closeImmediately();
    223 #endif
    224 }
    225 
    226 void DatabaseContext::stopDatabases()
    227 {
    228     stopSyncDatabases();
    229 
    230     // Though we initiate termination of the DatabaseThread here in
    231     // stopDatabases(), we can't clear the m_databaseThread ref till we get to
    232     // the destructor. This is because the Databases that are managed by
    233     // DatabaseThread still rely on this ref between the context and the thread
    234     // to execute the task for closing the database. By the time we get to the
    235     // destructor, we're guaranteed that the databases are destructed (which is
    236     // why our ref count is 0 then and we're destructing). Then, the
    237     // m_databaseThread RefPtr destructor will deref and delete the
    238     // DatabaseThread.
    239 
    240     if (m_databaseThread && !m_hasRequestedTermination) {
    241         TaskSynchronizer sync;
    242         m_databaseThread->requestTermination(&sync);
    243         m_hasRequestedTermination = true;
    244         sync.waitForTaskCompletion();
    245     }
    246 }
    247 
    248 bool DatabaseContext::allowDatabaseAccess() const
    249 {
    250     if (executionContext()->isDocument())
    251         return toDocument(executionContext())->isActive();
    252     ASSERT(executionContext()->isWorkerGlobalScope());
    253     // allowDatabaseAccess is not yet implemented for workers.
    254     return true;
    255 }
    256 
    257 SecurityOrigin* DatabaseContext::securityOrigin() const
    258 {
    259     return executionContext()->securityOrigin();
    260 }
    261 
    262 bool DatabaseContext::isContextThread() const
    263 {
    264     return executionContext()->isContextThread();
    265 }
    266 
    267 } // namespace WebCore
    268