Index: src/btree.c ================================================================== --- src/btree.c +++ src/btree.c @@ -2554,32 +2554,44 @@ sqlite3_free(p); return SQLITE_OK; } /* -** Change the limit on the number of pages allowed in the cache. -** -** The maximum number of cache pages is set to the absolute -** value of mxPage. If mxPage is negative, the pager will -** operate asynchronously - it will not stop to do fsync()s -** to insure data is written to the disk surface before -** continuing. Transactions still work if synchronous is off, -** and the database cannot be corrupted if this program -** crashes. But if the operating system crashes or there is -** an abrupt power failure when synchronous is off, the database -** could be left in an inconsistent and unrecoverable state. -** Synchronous is on by default so database corruption is not -** normally a worry. +** Change the "soft" limit on the number of pages in the cache. +** Unused and unmodified pages will be recycled when the number of +** pages in the cache exceeds this soft limit. But the size of the +** cache is allowed to grow larger than this limit if it contains +** dirty pages or pages still in active use. */ int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){ BtShared *pBt = p->pBt; assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3BtreeEnter(p); sqlite3PagerSetCachesize(pBt->pPager, mxPage); sqlite3BtreeLeave(p); return SQLITE_OK; } + +/* +** Change the "spill" limit on the number of pages in the cache. +** If the number of pages exceeds this limit during a write transaction, +** the pager might attempt to "spill" pages to the journal early in +** order to free up memory. +** +** The value returned is the current spill size. If zero is passed +** as an argument, no changes are made to the spill size setting, so +** using mxPage of 0 is a way to query the current spill size. +*/ +int sqlite3BtreeSetSpillSize(Btree *p, int mxPage){ + BtShared *pBt = p->pBt; + int res; + assert( sqlite3_mutex_held(p->db->mutex) ); + sqlite3BtreeEnter(p); + res = sqlite3PagerSetSpillsize(pBt->pPager, mxPage); + sqlite3BtreeLeave(p); + return res; +} #if SQLITE_MAX_MMAP_SIZE>0 /* ** Change the limit on the amount of the database file that may be ** memory mapped. Index: src/btree.h ================================================================== --- src/btree.h +++ src/btree.h @@ -61,10 +61,11 @@ #define BTREE_SINGLE 4 /* The file contains at most 1 b-tree */ #define BTREE_UNORDERED 8 /* Use of a hash implementation is OK */ int sqlite3BtreeClose(Btree*); int sqlite3BtreeSetCacheSize(Btree*,int); +int sqlite3BtreeSetSpillSize(Btree*,int); #if SQLITE_MAX_MMAP_SIZE>0 int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64); #endif int sqlite3BtreeSetPagerFlags(Btree*,unsigned); int sqlite3BtreeSyncDisabled(Btree*); Index: src/pager.c ================================================================== --- src/pager.c +++ src/pager.c @@ -3390,15 +3390,24 @@ return rc; } /* -** Change the maximum number of in-memory pages that are allowed. +** Change the maximum number of in-memory pages that are allowed +** before attempting to recycle clean and unused pages. */ void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){ sqlite3PcacheSetCachesize(pPager->pPCache, mxPage); } + +/* +** Change the maximum number of in-memory pages that are allowed +** before attempting to spill pages to journal. +*/ +int sqlite3PagerSetSpillsize(Pager *pPager, int mxPage){ + return sqlite3PcacheSetSpillsize(pPager->pPCache, mxPage); +} /* ** Invoke SQLITE_FCNTL_MMAP_SIZE based on the current value of szMmap. */ static void pagerFixMaplimit(Pager *pPager){ Index: src/pager.h ================================================================== --- src/pager.h +++ src/pager.h @@ -121,10 +121,11 @@ #ifdef SQLITE_HAS_CODEC void sqlite3PagerAlignReserve(Pager*,Pager*); #endif int sqlite3PagerMaxPageCount(Pager*, int); void sqlite3PagerSetCachesize(Pager*, int); +int sqlite3PagerSetSpillsize(Pager*, int); void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64); void sqlite3PagerShrink(Pager*); void sqlite3PagerSetFlags(Pager*,unsigned); int sqlite3PagerLockingMode(Pager *, int); int sqlite3PagerSetJournalMode(Pager *, int); Index: src/pcache.c ================================================================== --- src/pcache.c +++ src/pcache.c @@ -19,10 +19,11 @@ struct PCache { PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */ PgHdr *pSynced; /* Last synced page in dirty page list */ int nRefSum; /* Sum of ref counts over all pages */ int szCache; /* Configured cache size */ + int szSpill; /* Size before spilling occurs */ int szPage; /* Size of every page in this cache */ int szExtra; /* Size of extra space for each page */ u8 bPurgeable; /* True if pages are on backing store */ u8 eCreate; /* eCreate value for for xFetch() */ int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */ @@ -108,14 +109,12 @@ sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 0); } } /* -** Compute the number of pages of cache requested. p->szCache is the +** Compute the number of pages of cache requested. p->szCache is the ** cache size requested by the "PRAGMA cache_size" statement. -** -** */ static int numberOfCachePages(PCache *p){ if( p->szCache>=0 ){ /* IMPLEMENTATION-OF: R-42059-47211 If the argument N is positive then the ** suggested cache size is set to N. */ @@ -174,10 +173,11 @@ p->bPurgeable = bPurgeable; p->eCreate = 2; p->xStress = xStress; p->pStress = pStress; p->szCache = 100; + p->szSpill = 1; return sqlite3PcacheSetPageSize(p, szPage); } /* ** Change the page size for PCache object. The caller must ensure that there @@ -269,36 +269,37 @@ sqlite3_pcache_page **ppPage /* Write result here */ ){ PgHdr *pPg; if( pCache->eCreate==2 ) return 0; - - /* Find a dirty page to write-out and recycle. First try to find a - ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC - ** cleared), but if that is not possible settle for any other - ** unreferenced dirty page. - */ - for(pPg=pCache->pSynced; - pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC)); - pPg=pPg->pDirtyPrev - ); - pCache->pSynced = pPg; - if( !pPg ){ - for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev); - } - if( pPg ){ - int rc; + if( sqlite3PcachePagecount(pCache)>pCache->szSpill ){ + /* Find a dirty page to write-out and recycle. First try to find a + ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC + ** cleared), but if that is not possible settle for any other + ** unreferenced dirty page. + */ + for(pPg=pCache->pSynced; + pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC)); + pPg=pPg->pDirtyPrev + ); + pCache->pSynced = pPg; + if( !pPg ){ + for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev); + } + if( pPg ){ + int rc; #ifdef SQLITE_LOG_CACHE_SPILL - sqlite3_log(SQLITE_FULL, - "spill page %d making room for %d - cache used: %d/%d", - pPg->pgno, pgno, - sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache), + sqlite3_log(SQLITE_FULL, + "spill page %d making room for %d - cache used: %d/%d", + pPg->pgno, pgno, + sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache), numberOfCachePages(pCache)); #endif - rc = pCache->xStress(pCache->pStress, pPg); - if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){ - return rc; + rc = pCache->xStress(pCache->pStress, pPg); + if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){ + return rc; + } } } *ppPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2); return *ppPage==0 ? SQLITE_NOMEM : SQLITE_OK; } @@ -638,10 +639,29 @@ assert( pCache->pCache!=0 ); pCache->szCache = mxPage; sqlite3GlobalConfig.pcache2.xCachesize(pCache->pCache, numberOfCachePages(pCache)); } + +/* +** Set the suggested cache-spill value. Make no changes if if the +** argument is zero. Return the effective cache-spill size, which will +** be the larger of the szSpill and szCache. +*/ +int sqlite3PcacheSetSpillsize(PCache *p, int mxPage){ + int res; + assert( p->pCache!=0 ); + if( mxPage ){ + if( mxPage<0 ){ + mxPage = (int)((-1024*(i64)mxPage)/(p->szPage+p->szExtra)); + } + p->szSpill = mxPage; + } + res = numberOfCachePages(p); + if( resszSpill ) res = p->szSpill; + return res; +} /* ** Free up as much memory as possible from the page cache. */ void sqlite3PcacheShrink(PCache *pCache){ Index: src/pcache.h ================================================================== --- src/pcache.h +++ src/pcache.h @@ -143,10 +143,17 @@ */ void sqlite3PcacheSetCachesize(PCache *, int); #ifdef SQLITE_TEST int sqlite3PcacheGetCachesize(PCache *); #endif + +/* Set or get the suggested spill-size for the specified pager-cache. +** +** The spill-size is the minimum number of pages in cache before the cache +** will attempt to spill dirty pages by calling xStress. +*/ +int sqlite3PcacheSetSpillsize(PCache *, int); /* Free up as much memory as possible from the page cache */ void sqlite3PcacheShrink(PCache*); #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT Index: src/pragma.c ================================================================== --- src/pragma.c +++ src/pragma.c @@ -277,11 +277,11 @@ /* ** Process a pragma statement. ** ** Pragmas are of this form: ** -** PRAGMA [database.]id [= value] +** PRAGMA [schema.]id [= value] ** ** The identifier might also be a string. The value is a string, and ** identifier, or a number. If minusFlag is true, then the value is ** a number that was preceded by a minus sign. ** @@ -289,12 +289,12 @@ ** and pId2 is the id. If the left side is just "id" then pId1 is the ** id and pId2 is any empty string. */ void sqlite3Pragma( Parse *pParse, - Token *pId1, /* First part of [database.]id field */ - Token *pId2, /* Second part of [database.]id field, or NULL */ + Token *pId1, /* First part of [schema.]id field */ + Token *pId2, /* Second part of [schema.]id field, or NULL */ Token *pValue, /* Token for , or NULL */ int minusFlag /* True if a '-' sign preceded */ ){ char *zLeft = 0; /* Nul-terminated UTF-8 string */ char *zRight = 0; /* Nul-terminated UTF-8 string , or NULL */ @@ -311,11 +311,11 @@ if( v==0 ) return; sqlite3VdbeRunOnlyOnce(v); pParse->nMem = 2; - /* Interpret the [database.] part of the pragma statement. iDb is the + /* Interpret the [schema.] part of the pragma statement. iDb is the ** index of the database this pragma is being applied to in db.aDb[]. */ iDb = sqlite3TwoPartName(pParse, pId1, pId2, &pId); if( iDb<0 ) return; pDb = &db->aDb[iDb]; @@ -400,12 +400,12 @@ /* Jump to the appropriate pragma handler */ switch( pPragma->ePragTyp ){ #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) /* - ** PRAGMA [database.]default_cache_size - ** PRAGMA [database.]default_cache_size=N + ** PRAGMA [schema.]default_cache_size + ** PRAGMA [schema.]default_cache_size=N ** ** The first form reports the current persistent setting for the ** page cache size. The value returned is the maximum number of ** pages in the page cache. The second form sets both the current ** page cache size value and the persistent page cache size value @@ -452,12 +452,12 @@ } #endif /* !SQLITE_OMIT_PAGER_PRAGMAS && !SQLITE_OMIT_DEPRECATED */ #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) /* - ** PRAGMA [database.]page_size - ** PRAGMA [database.]page_size=N + ** PRAGMA [schema.]page_size + ** PRAGMA [schema.]page_size=N ** ** The first form reports the current setting for the ** database page size in bytes. The second form sets the ** database page size value. The value can only be set if ** the database has not yet been created. @@ -479,12 +479,12 @@ } break; } /* - ** PRAGMA [database.]secure_delete - ** PRAGMA [database.]secure_delete=ON/OFF + ** PRAGMA [schema.]secure_delete + ** PRAGMA [schema.]secure_delete=ON/OFF ** ** The first form reports the current setting for the ** secure_delete flag. The second form changes the secure_delete ** flag setting and reports thenew value. */ @@ -505,12 +505,12 @@ returnSingleInt(v, "secure_delete", b); break; } /* - ** PRAGMA [database.]max_page_count - ** PRAGMA [database.]max_page_count=N + ** PRAGMA [schema.]max_page_count + ** PRAGMA [schema.]max_page_count=N ** ** The first form reports the current setting for the ** maximum number of pages in the database file. The ** second form attempts to change this setting. Both ** forms return the current setting. @@ -517,11 +517,11 @@ ** ** The absolute value of N is used. This is undocumented and might ** change. The only purpose is to provide an easy way to test ** the sqlite3AbsInt32() function. ** - ** PRAGMA [database.]page_count + ** PRAGMA [schema.]page_count ** ** Return the number of pages in the specified database. */ case PragTyp_PAGE_COUNT: { int iReg; @@ -538,12 +538,12 @@ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT); break; } /* - ** PRAGMA [database.]locking_mode - ** PRAGMA [database.]locking_mode = (normal|exclusive) + ** PRAGMA [schema.]locking_mode + ** PRAGMA [schema.]locking_mode = (normal|exclusive) */ case PragTyp_LOCKING_MODE: { const char *zRet = "normal"; int eMode = getLockingMode(zRight); @@ -584,12 +584,12 @@ returnSingleText(v, "locking_mode", zRet); break; } /* - ** PRAGMA [database.]journal_mode - ** PRAGMA [database.]journal_mode = + ** PRAGMA [schema.]journal_mode + ** PRAGMA [schema.]journal_mode = ** (delete|persist|off|truncate|memory|wal|off) */ case PragTyp_JOURNAL_MODE: { int eMode; /* One of the PAGER_JOURNALMODE_XXX symbols */ int ii; /* Loop counter */ @@ -625,12 +625,12 @@ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1); break; } /* - ** PRAGMA [database.]journal_size_limit - ** PRAGMA [database.]journal_size_limit=N + ** PRAGMA [schema.]journal_size_limit + ** PRAGMA [schema.]journal_size_limit=N ** ** Get or set the size limit on rollback journal files. */ case PragTyp_JOURNAL_SIZE_LIMIT: { Pager *pPager = sqlite3BtreePager(pDb->pBt); @@ -645,12 +645,12 @@ } #endif /* SQLITE_OMIT_PAGER_PRAGMAS */ /* - ** PRAGMA [database.]auto_vacuum - ** PRAGMA [database.]auto_vacuum=N + ** PRAGMA [schema.]auto_vacuum + ** PRAGMA [schema.]auto_vacuum=N ** ** Get or set the value of the database 'auto-vacuum' parameter. ** The value is one of: 0 NONE 1 FULL 2 INCREMENTAL */ #ifndef SQLITE_OMIT_AUTOVACUUM @@ -697,11 +697,11 @@ break; } #endif /* - ** PRAGMA [database.]incremental_vacuum(N) + ** PRAGMA [schema.]incremental_vacuum(N) ** ** Do N steps of incremental vacuuming on a database. */ #ifndef SQLITE_OMIT_AUTOVACUUM case PragTyp_INCREMENTAL_VACUUM: { @@ -720,12 +720,12 @@ } #endif #ifndef SQLITE_OMIT_PAGER_PRAGMAS /* - ** PRAGMA [database.]cache_size - ** PRAGMA [database.]cache_size=N + ** PRAGMA [schema.]cache_size + ** PRAGMA [schema.]cache_size=N ** ** The first form reports the current local setting for the ** page cache size. The second form sets the local ** page cache size value. If N is positive then that is the ** number of pages in the cache. If N is negative, then the @@ -745,11 +745,55 @@ } break; } /* - ** PRAGMA [database.]mmap_size(N) + ** PRAGMA [schema.]cache_spill + ** PRAGMA cache_spill=BOOLEAN + ** PRAGMA [schema.]cache_spill=N + ** + ** The first form reports the current local setting for the + ** page cache spill size. The second form turns cache spill on + ** or off. When turnning cache spill on, the size is set to the + ** current cache_size. The third form sets a spill size that + ** may be different form the cache size. + ** If N is positive then that is the + ** number of pages in the cache. If N is negative, then the + ** number of pages is adjusted so that the cache uses -N kibibytes + ** of memory. + ** + ** If the number of cache_spill pages is less then the number of + ** cache_size pages, no spilling occurs until the page count exceeds + ** the number of cache_size pages. + ** + ** The cache_spill=BOOLEAN setting applies to all attached schemas, + ** not just the schema specified. + */ + case PragTyp_CACHE_SPILL: { + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + if( !zRight ){ + if( sqlite3ReadSchema(pParse) ) goto pragma_out; + returnSingleInt(v, "cache_spill", + (db->flags & SQLITE_CacheSpill)==0 ? 0 : + sqlite3BtreeSetSpillSize(pDb->pBt,0)); + }else{ + int size = 1; + if( sqlite3GetInt32(zRight, &size) ){ + sqlite3BtreeSetSpillSize(pDb->pBt, size); + } + if( sqlite3GetBoolean(zRight, size!=0) ){ + db->flags |= SQLITE_CacheSpill; + }else{ + db->flags &= ~SQLITE_CacheSpill; + } + setAllPagerFlags(db); + } + break; + } + + /* + ** PRAGMA [schema.]mmap_size(N) ** ** Used to set mapping size limit. The mapping size limit is ** used to limit the aggregate size of all memory mapped regions of the ** database file. If this parameter is set to zero, then memory mapping ** is not used at all. If N is negative, then the default memory map @@ -889,12 +933,12 @@ } #endif #if SQLITE_ENABLE_LOCKING_STYLE /* - ** PRAGMA [database.]lock_proxy_file - ** PRAGMA [database.]lock_proxy_file = ":auto:"|"lock_file_path" + ** PRAGMA [schema.]lock_proxy_file + ** PRAGMA [schema.]lock_proxy_file = ":auto:"|"lock_file_path" ** ** Return or set the value of the lock_proxy_file flag. Changing ** the value sets a specific file to be used for database access locks. ** */ @@ -925,12 +969,12 @@ break; } #endif /* SQLITE_ENABLE_LOCKING_STYLE */ /* - ** PRAGMA [database.]synchronous - ** PRAGMA [database.]synchronous=OFF|ON|NORMAL|FULL + ** PRAGMA [schema.]synchronous + ** PRAGMA [schema.]synchronous=OFF|ON|NORMAL|FULL ** ** Return or set the local value of the synchronous flag. Changing ** the local value does not make changes to the disk file and the ** default value will be restored the next time the database is ** opened. @@ -1642,20 +1686,20 @@ break; #endif /* SQLITE_OMIT_UTF16 */ #ifndef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS /* - ** PRAGMA [database.]schema_version - ** PRAGMA [database.]schema_version = - ** - ** PRAGMA [database.]user_version - ** PRAGMA [database.]user_version = - ** - ** PRAGMA [database.]freelist_count = - ** - ** PRAGMA [database.]application_id - ** PRAGMA [database.]application_id = + ** PRAGMA [schema.]schema_version + ** PRAGMA [schema.]schema_version = + ** + ** PRAGMA [schema.]user_version + ** PRAGMA [schema.]user_version = + ** + ** PRAGMA [schema.]freelist_count = + ** + ** PRAGMA [schema.]application_id + ** PRAGMA [schema.]application_id = ** ** The pragma's schema_version and user_version are used to set or get ** the value of the schema-version and user-version, respectively. Both ** the schema-version and the user-version are 32-bit signed integers ** stored in the database header. @@ -1726,11 +1770,11 @@ break; #endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ #ifndef SQLITE_OMIT_WAL /* - ** PRAGMA [database.]wal_checkpoint = passive|full|restart|truncate + ** PRAGMA [schema.]wal_checkpoint = passive|full|restart|truncate ** ** Checkpoint the database. */ case PragTyp_WAL_CHECKPOINT: { static const char *azCol[] = { "busy", "log", "checkpointed" }; Index: src/pragma.h ================================================================== --- src/pragma.h +++ src/pragma.h @@ -6,47 +6,48 @@ #define PragTyp_HEADER_VALUE 0 #define PragTyp_AUTO_VACUUM 1 #define PragTyp_FLAG 2 #define PragTyp_BUSY_TIMEOUT 3 #define PragTyp_CACHE_SIZE 4 -#define PragTyp_CASE_SENSITIVE_LIKE 5 -#define PragTyp_COLLATION_LIST 6 -#define PragTyp_COMPILE_OPTIONS 7 -#define PragTyp_DATA_STORE_DIRECTORY 8 -#define PragTyp_DATABASE_LIST 9 -#define PragTyp_DEFAULT_CACHE_SIZE 10 -#define PragTyp_ENCODING 11 -#define PragTyp_FOREIGN_KEY_CHECK 12 -#define PragTyp_FOREIGN_KEY_LIST 13 -#define PragTyp_INCREMENTAL_VACUUM 14 -#define PragTyp_INDEX_INFO 15 -#define PragTyp_INDEX_LIST 16 -#define PragTyp_INTEGRITY_CHECK 17 -#define PragTyp_JOURNAL_MODE 18 -#define PragTyp_JOURNAL_SIZE_LIMIT 19 -#define PragTyp_LOCK_PROXY_FILE 20 -#define PragTyp_LOCKING_MODE 21 -#define PragTyp_PAGE_COUNT 22 -#define PragTyp_MMAP_SIZE 23 -#define PragTyp_PAGE_SIZE 24 -#define PragTyp_SECURE_DELETE 25 -#define PragTyp_SHRINK_MEMORY 26 -#define PragTyp_SOFT_HEAP_LIMIT 27 -#define PragTyp_STATS 28 -#define PragTyp_SYNCHRONOUS 29 -#define PragTyp_TABLE_INFO 30 -#define PragTyp_TEMP_STORE 31 -#define PragTyp_TEMP_STORE_DIRECTORY 32 -#define PragTyp_THREADS 33 -#define PragTyp_WAL_AUTOCHECKPOINT 34 -#define PragTyp_WAL_CHECKPOINT 35 -#define PragTyp_ACTIVATE_EXTENSIONS 36 -#define PragTyp_HEXKEY 37 -#define PragTyp_KEY 38 -#define PragTyp_REKEY 39 -#define PragTyp_LOCK_STATUS 40 -#define PragTyp_PARSER_TRACE 41 +#define PragTyp_CACHE_SPILL 5 +#define PragTyp_CASE_SENSITIVE_LIKE 6 +#define PragTyp_COLLATION_LIST 7 +#define PragTyp_COMPILE_OPTIONS 8 +#define PragTyp_DATA_STORE_DIRECTORY 9 +#define PragTyp_DATABASE_LIST 10 +#define PragTyp_DEFAULT_CACHE_SIZE 11 +#define PragTyp_ENCODING 12 +#define PragTyp_FOREIGN_KEY_CHECK 13 +#define PragTyp_FOREIGN_KEY_LIST 14 +#define PragTyp_INCREMENTAL_VACUUM 15 +#define PragTyp_INDEX_INFO 16 +#define PragTyp_INDEX_LIST 17 +#define PragTyp_INTEGRITY_CHECK 18 +#define PragTyp_JOURNAL_MODE 19 +#define PragTyp_JOURNAL_SIZE_LIMIT 20 +#define PragTyp_LOCK_PROXY_FILE 21 +#define PragTyp_LOCKING_MODE 22 +#define PragTyp_PAGE_COUNT 23 +#define PragTyp_MMAP_SIZE 24 +#define PragTyp_PAGE_SIZE 25 +#define PragTyp_SECURE_DELETE 26 +#define PragTyp_SHRINK_MEMORY 27 +#define PragTyp_SOFT_HEAP_LIMIT 28 +#define PragTyp_STATS 29 +#define PragTyp_SYNCHRONOUS 30 +#define PragTyp_TABLE_INFO 31 +#define PragTyp_TEMP_STORE 32 +#define PragTyp_TEMP_STORE_DIRECTORY 33 +#define PragTyp_THREADS 34 +#define PragTyp_WAL_AUTOCHECKPOINT 35 +#define PragTyp_WAL_CHECKPOINT 36 +#define PragTyp_ACTIVATE_EXTENSIONS 37 +#define PragTyp_HEXKEY 38 +#define PragTyp_KEY 39 +#define PragTyp_REKEY 40 +#define PragTyp_LOCK_STATUS 41 +#define PragTyp_PARSER_TRACE 42 #define PragFlag_NeedSchema 0x01 #define PragFlag_ReadOnly 0x02 static const struct sPragmaNames { const char *const zName; /* Name of pragma */ u8 ePragTyp; /* PragTyp_XXX value */ @@ -89,13 +90,13 @@ /* ePragFlag: */ 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) { /* zName: */ "cache_spill", - /* ePragTyp: */ PragTyp_FLAG, + /* ePragTyp: */ PragTyp_CACHE_SPILL, /* ePragFlag: */ 0, - /* iArg: */ SQLITE_CacheSpill }, + /* iArg: */ 0 }, #endif { /* zName: */ "case_sensitive_like", /* ePragTyp: */ PragTyp_CASE_SENSITIVE_LIKE, /* ePragFlag: */ 0, /* iArg: */ 0 }, Index: test/pragma2.test ================================================================== --- test/pragma2.test +++ test/pragma2.test @@ -136,11 +136,11 @@ sqlite3 db test.db do_execsql_test pragma2-4.1 { PRAGMA cache_spill; PRAGMA main.cache_spill; PRAGMA temp.cache_spill; -} {1 1 1} +} {2000 2000 2000} do_execsql_test pragma2-4.2 { PRAGMA cache_spill=OFF; PRAGMA cache_spill; PRAGMA main.cache_spill; PRAGMA temp.cache_spill; @@ -176,25 +176,58 @@ BEGIN; UPDATE t1 SET c=c+1; PRAGMA lock_status; } } {main exclusive temp unknown} ;# EXCLUSIVE lock due to cache spill -do_test pragma2-4.5 { +do_test pragma2-4.5.1 { db eval { - COMMIT; + ROLLBACK; PRAGMA cache_spill=OFF; + PRAGMA Cache_Spill; + BEGIN; + UPDATE t1 SET c=c+1; + PRAGMA lock_status; + } +} {0 main reserved temp unknown} ;# No cache spill, so no exclusive lock +do_test pragma2-4.5.2 { + db eval { + ROLLBACK; + PRAGMA cache_spill=100000; + PRAGMA cache_spill; + BEGIN; + UPDATE t1 SET c=c+1; + PRAGMA lock_status; + } +} {100000 main reserved temp unknown} ;# Big spill threshold -> no excl lock +do_test pragma2-4.5.3 { + db eval { + ROLLBACK; + PRAGMA cache_spill=25; + PRAGMA main.cache_spill; + BEGIN; + UPDATE t1 SET c=c+1; + PRAGMA lock_status; + } +} {50 main exclusive temp unknown} ;# Small cache spill -> exclusive lock +do_test pragma2-4.5.4 { + db eval { + ROLLBACK; + PRAGMA cache_spill(-25); + PRAGMA main.cache_spill; BEGIN; - UPDATE t1 SET c=c-1; + UPDATE t1 SET c=c+1; PRAGMA lock_status; } -} {main reserved temp unknown} ;# No cache spill, so no exclusive lock +} {50 main exclusive temp unknown} ;# Small cache spill -> exclusive lock + # Verify that newly attached databases inherit the cache_spill=OFF # setting. # do_execsql_test pragma2-4.6 { - COMMIT; + ROLLBACK; + PRAGMA cache_spill=OFF; ATTACH 'test2.db' AS aux1; PRAGMA aux1.cache_size=50; BEGIN; UPDATE t2 SET c=c+1; PRAGMA lock_status; @@ -207,8 +240,28 @@ PRAGMA cache_spill=ON; -- Applies to all databases BEGIN; UPDATE t2 SET c=c-1; PRAGMA lock_status; } {main unlocked temp unknown aux1 exclusive} +db close +forcedelete test.db +sqlite3 db test.db + +breakpoint +do_execsql_test pragma2-5.1 { + PRAGMA page_size=16384; + CREATE TABLE t1(x); + PRAGMA cache_size=2; + PRAGMA cache_spill=YES; + PRAGMA cache_spill; +} {2} +do_execsql_test pragma2-5.2 { + PRAGMA cache_spill=NO; + PRAGMA cache_spill; +} {0} +do_execsql_test pragma2-5.3 { + PRAGMA cache_spill(-51); + PRAGMA cache_spill; +} {3} test_restore_config_pagecache finish_test Index: tool/mkpragmatab.tcl ================================================================== --- tool/mkpragmatab.tcl +++ tool/mkpragmatab.tcl @@ -45,12 +45,10 @@ TYPE: FLAG ARG: SQLITE_CkptFullFSync IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) NAME: cache_spill - TYPE: FLAG - ARG: SQLITE_CacheSpill IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) NAME: reverse_unordered_selects TYPE: FLAG ARG: SQLITE_ReverseOrder