From: danielk1977 Date: Sat, 28 Mar 2009 17:21:52 +0000 (+0000) Subject: Fix thread related problems in test modules test_async.c and test_journal.c. (CVS... X-Git-Tag: version-3.6.15~351 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1a321c329ba5b83da88fc30cc4efe732e985b101;p=thirdparty%2Fsqlite.git Fix thread related problems in test modules test_async.c and test_journal.c. (CVS 6399) FossilOrigin-Name: 45df27a22d283871ed1de334fe3b74b0121d57a6 --- diff --git a/manifest b/manifest index a5528cf709..51aaa8d7fe 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index a689bcee5e..095a202474 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -767a7f7b55456df404a7f8966a0c48318ddac120 \ No newline at end of file +45df27a22d283871ed1de334fe3b74b0121d57a6 \ No newline at end of file diff --git a/src/test_async.c b/src/test_async.c index 9cd5957cc3..d2fd95aab1 100644 --- a/src/test_async.c +++ b/src/test_async.c @@ -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; } diff --git a/src/test_journal.c b/src/test_journal.c index fab8d7f9d7..f2acfe4da6 100644 --- a/src/test_journal.c +++ b/src/test_journal.c @@ -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; }