Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch branch-3.5.9 Excluding Merge-Ins
This is equivalent to a diff from b6129f4c to bb18f578
2010-01-30
| ||
23:08 | The iInUseDB and iInUseMM variables do not need to be volatile. (Leaf check-in: bb18f578 user: drh tags: branch-3.5.9) | |
22:28 | Always hold the MEM2 mutex when initially marking a pager as in use by its database connection. (check-in: 622c1717 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: ea3b941a user: drh tags: branch-3.5.9) | |
19:46 | Changes to 3.5.9 proposed by Rob Stoddard. (check-in: 5ed168c4 user: drh tags: branch-3.5.9) | |
2008-05-15
| ||
08:34 | Do not write pages to disk to free memory after an IO error occurs. (CVS 5132) (check-in: 10ea8287 user: danielk1977 tags: trunk) | |
2008-05-14
| ||
16:18 | Version 3.5.9 (CVS 5131) (check-in: b6129f4c user: drh tags: trunk) | |
2008-05-13
| ||
19:41 | On instruction from DRH, only do malloc failure tests for O/S ops on non-Windows systems. Better test fixture code will be introduced in 3.6.0 to add this coverage back in for Windows. (CVS 5130) (check-in: e4aab150 user: shane tags: trunk) | |
Changes to src/pager.c.
︙ | ︙ | |||
397 398 399 400 401 402 403 | void *pCodecArg; /* First argument to xCodec() */ #endif 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 */ | < > > | 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 | void *pCodecArg; /* First argument to xCodec() */ #endif 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 iInUseDB; /* Non-zero if in sqlite3_release_memory() */ u8 iInUseMM; /* Non-zero if unavailable to MM */ 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 | ** 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){ | > > > > > | | < > < > > | 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){ if( p->iInUseDB>0 ){ p->iInUseDB++; }else{ #ifndef SQLITE_MUTEX_NOOP sqlite3_mutex *mutex; mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM2); #endif sqlite3_mutex_enter(mutex); assert( p->iInUseMM==0 ); p->iInUseDB = 1; sqlite3_mutex_leave(mutex); } } 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 |
︙ | ︙ | |||
695 696 697 698 699 700 701 702 703 704 705 706 707 708 | if( aHash==0 ){ /* Failure to rehash is not an error. It is only a performance hit. */ return; } sqlite3_free(pPager->aHash); pPager->nHash = N; pPager->aHash = aHash; for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ int h; if( pPg->pgno==0 ){ assert( pPg->pNextHash==0 && pPg->pPrevHash==0 ); continue; } h = pPg->pgno & (N-1); | > | 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 | if( aHash==0 ){ /* Failure to rehash is not an error. It is only a performance hit. */ return; } sqlite3_free(pPager->aHash); pPager->nHash = N; pPager->aHash = aHash; pagerMutexHeld(pPager); for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ int h; if( pPg->pgno==0 ){ assert( pPg->pNextHash==0 && pPg->pPrevHash==0 ); continue; } h = pPg->pgno & (N-1); |
︙ | ︙ | |||
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); | > | 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 | ** 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); |
︙ | ︙ | |||
1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 | pPager->journalOpen = 0; if( rc==SQLITE_OK ){ rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0); } } sqlite3BitvecDestroy(pPager->pInJournal); pPager->pInJournal = 0; for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ pPg->inJournal = 0; pPg->dirty = 0; pPg->needSync = 0; pPg->alwaysRollback = 0; #ifdef SQLITE_CHECK_PAGES pPg->pageHash = pager_pagehash(pPg); | > | 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 | pPager->journalOpen = 0; if( rc==SQLITE_OK ){ rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0); } } sqlite3BitvecDestroy(pPager->pInJournal); pPager->pInJournal = 0; pagerMutexHeld(pPager); for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ pPg->inJournal = 0; pPg->dirty = 0; pPg->needSync = 0; pPg->alwaysRollback = 0; #ifdef SQLITE_CHECK_PAGES pPg->pageHash = pager_pagehash(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; } /* | > | 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 | 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; | > | 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 | ** 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); | > > < | < > | < > > > > > < < < | 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 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 | 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 ** transaction is rolled back. All outstanding pages are invalidated ** and their memory is freed. Any attempt to use a page associated ** with this page cache after this function returns will likely ** result in a coredump. ** ** This function always succeeds. If a transaction is active an attempt ** is made to roll it back. If an error occurs during the rollback ** a hot journal may be left in the filesystem but no error is returned ** to the caller. */ int sqlite3PagerClose(Pager *pPager){ pagerEnter(pPager); pPager->errCode = 0; pager_reset(pPager); pagerLeave(pPager); #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT if( !MEMDB ){ #ifndef SQLITE_MUTEX_NOOP sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM2); #endif sqlite3_mutex_enter(mutex); if( pPager->pPrev ){ pPager->pPrev->pNext = pPager->pNext; }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->exclusiveMode = 0; pagerUnlockAndRollback(pPager); enable_simulated_io_errors(); sqlite3FaultEndBenign(-1); PAGERTRACE2("CLOSE %d\n", PAGERID(pPager)); IOTRACE(("CLOSE %p\n", pPager)) if( pPager->journalOpen ){ sqlite3OsClose(pPager->jfd); |
︙ | ︙ | |||
2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 | #ifndef NDEBUG /* If the Pager.needSync flag is clear then the PgHdr.needSync ** flag must also be clear for all pages. Verify that this ** invariant is true. */ else{ for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ assert( pPg->needSync==0 ); } assert( pPager->lru.pFirstSynced==pPager->lru.pFirst ); } #endif | > | 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 | #ifndef NDEBUG /* If the Pager.needSync flag is clear then the PgHdr.needSync ** flag must also be clear for all pages. Verify that this ** invariant is true. */ else{ pagerMutexHeld(pPager); for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ assert( pPg->needSync==0 ); } assert( pPager->lru.pFirstSynced==pPager->lru.pFirst ); } #endif |
︙ | ︙ | |||
3164 3165 3166 3167 3168 3169 3170 | */ static int pager_recycle(Pager *pPager, PgHdr **ppPg){ PgHdr *pPg; *ppPg = 0; /* It is illegal to call this function unless the pager object ** pointed to by pPager has at least one free page (page with nRef==0). | | | 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 | */ static int pager_recycle(Pager *pPager, PgHdr **ppPg){ PgHdr *pPg; *ppPg = 0; /* It is illegal to call this function unless the pager object ** pointed to by pPager has at least one free page (page with nRef==0). */ assert(!MEMDB); assert(pPager->lru.pFirst); /* Find a page to recycle. Try to locate a page that does not ** require us to do an fsync() on the journal. */ pPg = pPager->lru.pFirstSynced; |
︙ | ︙ | |||
3275 3276 3277 3278 3279 3280 3281 | */ for(pPager=sqlite3PagerList; pPager; pPager=pPager->pNext){ pPager->iInUseMM = 1; } while( rc==SQLITE_OK && (nReq<0 || nReleased<nReq) ){ PgHdr *pPg; | < | 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 | */ for(pPager=sqlite3PagerList; pPager; pPager=pPager->pNext){ pPager->iInUseMM = 1; } while( rc==SQLITE_OK && (nReq<0 || nReleased<nReq) ){ PgHdr *pPg; /* Try to find a page to recycle that does not require a sync(). If ** this is not possible, find one that does require a sync(). */ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU)); pPg = sqlite3LruPageList.pFirstSynced; while( pPg && (pPg->needSync || pPg->pPager->iInUseDB) ){ |
︙ | ︙ | |||
3300 3301 3302 3303 3304 3305 3306 | /* If pPg==0, then the block above has failed to find a page to ** recycle. In this case return early - no further memory will ** be released. */ if( !pPg ) break; pPager = pPg->pPager; | < < | | > < | 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 | /* If pPg==0, then the block above has failed to find a page to ** recycle. In this case return early - no further memory will ** be released. */ if( !pPg ) break; pPager = pPg->pPager; assert( pPager->iInUseDB==0 ); savedBusy = pPager->pBusyHandler; pPager->pBusyHandler = 0; rc = pager_recycle(pPager, &pPg); assert( pPager->iInUseDB==0 ); pPager->pBusyHandler = savedBusy; if( rc==SQLITE_OK ){ /* We've found a page to free. At this point the page has been ** removed from the page hash-table, free-list and synced-list ** (pFirstSynced). It is still in the all pages (pAll) list. ** Remove it from this list before freeing. ** ** Todo: Check the Pager.pStmt list to make sure this is Ok. It |
︙ | ︙ | |||
3613 3614 3615 3616 3617 3618 3619 3620 3621 | ** to be synced to disk or else disk syncing is currently ** allowed. */ static int pagerAllocatePage(Pager *pPager, PgHdr **ppPg){ int rc = SQLITE_OK; PgHdr *pPg; int nByteHdr; /* Create a new PgHdr if any of the four conditions defined | > | > > | 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 | ** to be synced to disk or else disk syncing is currently ** allowed. */ static int pagerAllocatePage(Pager *pPager, PgHdr **ppPg){ int rc = SQLITE_OK; PgHdr *pPg; int nByteHdr; /* Create a new PgHdr if any of the four conditions defined ** above are met: */ pagerMutexHeld(pPager); if( pPager->nPage<pPager->mxPage || pPager->lru.pFirst==0 || MEMDB || (pPager->lru.pFirstSynced==0 && pPager->doNotSync) ){ void *pData; if( pPager->nPage>=pPager->nHash ){ |
︙ | ︙ | |||
3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 | if( pPg==0 ){ rc = SQLITE_NOMEM; goto pager_allocate_out; } memset(pPg, 0, nByteHdr); pPg->pData = pData; pPg->pPager = pPager; pPg->pNextAll = pPager->pAll; pPager->pAll = pPg; pPager->nPage++; }else{ /* Recycle an existing page with a zero ref-count. */ rc = pager_recycle(pPager, &pPg); if( rc==SQLITE_BUSY ){ rc = SQLITE_IOERR_BLOCKED; } if( rc!=SQLITE_OK ){ goto pager_allocate_out; } | > > | 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 | if( pPg==0 ){ rc = SQLITE_NOMEM; goto pager_allocate_out; } memset(pPg, 0, nByteHdr); pPg->pData = pData; pPg->pPager = pPager; pagerMutexHeld(pPager); pPg->pNextAll = pPager->pAll; pPager->pAll = pPg; pPager->nPage++; }else{ /* Recycle an existing page with a zero ref-count. */ pagerMutexHeld(pPager); rc = pager_recycle(pPager, &pPg); if( rc==SQLITE_BUSY ){ rc = SQLITE_IOERR_BLOCKED; } if( rc!=SQLITE_OK ){ goto pager_allocate_out; } |
︙ | ︙ | |||
4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 | if( rc!=SQLITE_OK ) goto sync_exit; } } } #endif rc = writeMasterJournal(pPager, zMaster); if( rc!=SQLITE_OK ) goto sync_exit; rc = syncJournal(pPager); } if( rc!=SQLITE_OK ) goto sync_exit; #ifndef SQLITE_OMIT_AUTOVACUUM if( nTrunc!=0 ){ rc = sqlite3PagerTruncate(pPager, nTrunc); | > | 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 | if( rc!=SQLITE_OK ) goto sync_exit; } } } #endif rc = writeMasterJournal(pPager, zMaster); if( rc!=SQLITE_OK ) goto sync_exit; pagerMutexHeld(pPager); rc = syncJournal(pPager); } if( rc!=SQLITE_OK ) goto sync_exit; #ifndef SQLITE_OMIT_AUTOVACUUM if( nTrunc!=0 ){ rc = sqlite3PagerTruncate(pPager, nTrunc); |
︙ | ︙ | |||
4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 | ** SQLITE_OK is returned. */ int sqlite3PagerRollback(Pager *pPager){ int rc; PAGERTRACE2("ROLLBACK %d\n", PAGERID(pPager)); if( MEMDB ){ PgHdr *p; for(p=pPager->pAll; p; p=p->pNextAll){ PgHistory *pHist; assert( !p->alwaysRollback ); if( !p->dirty ){ assert( !((PgHistory *)PGHDR_TO_HIST(p, pPager))->pOrig ); assert( !((PgHistory *)PGHDR_TO_HIST(p, pPager))->pStmt ); continue; | > | 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 | ** SQLITE_OK is returned. */ int sqlite3PagerRollback(Pager *pPager){ int rc; PAGERTRACE2("ROLLBACK %d\n", PAGERID(pPager)); if( MEMDB ){ PgHdr *p; pagerMutexHeld(pPager); for(p=pPager->pAll; p; p=p->pNextAll){ PgHistory *pHist; assert( !p->alwaysRollback ); if( !p->dirty ){ assert( !((PgHistory *)PGHDR_TO_HIST(p, pPager))->pOrig ); assert( !((PgHistory *)PGHDR_TO_HIST(p, pPager))->pStmt ); continue; |
︙ | ︙ |