]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
When recycling a page, try to find one that does not require a call to xSync() on...
authordanielk1977 <danielk1977@noemail.net>
Fri, 22 Aug 2008 16:22:17 +0000 (16:22 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Fri, 22 Aug 2008 16:22:17 +0000 (16:22 +0000)
FossilOrigin-Name: 93dbc5427bebaa0b3d726731027caad3f70611c7

manifest
manifest.uuid
src/pager.c
src/pcache.c
src/pcache.h
test/mutex1.test

index 70d7356f2dbef8cee2e231374789423266c5b1b5..587bd40b4274c9e81f09c2b0be119409b86730af 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Make\ssure\sthe\sfunction\scontext\sis\sfully\sinitialized\sbefore\sinvoking\sthe\nfunction\sfinalizer.\s\sTicket\s#3326.\s(CVS\s5596)
-D 2008-08-22T14:41:01
+C When\srecycling\sa\spage,\stry\sto\sfind\sone\sthat\sdoes\snot\srequire\sa\scall\sto\sxSync()\son\sthe\sjournal\sfile.\sAlso\ssimplify\ssome\sof\sthe\smutex\srelated\sthings\sin\spcache.\s(CVS\s5597)
+D 2008-08-22T16:22:17
 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
 F Makefile.in 51b727303f84cf055e29514d8248e5eaf9701379
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -135,11 +135,11 @@ F src/os_common.h 24525d8b7bce66c374dfc1810a6c9043f3359b60
 F src/os_os2.c e391fc95adc744bbdcefd4d11e3066998185a0a0
 F src/os_unix.c f1be99705e4542f01830ccea327eb773814f4eb9
 F src/os_win.c aefe9ee26430678a19a058a874e4e2bd91398142
-F src/pager.c 620b0c34f2f43acc3cc770be75c832739465bb52
+F src/pager.c 3b6625d32cd6f43c54c160f246545f9f26ba7668
 F src/pager.h 3778bea71dfb9658b6c94394e18db4a5b27e6ded
 F src/parse.y d0f76d2cb8d6883d5600dc20beb961a6022b94b8
-F src/pcache.c f57227003d39d40fa7f9b5a86e36b99f74b93267
-F src/pcache.h d2becbe7255f6bf57fc9e0bf889a9ec73d50ee74
+F src/pcache.c e12359db2963c379f18b52c657b5ec0ebb7a02cd
+F src/pcache.h 1457e4e7ef08f6964399d5c039afdece25071d54
 F src/pragma.c f5b271b090af7fcedd308d7c5807a5503f7a853d
 F src/prepare.c c197041e0c4770672cda75e6bfe10242f885e510
 F src/printf.c 785f87120589c1db672e37c6eb1087c456e6f84d
@@ -434,7 +434,7 @@ F test/misc5.test 6a5c1e3217a95b0db05ff9a0f1ecb5ce9043ffef
 F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
 F test/misc7.test 0d763f703a34521e55ab30145b747aafa0e5f794
 F test/misuse.test 30b3a458e5a70c31e74c291937b6c82204c59f33
-F test/mutex1.test ee9fb9c12d03eb2291ab500a3ce30bcad6fb46e8
+F test/mutex1.test 342dd695567d307126e8f67f243e9b2bcd17898e
 F test/mutex2.test 56f282f436596e9febdc6e0db2c507432b6724bb
 F test/nan.test 14c41572ff52dbc740b1c3303dd313a90dc6084c
 F test/notnull.test 44d600f916b770def8b095a9962dbe3be5a70d82
@@ -623,7 +623,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
-P 7fd11f4ad8774e68f0a053eb2e1dd962a024da48
-R d422b5970a3ab5d1313431fc076c62e8
-U drh
-Z dc8b2c3e5eaef00fc8cce9d4dcda1b42
+P 8496f4a00a7e62006956e58f3d50c6c4de5347e4
+R 07c866e144c636ba349c06010da224eb
+U danielk1977
+Z 3fb2f6ec7de60b517a8379ad6632f407
index ed5ed203580047a071381dcb3f26d62aa74581f6..57db720933eeddcb5f470b5e4b49adf381bb44c0 100644 (file)
@@ -1 +1 @@
-8496f4a00a7e62006956e58f3d50c6c4de5347e4
\ No newline at end of file
+93dbc5427bebaa0b3d726731027caad3f70611c7
\ No newline at end of file
index 5e39b15a4e7aff64774f96a0a28baf82c5545865..5e7f8ff0ddcaeb764b8fdcbd843e717320a51fc5 100644 (file)
@@ -18,7 +18,7 @@
 ** file simultaneously, or one process from reading the database while
 ** another is writing.
 **
-** @(#) $Id: pager.c,v 1.474 2008/08/22 12:57:09 drh Exp $
+** @(#) $Id: pager.c,v 1.475 2008/08/22 16:22:17 danielk1977 Exp $
 */
 #ifndef SQLITE_OMIT_DISKIO
 #include "sqliteInt.h"
@@ -1707,7 +1707,7 @@ static int sqlite3PagerOpentemp(
   return rc;
 }
 
-static int pagerStress(void *);
+static int pagerStress(void *,PgHdr *);
 
 /*
 ** Create a new page cache and put a pointer to the page cache in *ppPager.
@@ -2366,8 +2366,10 @@ static int syncJournal(Pager *pPager){
 
 /*
 ** Given a list of pages (connected by the PgHdr.pDirty pointer) write
-** every one of those pages out to the database file and mark them all
-** as clean.
+** every one of those pages out to the database file. No calls are made
+** to the page-cache to mark the pages as clean. It is the responsibility
+** of the caller to use PcacheCleanAll() or PcacheMakeClean() to mark
+** the pages as clean.
 */
 static int pager_write_pagelist(PgHdr *pList){
   Pager *pPager;
@@ -2433,7 +2435,7 @@ static int pager_write_pagelist(PgHdr *pList){
 #ifdef SQLITE_CHECK_PAGES
     pList->pageHash = pager_pagehash(pList);
 #endif
-    makeClean(pList);
+    /* makeClean(pList); */
     pList = pList->pDirty;
   }
 
@@ -2448,32 +2450,32 @@ static int pager_write_pagelist(PgHdr *pList){
 ** outstanding references (if one exists) clean so that it can be recycled 
 ** by the pcache layer.
 */
-static int pagerStress(void *p){
+static int pagerStress(void *p, PgHdr *pPg){
   Pager *pPager = (Pager *)p;
-  PgHdr *pPg = sqlite3PcacheDirtyPage(pPager->pPCache);
   int rc = SQLITE_OK;
 
-  if( pPg ){
-    assert( pPg->flags&PGHDR_DIRTY );
-    if( pPager->errCode==SQLITE_OK ){
-      if( pPg->flags&PGHDR_NEED_SYNC ){
-        rc = syncJournal(pPager);
-        if( rc==SQLITE_OK && pPager->fullSync && 
-          !(sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND)
-        ){
-          pPager->nRec = 0;
-          rc = writeJournalHdr(pPager);
-        }
-      }
-      if( rc==SQLITE_OK ){
-        rc = pager_write_pagelist(pPg);
-      }
-      if( rc!=SQLITE_OK ){
-        pager_error(pPager, rc);
+  assert( pPg->flags&PGHDR_DIRTY );
+  if( pPager->errCode==SQLITE_OK ){
+    if( pPg->flags&PGHDR_NEED_SYNC ){
+      rc = syncJournal(pPager);
+      if( rc==SQLITE_OK && pPager->fullSync && 
+        !(sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND)
+      ){
+        pPager->nRec = 0;
+        rc = writeJournalHdr(pPager);
       }
-    }else{
-      sqlite3PcacheMakeClean(pPg);
     }
+    if( rc==SQLITE_OK ){
+      pPg->pDirty = 0;
+      rc = pager_write_pagelist(pPg);
+    }
+    if( rc!=SQLITE_OK ){
+      pager_error(pPager, rc);
+    }
+  }
+
+  if( rc==SQLITE_OK ){
+    sqlite3PcacheMakeClean(pPg);
   }
   return rc;
 }
index c93acd18b4d8557f6b6f518e39c71da659b97222..e99e9e3a64a19d663fe039fb540fdb6dab37ba79 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** This file implements that page cache.
 **
-** @(#) $Id: pcache.c,v 1.7 2008/08/21 20:21:35 drh Exp $
+** @(#) $Id: pcache.c,v 1.8 2008/08/22 16:22:17 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -28,7 +28,7 @@ struct PCache {
   PgHdr **apHash;                     /* Hash table for fast lookup by pgno */
   int bPurgeable;                     /* True if pages are on backing store */
   void (*xDestroy)(PgHdr*);           /* Called when refcnt goes 1->0 */
-  int (*xStress)(void*);              /* Call to try to make pages clean */
+  int (*xStress)(void*,PgHdr*);       /* Call to try make a page clean */
   void *pStress;                      /* Argument to xStress */
   PgHdr *pClean;                      /* List of clean pages in use */
   PgHdr *pDirty;                      /* List of dirty pages */
@@ -57,6 +57,13 @@ struct PgFreeslot {
 **
 ** If mxPage is zero, then the system tries to limit the number of
 ** pages held by purgable caches to mxPagePurgeable.
+**
+** The doubly-linked list that runs between pcache.pLruHead and 
+** pcache.pLruTail contains all pages in the system with a zero 
+** reference count. The pcache.pLruSynced variable points to the last
+** (closest to pcache.pLruTail) entry in this list that does not have
+** the PGHDR_NEED_SYNC flag set. This is the page that the pcacheRecycle()
+** function will try to recycle.
 */
 static struct PCacheGlobal {
   int isInit;                         /* True when initialized */
@@ -68,6 +75,9 @@ static struct PCacheGlobal {
   int mxPage;                         /* Globally configured page maximum */
   int mxPagePurgeable;                /* Purgeable page maximum */
   PgHdr *pLruHead, *pLruTail;         /* Global LRU list of unused pages */
+  PgHdr *pLruSynced;                  /* Last synced entry in LRU list  */
+
+  /* Variables related to SQLITE_CONFIG_PAGECACHE settings. */
   int szSlot;                         /* Size of each free slot */
   void *pStart, *pEnd;                /* Bounds of pagecache malloc range */
   PgFreeslot *pFree;                  /* Free page blocks */
@@ -80,9 +90,6 @@ static struct PCacheGlobal {
 ** SQLITE_MUTEX_STATIC_LRU mutex. A pointer to this mutex is stored in
 ** variable "pcache.mutex_lru".
 **
-** The list of all pager-caches (PCache structures) headed by pcache.pAll 
-** is protected by SQLITE_MUTEX_STATIC_MEM2.
-**
 ** Access to the contents of the individual PCache structures is not 
 ** protected. It is the job of the caller to ensure that these structures
 ** are accessed in a thread-safe manner. However, this module provides the
@@ -95,8 +102,7 @@ static struct PCacheGlobal {
 ** underway.
 **
 ** Before the xStress callback of a pager-cache (PCache) is invoked, the
-** SQLITE_MUTEX_STATIC_MEM2 mutex is obtained and the SQLITE_MUTEX_STATIC_LRU 
-** mutex released (in that order) before making the call.
+** SQLITE_MUTEX_STATIC_MEM2 mutex is obtained.
 **
 ** Deadlock within the module is avoided by never blocking on the MEM2 
 ** mutex while the LRU mutex is held.
@@ -249,6 +255,11 @@ static void pcacheAddToList(PgHdr **ppHead, PgHdr *pPage){
 static void pcacheRemoveFromLruList(PgHdr *pPage){
   assert( sqlite3_mutex_held(pcache.mutex_lru) );
   if( pPage->pCache->bPurgeable==0 ) return;
+  if( pPage==pcache.pLruSynced ){
+    PgHdr *p;
+    for(p=pPage->pPrevLru; p && (p->flags&PGHDR_NEED_SYNC); p=p->pPrevLru);
+    pcache.pLruSynced = p;
+  }
   if( pPage->pNextLru ){
     pPage->pNextLru->pPrevLru = pPage->pPrevLru;
   }else{
@@ -282,6 +293,9 @@ static void pcacheAddToLruList(PgHdr *pPage){
     pcache.pLruTail->pNextLru = pPage;
     pcache.pLruTail = pPage;
     pPage->flags &= ~PGHDR_REUSE_UNLIKELY;
+    if( 0==(pPage->flags&PGHDR_NEED_SYNC) ){
+      pcache.pLruSynced = pPage;
+    }
   }else{
     /* If reuse is possible. the page goes at the beginning of the LRU
     ** list so that it will be the last to be recycled.
@@ -295,6 +309,9 @@ static void pcacheAddToLruList(PgHdr *pPage){
     if( pcache.pLruTail==0 ){
       pcache.pLruTail = pPage;
     }
+    if( pcache.pLruSynced==0 && 0==(pPage->flags&PGHDR_NEED_SYNC) ){
+      pcache.pLruSynced = pPage;
+    }
   }
 }
 
@@ -437,33 +454,50 @@ static int pcachePageSize(PgHdr *p){
 }
 
 static PgHdr *pcacheRecycle(PCache *pCache){
-  PCache *pCsr;
   PgHdr *p = 0;
 
   assert( pcache.isInit );
   assert( sqlite3_mutex_held(pcache.mutex_lru) );
 
-  if( !pcache.pLruTail && SQLITE_OK==sqlite3_mutex_try(pcache.mutex_mem2) ){
+  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;
+      }
 
-    /* Invoke xStress() callbacks until the LRU list contains at least one
-    ** page that can be reused or until the xStress() callback of all
-    ** caches has been invoked.
-    */
-    for(pCsr=pcache.pAll; pCsr&&!pcache.pLruTail; pCsr=pCsr->pNextAll){
-      assert( pCsr->iInUseMM==0 );
-      pCsr->iInUseMM = 1;
-      if( pCsr->xStress && (pCsr->iInUseDB==0 || pCache==pCsr) ){
-        pcacheExitGlobal();
-        pCsr->xStress(pCsr->pStress);
-        pcacheEnterGlobal();
+      assert( pC->iInUseMM==0 );
+      pC->iInUseMM = 1;
+      if( pC->xStress && pC->iInUseDB==0 ){
+        pC->xStress(pC->pStress, p);
       }
-      pCsr->iInUseMM = 0;
+      if( pCache==pC ){
+        pCache->iInUseDB = iInUseDB;
+      }
+      pC->iInUseMM = 0;
+      sqlite3_mutex_leave(pcache.mutex_mem2);
     }
-
-    sqlite3_mutex_leave(pcache.mutex_mem2);
   }
-
-  p = pcache.pLruTail;
+  if( p && (p->flags&PGHDR_DIRTY) ){
+    p = 0;
+  }
 
   if( p ){
     pcacheRemoveFromLruList(p);
@@ -558,7 +592,7 @@ void sqlite3PcacheOpen(
   int szExtra,                 /* Extra space associated with each page */
   int bPurgeable,              /* True if pages are on backing store */
   void (*xDestroy)(PgHdr*),    /* Called to destroy a page */
-  int (*xStress)(void*),       /* Call to try to make pages clean */
+  int (*xStress)(void*,PgHdr*),/* Call to try to make pages clean */
   void *pStress,               /* Argument to xStress */
   PCache *p                    /* Preallocated space for the PCache */
 ){
@@ -579,15 +613,14 @@ void sqlite3PcacheOpen(
   }
 
   /* Add the new pager-cache to the list of caches starting at pcache.pAll */
-  assert( sqlite3_mutex_notheld(pcache.mutex_lru) );
-  sqlite3_mutex_enter(pcache.mutex_mem2);
+  pcacheEnterGlobal();
   p->pNextAll = pcache.pAll;
   if( pcache.pAll ){
     pcache.pAll->pPrevAll = p;
   }
   p->pPrevAll = 0;
   pcache.pAll = p;
-  sqlite3_mutex_leave(pcache.mutex_mem2);
+  pcacheExitGlobal();
 }
 
 /*
@@ -619,7 +652,7 @@ int sqlite3PcacheFetch(
     u32 h = pgno % pCache->nHash;
     for(pPage=pCache->apHash[h]; pPage; pPage=pPage->pNextHash){
       if( pPage->pgno==pgno ){
-        if( pPage->nRef==0 && (pPage->flags & PGHDR_DIRTY)==0 ){
+        if( pPage->nRef==0 /* && (pPage->flags & PGHDR_DIRTY)==0 */ ){
           pcacheEnterGlobal();
           pcacheRemoveFromLruList(pPage);
           pcacheExitGlobal();
@@ -673,7 +706,9 @@ void sqlite3PcacheRelease(PgHdr *p){
   if( p->pCache->xDestroy ){
     p->pCache->xDestroy(p);
   }
+#if 0
   if( (p->flags & PGHDR_DIRTY)!=0 ) return;
+#endif
   pcacheEnterGlobal();
   pcacheAddToLruList(p);
   pcacheExitGlobal();
@@ -731,16 +766,11 @@ void sqlite3PcacheMakeClean(PgHdr *p){
   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 ); */
+  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;
-  if( p->nRef==0 ){
-    pcacheEnterGlobal();
-    pcacheAddToLruList(p);
-    pcacheExitGlobal();
-  }
 }
 
 /*
@@ -749,17 +779,15 @@ void sqlite3PcacheMakeClean(PgHdr *p){
 void sqlite3PcacheCleanAll(PCache *pCache){
   PgHdr *p;
   assert( pCache->iInUseDB );
+  pcacheEnterGlobal();
   while( (p = pCache->pDirty)!=0 ){
     assert( p->apSave[0]==0 && p->apSave[1]==0 );
     pcacheRemoveFromList(&pCache->pDirty, p);
     pcacheAddToList(&pCache->pClean, p);
     p->flags &= ~PGHDR_DIRTY;
-    if( p->nRef==0 ){
-      pcacheEnterGlobal();
-      pcacheAddToLruList(p);
-      pcacheExitGlobal();
-    }
   }
+  sqlite3PcacheAssertFlags(pCache, 0, PGHDR_DIRTY);
+  pcacheExitGlobal();
 }
 
 /*
@@ -806,6 +834,7 @@ void pcacheClear(PCache *pCache){
   }
   for(p=pCache->pDirty; p; p=pNext){
     pNext = p->pNext;
+    pcacheRemoveFromLruList(p);
     pcachePageFree(p);
   }
   pCache->pClean = 0;
@@ -835,9 +864,9 @@ void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
         if( p->flags&PGHDR_DIRTY ){
           pcacheRemoveFromList(&pCache->pDirty, p);
         }else{
-          pcacheRemoveFromLruList(p);
           pcacheRemoveFromList(&pCache->pClean, p);
         }
+        pcacheRemoveFromLruList(p);
         pcachePageFree(p);
       }else{
         /* If there are references to the page, it cannot be freed. In this
@@ -856,24 +885,18 @@ void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
 */
 void sqlite3PcacheClose(PCache *pCache){
   assert( pCache->iInUseDB==1 );
-
-  /* Free all the pages used by this pager and remove them from the LRU
-  ** list. This requires the protection of the MUTEX_STATIC_LRU mutex.
-  */
   pcacheEnterGlobal();
+
+  /* Free all the pages used by this pager and remove them from the LRU list. */
   pcacheClear(pCache);
   if( pCache->bPurgeable ){
     pcache.mxPagePurgeable -= pCache->nMax;
   }
   sqlite3_free(pCache->apHash);
-  pcacheExitGlobal();
 
   /* Now remove the pager-cache structure itself from the list of
-  ** all such structures headed by pcache.pAll. This required the
-  ** MUTEX_STATIC_MEM2 mutex.
+  ** all such structures headed by pcache.pAll. 
   */
-  assert( sqlite3_mutex_notheld(pcache.mutex_lru) );
-  sqlite3_mutex_enter(pcache.mutex_mem2);
   assert(pCache==pcache.pAll || pCache->pPrevAll);
   assert(pCache->pNextAll==0 || pCache->pNextAll->pPrevAll==pCache);
   assert(pCache->pPrevAll==0 || pCache->pPrevAll->pNextAll==pCache);
@@ -885,7 +908,8 @@ void sqlite3PcacheClose(PCache *pCache){
   if( pCache->pNextAll ){
     pCache->pNextAll->pPrevAll = pCache->pPrevAll;
   }
-  sqlite3_mutex_leave(pcache.mutex_mem2);
+
+  pcacheExitGlobal();
 }
 
 /*
@@ -1060,37 +1084,6 @@ PgHdr *sqlite3PcacheDirtyList(PCache *pCache){
   return pcacheSortDirtyList(pCache->pDirty);
 }
 
-/*
-** This function searches cache pCache for a dirty page for which the
-** reference count is zero. If such a page can be found, the PgHdr.pDirty
-** pointer is set to 0 and a pointer to the page is returned. If no
-** such page is found, 0 is returned.
-**
-** This is used by the pager module to implement the xStress callback.
-*/
-PgHdr *sqlite3PcacheDirtyPage(PCache *pCache){
-  PgHdr *p = 0;
-#if 1
-  PgHdr *pIter;
-  Pgno min_pgno;
-  assert( pCache->iInUseMM );
-  for(pIter=pCache->pDirty; pIter; pIter=pIter->pNext){
-    if( pIter->nRef==0 && (p==0 || pIter->pgno<min_pgno) ){
-      p = pIter;
-      min_pgno = pIter->pgno;
-    }
-  }
-#else
-  assert( pCache->iInUseMM );
-  for(p=pCache->pDirty; p && p->nRef; p=p->pNext);
-#endif
-  assert( pCache->iInUseMM );
-  if( p ){
-    p->pDirty = 0;
-  }
-  return p;
-}
-
 /* 
 ** Return the total number of outstanding page references.
 */
@@ -1130,13 +1123,36 @@ void sqlite3PcacheIterate(PCache *pCache, void (*xIter)(PgHdr *)){
 */
 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();
+  }
 }
 
 /*
index 805f8183bae1f4917a5c731c3faf79a4cd83ca61..e55260d71d91eaaf7bfa64f362ff22f4670ec255 100644 (file)
@@ -12,7 +12,7 @@
 ** This header file defines the interface that the sqlite page cache
 ** subsystem. 
 **
-** @(#) $Id: pcache.h,v 1.3 2008/08/21 20:21:35 drh Exp $
+** @(#) $Id: pcache.h,v 1.4 2008/08/22 16:22:17 danielk1977 Exp $
 */
 
 #ifndef _PCACHE_H_
@@ -70,13 +70,13 @@ void sqlite3PCacheFree(void*);
 ** Only clean and unpinned pages can be reclaimed.
 */
 void sqlite3PcacheOpen(
-  int szPage,                  /* Size of every page */
-  int szExtra,                 /* Extra space associated with each page */
-  int bPurgeable,              /* True if pages are on backing store */
-  void (*xDestroy)(PgHdr *),   /* Called to destroy a page */
-  int (*xStress)(void*),       /* Call to try to make pages clean */
-  void *pStress,               /* Argument to xStress */
-  PCache *pToInit              /* Preallocated space for the PCache */
+  int szPage,                    /* Size of every page */
+  int szExtra,                   /* Extra space associated with each page */
+  int bPurgeable,                /* True if pages are on backing store */
+  void (*xDestroy)(PgHdr *),     /* Called to destroy a page */
+  int (*xStress)(void*, PgHdr*), /* Call to try to make pages clean */
+  void *pStress,                 /* Argument to xStress */
+  PCache *pToInit                /* Preallocated space for the PCache */
 );
 
 /* Modify the page-size after the cache has been created. */
@@ -118,9 +118,6 @@ void sqlite3PcacheRollback(PCache*, int);  /* Rollback to preserved copy */
 /* Get a list of all dirty pages in the cache, sorted by page number */
 PgHdr *sqlite3PcacheDirtyList(PCache*);
 
-/* Query the cache for a dirty page with a zero ref-count */
-PgHdr *sqlite3PcacheDirtyPage(PCache *);
-
 /* Reset and close the cache object */
 void sqlite3PcacheClose(PCache*);
 
index 56cab358db1f406a61d8fc6011709ce95d62d502..8637e08be3a13b40fd2ba6143d41e81726396775 100644 (file)
@@ -9,7 +9,7 @@
 #
 #***********************************************************************
 #
-# $Id: mutex1.test,v 1.12 2008/08/21 12:19:44 danielk1977 Exp $
+# $Id: mutex1.test,v 1.13 2008/08/22 16:22:17 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -96,8 +96,8 @@ set enable_shared_cache [sqlite3_enable_shared_cache 1]
 ifcapable threadsafe {
   foreach {mode mutexes} {
     singlethread {}
-    multithread  {fast static_lru static_master static_mem static_mem2 static_prng }
-    serialized   {fast recursive static_lru static_master static_mem static_mem2 static_prng }
+    multithread  {fast static_lru static_master static_mem static_prng }
+    serialized   {fast recursive static_lru static_master static_mem static_prng }
   } {
 
     do_test mutex1.2.$mode.1 {