1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Add the cache_spill pragma.

FossilOrigin-Name: cdb181c04fa99c6c29f23eb68ccb5475e7f6bf9c
This commit is contained in:
drh
2013-08-16 20:42:20 +00:00
parent 0af16ab2c2
commit 40c3941cfa
9 changed files with 120 additions and 80 deletions

View File

@@ -453,6 +453,13 @@ struct PagerSavepoint {
#endif
};
/*
** Bits of the Pager.doNotSpill flag. See further description below.
*/
#define SPILLFLAG_OFF 0x01 /* Never spill cache. Set via pragma */
#define SPILLFLAG_ROLLBACK 0x02 /* Current rolling back, so do not spill */
#define SPILLFLAG_NOSYNC 0x04 /* Spill is ok, but do not sync */
/*
** A open page cache is an instance of struct Pager. A description of
** some of the more important member variables follows:
@@ -519,19 +526,21 @@ struct PagerSavepoint {
** journal file from being successfully finalized, the setMaster flag
** is cleared anyway (and the pager will move to ERROR state).
**
** doNotSpill, doNotSyncSpill
** doNotSpill
**
** These two boolean variables control the behavior of cache-spills
** (calls made by the pcache module to the pagerStress() routine to
** write cached data to the file-system in order to free up memory).
** This variables control the behavior of cache-spills (calls made by
** the pcache module to the pagerStress() routine to write cached data
** to the file-system in order to free up memory).
**
** When doNotSpill is non-zero, writing to the database from pagerStress()
** is disabled altogether. This is done in a very obscure case that
** When bits SPILLFLAG_OFF or SPILLFLAG_ROLLBACK of doNotSpill are set,
** writing to the database from pagerStress() is disabled altogether.
** The SPILLFLAG_ROLLBACK case is done in a very obscure case that
** comes up during savepoint rollback that requires the pcache module
** to allocate a new page to prevent the journal file from being written
** while it is being traversed by code in pager_playback().
** while it is being traversed by code in pager_playback(). The SPILLFLAG_OFF
** case is a user preference.
**
** If doNotSyncSpill is non-zero, writing to the database from pagerStress()
** If the SPILLFLAG_NOSYNC bit is set, writing to the database from pagerStress()
** is permitted, but syncing the journal file is not. This flag is set
** by sqlite3PagerWrite() when the file-system sector-size is larger than
** the database page-size in order to prevent a journal sync from happening
@@ -635,7 +644,6 @@ struct Pager {
u8 changeCountDone; /* Set after incrementing the change-counter */
u8 setMaster; /* True if a m-j name has been written to jrnl */
u8 doNotSpill; /* Do not spill the cache when non-zero */
u8 doNotSyncSpill; /* Do not do a spill that requires jrnl sync */
u8 subjInMemory; /* True to use in-memory sub-journals */
Pgno dbSize; /* Number of pages in the database */
Pgno dbOrigSize; /* dbSize before the current transaction */
@@ -2295,11 +2303,11 @@ static int pager_playback_one_page(
** requiring a journal-sync before it is written.
*/
assert( isSavepnt );
assert( pPager->doNotSpill==0 );
pPager->doNotSpill++;
assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)==0 );
pPager->doNotSpill |= SPILLFLAG_ROLLBACK;
rc = sqlite3PagerAcquire(pPager, pgno, &pPg, 1);
assert( pPager->doNotSpill==1 );
pPager->doNotSpill--;
assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)!=0 );
pPager->doNotSpill &= ~SPILLFLAG_ROLLBACK;
if( rc!=SQLITE_OK ) return rc;
pPg->flags &= ~PGHDR_NEED_READ;
sqlite3PcacheMakeDirty(pPg);
@@ -3404,9 +3412,12 @@ void sqlite3PagerShrink(Pager *pPager){
}
/*
** Adjust the robustness of the database to damage due to OS crashes
** or power failures by changing the number of syncs()s when writing
** the rollback journal. There are three levels:
** Adjust settings of the pager to those specified in the pgFlags parameter.
**
** The "level" in pgFlags & PAGER_SYNCHRONOUS_MASK sets the robustness
** of the database to damage due to OS crashes or power failures by
** changing the number of syncs()s when writing the journals.
** There are three levels:
**
** OFF sqlite3OsSync() is never called. This is the default
** for temporary and transient files.
@@ -3447,22 +3458,21 @@ void sqlite3PagerShrink(Pager *pPager){
** and FULL=3.
*/
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
void sqlite3PagerSetSafetyLevel(
void sqlite3PagerSetFlags(
Pager *pPager, /* The pager to set safety level for */
int level, /* PRAGMA synchronous. 1=OFF, 2=NORMAL, 3=FULL */
int bFullFsync, /* PRAGMA fullfsync */
int bCkptFullFsync /* PRAGMA checkpoint_fullfsync */
unsigned pgFlags /* Various flags */
){
unsigned level = pgFlags & PAGER_SYNCHRONOUS_MASK;
assert( level>=1 && level<=3 );
pPager->noSync = (level==1 || pPager->tempFile) ?1:0;
pPager->fullSync = (level==3 && !pPager->tempFile) ?1:0;
if( pPager->noSync ){
pPager->syncFlags = 0;
pPager->ckptSyncFlags = 0;
}else if( bFullFsync ){
}else if( pgFlags & PAGER_FULLFSYNC ){
pPager->syncFlags = SQLITE_SYNC_FULL;
pPager->ckptSyncFlags = SQLITE_SYNC_FULL;
}else if( bCkptFullFsync ){
}else if( pgFlags & PAGER_CKPT_FULLFSYNC ){
pPager->syncFlags = SQLITE_SYNC_NORMAL;
pPager->ckptSyncFlags = SQLITE_SYNC_FULL;
}else{
@@ -3473,6 +3483,11 @@ void sqlite3PagerSetSafetyLevel(
if( pPager->fullSync ){
pPager->walSyncFlags |= WAL_SYNC_TRANSACTIONS;
}
if( pgFlags & PAGER_CACHESPILL ){
pPager->doNotSpill &= ~SPILLFLAG_OFF;
}else{
pPager->doNotSpill |= SPILLFLAG_OFF;
}
}
#endif
@@ -4373,13 +4388,14 @@ static int pagerStress(void *p, PgHdr *pPg){
assert( pPg->pPager==pPager );
assert( pPg->flags&PGHDR_DIRTY );
/* The doNotSyncSpill flag is set during times when doing a sync of
/* The doNotSpill NOSYNC bit is set during times when doing a sync of
** journal (and adding a new header) is not allowed. This occurs
** during calls to sqlite3PagerWrite() while trying to journal multiple
** pages belonging to the same sector.
**
** The doNotSpill flag inhibits all cache spilling regardless of whether
** or not a sync is required. This is set during a rollback.
** The doNotSpill ROLLBACK and OFF bits inhibits all cache spilling
** regardless of whether or not a sync is required. This is set during
** a rollback or by user request, respectively.
**
** Spilling is also prohibited when in an error state since that could
** lead to database corruption. In the current implementaton it
@@ -4389,8 +4405,13 @@ static int pagerStress(void *p, PgHdr *pPg){
** test for the error state as a safeguard against future changes.
*/
if( NEVER(pPager->errCode) ) return SQLITE_OK;
if( pPager->doNotSpill ) return SQLITE_OK;
if( pPager->doNotSyncSpill && (pPg->flags & PGHDR_NEED_SYNC)!=0 ){
testcase( pPager->doNotSpill & SPILLFLAG_ROLLBACK );
testcase( pPager->doNotSpill & SPILLFLAG_OFF );
testcase( pPager->doNotSpill & SPILLFLAG_NOSYNC );
if( pPager->doNotSpill
&& ((pPager->doNotSpill & (SPILLFLAG_ROLLBACK|SPILLFLAG_OFF))!=0
|| (pPg->flags & PGHDR_NEED_SYNC)!=0)
){
return SQLITE_OK;
}
@@ -5744,13 +5765,13 @@ int sqlite3PagerWrite(DbPage *pDbPage){
int ii; /* Loop counter */
int needSync = 0; /* True if any page has PGHDR_NEED_SYNC */
/* Set the doNotSyncSpill flag to 1. This is because we cannot allow
/* Set the doNotSpill NOSYNC bit to 1. This is because we cannot allow
** a journal header to be written between the pages journaled by
** this function.
*/
assert( !MEMDB );
assert( pPager->doNotSyncSpill==0 );
pPager->doNotSyncSpill++;
assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)==0 );
pPager->doNotSpill |= SPILLFLAG_NOSYNC;
/* This trick assumes that both the page-size and sector-size are
** an integer power of 2. It sets variable pg1 to the identifier
@@ -5809,8 +5830,8 @@ int sqlite3PagerWrite(DbPage *pDbPage){
}
}
assert( pPager->doNotSyncSpill==1 );
pPager->doNotSyncSpill--;
assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)!=0 );
pPager->doNotSpill &= ~SPILLFLAG_NOSYNC;
}else{
rc = pager_write(pDbPage);
}