Changeset 30172 in webkit


Ignore:
Timestamp:
Feb 12, 2008 11:37:03 AM (16 years ago)
Author:
ap@webkit.org
Message:

Reviewed by Brady.

http://bugs.webkit.org/show_bug.cgi?id=17177
<rdar://problem/5729619> Storage tasks are getting lost

<rdar://problem/5729445> REGRESSION: Cannot schedule more than one transaction at a time

<rdar://problem/5729446> Major thread safety issue in Database code

  • platform/MessageQueue.h: Added a thread-safe queue abstraction.
  • WebCore.vcproj/WebCore.vcproj:
  • WebCore.xcodeproj/project.pbxproj: Added MessageQueue.h.
  • dom/Document.cpp: (WebCore::Document::~Document): Fixed a race condition resulting in a hanging reference.
  • storage/Database.idl: Fixed parameter declarations to actually match implementation (which is custom, so it got out of sync).
  • storage/DatabaseTask.h: (WebCore::DatabaseTask::database): (WebCore::DatabaseTransactionTask::transaction): Changed tasks to hold more information internally. Added helpers for better debug logging.
  • storage/DatabaseTask.cpp: (WebCore::DatabaseTask::DatabaseTask): (WebCore::DatabaseTask::performTask): (WebCore::DatabaseOpenTask::DatabaseOpenTask): (WebCore::DatabaseOpenTask::doPerformTask): (WebCore::DatabaseOpenTask::debugTaskName): (WebCore::DatabaseTransactionTask::DatabaseTransactionTask): (WebCore::DatabaseTransactionTask::~DatabaseTransactionTask): (WebCore::DatabaseTransactionTask::doPerformTask): (WebCore::DatabaseTransactionTask::debugTaskName): (WebCore::DatabaseTableNamesTask::DatabaseTableNamesTask): (WebCore::DatabaseTableNamesTask::doPerformTask): (WebCore::DatabaseTableNamesTask::debugTaskName): Implementation for the above.

(WebCore::DatabaseTask::lockForSynchronousScheduling):
(WebCore::DatabaseTask::waitForSynchronousCompletion):
Fixed a potential race condition: if the task completed before we entered a wait, we'd never
wake up. There was an assertion guarding against this, but no actual guarantee that I could see.

  • storage/DatabaseThread.cpp: (WebCore::DatabaseThread::DatabaseThread): (WebCore::DatabaseThread::requestTermination): (WebCore::DatabaseThread::databaseThread): (WebCore::DatabaseThread::scheduleTask): (WebCore::DatabaseThread::scheduleImmediateTask): (WebCore::DatabaseThread::unscheduleDatabaseTasks):
  • storage/DatabaseThread.h: Changed to use MessageQueue.
  • storage/Database.cpp: (WebCore::guidMutex): (WebCore::guidToVersionMap): (WebCore::guidToDatabaseMap): (WebCore::Database::openDatabase): (WebCore::Database::Database): (WebCore::Database::~Database): (WebCore::Database::openAndVerifyVersion): (WebCore::guidForOriginAndName): (WebCore::Database::changeVersion): (WebCore::Database::transaction): (WebCore::Database::scheduleTransaction): (WebCore::Database::scheduleTransactionStep): (WebCore::Database::scheduleTransactionCallback): (WebCore::Database::version): (WebCore::Database::deliverPendingCallback): (WebCore::Database::tableNames):
  • storage/Database.h: Changed m_transactionQueue to a MessageQueue. Got rid of callback tracking - these can take care of themselves. Got rid of a DatabaseThread member, as the Document can be asked for it. Moved private static members and helpers out of the header. Lost CurrentThreadSetter debug helper on the way. We may need to re-add something like that later.
  • storage/SQLTransaction.h:
  • storage/SQLTransaction.cpp: Added a lot of debug logging. (WebCore::SQLTransaction::scheduleToRunStatements): Removed "m_currentStatement = 0" assignment, as it created a race condition. Everything seems to work better without it, although a real fix would be to get rid of this variable - it's evil shared data that isn't even protected in any way.
  • manual-tests/database-threading-stress-test-2.html: Added.
  • manual-tests/database-threading-stress-test.html: Added.
