]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix thread related problems in test modules test_async.c and test_journal.c. (CVS...
authordanielk1977 <danielk1977@noemail.net>
Sat, 28 Mar 2009 17:21:52 +0000 (17:21 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Sat, 28 Mar 2009 17:21:52 +0000 (17:21 +0000)
FossilOrigin-Name: 45df27a22d283871ed1de334fe3b74b0121d57a6

manifest
manifest.uuid
src/test_async.c
src/test_journal.c

index a5528cf709e3c90665af0914d1c64e6917b5e88e..51aaa8d7fedb16d6ca27b0aee9d85227c568b833 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Back\sout\scheck-in\s(6380).\s\sReplace\sit\swith\sa\sproper\sfix\sto\sthe\nxFullPathname\smethod\sin\sthe\sasync\sVFS.\s(CVS\s6398)
-D 2009-03-28T15:04:24
+C Fix\sthread\srelated\sproblems\sin\stest\smodules\stest_async.c\sand\stest_journal.c.\s(CVS\s6399)
+D 2009-03-28T17:21:52
 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
 F Makefile.in 583e87706abc3026960ed759aff6371faf84c211
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -173,7 +173,7 @@ F src/test6.c 1a0a7a1f179469044b065b4a88aab9faee114101
 F src/test7.c b94e68c2236de76889d82b8d7d8e00ad6a4d80b1
 F src/test8.c 3637439424d0d21ff2dcf9b015c30fcc1e7bcb24
 F src/test9.c 904ebe0ed1472d6bad17a81e2ecbfc20017dc237
-F src/test_async.c 9d75004dfee306f823cc26525cfef718c2e024d2
+F src/test_async.c fd2344c394ad27e76274aa60b74a1ad5ff27533e
 F src/test_autoext.c f53b0cdf7bf5f08100009572a5d65cdb540bd0ad
 F src/test_backup.c 79ac8daa03f0b3d360ff1eb56b23c7df0c14ecd1
 F src/test_btree.c d7b8716544611c323860370ee364e897c861f1b0
@@ -181,7 +181,7 @@ F src/test_config.c a05378089b6773ba36b85727dedf9ec0a16424ce
 F src/test_devsym.c 9f4bc2551e267ce7aeda195f3897d0f30c5228f4
 F src/test_func.c dd7bcaafb4e149702b506ede125ef6a4d4f6c471
 F src/test_hexio.c 2f1122aa3f012fa0142ee3c36ce5c902a70cd12f
-F src/test_journal.c 1d3fd9e79d8be1d99cdffa0b774805b2c962c782
+F src/test_journal.c 1e7baebc212b2c79f03f2c647cfd0b4f3678bf4c
 F src/test_loadext.c 97dc8800e46a46ed002c2968572656f37e9c0dd9
 F src/test_malloc.c d23050c7631ec9ee0369c7ca905e6c9233968e11
 F src/test_md5.c 032ae2bb6f81da350d2404e81fa8d560c8268026
@@ -710,7 +710,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
-P 9278f7b1e1f2d0d4c2f8829ca801a769e512c2a6
-R 121873619f687e25693398fc7592b8b5
-U drh
-Z 4d0af7748a59ba8b5aec187f6438633a
+P 767a7f7b55456df404a7f8966a0c48318ddac120
+R 4d38ca30ee6ed6fda0e3455931bed136
+U danielk1977
+Z e66cb9677f3d8d7ca66409e784f05095
index a689bcee5e35becf985e7a6f708cc941c2f8b85c..095a20247460fb66ae9d9bc0bdf23cc885b02c3b 100644 (file)
@@ -1 +1 @@
-767a7f7b55456df404a7f8966a0c48318ddac120
\ No newline at end of file
+45df27a22d283871ed1de334fe3b74b0121d57a6
\ No newline at end of file
index 9cd5957cc3adb171b63c7da8198bb0f5b8826349..d2fd95aab1ee77c68b656de9b5bc8a6e80bfa1d5 100644 (file)
@@ -10,7 +10,7 @@
 **
 *************************************************************************
 **
-** $Id: test_async.c,v 1.54 2009/03/28 15:04:24 drh Exp $
+** $Id: test_async.c,v 1.55 2009/03/28 17:21:52 danielk1977 Exp $
 **
 ** This file contains an example implementation of an asynchronous IO 
 ** backend for SQLite.
@@ -483,7 +483,6 @@ static int async_mutex_lock(pthread_mutex_t *pMutex){
   assert(&(aHolder[2])==&asyncdebug.writerMutexHolder);
 
   assert( pthread_self()!=0 );
-
   for(iIdx=0; iIdx<3; iIdx++){
     if( pMutex==&aMutex[iIdx] ) break;
 
@@ -610,7 +609,9 @@ static void assert_mutex_is_held(pthread_mutex_t *pMutex){
 */
 static void addAsyncWrite(AsyncWrite *pWrite){
   /* We must hold the queue mutex in order to modify the queue pointers */
-  pthread_mutex_lock(&async.queueMutex);
+  if( pWrite->op!=ASYNC_UNLOCK ){
+    pthread_mutex_lock(&async.queueMutex);
+  }
 
   /* Add the record to the end of the write-op queue */
   assert( !pWrite->pNext );
@@ -629,7 +630,9 @@ static void addAsyncWrite(AsyncWrite *pWrite){
   }
 
   /* Drop the queue mutex */
-  pthread_mutex_unlock(&async.queueMutex);
+  if( pWrite->op!=ASYNC_UNLOCK ){
+    pthread_mutex_unlock(&async.queueMutex);
+  }
 
   /* The writer thread might have been idle because there was nothing
   ** on the write-op queue for it to do.  So wake it up. */
@@ -956,10 +959,12 @@ static int asyncUnlock(sqlite3_file *pFile, int eLock){
   AsyncFileData *p = ((AsyncFile *)pFile)->pData;
   if( p->zName ){
     AsyncFileLock *pLock = &p->lock;
+    pthread_mutex_lock(&async.queueMutex);
     pthread_mutex_lock(&async.lockMutex);
     pLock->eLock = MIN(pLock->eLock, eLock);
-    pthread_mutex_unlock(&async.lockMutex);
     rc = addNewAsyncWrite(p, ASYNC_UNLOCK, 0, eLock, 0);
+    pthread_mutex_unlock(&async.lockMutex);
+    pthread_mutex_unlock(&async.queueMutex);
   }
   return rc;
 }
@@ -1526,15 +1531,54 @@ static void *asyncWriterThread(void *pIsStarted){
       }
 
       case ASYNC_UNLOCK: {
+        AsyncWrite *pIter;
         AsyncFileData *pData = p->pFileData;
         int eLock = p->nByte;
-        pthread_mutex_lock(&async.lockMutex);
-        pData->lock.eAsyncLock = MIN(
-            pData->lock.eAsyncLock, MAX(pData->lock.eLock, eLock)
-        );
-        assert(pData->lock.eAsyncLock>=pData->lock.eLock);
-        rc = getFileLock(pData->pLock);
-        pthread_mutex_unlock(&async.lockMutex);
+
+        /* When a file is locked by SQLite using the async backend, it is 
+        ** locked within the 'real' file-system synchronously. When it is
+        ** unlocked, an ASYNC_UNLOCK event is added to the write-queue to
+        ** unlock the file asynchronously. The design of the async backend
+        ** requires that the 'real' file-system file be locked from the
+        ** time that SQLite first locks it (and probably reads from it)
+        ** until all asynchronous write events that were scheduled before
+        ** SQLite unlocked the file have been processed.
+        **
+        ** This is more complex if SQLite locks and unlocks the file multiple
+        ** times in quick succession. For example, if SQLite does: 
+        ** 
+        **   lock, write, unlock, lock, write, unlock
+        **
+        ** Each "lock" operation locks the file immediately. Each "write" 
+        ** and "unlock" operation adds an event to the event queue. If the
+        ** second "lock" operation is performed before the first "unlock"
+        ** operation has been processed asynchronously, then the first
+        ** "unlock" cannot be safely processed as is, since this would mean
+        ** the file was unlocked when the second "write" operation is
+        ** processed. To work around this, when processing an ASYNC_UNLOCK
+        ** operation, SQLite:
+        **
+        **   1) Unlocks the file to the minimum of the argument passed to
+        **      the xUnlock() call and the current lock from SQLite's point
+        **      of view, and
+        **
+        **   2) Only unlocks the file at all if this event is the last
+        **      ASYNC_UNLOCK event on this file in the write-queue.
+        */ 
+        assert( holdingMutex==1 );
+        assert( async.pQueueFirst==p );
+        for(pIter=async.pQueueFirst->pNext; pIter; pIter=pIter->pNext){
+          if( pIter->pFileData==pData && pIter->op==ASYNC_UNLOCK ) break;
+        }
+        if( !pIter ){
+          pthread_mutex_lock(&async.lockMutex);
+          pData->lock.eAsyncLock = MIN(
+              pData->lock.eAsyncLock, MAX(pData->lock.eLock, eLock)
+          );
+          assert(pData->lock.eAsyncLock>=pData->lock.eLock);
+          rc = getFileLock(pData->pLock);
+          pthread_mutex_unlock(&async.lockMutex);
+        }
         break;
       }
 
index fab8d7f9d7915491cf53971312b6f2466b4bacf7..f2acfe4da61d7a8ee15781113d205ccb66e4abac 100644 (file)
@@ -15,7 +15,7 @@
 ** correctly populates and syncs a journal file before writing to a
 ** corresponding database file.
 **
-** $Id: test_journal.c,v 1.13 2009/03/26 11:49:11 danielk1977 Exp $
+** $Id: test_journal.c,v 1.14 2009/03/28 17:21:52 danielk1977 Exp $
 */
 #if SQLITE_TEST          /* This file is used for testing only */
 
@@ -206,6 +206,17 @@ struct JtGlobal {
 };
 static struct JtGlobal g = {0, 0};
 
+/*
+** Functions to obtain and relinquish a mutex to protect g.pList. The
+** STATIC_PRNG mutex is reused, purely for the sake of convenience.
+*/
+static void enterJtMutex(void){
+  sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PRNG));
+}
+static void leaveJtMutex(void){
+  sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PRNG));
+}
+
 extern int sqlite3_io_error_pending;
 static void stop_ioerr_simulation(int *piSave){
   *piSave = sqlite3_io_error_pending;
@@ -236,11 +247,12 @@ static int jtClose(sqlite3_file *pFile){
   jt_file *p = (jt_file *)pFile;
 
   closeTransaction(p);
+  enterJtMutex();
   if( p->zName ){
     for(pp=&g.pList; *pp!=p; pp=&(*pp)->pNext);
     *pp = p->pNext;
   }
-
+  leaveJtMutex();
   return sqlite3OsClose(p->pReal);
 }
 
@@ -257,7 +269,6 @@ static int jtRead(
   return sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst);
 }
 
-
 /*
 ** Parameter zJournal is the name of a journal file that is currently 
 ** open. This function locates and returns the handle opened on the
@@ -274,6 +285,7 @@ static int jtRead(
 **/
 static jt_file *locateDatabaseHandle(const char *zJournal){
   jt_file *pMain = 0;
+  enterJtMutex();
   for(pMain=g.pList; pMain; pMain=pMain->pNext){
     int nName = strlen(zJournal) - strlen("-journal");
     if( (pMain->flags&SQLITE_OPEN_MAIN_DB)
@@ -284,6 +296,7 @@ static jt_file *locateDatabaseHandle(const char *zJournal){
       break;
     }
   }
+  leaveJtMutex();
   return pMain;
 }
 
@@ -669,10 +682,12 @@ static int jtOpen(
     p->pNext = 0;
     p->pWritable = 0;
     p->aCksum = 0;
+    enterJtMutex();
     if( zName ){
       p->pNext = g.pList;
       g.pList = p;
     }
+    leaveJtMutex();
   }
   return rc;
 }