/ 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 Unified Diffs Ignore Whitespace Patch

Changes to src/pager.c.

399
400
401
402
403
404
405

406
407
408
409
410
411
412
...
507
508
509
510
511
512
513




514
515
516
517
518
519
520
...
527
528
529
530
531
532
533

534
535
536

537
538
539
540
541
542
543
....
1269
1270
1271
1272
1273
1274
1275

1276
1277
1278
1279
1280
1281
1282
....
2369
2370
2371
2372
2373
2374
2375

2376
2377
2378
2379
2380
2381
2382
....
2633
2634
2635
2636
2637
2638
2639

2640
2641
2642
2643
2644
2645
2646
....
2703
2704
2705
2706
2707
2708
2709

2710

2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
....
2755
2756
2757
2758
2759
2760
2761

2762
2763
2764
2765
2766
2767
2768
  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
................................................................................
** 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;
................................................................................
    }
    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
................................................................................
** 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);
................................................................................
    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;
}

/*
................................................................................
** 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;
................................................................................
    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);
  pagerLeave(pPager);
  if( rc!=SQLITE_OK ){
    return rc;
  }

  rc = pager_truncate(pPager, nPage);
  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
................................................................................
    }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;







>







 







>
>
>
>







 







>



>







 







>







 







>







 







>







 







>

>












|
|
|
|
<
<







 







>







399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
...
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
...
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
....
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
....
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
....
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
....
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
....
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
  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
................................................................................
** 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;
................................................................................
    }
    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
................................................................................
** 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);
................................................................................
    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;
}

/*
................................................................................
** 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;
................................................................................
    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
................................................................................
    }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;