From: drh Date: Wed, 16 Nov 2011 19:29:17 +0000 (+0000) Subject: Add the sqlite3_db_release_memory() interface and the shrink_memory pragma. X-Git-Tag: mountain-lion~9^2~18 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=09419b4bae13024d9bfc011e0a108eb3dfc6296f;p=thirdparty%2Fsqlite.git Add the sqlite3_db_release_memory() interface and the shrink_memory pragma. FossilOrigin-Name: 3f58e7c8895d1252eff56282c08b1a6f1194452c --- diff --git a/manifest b/manifest index 18ce75562b..32a5baf41b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\sthe\sPCACHE2\schanges\sinto\strunk. -D 2011-11-16T18:08:07.023 +C Add\sthe\ssqlite3_db_release_memory()\sinterface\sand\sthe\sshrink_memory\spragma. +D 2011-11-16T19:29:17.253 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5b4a3e12a850b021547e43daf886b25133b44c07 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -147,7 +147,7 @@ F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f F src/lempar.c 0ee69fca0be54cd93939df98d2aca4ca46f44416 F src/loadext.c d0d2022a5a07274d408820b978b9e549189d314f -F src/main.c 87dd4f6ee9b1700d54164ab4e14f2f7abc75486f +F src/main.c 3acbdf6f8b93093bd7f96bdfd7f88bab95a5cd7a F src/malloc.c 591aedb20ae40813f1045f2ef253438a334775d9 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c 7456e2ca0524609ebc06a9befeda5289d4575ad4 @@ -168,13 +168,13 @@ F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440 F src/os_unix.c 4fbb91726165e105c1679a2660f49a3f4c376e4f F src/os_win.c a22b88d2c088c09a678a471abafa8d60dbf56803 -F src/pager.c db33d4bf1e3e019c34c220971cc6c3aa07c30f54 -F src/pager.h 9f81b08efb06db4ba8be69446e10b005c351373d +F src/pager.c d981f3bfcc0e4460537d983899620700ccf8f539 +F src/pager.h 5cd760857707529b403837d813d86b68938d6183 F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58 -F src/pcache.c b9d52e9f844d91c27c161279234f273fc02abc71 -F src/pcache.h c770382f9fae4ca5025c5523bd0aa13cd6ddc6f8 -F src/pcache1.c 0ac7b63db83a705787f4ababf1e4cff27b5f8064 -F src/pragma.c 65d1d63d64f8b7350f28d5ee6d40f7985deccdfe +F src/pcache.c 1fdd77978c1525d1ca4b9ef48eb80abca710cb4c +F src/pcache.h b1d8775a9bddf44e65edb0d20bfc57a4982f840f +F src/pcache1.c 9d735349ac87ef08076c6b1230f04cd83b15c6da +F src/pragma.c dd66f21fafe7be40e1a48ad4195764cc191cf583 F src/prepare.c ec4989f7f480544bdc4192fe663470d2a2d7d61e F src/printf.c 03104cbff6959ff45df69dc9060ba6212f60a869 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 @@ -182,14 +182,14 @@ F src/resolve.c 365ab1c870e38596d6869e76fb544fe6e4ffc809 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697 F src/select.c 80f3ac44a8514b1d107b80f5df4a424ae059d2b6 F src/shell.c 29812a900a780eb0f835c4bc65e216272689def8 -F src/sqlite.h.in 557f4113a649f15d13e566aaa85820509b4daa52 +F src/sqlite.h.in a9d9b247a5e1a203bc24154fdfe8fad49978faa1 F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477 F src/sqliteInt.h f412e020e1009163c74be56eaac1bf7f6c0a4515 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 4568e72dfd36b6a5911f93457364deb072e0b03a F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/tclsqlite.c de581e2e71f5e7f98366156afad83b4742ac6fe0 -F src/test1.c 0f41b7c67719207a5de24b009e172c4dcf189827 +F src/test1.c 348de9657e874bff49b99dcd7307074b6feaf456 F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31 F src/test3.c 124ff9735fb6bb7d41de180d6bac90e7b1509432 F src/test4.c d1e5a5e904d4b444cf572391fdcb017638e36ff7 @@ -678,6 +678,7 @@ F test/shared7.test 960760bc8d03e1419e70dea69cf41db62853616e F test/shared_err.test 91e26ec4f3fbe07951967955585137e2f18993de F test/sharedlock.test ffa0a3c4ac192145b310f1254f8afca4d553eabf F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3 +F test/shrink.test 28165922bfea5c003c51a2d02bce69c4141ef013 F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329 F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f F test/softheap1.test c16709a16ad79fa43b32929b2e623d1d117ccf53 @@ -975,7 +976,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P a5418c7fc216a30abf7b2fa8c579aee586393a91 9f839ac05a9f3cfe587d2ccdccd50dac41baedbe -R e41a73511b92616ee76fa30eb271c907 +P 457513f21f2438c61b1a214716e338a4e3eeaafa +R 2aefebff3180a54a438215134f3a783d U drh -Z e97a12a6137cafdd18edeb6857a80579 +Z 6faa593abe3d90439929fe507a12385d diff --git a/manifest.uuid b/manifest.uuid index eb4dd66704..f09b57bd77 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -457513f21f2438c61b1a214716e338a4e3eeaafa \ No newline at end of file +3f58e7c8895d1252eff56282c08b1a6f1194452c \ No newline at end of file diff --git a/src/main.c b/src/main.c index 27dacac1b2..edca152903 100644 --- a/src/main.c +++ b/src/main.c @@ -530,6 +530,24 @@ sqlite3_mutex *sqlite3_db_mutex(sqlite3 *db){ return db->mutex; } +/* +** Free up as much memory as we can from the given database +** connection. +*/ +int sqlite3_db_release_memory(sqlite3 *db){ + int i; + sqlite3BtreeEnterAll(db); + for(i=0; inDb; i++){ + Btree *pBt = db->aDb[i].pBt; + if( pBt ){ + Pager *pPager = sqlite3BtreePager(pBt); + sqlite3PagerShrink(pPager); + } + } + sqlite3BtreeLeaveAll(db); + return SQLITE_OK; +} + /* ** Configuration settings for an individual database connection */ diff --git a/src/pager.c b/src/pager.c index 6900610b20..f3069e52ba 100644 --- a/src/pager.c +++ b/src/pager.c @@ -3294,6 +3294,13 @@ void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){ sqlite3PcacheSetCachesize(pPager->pPCache, mxPage); } +/* +** Free as much memory as possible from the pager. +*/ +void sqlite3PagerShrink(Pager *pPager){ + sqlite3PcacheShrink(pPager->pPCache); +} + /* ** Adjust the robustness of the database to damage due to OS crashes ** or power failures by changing the number of syncs()s when writing diff --git a/src/pager.h b/src/pager.h index e36e6c2e86..f68b19f6eb 100644 --- a/src/pager.h +++ b/src/pager.h @@ -103,6 +103,7 @@ void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *); int sqlite3PagerSetPagesize(Pager*, u32*, int); int sqlite3PagerMaxPageCount(Pager*, int); void sqlite3PagerSetCachesize(Pager*, int); +void sqlite3PagerShrink(Pager*); void sqlite3PagerSetSafetyLevel(Pager*,int,int,int); int sqlite3PagerLockingMode(Pager *, int); int sqlite3PagerSetJournalMode(Pager *, int); diff --git a/src/pcache.c b/src/pcache.c index a504633919..0c3e9ee0a2 100644 --- a/src/pcache.c +++ b/src/pcache.c @@ -595,6 +595,15 @@ void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){ } } +/* +** Free up as much memory as possible from the page cache. +*/ +void sqlite3PcacheShrink(PCache *pCache){ + if( pCache->pCache ){ + sqlite3GlobalConfig.pcache2.xShrink(pCache->pCache); + } +} + #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG) /* ** For all dirty pages currently in the cache, invoke the specified diff --git a/src/pcache.h b/src/pcache.h index c4a25b251f..82543dbc30 100644 --- a/src/pcache.h +++ b/src/pcache.h @@ -142,6 +142,9 @@ void sqlite3PcacheSetCachesize(PCache *, int); int sqlite3PcacheGetCachesize(PCache *); #endif +/* Free up as much memory as possible from the page cache */ +void sqlite3PcacheShrink(PCache*); + #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT /* Try to return memory used by the pcache module to the main memory heap */ int sqlite3PcacheReleaseMemory(int); diff --git a/src/pcache1.c b/src/pcache1.c index 35bdda8a9a..505941a3a7 100644 --- a/src/pcache1.c +++ b/src/pcache1.c @@ -227,8 +227,9 @@ static void *pcache1Alloc(int nByte){ /* ** Free an allocated buffer obtained from pcache1Alloc(). */ -static void pcache1Free(void *p){ - if( p==0 ) return; +static int pcache1Free(void *p){ + int nFreed = 0; + if( p==0 ) return 0; if( p>=pcache1.pStart && pbPurgeable ){ + PGroup *pGroup = pCache->pGroup; + int savedMaxPage; + pcache1EnterMutex(pGroup); + savedMaxPage = pGroup->nMaxPage; + pGroup->nMaxPage = 0; + pcache1EnforceMaxPage(pGroup); + pGroup->nMaxPage = savedMaxPage; + pcache1LeaveMutex(pGroup); + } +} + /* ** Implementation of the sqlite3_pcache.xPagecount method. */ @@ -935,7 +955,8 @@ void sqlite3PCacheSetDefault(void){ pcache1Unpin, /* xUnpin */ pcache1Rekey, /* xRekey */ pcache1Truncate, /* xTruncate */ - pcache1Destroy /* xDestroy */ + pcache1Destroy, /* xDestroy */ + pcache1Shrink /* xShrink */ }; sqlite3_config(SQLITE_CONFIG_PCACHE2, &defaultMethods); } diff --git a/src/pragma.c b/src/pragma.c index 538aa61083..bfdcb2370a 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1438,6 +1438,16 @@ void sqlite3Pragma( }else #endif + /* + ** PRAGMA shrink_memory + ** + ** This pragma attempts to free as much memory as possible from the + ** current database connection. + */ + if( sqlite3StrICmp(zLeft, "shrink_memory")==0 ){ + sqlite3_db_release_memory(db); + }else + #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) /* ** Report the current state of file logs for all databases diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 27c2b75db3..dc193c6daf 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -4529,9 +4529,24 @@ int sqlite3_enable_shared_cache(int); ** which might be more or less than the amount requested. ** ^The sqlite3_release_memory() routine is a no-op returning zero ** if SQLite is not compiled with [SQLITE_ENABLE_MEMORY_MANAGEMENT]. +** +** See also: [sqlite3_db_release_memory()] */ int sqlite3_release_memory(int); +/* +** CAPI3REF: Free Memory Used By A Database Connection +** +** ^The sqlite3_db_shrink(D) interface attempts to free as much heap +** memory as possible from database connection D. Unlike the +** [sqlite3_release_memory()] interface, this interface is effect even +** when then [SQLITE_ENABLE_MEMORY_MANAGEMENT] compile-time option is +** omitted. +** +** See also: [sqlite3_release_memory()] +*/ +int sqlite3_db_release_memory(sqlite3*); + /* ** CAPI3REF: Impose A Limit On Heap Size ** @@ -6106,6 +6121,12 @@ struct sqlite3_pcache_page { ** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*] ** handle invalid, and will not use it with any other sqlite3_pcache_methods ** functions. +** +** [[the xShrink() page cache method]] +** ^SQLite invokes the xShrink() method when it wants the page cache to +** free up as much of heap memory as possible. The page cache implementation +** is not obligated to free any memory, but well-behaved implementions should +** do their best. */ typedef struct sqlite3_pcache_methods2 sqlite3_pcache_methods2; struct sqlite3_pcache_methods2 { @@ -6122,6 +6143,7 @@ struct sqlite3_pcache_methods2 { unsigned oldKey, unsigned newKey); void (*xTruncate)(sqlite3_pcache*, unsigned iLimit); void (*xDestroy)(sqlite3_pcache*); + void (*xShrink)(sqlite3_pcache*); }; /* diff --git a/src/test1.c b/src/test1.c index 26342522c5..9cd54e4561 100644 --- a/src/test1.c +++ b/src/test1.c @@ -4593,6 +4593,31 @@ static int test_release_memory( return TCL_OK; } + +/* +** Usage: sqlite3_db_release_memory DB +** +** Attempt to release memory currently held by database DB. Return the +** result code (which in the current implementation is always zero). +*/ +static int test_db_release_memory( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + sqlite3 *db; + int rc; + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "DB"); + return TCL_ERROR; + } + if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; + rc = sqlite3_db_release_memory(db); + Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); + return TCL_OK; +} + /* ** Usage: sqlite3_soft_heap_limit ?N? ** @@ -5915,6 +5940,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "uses_stmt_journal", uses_stmt_journal ,0 }, { "sqlite3_release_memory", test_release_memory, 0}, + { "sqlite3_db_release_memory", test_db_release_memory, 0}, { "sqlite3_soft_heap_limit", test_soft_heap_limit, 0}, { "sqlite3_thread_cleanup", test_thread_cleanup, 0}, { "sqlite3_pager_refcounts", test_pager_refcounts, 0}, diff --git a/test/shrink.test b/test/shrink.test new file mode 100644 index 0000000000..cc055c63b5 --- /dev/null +++ b/test/shrink.test @@ -0,0 +1,42 @@ +# 2011 November 16 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# 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 contains test cases for sqlite3_db_release_memory and +# the PRAGMA shrink_memory statement. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +unset -nocomplain baseline +do_test shrink-1.1 { + db eval { + CREATE TABLE t1(x,y); + INSERT INTO t1 VALUES(randomblob(1000000),1); + } + set ::baseline sqlite3_memory_used + sqlite3_db_release_memory db + expr {$::baseline > [sqlite3_memory_used]+500000} +} {1} +do_test shrink-1.2 { + set baseline [sqlite3_memory_used] + db eval { + UPDATE t1 SET y=y+1; + } + expr {$::baseline+500000 < [sqlite3_memory_used]} +} {1} +do_test shrink-1.3 { + set baseline [sqlite3_memory_used] + db eval {PRAGMA shrink_memory} + expr {$::baseline > [sqlite3_memory_used]+500000} +} {1} + +finish_test