mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
When recycling a page, try to find one that does not require a call to xSync() on the journal file. Also simplify some of the mutex related things in pcache. (CVS 5597)
FossilOrigin-Name: 93dbc5427bebaa0b3d726731027caad3f70611c7
This commit is contained in:
20
manifest
20
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)
|
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-22T14:41:01
|
D 2008-08-22T16:22:17
|
||||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||||
F Makefile.in 51b727303f84cf055e29514d8248e5eaf9701379
|
F Makefile.in 51b727303f84cf055e29514d8248e5eaf9701379
|
||||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||||
@@ -135,11 +135,11 @@ F src/os_common.h 24525d8b7bce66c374dfc1810a6c9043f3359b60
|
|||||||
F src/os_os2.c e391fc95adc744bbdcefd4d11e3066998185a0a0
|
F src/os_os2.c e391fc95adc744bbdcefd4d11e3066998185a0a0
|
||||||
F src/os_unix.c f1be99705e4542f01830ccea327eb773814f4eb9
|
F src/os_unix.c f1be99705e4542f01830ccea327eb773814f4eb9
|
||||||
F src/os_win.c aefe9ee26430678a19a058a874e4e2bd91398142
|
F src/os_win.c aefe9ee26430678a19a058a874e4e2bd91398142
|
||||||
F src/pager.c 620b0c34f2f43acc3cc770be75c832739465bb52
|
F src/pager.c 3b6625d32cd6f43c54c160f246545f9f26ba7668
|
||||||
F src/pager.h 3778bea71dfb9658b6c94394e18db4a5b27e6ded
|
F src/pager.h 3778bea71dfb9658b6c94394e18db4a5b27e6ded
|
||||||
F src/parse.y d0f76d2cb8d6883d5600dc20beb961a6022b94b8
|
F src/parse.y d0f76d2cb8d6883d5600dc20beb961a6022b94b8
|
||||||
F src/pcache.c f57227003d39d40fa7f9b5a86e36b99f74b93267
|
F src/pcache.c e12359db2963c379f18b52c657b5ec0ebb7a02cd
|
||||||
F src/pcache.h d2becbe7255f6bf57fc9e0bf889a9ec73d50ee74
|
F src/pcache.h 1457e4e7ef08f6964399d5c039afdece25071d54
|
||||||
F src/pragma.c f5b271b090af7fcedd308d7c5807a5503f7a853d
|
F src/pragma.c f5b271b090af7fcedd308d7c5807a5503f7a853d
|
||||||
F src/prepare.c c197041e0c4770672cda75e6bfe10242f885e510
|
F src/prepare.c c197041e0c4770672cda75e6bfe10242f885e510
|
||||||
F src/printf.c 785f87120589c1db672e37c6eb1087c456e6f84d
|
F src/printf.c 785f87120589c1db672e37c6eb1087c456e6f84d
|
||||||
@@ -434,7 +434,7 @@ F test/misc5.test 6a5c1e3217a95b0db05ff9a0f1ecb5ce9043ffef
|
|||||||
F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
|
F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
|
||||||
F test/misc7.test 0d763f703a34521e55ab30145b747aafa0e5f794
|
F test/misc7.test 0d763f703a34521e55ab30145b747aafa0e5f794
|
||||||
F test/misuse.test 30b3a458e5a70c31e74c291937b6c82204c59f33
|
F test/misuse.test 30b3a458e5a70c31e74c291937b6c82204c59f33
|
||||||
F test/mutex1.test ee9fb9c12d03eb2291ab500a3ce30bcad6fb46e8
|
F test/mutex1.test 342dd695567d307126e8f67f243e9b2bcd17898e
|
||||||
F test/mutex2.test 56f282f436596e9febdc6e0db2c507432b6724bb
|
F test/mutex2.test 56f282f436596e9febdc6e0db2c507432b6724bb
|
||||||
F test/nan.test 14c41572ff52dbc740b1c3303dd313a90dc6084c
|
F test/nan.test 14c41572ff52dbc740b1c3303dd313a90dc6084c
|
||||||
F test/notnull.test 44d600f916b770def8b095a9962dbe3be5a70d82
|
F test/notnull.test 44d600f916b770def8b095a9962dbe3be5a70d82
|
||||||
@@ -623,7 +623,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
|
|||||||
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||||
F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1
|
F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1
|
||||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||||
P 7fd11f4ad8774e68f0a053eb2e1dd962a024da48
|
P 8496f4a00a7e62006956e58f3d50c6c4de5347e4
|
||||||
R d422b5970a3ab5d1313431fc076c62e8
|
R 07c866e144c636ba349c06010da224eb
|
||||||
U drh
|
U danielk1977
|
||||||
Z dc8b2c3e5eaef00fc8cce9d4dcda1b42
|
Z 3fb2f6ec7de60b517a8379ad6632f407
|
||||||
|
@@ -1 +1 @@
|
|||||||
8496f4a00a7e62006956e58f3d50c6c4de5347e4
|
93dbc5427bebaa0b3d726731027caad3f70611c7
|
54
src/pager.c
54
src/pager.c
@@ -18,7 +18,7 @@
|
|||||||
** file simultaneously, or one process from reading the database while
|
** file simultaneously, or one process from reading the database while
|
||||||
** another is writing.
|
** 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
|
#ifndef SQLITE_OMIT_DISKIO
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
@@ -1707,7 +1707,7 @@ static int sqlite3PagerOpentemp(
|
|||||||
return rc;
|
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.
|
** 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
|
** 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
|
** every one of those pages out to the database file. No calls are made
|
||||||
** as clean.
|
** 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){
|
static int pager_write_pagelist(PgHdr *pList){
|
||||||
Pager *pPager;
|
Pager *pPager;
|
||||||
@@ -2433,7 +2435,7 @@ static int pager_write_pagelist(PgHdr *pList){
|
|||||||
#ifdef SQLITE_CHECK_PAGES
|
#ifdef SQLITE_CHECK_PAGES
|
||||||
pList->pageHash = pager_pagehash(pList);
|
pList->pageHash = pager_pagehash(pList);
|
||||||
#endif
|
#endif
|
||||||
makeClean(pList);
|
/* makeClean(pList); */
|
||||||
pList = pList->pDirty;
|
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
|
** outstanding references (if one exists) clean so that it can be recycled
|
||||||
** by the pcache layer.
|
** by the pcache layer.
|
||||||
*/
|
*/
|
||||||
static int pagerStress(void *p){
|
static int pagerStress(void *p, PgHdr *pPg){
|
||||||
Pager *pPager = (Pager *)p;
|
Pager *pPager = (Pager *)p;
|
||||||
PgHdr *pPg = sqlite3PcacheDirtyPage(pPager->pPCache);
|
|
||||||
int rc = SQLITE_OK;
|
int rc = SQLITE_OK;
|
||||||
|
|
||||||
if( pPg ){
|
assert( pPg->flags&PGHDR_DIRTY );
|
||||||
assert( pPg->flags&PGHDR_DIRTY );
|
if( pPager->errCode==SQLITE_OK ){
|
||||||
if( pPager->errCode==SQLITE_OK ){
|
if( pPg->flags&PGHDR_NEED_SYNC ){
|
||||||
if( pPg->flags&PGHDR_NEED_SYNC ){
|
rc = syncJournal(pPager);
|
||||||
rc = syncJournal(pPager);
|
if( rc==SQLITE_OK && pPager->fullSync &&
|
||||||
if( rc==SQLITE_OK && pPager->fullSync &&
|
!(sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND)
|
||||||
!(sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND)
|
){
|
||||||
){
|
pPager->nRec = 0;
|
||||||
pPager->nRec = 0;
|
rc = writeJournalHdr(pPager);
|
||||||
rc = writeJournalHdr(pPager);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if( rc==SQLITE_OK ){
|
|
||||||
rc = pager_write_pagelist(pPg);
|
|
||||||
}
|
|
||||||
if( rc!=SQLITE_OK ){
|
|
||||||
pager_error(pPager, rc);
|
|
||||||
}
|
|
||||||
}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;
|
return rc;
|
||||||
}
|
}
|
||||||
|
186
src/pcache.c
186
src/pcache.c
@@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** This file implements that page cache.
|
** 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"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ struct PCache {
|
|||||||
PgHdr **apHash; /* Hash table for fast lookup by pgno */
|
PgHdr **apHash; /* Hash table for fast lookup by pgno */
|
||||||
int bPurgeable; /* True if pages are on backing store */
|
int bPurgeable; /* True if pages are on backing store */
|
||||||
void (*xDestroy)(PgHdr*); /* Called when refcnt goes 1->0 */
|
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 */
|
void *pStress; /* Argument to xStress */
|
||||||
PgHdr *pClean; /* List of clean pages in use */
|
PgHdr *pClean; /* List of clean pages in use */
|
||||||
PgHdr *pDirty; /* List of dirty pages */
|
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
|
** If mxPage is zero, then the system tries to limit the number of
|
||||||
** pages held by purgable caches to mxPagePurgeable.
|
** 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 {
|
static struct PCacheGlobal {
|
||||||
int isInit; /* True when initialized */
|
int isInit; /* True when initialized */
|
||||||
@@ -68,6 +75,9 @@ static struct PCacheGlobal {
|
|||||||
int mxPage; /* Globally configured page maximum */
|
int mxPage; /* Globally configured page maximum */
|
||||||
int mxPagePurgeable; /* Purgeable page maximum */
|
int mxPagePurgeable; /* Purgeable page maximum */
|
||||||
PgHdr *pLruHead, *pLruTail; /* Global LRU list of unused pages */
|
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 */
|
int szSlot; /* Size of each free slot */
|
||||||
void *pStart, *pEnd; /* Bounds of pagecache malloc range */
|
void *pStart, *pEnd; /* Bounds of pagecache malloc range */
|
||||||
PgFreeslot *pFree; /* Free page blocks */
|
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
|
** SQLITE_MUTEX_STATIC_LRU mutex. A pointer to this mutex is stored in
|
||||||
** variable "pcache.mutex_lru".
|
** 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
|
** Access to the contents of the individual PCache structures is not
|
||||||
** protected. It is the job of the caller to ensure that these structures
|
** 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
|
** are accessed in a thread-safe manner. However, this module provides the
|
||||||
@@ -95,8 +102,7 @@ static struct PCacheGlobal {
|
|||||||
** underway.
|
** underway.
|
||||||
**
|
**
|
||||||
** Before the xStress callback of a pager-cache (PCache) is invoked, the
|
** 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
|
** SQLITE_MUTEX_STATIC_MEM2 mutex is obtained.
|
||||||
** mutex released (in that order) before making the call.
|
|
||||||
**
|
**
|
||||||
** Deadlock within the module is avoided by never blocking on the MEM2
|
** Deadlock within the module is avoided by never blocking on the MEM2
|
||||||
** mutex while the LRU mutex is held.
|
** mutex while the LRU mutex is held.
|
||||||
@@ -249,6 +255,11 @@ static void pcacheAddToList(PgHdr **ppHead, PgHdr *pPage){
|
|||||||
static void pcacheRemoveFromLruList(PgHdr *pPage){
|
static void pcacheRemoveFromLruList(PgHdr *pPage){
|
||||||
assert( sqlite3_mutex_held(pcache.mutex_lru) );
|
assert( sqlite3_mutex_held(pcache.mutex_lru) );
|
||||||
if( pPage->pCache->bPurgeable==0 ) return;
|
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 ){
|
if( pPage->pNextLru ){
|
||||||
pPage->pNextLru->pPrevLru = pPage->pPrevLru;
|
pPage->pNextLru->pPrevLru = pPage->pPrevLru;
|
||||||
}else{
|
}else{
|
||||||
@@ -282,6 +293,9 @@ static void pcacheAddToLruList(PgHdr *pPage){
|
|||||||
pcache.pLruTail->pNextLru = pPage;
|
pcache.pLruTail->pNextLru = pPage;
|
||||||
pcache.pLruTail = pPage;
|
pcache.pLruTail = pPage;
|
||||||
pPage->flags &= ~PGHDR_REUSE_UNLIKELY;
|
pPage->flags &= ~PGHDR_REUSE_UNLIKELY;
|
||||||
|
if( 0==(pPage->flags&PGHDR_NEED_SYNC) ){
|
||||||
|
pcache.pLruSynced = pPage;
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
/* If reuse is possible. the page goes at the beginning of the LRU
|
/* If reuse is possible. the page goes at the beginning of the LRU
|
||||||
** list so that it will be the last to be recycled.
|
** list so that it will be the last to be recycled.
|
||||||
@@ -295,6 +309,9 @@ static void pcacheAddToLruList(PgHdr *pPage){
|
|||||||
if( pcache.pLruTail==0 ){
|
if( pcache.pLruTail==0 ){
|
||||||
pcache.pLruTail = pPage;
|
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){
|
static PgHdr *pcacheRecycle(PCache *pCache){
|
||||||
PCache *pCsr;
|
|
||||||
PgHdr *p = 0;
|
PgHdr *p = 0;
|
||||||
|
|
||||||
assert( pcache.isInit );
|
assert( pcache.isInit );
|
||||||
assert( sqlite3_mutex_held(pcache.mutex_lru) );
|
assert( sqlite3_mutex_held(pcache.mutex_lru) );
|
||||||
|
|
||||||
if( !pcache.pLruTail && SQLITE_OK==sqlite3_mutex_try(pcache.mutex_mem2) ){
|
p = pcache.pLruSynced;
|
||||||
|
if( !p ){
|
||||||
/* Invoke xStress() callbacks until the LRU list contains at least one
|
p = pcache.pLruTail;
|
||||||
** 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();
|
|
||||||
}
|
|
||||||
pCsr->iInUseMM = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlite3_mutex_leave(pcache.mutex_mem2);
|
|
||||||
}
|
}
|
||||||
|
if( p && (p->flags&PGHDR_DIRTY) ){
|
||||||
|
if( SQLITE_OK==sqlite3_mutex_try(pcache.mutex_mem2) ){
|
||||||
|
int iInUseDB;
|
||||||
|
PCache *pC = p->pCache;
|
||||||
|
|
||||||
p = pcache.pLruTail;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
if( p ){
|
if( p ){
|
||||||
pcacheRemoveFromLruList(p);
|
pcacheRemoveFromLruList(p);
|
||||||
@@ -558,7 +592,7 @@ void sqlite3PcacheOpen(
|
|||||||
int szExtra, /* Extra space associated with each page */
|
int szExtra, /* Extra space associated with each page */
|
||||||
int bPurgeable, /* True if pages are on backing store */
|
int bPurgeable, /* True if pages are on backing store */
|
||||||
void (*xDestroy)(PgHdr*), /* Called to destroy a page */
|
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 */
|
void *pStress, /* Argument to xStress */
|
||||||
PCache *p /* Preallocated space for the PCache */
|
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 */
|
/* Add the new pager-cache to the list of caches starting at pcache.pAll */
|
||||||
assert( sqlite3_mutex_notheld(pcache.mutex_lru) );
|
pcacheEnterGlobal();
|
||||||
sqlite3_mutex_enter(pcache.mutex_mem2);
|
|
||||||
p->pNextAll = pcache.pAll;
|
p->pNextAll = pcache.pAll;
|
||||||
if( pcache.pAll ){
|
if( pcache.pAll ){
|
||||||
pcache.pAll->pPrevAll = p;
|
pcache.pAll->pPrevAll = p;
|
||||||
}
|
}
|
||||||
p->pPrevAll = 0;
|
p->pPrevAll = 0;
|
||||||
pcache.pAll = p;
|
pcache.pAll = p;
|
||||||
sqlite3_mutex_leave(pcache.mutex_mem2);
|
pcacheExitGlobal();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -619,7 +652,7 @@ int sqlite3PcacheFetch(
|
|||||||
u32 h = pgno % pCache->nHash;
|
u32 h = pgno % pCache->nHash;
|
||||||
for(pPage=pCache->apHash[h]; pPage; pPage=pPage->pNextHash){
|
for(pPage=pCache->apHash[h]; pPage; pPage=pPage->pNextHash){
|
||||||
if( pPage->pgno==pgno ){
|
if( pPage->pgno==pgno ){
|
||||||
if( pPage->nRef==0 && (pPage->flags & PGHDR_DIRTY)==0 ){
|
if( pPage->nRef==0 /* && (pPage->flags & PGHDR_DIRTY)==0 */ ){
|
||||||
pcacheEnterGlobal();
|
pcacheEnterGlobal();
|
||||||
pcacheRemoveFromLruList(pPage);
|
pcacheRemoveFromLruList(pPage);
|
||||||
pcacheExitGlobal();
|
pcacheExitGlobal();
|
||||||
@@ -673,7 +706,9 @@ void sqlite3PcacheRelease(PgHdr *p){
|
|||||||
if( p->pCache->xDestroy ){
|
if( p->pCache->xDestroy ){
|
||||||
p->pCache->xDestroy(p);
|
p->pCache->xDestroy(p);
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
if( (p->flags & PGHDR_DIRTY)!=0 ) return;
|
if( (p->flags & PGHDR_DIRTY)!=0 ) return;
|
||||||
|
#endif
|
||||||
pcacheEnterGlobal();
|
pcacheEnterGlobal();
|
||||||
pcacheAddToLruList(p);
|
pcacheAddToLruList(p);
|
||||||
pcacheExitGlobal();
|
pcacheExitGlobal();
|
||||||
@@ -731,16 +766,11 @@ void sqlite3PcacheMakeClean(PgHdr *p){
|
|||||||
if( (p->flags & PGHDR_DIRTY)==0 ) return;
|
if( (p->flags & PGHDR_DIRTY)==0 ) return;
|
||||||
assert( p->apSave[0]==0 && p->apSave[1]==0 );
|
assert( p->apSave[0]==0 && p->apSave[1]==0 );
|
||||||
assert( p->flags & PGHDR_DIRTY );
|
assert( p->flags & PGHDR_DIRTY );
|
||||||
/* assert( p->nRef>0 ); */
|
assert( p->nRef>0 || sqlite3_mutex_held(pcache.mutex_lru) );
|
||||||
pCache = p->pCache;
|
pCache = p->pCache;
|
||||||
pcacheRemoveFromList(&pCache->pDirty, p);
|
pcacheRemoveFromList(&pCache->pDirty, p);
|
||||||
pcacheAddToList(&pCache->pClean, p);
|
pcacheAddToList(&pCache->pClean, p);
|
||||||
p->flags &= ~PGHDR_DIRTY;
|
p->flags &= ~PGHDR_DIRTY;
|
||||||
if( p->nRef==0 ){
|
|
||||||
pcacheEnterGlobal();
|
|
||||||
pcacheAddToLruList(p);
|
|
||||||
pcacheExitGlobal();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -749,17 +779,15 @@ void sqlite3PcacheMakeClean(PgHdr *p){
|
|||||||
void sqlite3PcacheCleanAll(PCache *pCache){
|
void sqlite3PcacheCleanAll(PCache *pCache){
|
||||||
PgHdr *p;
|
PgHdr *p;
|
||||||
assert( pCache->iInUseDB );
|
assert( pCache->iInUseDB );
|
||||||
|
pcacheEnterGlobal();
|
||||||
while( (p = pCache->pDirty)!=0 ){
|
while( (p = pCache->pDirty)!=0 ){
|
||||||
assert( p->apSave[0]==0 && p->apSave[1]==0 );
|
assert( p->apSave[0]==0 && p->apSave[1]==0 );
|
||||||
pcacheRemoveFromList(&pCache->pDirty, p);
|
pcacheRemoveFromList(&pCache->pDirty, p);
|
||||||
pcacheAddToList(&pCache->pClean, p);
|
pcacheAddToList(&pCache->pClean, p);
|
||||||
p->flags &= ~PGHDR_DIRTY;
|
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){
|
for(p=pCache->pDirty; p; p=pNext){
|
||||||
pNext = p->pNext;
|
pNext = p->pNext;
|
||||||
|
pcacheRemoveFromLruList(p);
|
||||||
pcachePageFree(p);
|
pcachePageFree(p);
|
||||||
}
|
}
|
||||||
pCache->pClean = 0;
|
pCache->pClean = 0;
|
||||||
@@ -835,9 +864,9 @@ void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
|
|||||||
if( p->flags&PGHDR_DIRTY ){
|
if( p->flags&PGHDR_DIRTY ){
|
||||||
pcacheRemoveFromList(&pCache->pDirty, p);
|
pcacheRemoveFromList(&pCache->pDirty, p);
|
||||||
}else{
|
}else{
|
||||||
pcacheRemoveFromLruList(p);
|
|
||||||
pcacheRemoveFromList(&pCache->pClean, p);
|
pcacheRemoveFromList(&pCache->pClean, p);
|
||||||
}
|
}
|
||||||
|
pcacheRemoveFromLruList(p);
|
||||||
pcachePageFree(p);
|
pcachePageFree(p);
|
||||||
}else{
|
}else{
|
||||||
/* If there are references to the page, it cannot be freed. In this
|
/* 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){
|
void sqlite3PcacheClose(PCache *pCache){
|
||||||
assert( pCache->iInUseDB==1 );
|
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();
|
pcacheEnterGlobal();
|
||||||
|
|
||||||
|
/* Free all the pages used by this pager and remove them from the LRU list. */
|
||||||
pcacheClear(pCache);
|
pcacheClear(pCache);
|
||||||
if( pCache->bPurgeable ){
|
if( pCache->bPurgeable ){
|
||||||
pcache.mxPagePurgeable -= pCache->nMax;
|
pcache.mxPagePurgeable -= pCache->nMax;
|
||||||
}
|
}
|
||||||
sqlite3_free(pCache->apHash);
|
sqlite3_free(pCache->apHash);
|
||||||
pcacheExitGlobal();
|
|
||||||
|
|
||||||
/* Now remove the pager-cache structure itself from the list of
|
/* Now remove the pager-cache structure itself from the list of
|
||||||
** all such structures headed by pcache.pAll. This required the
|
** all such structures headed by pcache.pAll.
|
||||||
** MUTEX_STATIC_MEM2 mutex.
|
|
||||||
*/
|
*/
|
||||||
assert( sqlite3_mutex_notheld(pcache.mutex_lru) );
|
|
||||||
sqlite3_mutex_enter(pcache.mutex_mem2);
|
|
||||||
assert(pCache==pcache.pAll || pCache->pPrevAll);
|
assert(pCache==pcache.pAll || pCache->pPrevAll);
|
||||||
assert(pCache->pNextAll==0 || pCache->pNextAll->pPrevAll==pCache);
|
assert(pCache->pNextAll==0 || pCache->pNextAll->pPrevAll==pCache);
|
||||||
assert(pCache->pPrevAll==0 || pCache->pPrevAll->pNextAll==pCache);
|
assert(pCache->pPrevAll==0 || pCache->pPrevAll->pNextAll==pCache);
|
||||||
@@ -885,7 +908,8 @@ void sqlite3PcacheClose(PCache *pCache){
|
|||||||
if( pCache->pNextAll ){
|
if( pCache->pNextAll ){
|
||||||
pCache->pNextAll->pPrevAll = pCache->pPrevAll;
|
pCache->pNextAll->pPrevAll = pCache->pPrevAll;
|
||||||
}
|
}
|
||||||
sqlite3_mutex_leave(pcache.mutex_mem2);
|
|
||||||
|
pcacheExitGlobal();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1060,37 +1084,6 @@ PgHdr *sqlite3PcacheDirtyList(PCache *pCache){
|
|||||||
return pcacheSortDirtyList(pCache->pDirty);
|
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.
|
** 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){
|
void sqlite3PcacheSetFlags(PCache *pCache, int andMask, int orMask){
|
||||||
PgHdr *p;
|
PgHdr *p;
|
||||||
|
|
||||||
|
assert( (orMask&PGHDR_NEED_SYNC)==0 );
|
||||||
assert( pCache->iInUseDB || pCache->iInUseMM );
|
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){
|
for(p=pCache->pDirty; p; p=p->pNext){
|
||||||
p->flags = (p->flags&andMask)|orMask;
|
p->flags = (p->flags&andMask)|orMask;
|
||||||
}
|
}
|
||||||
for(p=pCache->pClean; p; p=p->pNext){
|
for(p=pCache->pClean; p; p=p->pNext){
|
||||||
p->flags = (p->flags&andMask)|orMask;
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
19
src/pcache.h
19
src/pcache.h
@@ -12,7 +12,7 @@
|
|||||||
** This header file defines the interface that the sqlite page cache
|
** This header file defines the interface that the sqlite page cache
|
||||||
** subsystem.
|
** 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_
|
#ifndef _PCACHE_H_
|
||||||
@@ -70,13 +70,13 @@ void sqlite3PCacheFree(void*);
|
|||||||
** Only clean and unpinned pages can be reclaimed.
|
** Only clean and unpinned pages can be reclaimed.
|
||||||
*/
|
*/
|
||||||
void sqlite3PcacheOpen(
|
void sqlite3PcacheOpen(
|
||||||
int szPage, /* Size of every page */
|
int szPage, /* Size of every page */
|
||||||
int szExtra, /* Extra space associated with each page */
|
int szExtra, /* Extra space associated with each page */
|
||||||
int bPurgeable, /* True if pages are on backing store */
|
int bPurgeable, /* True if pages are on backing store */
|
||||||
void (*xDestroy)(PgHdr *), /* Called to destroy a page */
|
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 */
|
void *pStress, /* Argument to xStress */
|
||||||
PCache *pToInit /* Preallocated space for the PCache */
|
PCache *pToInit /* Preallocated space for the PCache */
|
||||||
);
|
);
|
||||||
|
|
||||||
/* Modify the page-size after the cache has been created. */
|
/* 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 */
|
/* Get a list of all dirty pages in the cache, sorted by page number */
|
||||||
PgHdr *sqlite3PcacheDirtyList(PCache*);
|
PgHdr *sqlite3PcacheDirtyList(PCache*);
|
||||||
|
|
||||||
/* Query the cache for a dirty page with a zero ref-count */
|
|
||||||
PgHdr *sqlite3PcacheDirtyPage(PCache *);
|
|
||||||
|
|
||||||
/* Reset and close the cache object */
|
/* Reset and close the cache object */
|
||||||
void sqlite3PcacheClose(PCache*);
|
void sqlite3PcacheClose(PCache*);
|
||||||
|
|
||||||
|
@@ -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]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
@@ -96,8 +96,8 @@ set enable_shared_cache [sqlite3_enable_shared_cache 1]
|
|||||||
ifcapable threadsafe {
|
ifcapable threadsafe {
|
||||||
foreach {mode mutexes} {
|
foreach {mode mutexes} {
|
||||||
singlethread {}
|
singlethread {}
|
||||||
multithread {fast 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_mem2 static_prng }
|
serialized {fast recursive static_lru static_master static_mem static_prng }
|
||||||
} {
|
} {
|
||||||
|
|
||||||
do_test mutex1.2.$mode.1 {
|
do_test mutex1.2.$mode.1 {
|
||||||
|
Reference in New Issue
Block a user