]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the sqlite3_db_release_memory() interface and the shrink_memory pragma.
authordrh <drh@noemail.net>
Wed, 16 Nov 2011 19:29:17 +0000 (19:29 +0000)
committerdrh <drh@noemail.net>
Wed, 16 Nov 2011 19:29:17 +0000 (19:29 +0000)
FossilOrigin-Name: 3f58e7c8895d1252eff56282c08b1a6f1194452c

12 files changed:
manifest
manifest.uuid
src/main.c
src/pager.c
src/pager.h
src/pcache.c
src/pcache.h
src/pcache1.c
src/pragma.c
src/sqlite.h.in
src/test1.c
test/shrink.test [new file with mode: 0644]

index 18ce75562bc67790a1bbe6fb2cf235ac2f2ad088..32a5baf41bfa291a8d0219242ad2e247073c9ec0 100644 (file)
--- 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
index eb4dd66704e4884fcb6d6c939cca277be8f9c02f..f09b57bd77b1018b88f5e57cfb54824e153bc8b0 100644 (file)
@@ -1 +1 @@
-457513f21f2438c61b1a214716e338a4e3eeaafa
\ No newline at end of file
+3f58e7c8895d1252eff56282c08b1a6f1194452c
\ No newline at end of file
index 27dacac1b2ddb0a6f12041427ab5ea39d1abe99b..edca15290330d3983ade23dfc19dcb6f2fd3a376 100644 (file)
@@ -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; i<db->nDb; 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
 */
index 6900610b204b633f6bf2944a5fb69beb35016205..f3069e52bad0a63568b2b71bc8e64c42491e9ca3 100644 (file)
@@ -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
index e36e6c2e861ab53eb56a90f787084a58bf9adb84..f68b19f6eb78d3c9db441b12522f69d004c3ae6d 100644 (file)
@@ -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);
index a504633919bb50f28c6877711d8ccc8baf299a79..0c3e9ee0a2c4b900a778986876221b910f4786ea 100644 (file)
@@ -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
index c4a25b251f2fabdf016c6a3736f9249f29497470..82543dbc304e8722e9755ec063458ba06d705220 100644 (file)
@@ -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);
index 35bdda8a9aa42ad5962edc58d97faf2f16bb256a..505941a3a7d644a616d632a292c02f132c3551e5 100644 (file)
@@ -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 && p<pcache1.pEnd ){
     PgFreeslot *pSlot;
     sqlite3_mutex_enter(pcache1.mutex);
@@ -241,15 +242,15 @@ static void pcache1Free(void *p){
     assert( pcache1.nFreeSlot<=pcache1.nSlot );
     sqlite3_mutex_leave(pcache1.mutex);
   }else{
-    int iSize;
     assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
     sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
-    iSize = sqlite3MallocSize(p);
+    nFreed = sqlite3MallocSize(p);
     sqlite3_mutex_enter(pcache1.mutex);
-    sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -iSize);
+    sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -nFreed);
     sqlite3_mutex_leave(pcache1.mutex);
     sqlite3_free(p);
   }
+  return nFreed;
 }
 
 #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
@@ -623,6 +624,25 @@ static void pcache1Cachesize(sqlite3_pcache *p, int nMax){
   }
 }
 
+/*
+** Implementation of the sqlite3_pcache.xShrink method. 
+**
+** Free up as much memory as possible.
+*/
+static void pcache1Shrink(sqlite3_pcache *p){
+  PCache1 *pCache = (PCache1*)p;
+  if( pCache->bPurgeable ){
+    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);
 }
index 538aa610832d308491d1fddc5c254c25e1e0bcf5..bfdcb2370ac134c20d22ed8d4798baa626edacab 100644 (file)
@@ -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
index 27c2b75db3898df4dd79c67ab9f98508681aad4a..dc193c6dafe0f2826a37ba8a157781c2ac26d74f 100644 (file)
@@ -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*);
 };
 
 /*
index 26342522c5990826d002a8bec08ece0071fe3c16..9cd54e45610788b72159603e985b296517b412d8 100644 (file)
@@ -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 (file)
index 0000000..cc055c6
--- /dev/null
@@ -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