Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix thread related problems in test modules test_async.c and test_journal.c. (CVS 6399) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
45df27a22d283871ed1de334fe3b74b0 |
User & Date: | danielk1977 2009-03-28 17:21:52.000 |
Context
2009-03-28
| ||
18:56 | The test_async.c module must pass an unchanging filename to the underlying VFS. (CVS 6400) (check-in: d1eeee2167 user: drh tags: trunk) | |
17:21 | Fix thread related problems in test modules test_async.c and test_journal.c. (CVS 6399) (check-in: 45df27a22d user: danielk1977 tags: trunk) | |
15:04 | Back out check-in (6380). Replace it with a proper fix to the xFullPathname method in the async VFS. (CVS 6398) (check-in: 767a7f7b55 user: drh tags: trunk) | |
Changes
Changes to src/test_async.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 2005 December 14 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* ** 2005 December 14 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** $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. ** ** WHAT IS ASYNCHRONOUS I/O? ** ** With asynchronous I/O, write requests are handled by a separate thread |
︙ | ︙ | |||
479 480 481 482 483 484 485 | assert(&(aMutex[1])==&async.queueMutex); assert(&(aMutex[2])==&async.writerMutex); assert(&(aHolder[0])==&asyncdebug.lockMutexHolder); assert(&(aHolder[1])==&asyncdebug.queueMutexHolder); assert(&(aHolder[2])==&asyncdebug.writerMutexHolder); assert( pthread_self()!=0 ); | < | 479 480 481 482 483 484 485 486 487 488 489 490 491 492 | assert(&(aMutex[1])==&async.queueMutex); assert(&(aMutex[2])==&async.writerMutex); assert(&(aHolder[0])==&asyncdebug.lockMutexHolder); assert(&(aHolder[1])==&asyncdebug.queueMutexHolder); assert(&(aHolder[2])==&asyncdebug.writerMutexHolder); assert( pthread_self()!=0 ); for(iIdx=0; iIdx<3; iIdx++){ if( pMutex==&aMutex[iIdx] ) break; /* This is the key assert(). Here we are checking that if the caller * is trying to block on async.writerMutex, neither of the other two * mutex are held. If the caller is trying to block on async.queueMutex, * lockMutex is not held. |
︙ | ︙ | |||
606 607 608 609 610 611 612 | ** ** Once an AsyncWrite structure has been added to the list, it becomes the ** property of the writer thread and must not be read or modified by the ** caller. */ static void addAsyncWrite(AsyncWrite *pWrite){ /* We must hold the queue mutex in order to modify the queue pointers */ | > | > > | > | 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 | ** ** Once an AsyncWrite structure has been added to the list, it becomes the ** property of the writer thread and must not be read or modified by the ** caller. */ static void addAsyncWrite(AsyncWrite *pWrite){ /* We must hold the queue mutex in order to modify the queue pointers */ if( pWrite->op!=ASYNC_UNLOCK ){ pthread_mutex_lock(&async.queueMutex); } /* Add the record to the end of the write-op queue */ assert( !pWrite->pNext ); if( async.pQueueLast ){ assert( async.pQueueFirst ); async.pQueueLast->pNext = pWrite; }else{ async.pQueueFirst = pWrite; } async.pQueueLast = pWrite; ASYNC_TRACE(("PUSH %p (%s %s %d)\n", pWrite, azOpcodeName[pWrite->op], pWrite->pFileData ? pWrite->pFileData->zName : "-", pWrite->iOffset)); if( pWrite->op==ASYNC_CLOSE ){ async.nFile--; } /* Drop the queue mutex */ 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. */ pthread_cond_signal(&async.queueSignal); } /* |
︙ | ︙ | |||
952 953 954 955 956 957 958 959 960 | return rc; } static int asyncUnlock(sqlite3_file *pFile, int eLock){ int rc = SQLITE_OK; AsyncFileData *p = ((AsyncFile *)pFile)->pData; if( p->zName ){ AsyncFileLock *pLock = &p->lock; pthread_mutex_lock(&async.lockMutex); pLock->eLock = MIN(pLock->eLock, eLock); | > < > > | 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 | return rc; } static int asyncUnlock(sqlite3_file *pFile, int eLock){ int rc = SQLITE_OK; 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); rc = addNewAsyncWrite(p, ASYNC_UNLOCK, 0, eLock, 0); pthread_mutex_unlock(&async.lockMutex); pthread_mutex_unlock(&async.queueMutex); } return rc; } /* ** This function is called when the pager layer first opens a database file ** and is checking for a hot-journal. |
︙ | ︙ | |||
1522 1523 1524 1525 1526 1527 1528 1529 1530 | async.pQueueFirst = p->pNext; sqlite3_free(pData); doNotFree = 1; break; } case ASYNC_UNLOCK: { AsyncFileData *pData = p->pFileData; int eLock = p->nByte; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | > | 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 | async.pQueueFirst = p->pNext; sqlite3_free(pData); doNotFree = 1; break; } case ASYNC_UNLOCK: { AsyncWrite *pIter; AsyncFileData *pData = p->pFileData; int eLock = p->nByte; /* 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; } case ASYNC_DELETE: ASYNC_TRACE(("DELETE %s\n", p->zBuf)); rc = pVfs->xDelete(pVfs, p->zBuf, (int)p->iOffset); break; |
︙ | ︙ |
Changes to src/test_journal.c.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ****************************************************************************** ** ** This file contains code for a VFS layer that acts as a wrapper around ** an existing VFS. The code in this file attempts to verify that SQLite ** correctly populates and syncs a journal file before writing to a ** corresponding database file. ** | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ****************************************************************************** ** ** This file contains code for a VFS layer that acts as a wrapper around ** an existing VFS. The code in this file attempts to verify that SQLite ** correctly populates and syncs a journal file before writing to a ** corresponding database file. ** ** $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 */ #include "sqlite3.h" #include "sqliteInt.h" /* |
︙ | ︙ | |||
201 202 203 204 205 206 207 208 209 210 211 212 213 214 | }; struct JtGlobal { sqlite3_vfs *pVfs; /* Parent VFS */ jt_file *pList; /* List of all open files */ }; static struct JtGlobal g = {0, 0}; extern int sqlite3_io_error_pending; static void stop_ioerr_simulation(int *piSave){ *piSave = sqlite3_io_error_pending; sqlite3_io_error_pending = -1; } static void start_ioerr_simulation(int iSave){ | > > > > > > > > > > > | 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 | }; struct JtGlobal { sqlite3_vfs *pVfs; /* Parent VFS */ jt_file *pList; /* List of all open files */ }; 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; sqlite3_io_error_pending = -1; } static void start_ioerr_simulation(int iSave){ |
︙ | ︙ | |||
232 233 234 235 236 237 238 239 240 241 242 | ** Close an jt-file. */ static int jtClose(sqlite3_file *pFile){ jt_file **pp; jt_file *p = (jt_file *)pFile; closeTransaction(p); if( p->zName ){ for(pp=&g.pList; *pp!=p; pp=&(*pp)->pNext); *pp = p->pNext; } | > | < > > | 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 | ** Close an jt-file. */ static int jtClose(sqlite3_file *pFile){ jt_file **pp; 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); } /* ** Read data from an jt-file. */ static int jtRead( sqlite3_file *pFile, void *zBuf, int iAmt, sqlite_int64 iOfst ){ jt_file *p = (jt_file *)pFile; 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 ** corresponding database file by the pager that currently has the ** journal file opened. This file-handle is identified by the ** following properties: ** ** a) SQLITE_OPEN_MAIN_DB was specified when the file was opened. ** ** b) The file-name specified when the file was opened matches ** all but the final 8 characters of the journal file name. ** ** c) There is currently a reserved lock on the file. **/ 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) && (strlen(pMain->zName)==nName) && 0==memcmp(pMain->zName, zJournal, nName) && (pMain->eLock>=SQLITE_LOCK_RESERVED) ){ break; } } leaveJtMutex(); return pMain; } /* ** Parameter z points to a buffer of 4 bytes in size containing a ** unsigned 32-bit integer stored in big-endian format. Decode the ** integer and return its value. |
︙ | ︙ | |||
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 | pFile->pMethods = &jt_io_methods; p->eLock = 0; p->zName = zName; p->flags = flags; p->pNext = 0; p->pWritable = 0; p->aCksum = 0; if( zName ){ p->pNext = g.pList; g.pList = p; } } return rc; } /* ** Delete the file located at zPath. If the dirSync argument is true, ** ensure the file-system modifications are synced to disk before | > > | 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 | pFile->pMethods = &jt_io_methods; p->eLock = 0; p->zName = zName; p->flags = flags; p->pNext = 0; p->pWritable = 0; p->aCksum = 0; enterJtMutex(); if( zName ){ p->pNext = g.pList; g.pList = p; } leaveJtMutex(); } return rc; } /* ** Delete the file located at zPath. If the dirSync argument is true, ** ensure the file-system modifications are synced to disk before |
︙ | ︙ |