/ Check-in [8fe234b2]
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 | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:8fe234b2ca1292955162d38922a45c93004fb6ae
User & Date: danielk1977 2008-08-22 17:09:50
Context
2008-08-22
17:28
add legacy.lo back (in alphabetical order) (CVS 5600) check-in: a861aa73 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: 8fe234b2 user: danielk1977 tags: trunk
16:29
Enhanced test coverage. (CVS 5598) check-in: cc36b4e0 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/pcache.c.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
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
...
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
....
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
**    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 {
................................................................................
  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;
................................................................................
*/
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;
}

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







|







 







>
>
>
>
>
>
>
>












<

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


|
>

<
<
<
>







 







<







 







<
<
<
|
|

<
|
<







 







<
|
<







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
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
...
752
753
754
755
756
757
758

759
760
761
762
763
764
765
....
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
**    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 {
................................................................................
  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;
................................................................................
*/
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;
}

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