Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix a missing mutex on page cache truncation during vacuum and auto-vacuum when SQLITE_ENABLE_MEMORY_MANAGEMENT is engaged. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | branch-3.5.9 |
Files: | files | file ages | folders |
SHA1: |
ea3b941a7182851117fab9851e98e175 |
User & Date: | drh 2010-01-29 21:23:35.000 |
Context
2010-01-30
| ||
18:22 | Add additional pagerMutexHeld() macros to better verify the correct operation of pager.c. (check-in: c50e972f1b user: drh tags: branch-3.5.9) | |
2010-01-29
| ||
21:23 | Fix a missing mutex on page cache truncation during vacuum and auto-vacuum when SQLITE_ENABLE_MEMORY_MANAGEMENT is engaged. (check-in: ea3b941a71 user: drh tags: branch-3.5.9) | |
2008-05-14
| ||
16:18 | Version 3.5.9 (CVS 5131) (check-in: b6129f4cc2 user: drh tags: trunk) | |
Changes
Changes to src/pager.c.
︙ | ︙ | |||
399 400 401 402 403 404 405 406 407 408 409 410 411 412 | int nHash; /* Size of the pager hash table */ PgHdr **aHash; /* Hash table to map page number to PgHdr */ #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT Pager *pNext; /* Doubly linked list of pagers on which */ Pager *pPrev; /* sqlite3_release_memory() will work */ int iInUseMM; /* Non-zero if unavailable to MM */ int iInUseDB; /* Non-zero if in sqlite3_release_memory() */ #endif char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */ char dbFileVers[16]; /* Changes whenever database file changes */ }; /* ** The following global variables hold counters used for | > | 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 | int nHash; /* Size of the pager hash table */ PgHdr **aHash; /* Hash table to map page number to PgHdr */ #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT Pager *pNext; /* Doubly linked list of pagers on which */ Pager *pPrev; /* sqlite3_release_memory() will work */ int iInUseMM; /* Non-zero if unavailable to MM */ int iInUseDB; /* Non-zero if in sqlite3_release_memory() */ u8 onPagerList; /* True if part of the sqlite3PagerList */ #endif char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */ char dbFileVers[16]; /* Changes whenever database file changes */ }; /* ** The following global variables hold counters used for |
︙ | ︙ | |||
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 | ** a mutex on each pager. The mutex is recursive. ** ** This is a special-purpose mutex. It only provides mutual exclusion ** between the Btree and the Memory Management sqlite3_release_memory() ** function. It does not prevent, for example, two Btrees from accessing ** the same pager at the same time. Other general-purpose mutexes in ** the btree layer handle that chore. */ #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT static void pagerEnter(Pager *p){ p->iInUseDB++; if( p->iInUseMM && p->iInUseDB==1 ){ #ifndef SQLITE_MUTEX_NOOP sqlite3_mutex *mutex; mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM2); #endif p->iInUseDB = 0; sqlite3_mutex_enter(mutex); p->iInUseDB = 1; sqlite3_mutex_leave(mutex); } assert( p->iInUseMM==0 ); } static void pagerLeave(Pager *p){ p->iInUseDB--; assert( p->iInUseDB>=0 ); } #else # define pagerEnter(X) # define pagerLeave(X) #endif /* ** Add page pPg to the end of the linked list managed by structure ** pList (pPg becomes the last entry in the list - the most recently ** used). Argument pLink should point to either pPg->free or pPg->gfree, ** depending on whether pPg is being added to the pager-specific or | > > > > > > | 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 | ** a mutex on each pager. The mutex is recursive. ** ** This is a special-purpose mutex. It only provides mutual exclusion ** between the Btree and the Memory Management sqlite3_release_memory() ** function. It does not prevent, for example, two Btrees from accessing ** the same pager at the same time. Other general-purpose mutexes in ** the btree layer handle that chore. ** ** The pagerMutexHeld(X) macro is for sanity checking. This macro verifies ** that the database-connection mutex is held for pager X and asserts if it ** is not. */ #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT static void pagerEnter(Pager *p){ p->iInUseDB++; if( p->iInUseMM && p->iInUseDB==1 ){ #ifndef SQLITE_MUTEX_NOOP sqlite3_mutex *mutex; mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM2); #endif p->iInUseDB = 0; sqlite3_mutex_enter(mutex); p->iInUseDB = 1; sqlite3_mutex_leave(mutex); } assert( p->iInUseMM==0 ); } static void pagerLeave(Pager *p){ p->iInUseDB--; assert( p->iInUseDB>=0 ); } # define pagerMutexHeld(X) assert( (X)->iInUseDB>0 || !(X)->onPagerList ) #else # define pagerEnter(X) # define pagerLeave(X) # define pagerMutexHeld(X) #endif /* ** Add page pPg to the end of the linked list managed by structure ** pList (pPg becomes the last entry in the list - the most recently ** used). Argument pLink should point to either pPg->free or pPg->gfree, ** depending on whether pPg is being added to the pager-specific or |
︙ | ︙ | |||
1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 | ** sets the state of the pager back to what it was when it was first ** opened. Any outstanding pages are invalidated and subsequent attempts ** to access those pages will likely result in a coredump. */ static void pager_reset(Pager *pPager){ PgHdr *pPg, *pNext; if( pPager->errCode ) return; for(pPg=pPager->pAll; pPg; pPg=pNext){ IOTRACE(("PGFREE %p %d\n", pPager, pPg->pgno)); PAGER_INCR(sqlite3_pager_pgfree_count); pNext = pPg->pNextAll; lruListRemove(pPg); sqlite3_free(pPg->pData); sqlite3_free(pPg); | > | 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 | ** sets the state of the pager back to what it was when it was first ** opened. Any outstanding pages are invalidated and subsequent attempts ** to access those pages will likely result in a coredump. */ static void pager_reset(Pager *pPager){ PgHdr *pPg, *pNext; if( pPager->errCode ) return; pagerMutexHeld(pPager); for(pPg=pPager->pAll; pPg; pPg=pNext){ IOTRACE(("PGFREE %p %d\n", pPager, pPg->pgno)); PAGER_INCR(sqlite3_pager_pgfree_count); pNext = pPg->pNextAll; lruListRemove(pPg); sqlite3_free(pPg->pData); sqlite3_free(pPg); |
︙ | ︙ | |||
2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 | pPager->pNext = sqlite3PagerList; if( sqlite3PagerList ){ assert( sqlite3PagerList->pPrev==0 ); sqlite3PagerList->pPrev = pPager; } pPager->pPrev = 0; sqlite3PagerList = pPager; sqlite3_mutex_leave(mutex); } #endif return SQLITE_OK; } /* | > | 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 | pPager->pNext = sqlite3PagerList; if( sqlite3PagerList ){ assert( sqlite3PagerList->pPrev==0 ); sqlite3PagerList->pPrev = pPager; } pPager->pPrev = 0; sqlite3PagerList = pPager; pPager->onPagerList = 1; sqlite3_mutex_leave(mutex); } #endif return SQLITE_OK; } /* |
︙ | ︙ | |||
2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 | ** to zero it and hope that we error out sanely. */ static void pager_truncate_cache(Pager *pPager){ PgHdr *pPg; PgHdr **ppPg; int dbSize = pPager->dbSize; ppPg = &pPager->pAll; while( (pPg = *ppPg)!=0 ){ if( pPg->pgno<=dbSize ){ ppPg = &pPg->pNextAll; }else if( pPg->nRef>0 ){ memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize); ppPg = &pPg->pNextAll; | > | 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 | ** to zero it and hope that we error out sanely. */ static void pager_truncate_cache(Pager *pPager){ PgHdr *pPg; PgHdr **ppPg; int dbSize = pPager->dbSize; pagerMutexHeld(pPager); ppPg = &pPager->pAll; while( (pPg = *ppPg)!=0 ){ if( pPg->pgno<=dbSize ){ ppPg = &pPg->pNextAll; }else if( pPg->nRef>0 ){ memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize); ppPg = &pPg->pNextAll; |
︙ | ︙ | |||
2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 | return rc; } if( nPage>=(unsigned)pPager->dbSize ){ return SQLITE_OK; } if( MEMDB ){ pPager->dbSize = nPage; pager_truncate_cache(pPager); return SQLITE_OK; } pagerEnter(pPager); rc = syncJournal(pPager); pagerLeave(pPager); if( rc!=SQLITE_OK ){ return rc; } /* Get an exclusive lock on the database before truncating. */ pagerEnter(pPager); rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); | > > < | < > | < | 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 | return rc; } if( nPage>=(unsigned)pPager->dbSize ){ return SQLITE_OK; } if( MEMDB ){ pPager->dbSize = nPage; pagerEnter(pPager); pager_truncate_cache(pPager); pagerLeave(pPager); return SQLITE_OK; } pagerEnter(pPager); rc = syncJournal(pPager); pagerLeave(pPager); if( rc!=SQLITE_OK ){ return rc; } /* Get an exclusive lock on the database before truncating. */ pagerEnter(pPager); rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); if( rc==SQLITE_OK ){ rc = pager_truncate(pPager, nPage); } pagerLeave(pPager); return rc; } /* ** Shutdown the page cache. Free all memory and close all files. ** ** If a transaction was in progress when this routine is called, that |
︙ | ︙ | |||
2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 | }else{ sqlite3PagerList = pPager->pNext; } if( pPager->pNext ){ pPager->pNext->pPrev = pPager->pPrev; } sqlite3_mutex_leave(mutex); } #endif disable_simulated_io_errors(); sqlite3FaultBeginBenign(-1); pPager->errCode = 0; pPager->exclusiveMode = 0; | > | 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 | }else{ sqlite3PagerList = pPager->pNext; } if( pPager->pNext ){ pPager->pNext->pPrev = pPager->pPrev; } sqlite3_mutex_leave(mutex); pPager->onPagerList = 0; } #endif disable_simulated_io_errors(); sqlite3FaultBeginBenign(-1); pPager->errCode = 0; pPager->exclusiveMode = 0; |
︙ | ︙ |