Location:
trunk/WebCore
Files:
3 added
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r30171 r30172  
     12008-02-12  Alexey Proskuryakov <ap@webkit.org> and Brady Eidson <beidson@apple.com>
     2
     3        Reviewed by Brady.
     4
     5        http://bugs.webkit.org/show_bug.cgi?id=17177
     6        <rdar://problem/5729619> Storage tasks are getting lost
     7
     8        <rdar://problem/5729445> REGRESSION: Cannot schedule more than one transaction at a time
     9
     10        <rdar://problem/5729446> Major thread safety issue in Database code
     11
     12        * platform/MessageQueue.h: Added a thread-safe queue abstraction.
     13
     14        * WebCore.vcproj/WebCore.vcproj:
     15        * WebCore.xcodeproj/project.pbxproj:
     16        Added MessageQueue.h.
     17
     18        * dom/Document.cpp:
     19        (WebCore::Document::~Document): Fixed a race condition resulting in a hanging reference.
     20
     21        * storage/Database.idl: Fixed parameter declarations to actually match implementation
     22        (which is custom, so it got out of sync).
     23
     24        * storage/DatabaseTask.h:
     25        (WebCore::DatabaseTask::database):
     26        (WebCore::DatabaseTransactionTask::transaction):
     27        Changed tasks to hold more information internally. Added helpers for better debug logging.
     28
     29        * storage/DatabaseTask.cpp:
     30        (WebCore::DatabaseTask::DatabaseTask):
     31        (WebCore::DatabaseTask::performTask):
     32        (WebCore::DatabaseOpenTask::DatabaseOpenTask):
     33        (WebCore::DatabaseOpenTask::doPerformTask):
     34        (WebCore::DatabaseOpenTask::debugTaskName):
     35        (WebCore::DatabaseTransactionTask::DatabaseTransactionTask):
     36        (WebCore::DatabaseTransactionTask::~DatabaseTransactionTask):
     37        (WebCore::DatabaseTransactionTask::doPerformTask):
     38        (WebCore::DatabaseTransactionTask::debugTaskName):
     39        (WebCore::DatabaseTableNamesTask::DatabaseTableNamesTask):
     40        (WebCore::DatabaseTableNamesTask::doPerformTask):
     41        (WebCore::DatabaseTableNamesTask::debugTaskName):
     42        Implementation for the above.
     43
     44        (WebCore::DatabaseTask::lockForSynchronousScheduling):
     45        (WebCore::DatabaseTask::waitForSynchronousCompletion):
     46        Fixed a potential race condition: if the task completed before we entered a wait, we'd never
     47        wake up. There was an assertion guarding against this, but no actual guarantee that I could see.
     48
     49        * storage/DatabaseThread.cpp:
     50        (WebCore::DatabaseThread::DatabaseThread):
     51        (WebCore::DatabaseThread::requestTermination):
     52        (WebCore::DatabaseThread::databaseThread):
     53        (WebCore::DatabaseThread::scheduleTask):
     54        (WebCore::DatabaseThread::scheduleImmediateTask):
     55        (WebCore::DatabaseThread::unscheduleDatabaseTasks):
     56        * storage/DatabaseThread.h:
     57        Changed to use MessageQueue.
     58
     59        * storage/Database.cpp:
     60        (WebCore::guidMutex):
     61        (WebCore::guidToVersionMap):
     62        (WebCore::guidToDatabaseMap):
     63        (WebCore::Database::openDatabase):
     64        (WebCore::Database::Database):
     65        (WebCore::Database::~Database):
     66        (WebCore::Database::openAndVerifyVersion):
     67        (WebCore::guidForOriginAndName):
     68        (WebCore::Database::changeVersion):
     69        (WebCore::Database::transaction):
     70        (WebCore::Database::scheduleTransaction):
     71        (WebCore::Database::scheduleTransactionStep):
     72        (WebCore::Database::scheduleTransactionCallback):
     73        (WebCore::Database::version):
     74        (WebCore::Database::deliverPendingCallback):
     75        (WebCore::Database::tableNames):
     76        * storage/Database.h:
     77        Changed m_transactionQueue to a MessageQueue.
     78        Got rid of callback tracking - these can take care of themselves.
     79        Got rid of a DatabaseThread member, as the Document can be asked for it.
     80        Moved private static members and helpers out of the header.
     81        Lost CurrentThreadSetter debug helper on the way. We may need to re-add something like that later.
     82
     83        * storage/SQLTransaction.h:
     84        * storage/SQLTransaction.cpp: Added a lot of debug logging.
     85        (WebCore::SQLTransaction::scheduleToRunStatements): Removed "m_currentStatement = 0" assignment,
     86        as it created a race condition. Everything seems to work better without it, although a real fix
     87        would be to get rid of this variable - it's evil shared data that isn't even protected in any way.
     88
     89        * manual-tests/database-threading-stress-test-2.html: Added.
     90        * manual-tests/database-threading-stress-test.html: Added.
     91
    1922008-02-12  Adam Roben  <aroben@apple.com>
    293
  • trunk/WebCore/WebCore.vcproj/WebCore.vcproj

    r30059 r30172  
    32403240                        </File>
    32413241                        <File
     3242                                RelativePath="..\platform\MessageQueue.h"
     3243                                >
     3244                        </File>
     3245                        <File
    32423246                                RelativePath="..\platform\MIMETypeRegistry.cpp"
    32433247                                >
  • trunk/WebCore/WebCore.xcodeproj/project.pbxproj

    r30168 r30172  
    37183718                E1BE512D0CF6C512002EA959 /* XSLTUnicodeSort.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E1BE512B0CF6C512002EA959 /* XSLTUnicodeSort.cpp */; };
    37193719                E1BE512E0CF6C512002EA959 /* XSLTUnicodeSort.h in Headers */ = {isa = PBXBuildFile; fileRef = E1BE512C0CF6C512002EA959 /* XSLTUnicodeSort.h */; };
     3720                E1DE1C080D5CE4CF0034C38F /* MessageQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = E1DE1C070D5CE4CF0034C38F /* MessageQueue.h */; };
    37203721                E1E6EEA40B628DA8005F2F70 /* JSHTMLSelectElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E1E6EEA30B628DA8005F2F70 /* JSHTMLSelectElement.cpp */; };
    37213722                E1E6EEA80B628DB3005F2F70 /* JSHTMLSelectElement.h in Headers */ = {isa = PBXBuildFile; fileRef = E1E6EEA70B628DB3005F2F70 /* JSHTMLSelectElement.h */; };
     
    78177818                E1BE512B0CF6C512002EA959 /* XSLTUnicodeSort.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = XSLTUnicodeSort.cpp; sourceTree = "<group>"; };
    78187819                E1BE512C0CF6C512002EA959 /* XSLTUnicodeSort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XSLTUnicodeSort.h; sourceTree = "<group>"; };
     7820                E1DE1C070D5CE4CF0034C38F /* MessageQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessageQueue.h; sourceTree = "<group>"; };
    78197821                E1E6EEA30B628DA8005F2F70 /* JSHTMLSelectElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSHTMLSelectElement.cpp; sourceTree = "<group>"; };
    78207822                E1E6EEA70B628DB3005F2F70 /* JSHTMLSelectElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = JSHTMLSelectElement.h; sourceTree = "<group>"; };
     
    1173211734                                A8239DFE09B3CF8A00B60641 /* Logging.cpp */,
    1173311735                                A8239DFF09B3CF8A00B60641 /* Logging.h */,
     11736                                E1DE1C070D5CE4CF0034C38F /* MessageQueue.h */,
    1173411737                                BC772C4C0C4EB3040083285F /* MIMETypeRegistry.cpp */,
    1173511738                                BC772C4D0C4EB3040083285F /* MIMETypeRegistry.h */,
     
    1422814231                                5DCF836D0D59159800953BC6 /* PluginInfoStore.h in Headers */,
    1422914232                                C0294DF40D5A6FD800CC7D6B /* UserStyleSheetLoader.h in Headers */,
     14233                                E1DE1C080D5CE4CF0034C38F /* MessageQueue.h in Headers */,
    1423014234                        );
    1423114235                        runOnlyForDeploymentPostprocessing = 0;
  • trunk/WebCore/dom/Document.cpp

    r30147 r30172  
    445445#if ENABLE(DATABASE)
    446446    if (m_databaseThread) {
    447         m_databaseThread->documentGoingAway();
     447        RefPtr<DatabaseThread> databaseThread = m_databaseThread;
    448448        m_databaseThread = 0;
     449        databaseThread->requestTermination();
    449450    }
    450451#endif
  • trunk/WebCore/storage/Database.cpp

    r30104 r30172  
    5050
    5151namespace WebCore {
    52        
    53 #ifndef NDEBUG
    54 class CurrentThreadSetter {
    55 public:
    56     CurrentThreadSetter(ThreadIdentifier& thread)
    57         : threadIdentifierStorage(thread)
    58     {
    59         ASSERT(!thread);
    60         thread = currentThread();
    61     }
    62 
    63     ~CurrentThreadSetter()
    64     {
    65         ASSERT(threadIdentifierStorage == currentThread());
    66         threadIdentifierStorage = 0;
    67     }
    68 
    69 private:
    70     ThreadIdentifier& threadIdentifierStorage;
    71 };
    72 #endif
    73 
    74 Mutex& Database::globalCallbackMutex()
    75 {
     52
     53static Mutex& guidMutex()
     54{
     55    // FIXME: this is not a thread-safe way to initialize a shared global.
    7656    static Mutex mutex;
    7757    return mutex;
    7858}
    7959
    80 HashSet<RefPtr<Database> >& Database::globalCallbackSet()
    81 {
    82     static HashSet<RefPtr<Database> > set;
    83     return set;
    84 }
    85 
    86 bool Database::s_globalCallbackScheduled = false;
    87 
    88 Mutex& Database::guidMutex()
    89 {
    90     static Mutex mutex;
    91     return mutex;
    92 }
    93 
    94 HashMap<int, String>& Database::guidToVersionMap()
     60static HashMap<int, String>& guidToVersionMap()
    9561{
    9662    static HashMap<int, String> map;
     
    9864}
    9965
    100 HashMap<int, HashSet<Database*>*>& Database::guidToDatabaseMap()
     66static HashMap<int, HashSet<Database*>*>& guidToDatabaseMap()
    10167{
    10268    static HashMap<int, HashSet<Database*>*> map;
     
    11682}
    11783
     84static int guidForOriginAndName(const String& origin, const String& name);
     85
    11886PassRefPtr<Database> Database::openDatabase(Document* document, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize, ExceptionCode& e)
    11987{
    12088    if (!DatabaseTracker::tracker().canEstablishDatabase(document, name, displayName, estimatedSize)) {
    121         // There should be an exception raised here in addition to returning a null Database object.  The question has been raised with the WHATWG
     89        // FIXME: There should be an exception raised here in addition to returning a null Database object.  The question has been raised with the WHATWG.
    12290        LOG(StorageAPI, "Database %s for origin %s not allowed to be established", name.ascii().data(), document->securityOrigin()->toString().ascii().data());
    12391        return 0;
     
    142110
    143111Database::Database(Document* document, const String& name, const String& expectedVersion)
    144     : m_document(document)
     112    : m_transactionInProgress(false)
     113    , m_document(document)
    145114    , m_name(name.copy())
    146115    , m_guid(0)
    147116    , m_expectedVersion(expectedVersion)
    148117    , m_deleted(0)
    149     , m_databaseThread(0)
    150 #ifndef NDEBUG
    151     , m_transactionStepThread(0)
    152 #endif
    153118{
    154119    ASSERT(document);
     
    174139    }
    175140
    176     m_databaseThread = document->databaseThread();
    177     ASSERT(m_databaseThread);
     141    ASSERT(m_document->databaseThread());
    178142
    179143    m_filename = DatabaseTracker::tracker().fullPathForDatabase(m_securityOrigin.get(), m_name);
     
    184148Database::~Database()
    185149{
    186     MutexLocker locker(guidMutex());
    187 
    188     HashSet<Database*>* hashSet = guidToDatabaseMap().get(m_guid);
    189     ASSERT(hashSet);
    190     ASSERT(hashSet->contains(this));
    191     hashSet->remove(this);
    192     if (hashSet->isEmpty()) {
    193         guidToDatabaseMap().remove(m_guid);
    194         delete hashSet;
    195         guidToVersionMap().remove(m_guid);
    196     }
     150    {
     151        MutexLocker locker(guidMutex());
     152
     153        HashSet<Database*>* hashSet = guidToDatabaseMap().get(m_guid);
     154        ASSERT(hashSet);
     155        ASSERT(hashSet->contains(this));
     156        hashSet->remove(this);
     157        if (hashSet->isEmpty()) {
     158            guidToDatabaseMap().remove(m_guid);
     159            delete hashSet;
     160            guidToVersionMap().remove(m_guid);
     161        }
     162    }
     163
     164    if (m_document->databaseThread())
     165        m_document->databaseThread()->unscheduleDatabaseTasks(this);
    197166
    198167    DatabaseTracker::tracker().removeOpenDatabase(this);
     
    203172    m_databaseAuthorizer = new DatabaseAuthorizer();
    204173
    205     RefPtr<DatabaseOpenTask> task = new DatabaseOpenTask();
     174    RefPtr<DatabaseOpenTask> task = new DatabaseOpenTask(this);
    206175
    207176    task->lockForSynchronousScheduling();
    208     m_databaseThread->scheduleImmediateTask(this, task.get());
     177    m_document->databaseThread()->scheduleImmediateTask(task.get());
    209178    task->waitForSynchronousCompletion();
    210179
     
    326295}
    327296
    328 void Database::databaseThreadGoingAway()
    329 {
    330     // FIXME: We might not need this anymore
    331 
    332     LOG(StorageAPI, "Database thread is going away for database %p\n", this);
    333 }
    334 
    335297void Database::disableAuthorizer()
    336298{
     
    345307}
    346308
    347 int Database::guidForOriginAndName(const String& origin, const String& name)
     309static int guidForOriginAndName(const String& origin, const String& name)
    348310{
    349311    static int currentNewGUID = 1;
     
    459421}
    460422
    461 void Database::performTransactionStep()
    462 {
    463 #ifndef NDEBUG
    464     CurrentThreadSetter threadSetter(m_transactionStepThread);
    465 #endif
    466 
    467     // Do not perform a transaction if a global callback is scheduled.
    468     MutexLocker locker(globalCallbackMutex());
    469     if (s_globalCallbackScheduled)
    470         return;
    471 
    472     {
    473         MutexLocker locker(m_transactionMutex);
    474 
    475         if (!m_currentTransaction) {
    476             ASSERT(m_transactionQueue.size());
    477             m_currentTransaction = m_transactionQueue.first();
    478             m_transactionQueue.removeFirst();
    479         }
    480     }
    481 
    482     // If this step completes the entire transaction, clear the working transaction
    483     // and schedule the next one if necessary
    484     if (!m_currentTransaction->performNextStep())
    485         return;
    486 
    487     {
    488         MutexLocker locker(m_transactionMutex);
    489         ASSERT(!m_sqliteDatabase.transactionInProgress());
    490         m_currentTransaction = 0;
    491 
    492         if (m_transactionQueue.size())
    493             m_databaseThread->scheduleTask(this, new DatabaseTransactionTask);
    494     }
    495 }
    496 
    497423void Database::changeVersion(const String& oldVersion, const String& newVersion,
    498424                             PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback,
    499425                             PassRefPtr<VoidCallback> successCallback)
    500426{
    501     scheduleTransaction(new SQLTransaction(this, callback, errorCallback, new ChangeVersionWrapper(oldVersion, newVersion)));
     427    // FIXME: pass successCallback, too.
     428    m_transactionQueue.append(new SQLTransaction(this, callback, errorCallback, new ChangeVersionWrapper(oldVersion, newVersion)));
     429    MutexLocker locker(m_transactionInProgressMutex);
     430    if (!m_transactionInProgress)
     431        scheduleTransaction();
    502432}
    503433
     
    505435                           PassRefPtr<VoidCallback> successCallback)
    506436{
    507     scheduleTransaction(new SQLTransaction(this, callback, errorCallback, 0));
    508 }
    509 
    510 void Database::scheduleTransaction(PassRefPtr<SQLTransaction> transaction)
    511 {   
    512     MutexLocker locker(m_transactionMutex);
    513     m_transactionQueue.append(transaction);
    514     if (!m_currentTransaction)
    515         m_databaseThread->scheduleTask(this, new DatabaseTransactionTask);
    516 }
    517 
    518 void Database::scheduleTransactionStep()
    519 {
    520     MutexLocker locker(m_transactionMutex);
    521     m_databaseThread->scheduleTask(this, new DatabaseTransactionTask);
     437    // FIXME: pass successCallback, too.
     438    m_transactionQueue.append(new SQLTransaction(this, callback, errorCallback, 0));
     439    MutexLocker locker(m_transactionInProgressMutex);
     440    if (!m_transactionInProgress)
     441        scheduleTransaction();
     442}
     443
     444void Database::scheduleTransaction()
     445{
     446    ASSERT(!m_transactionInProgressMutex.tryLock()); // Locked by caller.
     447    RefPtr<SQLTransaction> transaction;
     448    if (m_transactionQueue.tryGetMessage(transaction) && m_document->databaseThread()) {
     449        DatabaseTransactionTask* task = new DatabaseTransactionTask(transaction);
     450        LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for transaction %p\n", task, task->transaction());
     451        m_transactionInProgress = true;
     452        m_document->databaseThread()->scheduleTask(task);
     453    } else
     454        m_transactionInProgress = false;
     455}
     456
     457void Database::scheduleTransactionStep(SQLTransaction* transaction)
     458{
     459    if (m_document->databaseThread()) {
     460        DatabaseTransactionTask* task = new DatabaseTransactionTask(transaction);
     461        LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for the transaction step\n", task);
     462        m_document->databaseThread()->scheduleTask(task);
     463    }
    522464}
    523465
    524466void Database::scheduleTransactionCallback(SQLTransaction* transaction)
    525467{
    526     ASSERT(m_transactionStepThread == currentThread());
    527 
    528     MutexLocker locker(m_callbackMutex);
    529 
    530     ASSERT(!m_transactionPendingCallback);
    531     m_transactionPendingCallback = transaction;
    532 
    533     globalCallbackSet().add(this);
    534 
    535     if (!s_globalCallbackScheduled) {
    536         callOnMainThread(deliverAllPendingCallbacks, 0);
    537         s_globalCallbackScheduled = true;
    538     }
     468    transaction->ref();
     469    callOnMainThread(deliverPendingCallback, transaction);
    539470}
    540471
     
    575506    return guidToVersionMap().get(m_guid).copy();
    576507}
    577    
    578 void Database::deliverAllPendingCallbacks(void*)
    579 {
    580     Vector<RefPtr<Database> > databases;
    581     {
    582         MutexLocker locker(globalCallbackMutex());
    583         copyToVector(globalCallbackSet(), databases);
    584         globalCallbackSet().clear();
    585         s_globalCallbackScheduled = false;
    586     }
    587 
    588     LOG(StorageAPI, "Having %zu databases deliver their pending callbacks", databases.size());
    589     for (unsigned i = 0; i < databases.size(); ++i)
    590         databases[i]->deliverPendingCallback();
    591 }
    592 
    593 void Database::deliverPendingCallback()
    594 {
    595     RefPtr<SQLTransaction> transaction;
    596     {
    597         MutexLocker locker(m_callbackMutex);
    598        
    599         ASSERT(m_transactionPendingCallback);
    600         transaction = m_transactionPendingCallback.release();
    601     }
    602 
     508
     509void Database::deliverPendingCallback(void* context)
     510{
     511    SQLTransaction* transaction = static_cast<SQLTransaction*>(context);
    603512    transaction->performPendingCallback();
     513    transaction->deref(); // Was ref'd in scheduleTransactionCallback().
    604514}
    605515
    606516Vector<String> Database::tableNames()
    607517{
    608     RefPtr<DatabaseTableNamesTask> task = new DatabaseTableNamesTask();
     518    RefPtr<DatabaseTableNamesTask> task = new DatabaseTableNamesTask(this);
    609519
    610520    task->lockForSynchronousScheduling();
    611     m_databaseThread->scheduleImmediateTask(this, task.get());
     521    m_document->databaseThread()->scheduleImmediateTask(task.get());
    612522    task->waitForSynchronousCompletion();
    613523
  • trunk/WebCore/storage/Database.h

    r30104 r30172  
    3030#define Database_h
    3131
     32#include "MessageQueue.h"
    3233#include "PlatformString.h"
    3334#include "SecurityOrigin.h"
     
    3536#include "SQLTransaction.h"
    3637#include "StringHash.h"
    37 #include "Threading.h"
    3838#include "Timer.h"
    3939#include "VoidCallback.h"
     
    5959
    6060class Database : public ThreadSafeShared<Database> {
     61    friend class DatabaseTransactionTask;
    6162    friend class SQLStatement;
    6263    friend class SQLTransaction;
     
    7475   
    7576// Internal engine support
    76     void databaseThreadGoingAway();
    7777    static const String& databaseInfoTableName();
    7878
     
    103103    bool performOpenAndVerify(ExceptionCode&);
    104104
    105     void performTransactionStep();
    106 
    107105    Vector<String> performGetTableNames();
    108106
     
    112110    bool openAndVerifyVersion(ExceptionCode&);
    113111
    114     void scheduleTransaction(PassRefPtr<SQLTransaction>);
     112    void scheduleTransaction();
    115113    void scheduleTransactionCallback(SQLTransaction*);
    116     void scheduleTransactionStep();
     114    void scheduleTransactionStep(SQLTransaction* transaction);
    117115   
    118     Mutex m_transactionMutex;
    119     Deque<RefPtr<SQLTransaction> > m_transactionQueue;
    120     RefPtr<SQLTransaction> m_currentTransaction;
     116    MessageQueue<RefPtr<SQLTransaction> > m_transactionQueue;
     117    Mutex m_transactionInProgressMutex;
     118    bool m_transactionInProgress;
    121119
    122     static void deliverAllPendingCallbacks(void*);
    123     void deliverPendingCallback();
     120    static void deliverPendingCallback(void*);
    124121
    125122    Document* m_document;
     
    135132    RefPtr<DatabaseAuthorizer> m_databaseAuthorizer;
    136133
    137     DatabaseThread* m_databaseThread;
    138 
    139     Mutex m_callbackMutex;
    140     RefPtr<SQLTransaction> m_transactionPendingCallback;
    141 
    142134#ifndef NDEBUG
    143     ThreadIdentifier m_transactionStepThread;
    144 
    145135    String databaseDebugName() const { return m_securityOrigin->toString() + "::" + m_name; }
    146136#endif
    147 
    148     static Mutex& globalCallbackMutex();
    149     static HashSet<RefPtr<Database> >& globalCallbackSet();
    150     static bool s_globalCallbackScheduled;
    151 
    152     static int guidForOriginAndName(const String&, const String&);
    153 
    154     static Mutex& guidMutex();
    155     static HashMap<int, String>& guidToVersionMap();
    156     static HashMap<int, HashSet<Database*>*>& guidToDatabaseMap();
    157137};
    158138
  • trunk/WebCore/storage/Database.idl

    r29672 r30172  
    3131    interface Database {
    3232        readonly attribute DOMString version;
    33         [Custom] void changeVersion(in DOMString oldVersion, in DOMString newVersion, in SQLTransactionCallback callback, in SQLTransactionErrorCallback errorCallback);
    34         [Custom] void transaction(in SQLTransactionCallback callback, in SQLTransactionErrorCallback errorCallback);
     33        [Custom] void changeVersion(in DOMString oldVersion, in DOMString newVersion, in SQLTransactionCallback callback, in SQLTransactionErrorCallback errorCallback, in VoidCallback successCallback);
     34        [Custom] void transaction(in SQLTransactionCallback callback, in SQLTransactionErrorCallback errorCallback, in VoidCallback successCallback);
    3535    };
    3636
  • trunk/WebCore/storage/DatabaseTask.cpp

    r29663 r30172  
    11/*
    2  * Copyright (C) 2007 Apple Inc. All rights reserved.
     2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3131#include "Database.h"
    3232#include "Logging.h"
    33 #include "SQLValue.h"
    3433
    3534namespace WebCore {
    3635
    37 DatabaseTask::DatabaseTask()
    38     : m_complete(false)
     36DatabaseTask::DatabaseTask(Database* database)
     37    : m_database(database)
     38    , m_complete(false)
    3939{
    4040}
     
    4444}
    4545
    46 void DatabaseTask::performTask(Database* db)
     46void DatabaseTask::performTask()
    4747{
    48     // Database tasks are meant to be used only once, so make sure this one hasn't been performed before
     48    // Database tasks are meant to be used only once, so make sure this one hasn't been performed before.
    4949    ASSERT(!m_complete);
    5050
    51     LOG(StorageAPI, "Performing DatabaseTask %p\n", this);
     51    LOG(StorageAPI, "Performing %s %p\n", debugTaskName(), this);
     52
     53    m_database->resetAuthorizer();
     54    doPerformTask();
     55    m_database->performPolicyChecks();
    5256
    5357    if (m_synchronousMutex)
    5458        m_synchronousMutex->lock();
    55        
    56 
    57     db->resetAuthorizer();
    58     doPerformTask(db);
    59     db->performPolicyChecks();
    6059
    6160    m_complete = true;
    6261
    6362    if (m_synchronousMutex) {
    64         ASSERT(m_synchronousCondition);
    6563        m_synchronousCondition->signal();
    6664        m_synchronousMutex->unlock();
    6765    }
    68 
    6966}
    7067
    7168void DatabaseTask::lockForSynchronousScheduling()
    7269{
     70    // Called from main thread.
    7371    ASSERT(!m_synchronousMutex);
     72    ASSERT(!m_synchronousCondition);
    7473    m_synchronousMutex.set(new Mutex);
    75     m_synchronousMutex->lock();
     74    m_synchronousCondition.set(new ThreadCondition);
    7675}
    7776
    7877void DatabaseTask::waitForSynchronousCompletion()
    7978{
    80     // Caller of this method must lock this object beforehand
    81     ASSERT(m_synchronousMutex && m_synchronousMutex->tryLock() == false);
    82     m_synchronousCondition.set(new ThreadCondition);
    83     m_synchronousCondition->wait(*m_synchronousMutex.get());
     79    // Called from main thread.
     80    m_synchronousMutex->lock();
     81    if (!m_complete)
     82        m_synchronousCondition->wait(*m_synchronousMutex);
    8483    m_synchronousMutex->unlock();
    8584}
    8685
    8786// *** DatabaseOpenTask ***
    88 // Opens the database file and verifies the version matches the expected version
     87// Opens the database file and verifies the version matches the expected version.
    8988
    90 DatabaseOpenTask::DatabaseOpenTask()
    91     : DatabaseTask()
     89DatabaseOpenTask::DatabaseOpenTask(Database* database)
     90    : DatabaseTask(database)
    9291    , m_code(0)
    9392    , m_success(false)
     
    9594}
    9695
    97 void DatabaseOpenTask::doPerformTask(Database* db)
     96void DatabaseOpenTask::doPerformTask()
    9897{
    99     m_success = db->performOpenAndVerify(m_code);
     98    m_success = database()->performOpenAndVerify(m_code);
    10099}
    101100
    102 // *** DatabaseExecuteSqlTask ***
    103 // Runs the passed in sql query along with the arguments, and calls the callback with the results
     101const char* DatabaseOpenTask::debugTaskName() const
     102{
     103    return "DatabaseOpenTask";
     104}
    104105
    105 DatabaseTransactionTask::DatabaseTransactionTask()
    106     : DatabaseTask()
     106// *** DatabaseTransactionTask ***
     107// Starts a transaction that will report its results via a callback.
     108
     109DatabaseTransactionTask::DatabaseTransactionTask(PassRefPtr<SQLTransaction> transaction)
     110    : DatabaseTask(transaction->database())
     111    , m_transaction(transaction)
    107112{
    108113}
    109114
    110 void DatabaseTransactionTask::doPerformTask(Database* db)
     115DatabaseTransactionTask::~DatabaseTransactionTask()
    111116{
    112     db->performTransactionStep();
     117}
     118
     119void DatabaseTransactionTask::doPerformTask()
     120{
     121    if (m_transaction->performNextStep()) {
     122        // The transaction is complete, we can move on to the next one.
     123        MutexLocker locker(m_transaction->database()->m_transactionInProgressMutex);
     124        m_transaction->database()->scheduleTransaction();
     125    }
     126}
     127
     128const char* DatabaseTransactionTask::debugTaskName() const
     129{
     130    return "DatabaseTransactionTask";
    113131}
    114132
    115133// *** DatabaseTableNamesTask ***
    116 // Retrieves a list of all tables in the database - for WebInspector support
     134// Retrieves a list of all tables in the database - for WebInspector support.
    117135
    118 DatabaseTableNamesTask::DatabaseTableNamesTask()
     136DatabaseTableNamesTask::DatabaseTableNamesTask(Database* database)
     137    : DatabaseTask(database)
    119138{
    120139}
    121140
    122 void DatabaseTableNamesTask::doPerformTask(Database* db)
     141void DatabaseTableNamesTask::doPerformTask()
    123142{
    124     m_tableNames = db->performGetTableNames();
     143    m_tableNames = database()->performGetTableNames();
     144}
     145
     146const char* DatabaseTableNamesTask::debugTaskName() const
     147{
     148    return "DatabaseTableNamesTask";
    125149}
    126150
  • trunk/WebCore/storage/DatabaseTask.h

    r29663 r30172  
    11/*
    2  * Copyright (C) 2007 Apple Inc. All rights reserved.
     2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    5151    virtual ~DatabaseTask();
    5252
    53     void performTask(Database*);
     53    void performTask();
    5454
     55    Database* database() const { return m_database; }
    5556    bool isComplete() const { return m_complete; }
     57
    5658protected:
    57     DatabaseTask();
    58     virtual void doPerformTask(Database* db) = 0;
     59    DatabaseTask(Database*);
    5960
    6061private:
     62    virtual void doPerformTask() = 0;
     63#ifndef NDEBUG
     64    virtual const char* debugTaskName() const = 0;
     65#endif
     66
    6167    void lockForSynchronousScheduling();
    6268    void waitForSynchronousCompletion();
     69
     70    Database* m_database;
    6371
    6472    bool m_complete;
     
    7179{
    7280public:
    73     DatabaseOpenTask();
     81    DatabaseOpenTask(Database*);
    7482
    7583    ExceptionCode exceptionCode() const { return m_code; }
    7684    bool openSuccessful() const { return m_success; }
    7785
    78 protected:
    79     virtual void doPerformTask(Database* db);
     86private:
     87    virtual void doPerformTask();
     88#ifndef NDEBUG
     89    virtual const char* debugTaskName() const;
     90#endif
    8091
    81 private:
    8292    ExceptionCode m_code;
    8393    bool m_success;
     
    8797{
    8898public:
    89     DatabaseTransactionTask();
     99    DatabaseTransactionTask(PassRefPtr<SQLTransaction>);
     100    SQLTransaction* transaction() const { return m_transaction.get(); }
    90101
    91 protected:
    92     virtual void doPerformTask(Database* db);
     102    virtual ~DatabaseTransactionTask();
     103private:
     104    virtual void doPerformTask();
     105#ifndef NDEBUG
     106    virtual const char* debugTaskName() const;
     107#endif
     108
     109    RefPtr<SQLTransaction> m_transaction;
    93110};
    94111
     
    96113{
    97114public:
    98     DatabaseTableNamesTask();
     115    DatabaseTableNamesTask(Database*);
    99116
    100117    Vector<String>& tableNames() { return m_tableNames; }
    101 protected:
    102     virtual void doPerformTask(Database* db);
     118
    103119private:
     120    virtual void doPerformTask();
     121#ifndef NDEBUG
     122    virtual const char* debugTaskName() const;
     123#endif
     124
    104125    Vector<String> m_tableNames;
    105126};
  • trunk/WebCore/storage/DatabaseThread.cpp

    r29663 r30172  
    11/*
    2  * Copyright (C) 2007 Apple Inc. All rights reserved.
     2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3838DatabaseThread::DatabaseThread(Document* document)
    3939    : m_threadID(0)
    40     , m_terminationRequested(false)
    4140{
    4241    m_selfRef = this;
     
    5857}
    5958
    60 void DatabaseThread::documentGoingAway()
     59void DatabaseThread::requestTermination()
    6160{
    62     // This document is going away, so this thread is going away.
    63     // -Clear records of all Databases out
    64     // -Leave the thread main loop
    65     // -Detach the thread so the thread itself runs out and releases all thread resources
    66     // -Clear the RefPtr<> self so if noone else is hanging on the thread, the object itself is deleted.
    67 
    6861    LOG(StorageAPI, "Document owning DatabaseThread %p is going away - starting thread shutdown", this);
    69 
    70     // Clear all database records out, and let Databases know that this DatabaseThread is going away
    71     {
    72         MutexLocker locker(m_databaseWorkMutex);
    73 
    74         // FIXME - The policy we're enforcing right here is that when a document goes away, any pending
    75         // sql queries that were queued up also go away.  Is this appropriate?
    76 
    77         HashSet<RefPtr<Database> >::iterator i = m_activeDatabases.begin();
    78         HashSet<RefPtr<Database> >::iterator end = m_activeDatabases.end();
    79 
    80         for (; i != end; ++i) {
    81             (*i)->databaseThreadGoingAway();
    82             Deque<RefPtr<DatabaseTask> >* databaseQueue = m_databaseTaskQueues.get((*i).get());
    83             ASSERT(databaseQueue);
    84             m_databaseTaskQueues.remove((*i).get());
    85             delete databaseQueue;
    86         }
    87         ASSERT(m_databaseTaskQueues.isEmpty());
    88         m_activeDatabases.clear();
    89     }
    90 
    91     // Request the thread to cleanup and shutdown
    92     m_terminationRequested = true;
    93     wakeWorkThread();
    94 }
    95 
    96 void DatabaseThread::databaseGoingAway(Database* database)
    97 {
    98     MutexLocker locker(m_databaseWorkMutex);
    99     if (!m_activeDatabases.contains(database))
    100         return;
    101 
    102     // FIXME - The policy we're enforcing right here is that when a document goes away, any pending
    103     // sql queries that were queued up also go away.  Is this appropriate?
    104     Deque<RefPtr<DatabaseTask> >* databaseQueue = m_databaseTaskQueues.get(database);
    105     ASSERT(databaseQueue);
    106     m_databaseTaskQueues.remove(database);
    107     delete databaseQueue;
    108 
    109     m_activeDatabases.remove(database);
     62    m_queue.kill();
    11063}
    11164
     
    12073    LOG(StorageAPI, "Starting DatabaseThread %p", this);
    12174
    122     m_threadMutex.lock();
    123     while (!m_terminationRequested) {
    124         m_threadMutex.unlock();
    125         AutodrainedPool pool;
    126 
    127         LOG(StorageAPI, "Iteration of main loop for DatabaseThread %p", this);
    128 
    129         bool result;
    130         do {
    131             result = dispatchNextTaskIdentifier();
    132             if (m_terminationRequested)
    133                 break;
    134         } while(result);
    135 
    136         if (m_terminationRequested)
     75    AutodrainedPool pool;
     76    while (true) {
     77        RefPtr<DatabaseTask> task;
     78        if (!m_queue.waitForMessage(task))
    13779            break;
    13880
     81        task->performTask();
     82
    13983        pool.cycle();
    140         m_threadMutex.lock();
    141         m_threadCondition.wait(m_threadMutex);
    14284    }
    143     m_threadMutex.unlock();
    14485
    14586    LOG(StorageAPI, "About to detach thread %i and clear the ref to DatabaseThread %p, which currently has %i ref(s)", m_threadID, this, refCount());
     
    15495}
    15596
    156 bool DatabaseThread::dispatchNextTaskIdentifier()
     97void DatabaseThread::scheduleTask(DatabaseTask* task)
    15798{
    158     RefPtr<Database> workDatabase;
     99    m_queue.append(task);
     100}
     101
     102void DatabaseThread::scheduleImmediateTask(DatabaseTask* task)
     103{
     104    m_queue.prepend(task);
     105}
     106
     107void DatabaseThread::unscheduleDatabaseTasks(Database* database)
     108{
     109    // Note that the thread loop is running, so some tasks for the database
     110    // may still be executed. This is unavoidable.
     111
     112    Deque<RefPtr<DatabaseTask> > filteredReverseQueue;
    159113    RefPtr<DatabaseTask> task;
    160 
    161     {
    162         MutexLocker locker(m_databaseWorkMutex);
    163         while (!task && m_globalQueue.size()) {
    164             Database* database = m_globalQueue.first();
    165             m_globalQueue.removeFirst();
    166 
    167             Deque<RefPtr<DatabaseTask> >* databaseQueue = m_databaseTaskQueues.get(database);
    168             ASSERT(databaseQueue || !m_activeDatabases.contains(database));
    169             if (!databaseQueue)
    170                 continue;
    171 
    172             ASSERT(databaseQueue->size());
    173             task = databaseQueue->first();
    174             workDatabase = database;
    175             databaseQueue->removeFirst();
    176         }
     114    while (m_queue.tryGetMessage(task)) {
     115        if (task->database() != database)
     116            filteredReverseQueue.append(task);
    177117    }
    178118
    179     if (task) {
    180         ASSERT(workDatabase);
    181         workDatabase->resetAuthorizer();
    182         task->performTask(workDatabase.get());
    183         return true;
     119    while (!filteredReverseQueue.isEmpty()) {
     120        m_queue.append(filteredReverseQueue.first());
     121        filteredReverseQueue.removeFirst();
    184122    }
    185 
    186     return false;
    187 }
    188 
    189 void DatabaseThread::scheduleTask(Database* database, DatabaseTask* task)
    190 {
    191     if (m_terminationRequested) {
    192         LOG(StorageAPI, "Attempted to schedule task %p from database %p on DatabaseThread %p after it was requested to terminate", task, database, this);
    193         return;
    194     }
    195 
    196     MutexLocker locker(m_databaseWorkMutex);
    197 
    198     Deque<RefPtr<DatabaseTask> >* databaseQueue = 0;
    199 
    200     if (!m_activeDatabases.contains(database)) {
    201         m_activeDatabases.add(database);
    202         databaseQueue = new Deque<RefPtr<DatabaseTask> >;
    203         m_databaseTaskQueues.set(database, databaseQueue);
    204     }
    205 
    206     if (!databaseQueue)
    207         databaseQueue = m_databaseTaskQueues.get(database);
    208 
    209     ASSERT(databaseQueue);
    210 
    211     databaseQueue->append(task);
    212     m_globalQueue.append(database);
    213 
    214     wakeWorkThread();
    215 }
    216 
    217 void DatabaseThread::scheduleImmediateTask(Database* database, DatabaseTask* task)
    218 {
    219     if (m_terminationRequested) {
    220         LOG_ERROR("Attempted to schedule immediate task %p from database %p on DatabaseThread %p after it was requested to terminate", task, database, this);
    221         return;
    222     }
    223     MutexLocker locker(m_databaseWorkMutex);
    224 
    225     Deque<RefPtr<DatabaseTask> >* databaseQueue = 0;
    226 
    227     if (!m_activeDatabases.contains(database)) {
    228         m_activeDatabases.add(database);
    229         databaseQueue = new Deque<RefPtr<DatabaseTask> >;
    230         m_databaseTaskQueues.set(database, databaseQueue);
    231     }
    232 
    233     if (!databaseQueue)
    234         databaseQueue = m_databaseTaskQueues.get(database);
    235 
    236     ASSERT(databaseQueue);
    237 
    238     databaseQueue->prepend(task);
    239     m_globalQueue.prepend(database);
    240 
    241     wakeWorkThread();
    242 }
    243 
    244 void DatabaseThread::wakeWorkThread()
    245 {
    246     MutexLocker locker(m_threadMutex);
    247     m_threadCondition.signal();
    248123}
    249124
  • trunk/WebCore/storage/DatabaseThread.h

    r29663 r30172  
    11/*
    2  * Copyright (C) 2007 Apple Inc. All rights reserved.
     2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2929#define DatabaseThread_h
    3030
    31 #include "Threading.h"
     31#include "MessageQueue.h"
    3232
    3333#include <wtf/HashMap.h>
     
    4949
    5050    bool start();
    51     void documentGoingAway();
    52     void databaseGoingAway(Database*);
     51    void requestTermination();
    5352
    54     void scheduleTask(Database*, DatabaseTask*);
    55     void scheduleImmediateTask(Database*, DatabaseTask*);
     53    void scheduleTask(DatabaseTask*);
     54    void scheduleImmediateTask(DatabaseTask*); // This just adds the task to the front of the queue - the caller needs to be extremely careful not to create deadlocks when waiting for completion.
     55    void unscheduleDatabaseTasks(Database*);
     56
    5657private:
    5758    static void* databaseThreadStart(void*);
    5859    void* databaseThread();
    59     void wakeWorkThread();
    60     bool dispatchNextTaskIdentifier();
    6160
    6261    ThreadIdentifier m_threadID;
    6362    RefPtr<DatabaseThread> m_selfRef;
    6463
    65     // For waking/sleeping the work thread
    66     ThreadCondition m_threadCondition;
    67     Mutex m_threadMutex;
    68     bool m_terminationRequested;
    69 
    70     // FIXME: Need a much better queue structure than the linked-list based queue being used
    71 
    72     // Work unit and Database management
    73     Mutex m_databaseWorkMutex;
    74     HashMap<Database*, Deque<RefPtr<DatabaseTask> >*> m_databaseTaskQueues;
    75     HashSet<RefPtr<Database> > m_activeDatabases;
    76     Deque<Database*> m_globalQueue;
     64    MessageQueue<RefPtr<DatabaseTask> > m_queue;
    7765};
    7866
  • trunk/WebCore/storage/SQLTransaction.cpp

    r30104 r30172  
    7171}
    7272
     73SQLTransaction::~SQLTransaction()
     74{
     75    LOG(StorageAPI, "Transaction %p destructor\n", this);
     76}
     77
    7378void SQLTransaction::executeSQL(const String& sqlStatement, const Vector<SQLValue>& arguments, PassRefPtr<SQLStatementCallback> callback, PassRefPtr<SQLStatementErrorCallback> callbackError, ExceptionCode& e)
    7479{
     
    95100}
    96101
     102#ifndef NDEBUG
     103const char* SQLTransaction::debugStepName(SQLTransaction::TransactionStepMethod step)
     104{
     105    if (step == &SQLTransaction::openTransactionAndPreflight)
     106        return "openTransactionAndPreflight";
     107    else if (step == &SQLTransaction::runStatements)
     108        return "runStatements";
     109    else if (step == &SQLTransaction::postflightAndCommit)
     110        return "postflightAndCommit";
     111    else if (step == &SQLTransaction::cleanupAfterTransactionErrorCallback)
     112        return "cleanupAfterTransactionErrorCallback";
     113    else if (step == &SQLTransaction::deliverTransactionCallback)
     114        return "deliverTransactionCallback";
     115    else if (step == &SQLTransaction::deliverTransactionErrorCallback)
     116        return "deliverTransactionErrorCallback";
     117    else if (step == &SQLTransaction::deliverStatementCallback)
     118        return "deliverStatementCallback";
     119    else if (step == &SQLTransaction::deliverQuotaIncreaseCallback)
     120        return "deliverQuotaIncreaseCallback";
     121    else
     122        return "UNKNOWN";
     123}
     124#endif
     125
    97126bool SQLTransaction::performNextStep()
    98127{
     128    LOG(StorageAPI, "Step %s\n", debugStepName(m_nextStep));
     129
    99130    ASSERT(m_nextStep == &SQLTransaction::openTransactionAndPreflight ||
    100131           m_nextStep == &SQLTransaction::runStatements ||
     
    110141void SQLTransaction::performPendingCallback()
    111142{
     143    LOG(StorageAPI, "Callback %s\n", debugStepName(m_nextStep));
     144
    112145    ASSERT(m_nextStep == &SQLTransaction::deliverTransactionCallback ||
    113146           m_nextStep == &SQLTransaction::deliverTransactionErrorCallback ||
     
    164197    // Transaction Step 4 - Invoke the transaction callback with the new SQLTransaction object
    165198    m_nextStep = &SQLTransaction::deliverTransactionCallback;
     199    LOG(StorageAPI, "Scheduling deliverTransactionCallback for transaction %p\n", this);
    166200    m_database->scheduleTransactionCallback(this);
    167201}
     
    188222void SQLTransaction::scheduleToRunStatements()
    189223{
    190     m_currentStatement = 0;
    191224    m_nextStep = &SQLTransaction::runStatements;
    192     m_database->scheduleTransactionStep();
     225    LOG(StorageAPI, "Scheduling runStatements for transaction %p\n", this);
     226    m_database->scheduleTransactionStep(this);
    193227}
    194228
     
    256290        if (m_currentStatement->hasStatementCallback()) {
    257291            m_nextStep = &SQLTransaction::deliverStatementCallback;
     292            LOG(StorageAPI, "Scheduling deliverStatementCallback for transaction %p\n", this);
    258293            m_database->scheduleTransactionCallback(this);
    259294            return false;
     
    264299    if (m_currentStatement->lastExecutionFailedDueToQuota()) {
    265300        m_nextStep = &SQLTransaction::deliverQuotaIncreaseCallback;
     301        LOG(StorageAPI, "Scheduling deliverQuotaIncreaseCallback for transaction %p\n", this);
    266302        m_database->scheduleTransactionCallback(this);
    267303        return false;
     
    279315    if (m_currentStatement->hasStatementErrorCallback()) {
    280316        m_nextStep = &SQLTransaction::deliverStatementCallback;
     317        LOG(StorageAPI, "Scheduling deliverStatementCallback for transaction %p\n", this);
    281318        m_database->scheduleTransactionCallback(this);
    282319    } else {
     
    324361       
    325362    m_nextStep = &SQLTransaction::runStatements;
    326     m_database->scheduleTransactionStep();
     363    LOG(StorageAPI, "Scheduling runStatements for transaction %p\n", this);
     364    m_database->scheduleTransactionStep(this);
    327365}
    328366
     
    343381    m_database->m_databaseAuthorizer->disable();
    344382    m_sqliteTransaction->commit();
    345     m_database->m_databaseAuthorizer->enable();   
    346        
     383    m_database->m_databaseAuthorizer->enable();
     384
    347385    // If the commit failed, the transaction will still be marked as "in progress"
    348386    if (m_sqliteTransaction->inProgress()) {
     
    359397    // Transaction Step 10 - End transaction steps
    360398    // There is no next step
     399    LOG(StorageAPI, "Transaction %p is complete\n", this);
    361400    ASSERT(!m_database->m_sqliteDatabase.transactionInProgress());
    362401    m_nextStep = 0;
     
    374413        else {
    375414            m_nextStep = &SQLTransaction::deliverTransactionErrorCallback;
     415            LOG(StorageAPI, "Scheduling deliverTransactionErrorCallback for transaction %p\n", this);
    376416            m_database->scheduleTransactionCallback(this);
    377417        }
     
    383423    if (inCallback) {
    384424        m_nextStep = &SQLTransaction::cleanupAfterTransactionErrorCallback;
    385         m_database->scheduleTransactionStep();
     425        LOG(StorageAPI, "Scheduling cleanupAfterTransactionErrorCallback for transaction %p\n", this);
     426        m_database->scheduleTransactionStep(this);
    386427    } else {
    387428        cleanupAfterTransactionErrorCallback();
     
    399440
    400441    m_nextStep = &SQLTransaction::cleanupAfterTransactionErrorCallback;
    401     m_database->scheduleTransactionStep();
     442    LOG(StorageAPI, "Scheduling cleanupAfterTransactionErrorCallback for transaction %p\n", this);
     443    m_database->scheduleTransactionStep(this);
    402444}
    403445
     
    432474   
    433475    // Transaction is complete!  There is no next step
     476    LOG(StorageAPI, "Transaction %p is complete with an error\n", this);
    434477    ASSERT(!m_database->m_sqliteDatabase.transactionInProgress());
    435478    m_nextStep = 0;
  • trunk/WebCore/storage/SQLTransaction.h

    r29663 r30172  
    6565public:
    6666    SQLTransaction(Database*, PassRefPtr<SQLTransactionCallback>, PassRefPtr<SQLTransactionErrorCallback>, PassRefPtr<SQLTransactionWrapper>);
     67    ~SQLTransaction();
    6768   
    6869    void executeSQL(const String& sqlStatement, const Vector<SQLValue>& arguments,
     
    7374   
    7475    Database* database() { return m_database; }
    75    
     76
    7677private:
    7778    typedef void (SQLTransaction::*TransactionStepMethod)();
     
    9394    void deliverTransactionErrorCallback();
    9495    void cleanupAfterTransactionErrorCallback();
     96
     97#ifndef NDEBUG
     98    static const char* debugStepName(TransactionStepMethod);
     99#endif
    95100
    96101    RefPtr<SQLStatement> m_currentStatement;
Note: See TracChangeset for help on using the changeset viewer.