diff --git a/manifest b/manifest index f320f73030..989f928c10 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\san\sincorrect\sassert()\sstatement\sin\ssqlite3GenerateConstraintChecks().\ndbsqlfuzz\s4190cff310aeab359a55f354e560db95d3a6f47d -D 2021-10-30T18:17:59.636 +C Add\sthe\ssqlite3_autovacuum_pages()\sinterface. +D 2021-10-30T20:22:32.855 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -490,7 +490,7 @@ F src/auth.c f4fa91b6a90bbc8e0d0f738aa284551739c9543a367071f55574681e0f24f8cf F src/backup.c 3014889fa06e20e6adfa0d07b60097eec1f6e5b06671625f476a714d2356513d F src/bitvec.c 7c849aac407230278445cb069bebc5f89bf2ddd87c5ed9459b070a9175707b3d F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 -F src/btree.c 004c647dfb5332ee4b56385f3ac264ebea781cb00f7a1561a48f4a45b78fed61 +F src/btree.c 2c8a52a7fd84b1aec4a79e7861b6368aecbf011a43247cc7d9a2946c7f0ae5ea F src/btree.h 74d64b8f28cfa4a894d14d4ed64fa432cd697b98b61708d4351482ae15913e22 F src/btreeInt.h ee9348c4cb9077243b049edc93a82c1f32ca48baeabf2140d41362b9f9139ff7 F src/build.c 8bdda90f9b1189c7b0813575171b3c6b2d74b3ade57c11cb4383776781ea9335 @@ -512,8 +512,8 @@ F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/insert.c 3f2892de7820d8e0b34a90bff8a3e2f879bc528683fa2ebb9e779ae56b64b741 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa -F src/loadext.c 0aa9e7f08e168e3874cb54984408e3976dafdf5616d511952c425b5ac088ea3e -F src/main.c bfe067d61ebbd0e6eb023f1fb6b353021e621cf1657e061d629064a740bfbf6f +F src/loadext.c e1dcff1c916bf6834e150b492eddda5d9792453182d2ad64294d2266b6e93c4c +F src/main.c 546dd2418c4f5d59aced76c68e55290735feb420ee305051fbd55ab8fff0d255 F src/malloc.c ef796bcc0e81d845d59a469f1cf235056caf9024172fd524e32136e65593647b F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de @@ -551,15 +551,15 @@ F src/resolve.c ae65c88f5d0d4bc0052b203773d407efa2387c2bd6b202f87178006c7bb8632c F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c 32d25b5af6c708aa63373c78c2e59681910387a7a78c08ec3086cadc77d41627 F src/shell.c.in 185e4b905c3a399e9376597a04cf668f6f992513290978ac978cf4991954d89f -F src/sqlite.h.in f0c1ecb5af508aa8e970cd8bc0ec851e6c380b81825038d458846c2fcdfcef50 +F src/sqlite.h.in 99786216caf1c57aa3d70f95a7f84566dff6a9eeb50174799ea3b387eafd2a22 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 -F src/sqlite3ext.h e97f4e9b509408fea4c4e9bef5a41608dfac343b4d3c7a990dedde1e19af9510 -F src/sqliteInt.h 317bbdf926ec7c391fb00bcaa1f82799836a1151568bd9d343f43c2cdf1a48b9 +F src/sqlite3ext.h d8f6f67ae9ad990a70dd03c093bcdc8883e159ff4bfd16a496f8fb80c6840b5a +F src/sqliteInt.h 02f7ccc971d67d8641707f219b9c304113d43a9a128b73a39d1fcaa036c885b7 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 F src/tclsqlite.c 428e813dabf82804bc13196af35a0c3c6ef4347fe557fa6717c5c66bba6e8520 -F src/test1.c 63761c2be2607f1b425fde991beda48aed384f8d67f2b4ee549174c88b433009 +F src/test1.c bd1c3c2637db35c0a69513e008c0e6a177b360ccae7689e0bf69f15b55e24bae F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5 F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644 F src/test4.c 7c4420e01c577b5c4add2cb03119743b1a357543d347773b9e717195ea967159 @@ -705,7 +705,8 @@ F test/autoindex2.test 12ef578928102baaa0dc23ad397601a2f4ecb0df F test/autoindex3.test 2d13958a5617e987624a428d7aed91bf51f322b49b476e3573fadec697ce6da5 F test/autoindex4.test 49d3cd791a9baa16fb461d7ea3de80d019a819cf F test/autoindex5.test 2ee94f033b87ca0160e08d81034c507aff8e230df2627f0304fa309b2fee19a3 -F test/autovacuum.test 0831cd34e14695d297187f7f6519265e3121c5b0a1720e548e86829e796129e9 +F test/autovacuum.test 00671369bbf96c6a49989a9425f5b78b94075d6a4b031e5e00000c2c32f365df +F test/autovacuum2.test 76f7eb4fe6a6bf6d33a196a7141dba98886d2fb53a268d7feca285d5da4759d7 F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4 F test/avfs.test 0c3a38e03cccb0fc3127838462dc05dc3f4c1480d770c084b388304c25de3652 F test/avtrans.test b7dc25459ecbd86c6fa9c606ee3068f59d81e225118617dcf2bbb6ded2ade89e @@ -1929,7 +1930,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 8ba73b3cadb72ffcf176d19f9f946c1b90b224e5ab9a0e9eb9a83affa7476d23 -R b527768918a8e4077efc0dd96c45874f +P 623c0d086bda135c49bfc238c31498facdcbe8ecc7659cc1af61594df0c6e899 60cd9da9258e0b701d4bb3f9c91c5d0a12e925b9b937df619b09f33a287b4a33 +R c2365c0f257a6e1be84889548b719edd +T +closed 60cd9da9258e0b701d4bb3f9c91c5d0a12e925b9b937df619b09f33a287b4a33 U drh -Z ea8a849e6713aaef4d0e7842051d5f8f +Z 46db034af6d2112bb92acfe1ff1351cf diff --git a/manifest.uuid b/manifest.uuid index e54f60e5fa..0e9b7b2571 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -623c0d086bda135c49bfc238c31498facdcbe8ecc7659cc1af61594df0c6e899 \ No newline at end of file +ca2703c339f76101f25051a2ed380398b018782883bfee68b5f2d69a1de9091a \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 0d220a3b93..67611c3bf5 100644 --- a/src/btree.c +++ b/src/btree.c @@ -3939,16 +3939,18 @@ int sqlite3BtreeIncrVacuum(Btree *p){ /* ** This routine is called prior to sqlite3PagerCommit when a transaction ** is committed for an auto-vacuum database. -** -** If SQLITE_OK is returned, then *pnTrunc is set to the number of pages -** the database file should be truncated to during the commit process. -** i.e. the database has been reorganized so that only the first *pnTrunc -** pages are in use. */ -static int autoVacuumCommit(BtShared *pBt){ +static int autoVacuumCommit(Btree *p){ int rc = SQLITE_OK; - Pager *pPager = pBt->pPager; - VVA_ONLY( int nRef = sqlite3PagerRefcount(pPager); ) + Pager *pPager; + BtShared *pBt; + sqlite3 *db; + VVA_ONLY( int nRef ); + + assert( p!=0 ); + pBt = p->pBt; + pPager = pBt->pPager; + VVA_ONLY( nRef = sqlite3PagerRefcount(pPager); ) assert( sqlite3_mutex_held(pBt->mutex) ); invalidateAllOverflowCache(pBt); @@ -3956,6 +3958,7 @@ static int autoVacuumCommit(BtShared *pBt){ if( !pBt->incrVacuum ){ Pgno nFin; /* Number of pages in database after autovacuuming */ Pgno nFree; /* Number of pages on the freelist initially */ + Pgno nVac; /* Number of pages to vacuum */ Pgno iFree; /* The next page to be freed */ Pgno nOrig; /* Database size before freeing */ @@ -3969,18 +3972,42 @@ static int autoVacuumCommit(BtShared *pBt){ } nFree = get4byte(&pBt->pPage1->aData[36]); - nFin = finalDbSize(pBt, nOrig, nFree); + db = p->db; + if( db->xAutovacPages ){ + int iDb; + for(iDb=0; ALWAYS(iDbnDb); iDb++){ + if( db->aDb[iDb].pBt==p ) break; + } + nVac = db->xAutovacPages( + db->pAutovacPagesArg, + db->aDb[iDb].zDbSName, + nOrig, + nFree, + pBt->pageSize + ); + if( nVac>nFree ){ + nVac = nFree; + } + if( nVac==0 ){ + return SQLITE_OK; + } + }else{ + nVac = nFree; + } + nFin = finalDbSize(pBt, nOrig, nVac); if( nFin>nOrig ) return SQLITE_CORRUPT_BKPT; if( nFinnFin && rc==SQLITE_OK; iFree--){ - rc = incrVacuumStep(pBt, nFin, iFree, 1); + rc = incrVacuumStep(pBt, nFin, iFree, nVac==nFree); } if( (rc==SQLITE_DONE || rc==SQLITE_OK) && nFree>0 ){ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); - put4byte(&pBt->pPage1->aData[32], 0); - put4byte(&pBt->pPage1->aData[36], 0); + if( nVac==nFree ){ + put4byte(&pBt->pPage1->aData[32], 0); + put4byte(&pBt->pPage1->aData[36], 0); + } put4byte(&pBt->pPage1->aData[28], nFin); pBt->bDoTruncate = 1; pBt->nPage = nFin; @@ -4031,7 +4058,7 @@ int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zSuperJrnl){ sqlite3BtreeEnter(p); #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum ){ - rc = autoVacuumCommit(pBt); + rc = autoVacuumCommit(p); if( rc!=SQLITE_OK ){ sqlite3BtreeLeave(p); return rc; diff --git a/src/loadext.c b/src/loadext.c index 29371336c4..4edefec0c9 100644 --- a/src/loadext.c +++ b/src/loadext.c @@ -483,6 +483,8 @@ static const sqlite3_api_routines sqlite3Apis = { /* Version 3.36.1 and later */ sqlite3_changes64, sqlite3_total_changes64, + /* Version 3.37.0 and later */ + sqlite3_autovacuum_pages, }; /* True if x is the directory separator character diff --git a/src/main.c b/src/main.c index bf33b640b8..aa34977bf9 100644 --- a/src/main.c +++ b/src/main.c @@ -1403,6 +1403,9 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){ ** structure? */ sqlite3DbFree(db, db->aDb[1].pSchema); + if( db->xAutovacDestr ){ + db->xAutovacDestr(db->pAutovacPagesArg); + } sqlite3_mutex_leave(db->mutex); db->eOpenState = SQLITE_STATE_CLOSED; sqlite3_mutex_free(db->mutex); @@ -2304,6 +2307,34 @@ void *sqlite3_preupdate_hook( } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ +/* +** Register a function to be invoked prior to each autovacuum that +** determines the number of pages to vacuum. +*/ +int sqlite3_autovacuum_pages( + sqlite3 *db, /* Attach the hook to this database */ + unsigned int (*xCallback)(void*,const char*,u32,u32,u32), + void *pArg, /* Argument to the function */ + void (*xDestructor)(void*) /* Destructor for pArg */ +){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + if( xDestructor ) xDestructor(pArg); + return SQLITE_MISUSE_BKPT; + } +#endif + sqlite3_mutex_enter(db->mutex); + if( db->xAutovacDestr ){ + db->xAutovacDestr(db->pAutovacPagesArg); + } + db->xAutovacPages = xCallback; + db->pAutovacPagesArg = pArg; + db->xAutovacDestr = xDestructor; + sqlite3_mutex_leave(db->mutex); + return SQLITE_OK; +} + + #ifndef SQLITE_OMIT_WAL /* ** The sqlite3_wal_hook() callback registered by sqlite3_wal_autocheckpoint(). diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 4435925de4..f20d457e3a 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -6406,6 +6406,72 @@ sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt); void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*); void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); +/* +** CAPI3REF: Autovacuum Compaction Amount Callback +** METHOD: sqlite3 +** +** ^The sqlite3_autovacuum_pages(D,C,P,X) interface registers a callback +** function C that is invoked prior to each autovacuum of the database +** file. ^The callback is passed a copy of the generic data pointer (P), +** the schema-name of the attached database that is being autovacuumed, +** the the size of the database file in pages, the number of free pages, +** and the number of bytes per page, respectively. The callback should +** return the number of free pages that should be removed by the +** autovacuum. ^If the callback returns zero, then no autovacuum happens. +** ^If the value returned is greater than or equal to the number of +** free pages, then a complete autovacuum happens. +** +**

^If there are multiple ATTACH-ed database files that are being +** modified as part of a transaction commit, then the autovacuum pages +** callback is invoked separately for each file. +** +**

The callback is not reentrant. The callback function should +** not attempt to invoke any other SQLite interface. If it does, bad +** things may happen, including segmentation faults and corrupt database +** files. The callback function should be a simple function that +** does some arithmetic on its input parameters and returns a result. +** +** ^The X parameter to sqlite3_autovacuum_pages(D,C,P,X) is an optional +** destructor for the P parameter. ^If X is not NULL, then X(P) is +** invoked whenever the database connection closes or when the callback +** is overwritten by another invocation of sqlite3_autovacuum_pages(). +** +**

^There is only one autovacuum pages callback per database connection. +** ^Each call to the sqlite3_autovacuum_pages() interface overrides all +** previous invocations for that database connection. ^If the callback +** argument (C) to sqlite3_autovacuum_pages(D,C,P,X) is a NULL pointer, +** then the autovacuum steps callback is cancelled. The return value +** from sqlite3_autovacuum_pages() is normally SQLITE_OK, but might +** be some other error code if something goes wrong. The current +** implementation will only return SQLITE_OK or SQLITE_MISUSE, but other +** return codes might be added in future releases. +** +**

If no autovacuum pages callback is specified (the usual case) or +** a NULL pointer is provided for the callback, +** then the default behavior is to vacuum all free pages. So, in other +** words, the default behavior is the same as if the callback function +** were something like this: +** +**

+**     unsigned int demonstration_autovac_pages_callback(
+**       void *pClientData,
+**       const char *zSchema,
+**       unsigned int nDbPage,
+**       unsigned int nFreePage,
+**       unsigned int nBytePerPage
+**     ){
+**       return nFreePage;
+**     }
+** 
+*/ +int sqlite3_autovacuum_pages( + sqlite3 *db, + unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int), + void*, + void(*)(void*) +); + + /* ** CAPI3REF: Data Change Notification Callbacks ** METHOD: sqlite3 diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h index 98d9305240..4ec11324b2 100644 --- a/src/sqlite3ext.h +++ b/src/sqlite3ext.h @@ -340,6 +340,10 @@ struct sqlite3_api_routines { /* Version 3.36.1 and later */ sqlite3_int64 (*changes64)(sqlite3*); sqlite3_int64 (*total_changes64)(sqlite3*); + /* Version 3.37.0 and later */ + int (*autovacuum_pages)(sqlite3*, + unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int), + void*, void(*)(void*)); }; /* @@ -646,6 +650,11 @@ typedef int (*sqlite3_loadext_entry)( #define sqlite3_database_file_object sqlite3_api->database_file_object /* Version 3.34.0 and later */ #define sqlite3_txn_state sqlite3_api->txn_state +/* Version 3.36.1 and later */ +#define sqlite3_changes64 sqlite3_api->changes64 +#define sqlite3_total_changes64 sqlite3_api->total_changes64 +* Version 3.37.0 and later */ +#define sqlite3_autovacuum_pages sqlite3_api->autovacuum_pages #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) diff --git a/src/sqliteInt.h b/src/sqliteInt.h index cb20a37f24..53e9033183 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1566,6 +1566,9 @@ struct sqlite3 { void (*xRollbackCallback)(void*); /* Invoked at every commit. */ void *pUpdateArg; void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64); + void *pAutovacPagesArg; /* Client argument to autovac_pages */ + void (*xAutovacDestr)(void*); /* Destructor for pAutovacPAgesArg */ + unsigned int (*xAutovacPages)(void*,const char*,u32,u32,u32); Parse *pParse; /* Current parse */ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK void *pPreUpdateArg; /* First argument to xPreUpdateCallback */ diff --git a/src/test1.c b/src/test1.c index ceafbe5038..db14a607da 100644 --- a/src/test1.c +++ b/src/test1.c @@ -8233,6 +8233,96 @@ static int SQLITE_TCLAPI test_decode_hexdb( return TCL_OK; } +/* +** Client data for the autovacuum_pages callback. +*/ +struct AutovacPageData { + Tcl_Interp *interp; + char *zScript; +}; +typedef struct AutovacPageData AutovacPageData; + +/* +** Callback functions for sqlite3_autovacuum_pages +*/ +static unsigned int test_autovacuum_pages_callback( + void *pClientData, + const char *zSchema, + unsigned int nFilePages, + unsigned int nFreePages, + unsigned int nBytePerPage +){ + AutovacPageData *pData = (AutovacPageData*)pClientData; + Tcl_DString str; + unsigned int x; + char zBuf[100]; + Tcl_DStringInit(&str); + Tcl_DStringAppend(&str, pData->zScript, -1); + Tcl_DStringAppendElement(&str, zSchema); + sqlite3_snprintf(sizeof(zBuf), zBuf, "%u", nFilePages); + Tcl_DStringAppendElement(&str, zBuf); + sqlite3_snprintf(sizeof(zBuf), zBuf, "%u", nFreePages); + Tcl_DStringAppendElement(&str, zBuf); + sqlite3_snprintf(sizeof(zBuf), zBuf, "%u", nBytePerPage); + Tcl_DStringAppendElement(&str, zBuf); + Tcl_ResetResult(pData->interp); + Tcl_Eval(pData->interp, Tcl_DStringValue(&str)); + Tcl_DStringFree(&str); + x = nFreePages; + (void)Tcl_GetIntFromObj(0, Tcl_GetObjResult(pData->interp), (int*)&x); + return x; +} + +/* +** Usage: sqlite3_autovacuum_pages DB SCRIPT +** +** Add an autovacuum-pages callback to database connection DB. The callback +** will invoke SCRIPT, after appending parameters. +** +** If SCRIPT is an empty string or is omitted, then the callback is +** cancelled. +*/ +static int SQLITE_TCLAPI test_autovacuum_pages( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + AutovacPageData *pData; + sqlite3 *db; + int rc; + const char *zScript; + if( objc!=2 && objc!=3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "DB ?SCRIPT?"); + return TCL_ERROR; + } + if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; + zScript = objc==3 ? Tcl_GetString(objv[2]) : 0; + if( zScript ){ + size_t nScript = strlen(zScript); + pData = sqlite3_malloc64( sizeof(*pData) + nScript + 1 ); + if( pData==0 ){ + Tcl_AppendResult(interp, "out of memory", (void*)0); + return TCL_ERROR; + } + pData->interp = interp; + pData->zScript = (char*)&pData[1]; + memcpy(pData->zScript, zScript, nScript+1); + rc = sqlite3_autovacuum_pages(db,test_autovacuum_pages_callback, + pData, sqlite3_free); + }else{ + rc = sqlite3_autovacuum_pages(db, 0, 0, 0); + } + if( rc ){ + char zBuf[1000]; + sqlite3_snprintf(sizeof(zBuf), zBuf, + "sqlite3_autovacuum_pages() returns %d", rc); + Tcl_AppendResult(interp, zBuf, (void*)0); + return TCL_ERROR; + } + return TCL_OK; +} + /* ** Register commands with the TCL interpreter. @@ -8524,6 +8614,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "atomic_batch_write", test_atomic_batch_write, 0 }, { "sqlite3_mmap_warm", test_mmap_warm, 0 }, { "sqlite3_config_sorterref", test_config_sorterref, 0 }, + { "sqlite3_autovacuum_pages", test_autovacuum_pages, 0 }, { "decode_hexdb", test_decode_hexdb, 0 }, { "test_write_db", test_write_db, 0 }, { "sqlite3_register_cksumvfs", test_register_cksumvfs, 0 }, diff --git a/test/autovacuum.test b/test/autovacuum.test index 431c4b8a2a..245ea8b51d 100644 --- a/test/autovacuum.test +++ b/test/autovacuum.test @@ -9,9 +9,8 @@ # #*********************************************************************** # This file implements regression tests for SQLite library. The -# focus of this file is testing the SELECT statement. +# focus of this file is testing the autovacuum feature. # -# $Id: autovacuum.test,v 1.29 2009/04/06 17:50:03 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl diff --git a/test/autovacuum2.test b/test/autovacuum2.test new file mode 100644 index 0000000000..a3c409839e --- /dev/null +++ b/test/autovacuum2.test @@ -0,0 +1,87 @@ +# 2021-10-15 +# +# 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 implements regression tests for SQLite library. The +# focus of this file is testing the sqlite3_autovacuum_pages() interface +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# If this build of the library does not support auto-vacuum, omit this +# whole file. +ifcapable {!autovacuum || !pragma} { + finish_test + return +} + +# Demonstrate basic sqlite3_autovacuum_pages functionality +# +do_execsql_test autovacuum2-1.0 { + PRAGMA page_size=1024; + PRAGMA auto_vacuum=FULL; + CREATE TABLE t1(x); + VACUUM; + INSERT INTO t1(x) VALUES(zeroblob(10000)); + PRAGMA page_count; +} {12} +proc autovac_page_callback {schema filesize freesize pagesize} { + global autovac_callback_data + lappend autovac_callback_data $schema $filesize $freesize $pagesize + return [expr {$freesize/2}] +} +sqlite3_autovacuum_pages db autovac_page_callback +set autovac_callback_data {} +do_execsql_test autovacuum2-1.1 { + BEGIN; + DELETE FROM t1; + PRAGMA freelist_count; + PRAGMA page_count; +} {9 12} +do_execsql_test autovacuum2-1.2 { + COMMIT; +} {} +do_test autovacuum2-1.3 { + set autovac_callback_data +} {main 12 9 1024} +do_execsql_test autovacuum2-1.4 { + PRAGMA freelist_count; + PRAGMA page_count; +} {5 8} +do_execsql_test autovacuum2-1.5 { + PRAGMA integrity_check; +} {ok} + +# Disable the autovacuum-pages callback. Then do any transaction. +# The database should shrink to minimal size +# +sqlite3_autovacuum_pages db +do_execsql_test autovacuum2-1.10 { + CREATE TABLE t2(x); + PRAGMA freelist_count; +} {0} + +# Rig the autovacuum-pages callback to always return zero. No +# autovacuum will happen. +# +proc autovac_page_callback_off {schema filesize freesize pagesize} { + return 0 +} +sqlite3_autovacuum_pages db autovac_page_callback_off +do_execsql_test autovacuum2-1.20 { + BEGIN; + INSERT INTO t1(x) VALUES(zeroblob(10000)); + DELETE FROM t1; + PRAGMA freelist_count; + COMMIT; + PRAGMA freelist_count; +} {9 9} + +finish_test