/ Check-in [ea3b941a]
Login

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 | SQL archive
Timelines: family | ancestors | descendants | both | branch-3.5.9
Files: files | file ages | folders
SHA1: ea3b941a7182851117fab9851e98e175ebb356e2
User & Date: drh 2010-01-29 21:23:35
Context
2010-01-30
18:22
Add additional pagerMutexHeld() macros to better verify the correct operation of pager.c. check-in: c50e972f 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
2008-05-14
16:18
Version 3.5.9 (CVS 5131) check-in: b6129f4c user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/pager.c.

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