SQLite

Check-in [8fe234b2ca]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Relinquish the pcache mutex before calling an xStress callback. This ensures that the pcache mutex is never held while IO is performed. (CVS 5599)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 8fe234b2ca1292955162d38922a45c93004fb6ae
User & Date: danielk1977 2008-08-22 17:09:50.000
Context
2008-08-22
17:28
add legacy.lo back (in alphabetical order) (CVS 5600) (check-in: a861aa73c4 user: pweilbacher tags: trunk)
17:09
Relinquish the pcache mutex before calling an xStress callback. This ensures that the pcache mutex is never held while IO is performed. (CVS 5599) (check-in: 8fe234b2ca user: danielk1977 tags: trunk)
16:29
Enhanced test coverage. (CVS 5598) (check-in: cc36b4e016 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/pcache.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2008 August 05
**
** 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.
**
*************************************************************************
** This file implements that page cache.
**
** @(#) $Id: pcache.c,v 1.8 2008/08/22 16:22:17 danielk1977 Exp $
*/
#include "sqliteInt.h"

/*
** A complete page cache is an instance of this structure.
*/
struct PCache {













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2008 August 05
**
** 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.
**
*************************************************************************
** This file implements that page cache.
**
** @(#) $Id: pcache.c,v 1.9 2008/08/22 17:09:50 danielk1977 Exp $
*/
#include "sqliteInt.h"

/*
** A complete page cache is an instance of this structure.
*/
struct PCache {
449
450
451
452
453
454
455








456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488

489
490
491
492
493
494
495
496
497
498
499
  assert( !pcache.pStart );
  assert( p->apSave[0]==0 );
  assert( p->apSave[1]==0 );
  assert( p && p->pCache );
  return sqlite3MallocSize(p);
}









static PgHdr *pcacheRecycle(PCache *pCache){
  PgHdr *p = 0;

  assert( pcache.isInit );
  assert( sqlite3_mutex_held(pcache.mutex_lru) );

  p = pcache.pLruSynced;
  if( !p ){
    p = pcache.pLruTail;
  }
  if( p && (p->flags&PGHDR_DIRTY) ){
    if( SQLITE_OK==sqlite3_mutex_try(pcache.mutex_mem2) ){
      int iInUseDB;
      PCache *pC = p->pCache;

      if( pCache==pC ){
        /* If trying to recycle a page from pCache, then set the iInUseDb
        ** flag to zero. This is done so that the sqlite3PcacheSetFlags()
        ** can tell that the LRU mutex is already held.
        **
        ** It is quite safe to modify the iInUseDB variable, because we 
        ** know no other thread will attempt to use pCache (because this
        ** call is being made from within a call to sqlite3PcacheFetch()
        ** on pCache). 
        */
        assert( pCache->iInUseDB );
        iInUseDB = pCache->iInUseDB;
        pCache->iInUseDB = 0;
      }

      assert( pC->iInUseMM==0 );
      pC->iInUseMM = 1;
      if( pC->xStress && pC->iInUseDB==0 ){

        pC->xStress(pC->pStress, p);
      }
      if( pCache==pC ){
        pCache->iInUseDB = iInUseDB;
      }
      pC->iInUseMM = 0;
      sqlite3_mutex_leave(pcache.mutex_mem2);
    }
  }
  if( p && (p->flags&PGHDR_DIRTY) ){
    p = 0;







>
>
>
>
>
>
>
>












<

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


|
>

<
|
<







449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475

476
















477
478
479
480
481

482

483
484
485
486
487
488
489
  assert( !pcache.pStart );
  assert( p->apSave[0]==0 );
  assert( p->apSave[1]==0 );
  assert( p && p->pCache );
  return sqlite3MallocSize(p);
}

/*
** Recycle a page from the global LRU list. If no page can be recycled, 
** return NULL. Otherwise, the pointer returned points to a PgHdr 
** object that has been removed from all lists and hash tables in
** which is was referenced. The caller may reuse the allocation directly
** or may pass it to pcachePageFree() to return the memory to the heap
** (or pcache.pFree list).
*/ 
static PgHdr *pcacheRecycle(PCache *pCache){
  PgHdr *p = 0;

  assert( pcache.isInit );
  assert( sqlite3_mutex_held(pcache.mutex_lru) );

  p = pcache.pLruSynced;
  if( !p ){
    p = pcache.pLruTail;
  }
  if( p && (p->flags&PGHDR_DIRTY) ){
    if( SQLITE_OK==sqlite3_mutex_try(pcache.mutex_mem2) ){

      PCache *pC = p->pCache;
















      assert( pC->iInUseMM==0 );
      pC->iInUseMM = 1;
      if( pC->xStress && (pC->iInUseDB==0 || pC==pCache) ){
        pcacheExitGlobal();
        pC->xStress(pC->pStress, p);

        pcacheEnterGlobal();

      }
      pC->iInUseMM = 0;
      sqlite3_mutex_leave(pcache.mutex_mem2);
    }
  }
  if( p && (p->flags&PGHDR_DIRTY) ){
    p = 0;
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
*/
void sqlite3PcacheMakeClean(PgHdr *p){
  PCache *pCache;
  assert( p->pCache->iInUseDB || p->pCache->iInUseMM );
  if( (p->flags & PGHDR_DIRTY)==0 ) return;
  assert( p->apSave[0]==0 && p->apSave[1]==0 );
  assert( p->flags & PGHDR_DIRTY );
  assert( p->nRef>0 || sqlite3_mutex_held(pcache.mutex_lru) );
  pCache = p->pCache;
  pcacheRemoveFromList(&pCache->pDirty, p);
  pcacheAddToList(&pCache->pClean, p);
  p->flags &= ~PGHDR_DIRTY;
}

/*







<







752
753
754
755
756
757
758

759
760
761
762
763
764
765
*/
void sqlite3PcacheMakeClean(PgHdr *p){
  PCache *pCache;
  assert( p->pCache->iInUseDB || p->pCache->iInUseMM );
  if( (p->flags & PGHDR_DIRTY)==0 ) return;
  assert( p->apSave[0]==0 && p->apSave[1]==0 );
  assert( p->flags & PGHDR_DIRTY );

  pCache = p->pCache;
  pcacheRemoveFromList(&pCache->pDirty, p);
  pcacheAddToList(&pCache->pClean, p);
  p->flags &= ~PGHDR_DIRTY;
}

/*
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
*/
void sqlite3PcacheSetFlags(PCache *pCache, int andMask, int orMask){
  PgHdr *p;

  assert( (orMask&PGHDR_NEED_SYNC)==0 );
  assert( pCache->iInUseDB || pCache->iInUseMM );

  /* If this call is being made from within a call to the xStress callback
  ** of a pager-cache (i.e. from within pagerRecycle()), then the 
  ** PCache.iInUseDB will be set to zero. In this case, the LRU mutex is
  ** already held. Otherwise, obtain it before modifying any PgHdr.flags
  ** variables or traversing the LRU list.
  */ 
  if( pCache->iInUseDB ){
    pcacheEnterGlobal();
  }
  assert( sqlite3_mutex_held(pcache.mutex_lru) );

  for(p=pCache->pDirty; p; p=p->pNext){
    p->flags = (p->flags&andMask)|orMask;
  }
  for(p=pCache->pClean; p; p=p->pNext){
    p->flags = (p->flags&andMask)|orMask;
  }

  if( 0==(andMask&PGHDR_NEED_SYNC) ){
    for(p=pcache.pLruTail; p && (p->flags&PGHDR_NEED_SYNC); p=p->pPrevLru);
    pcache.pLruSynced = p;
  }

  if( pCache->iInUseDB ){
    pcacheExitGlobal();
  }
}

/*
** Set the suggested cache-size value.
*/
int sqlite3PcacheGetCachesize(PCache *pCache){
  return pCache->nMax;







<
<
<
|
|

<
|
<














<
|
<







1112
1113
1114
1115
1116
1117
1118



1119
1120
1121

1122

1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136

1137

1138
1139
1140
1141
1142
1143
1144
*/
void sqlite3PcacheSetFlags(PCache *pCache, int andMask, int orMask){
  PgHdr *p;

  assert( (orMask&PGHDR_NEED_SYNC)==0 );
  assert( pCache->iInUseDB || pCache->iInUseMM );




  /* Obtain the global mutex before modifying any PgHdr.flags variables 
  ** or traversing the LRU list.
  */ 

  pcacheEnterGlobal();

  assert( sqlite3_mutex_held(pcache.mutex_lru) );

  for(p=pCache->pDirty; p; p=p->pNext){
    p->flags = (p->flags&andMask)|orMask;
  }
  for(p=pCache->pClean; p; p=p->pNext){
    p->flags = (p->flags&andMask)|orMask;
  }

  if( 0==(andMask&PGHDR_NEED_SYNC) ){
    for(p=pcache.pLruTail; p && (p->flags&PGHDR_NEED_SYNC); p=p->pPrevLru);
    pcache.pLruSynced = p;
  }


  pcacheExitGlobal();

}

/*
** Set the suggested cache-size value.
*/
int sqlite3PcacheGetCachesize(PCache *pCache){
  return pCache->nMax;