blob: eeb1db0c366e4038a2d6b0c96b48911e12db4808 [file] [log] [blame]
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Scott Hess <shess@chromium.org>
Date: Thu, 2 Mar 2017 15:23:09 -0800
Subject: [PATCH 09/10] Allow auto-vacuum to work with chunks.
SQLITE_FCNTL_CHUNK_SIZE can advise the VFS to resize files in quantum
amounts, to reduce fragmentation from tiny appends. This change allows
a new PRAGMA auto_vacuum_slack_pages to provide auto_vacuum with a hint
to only rearrange pages when an entire quantum can be released.
When rebasing this patch, first ignore the conflicts in src/pragma.h,
and fix all the other conflicts. Then run the commands below (in
third_party/sqlite) to re-generate src/pragma.h.
tclsh src/tool/mkpragmatab.tcl
find src/ -type f -iname "*.h" -exec \
$GNU_SED --in-place 's/[[:space:]]\+$//' {} \+
BUG=698010
---
third_party/sqlite/src/src/btree.c | 56 +++++++++++-
third_party/sqlite/src/src/btree.h | 2 +
third_party/sqlite/src/src/btreeInt.h | 1 +
third_party/sqlite/src/src/pragma.c | 21 +++++
third_party/sqlite/src/src/pragma.h | 96 +++++++++++----------
third_party/sqlite/src/tool/mkpragmatab.tcl | 4 +
6 files changed, 134 insertions(+), 46 deletions(-)
diff --git a/third_party/sqlite/src/src/btree.c b/third_party/sqlite/src/src/btree.c
index b125859bf570..3fa8f88f1465 100644
--- a/third_party/sqlite/src/src/btree.c
+++ b/third_party/sqlite/src/src/btree.c
@@ -2980,6 +2980,46 @@ static void setDefaultSyncFlag(BtShared *pBt, u8 safety_level){
static int newDatabase(BtShared*);
+/*
+** Change the 'auto-vacuum-slack-pages' property of the database. If auto vacuum
+** is enabled, this is the number of chunks of slack to allow before
+** automatically running an incremental vacuum.
+*/
+int sqlite3BtreeSetAutoVacuumSlackPages(Btree *p, int autoVacuumSlack){
+#ifdef SQLITE_OMIT_AUTOVACUUM
+ return SQLITE_READONLY;
+#else
+ BtShared *pBt = p->pBt;
+ int rc = SQLITE_OK;
+ u8 avs = (u8)autoVacuumSlack;
+ if( autoVacuumSlack>avs ){
+ avs = 0xFF;
+ }
+
+ sqlite3BtreeEnter(p);
+ pBt->autoVacuumSlack = avs;
+ sqlite3BtreeLeave(p);
+ return rc;
+#endif
+}
+
+/*
+** Return the value of the 'auto-vacuum-slack-pages' property.
+*/
+int sqlite3BtreeGetAutoVacuumSlackPages(Btree *p){
+#ifdef SQLITE_OMIT_AUTOVACUUM
+ return 0;
+#else
+ int rc = 0;
+ sqlite3BtreeEnter(p);
+ if( p->pBt->autoVacuum!=0 ){
+ rc = p->pBt->autoVacuumSlack;
+ }
+ sqlite3BtreeLeave(p);
+ return rc;
+#endif
+}
+
/*
** Get a reference to pPage1 of the database file. This will
** also acquire a readlock on that file.
@@ -3828,13 +3868,27 @@ int sqlite3BtreeIncrVacuum(Btree *p){
*/
static int autoVacuumCommit(BtShared *pBt){
int rc = SQLITE_OK;
+ int bShouldVacuum = pBt->autoVacuum && !pBt->incrVacuum;
Pager *pPager = pBt->pPager;
VVA_ONLY( int nRef = sqlite3PagerRefcount(pPager); )
assert( sqlite3_mutex_held(pBt->mutex) );
invalidateAllOverflowCache(pBt);
assert(pBt->autoVacuum);
- if( !pBt->incrVacuum ){
+ if( bShouldVacuum && pBt->autoVacuumSlack ){
+ Pgno nOrig; /* Database size before freeing */
+ Pgno nFree; /* Number of pages on the freelist initially */
+
+ nOrig = btreePagecount(pBt);
+ nFree = get4byte(&pBt->pPage1->aData[36]);
+ bShouldVacuum =
+ (nOrig-nFree-1)/pBt->autoVacuumSlack < (nOrig-1)/pBt->autoVacuumSlack;
+ /* TODO: When integrating this test with the following code, contrive to
+ ** trim to the integral chunk boundary, rather than trimming the entire free
+ ** list.
+ */
+ }
+ if( bShouldVacuum ){
Pgno nFin; /* Number of pages in database after autovacuuming */
Pgno nFree; /* Number of pages on the freelist initially */
Pgno iFree; /* The next page to be freed */
diff --git a/third_party/sqlite/src/src/btree.h b/third_party/sqlite/src/src/btree.h
index e4bd09c7e727..b360be3f21de 100644
--- a/third_party/sqlite/src/src/btree.h
+++ b/third_party/sqlite/src/src/btree.h
@@ -78,6 +78,8 @@ int sqlite3BtreeGetOptimalReserve(Btree*);
int sqlite3BtreeGetReserveNoMutex(Btree *p);
int sqlite3BtreeSetAutoVacuum(Btree *, int);
int sqlite3BtreeGetAutoVacuum(Btree *);
+int sqlite3BtreeSetAutoVacuumSlackPages(Btree*, int);
+int sqlite3BtreeGetAutoVacuumSlackPages(Btree*);
int sqlite3BtreeBeginTrans(Btree*,int,int*);
int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
int sqlite3BtreeCommitPhaseTwo(Btree*, int);
diff --git a/third_party/sqlite/src/src/btreeInt.h b/third_party/sqlite/src/src/btreeInt.h
index 8fe8e280fe5f..88f3b437b8ea 100644
--- a/third_party/sqlite/src/src/btreeInt.h
+++ b/third_party/sqlite/src/src/btreeInt.h
@@ -412,6 +412,7 @@ struct BtShared {
u8 openFlags; /* Flags to sqlite3BtreeOpen() */
#ifndef SQLITE_OMIT_AUTOVACUUM
u8 autoVacuum; /* True if auto-vacuum is enabled */
+ u8 autoVacuumSlack; /* Optional pages of slack for auto-vacuum */
u8 incrVacuum; /* True if incr-vacuum is enabled */
u8 bDoTruncate; /* True to truncate db on commit */
#endif
diff --git a/third_party/sqlite/src/src/pragma.c b/third_party/sqlite/src/src/pragma.c
index 6e026557d561..472fca7ee699 100644
--- a/third_party/sqlite/src/src/pragma.c
+++ b/third_party/sqlite/src/src/pragma.c
@@ -756,6 +756,27 @@ void sqlite3Pragma(
}
#endif
+ /*
+ ** PRAGMA [schema.]auto_vacuum_slack_pages(N)
+ **
+ ** Control chunk size of auto-vacuum.
+ */
+#ifndef SQLITE_OMIT_AUTOVACUUM
+ case PragTyp_AUTO_VACUUM_SLACK_PAGES: {
+ Btree *pBt = pDb->pBt;
+ assert( pBt!=0 );
+ if( !zRight ){
+ returnSingleInt(v, sqlite3BtreeGetAutoVacuumSlackPages(pBt));
+ }else{
+ int nPages = 8;
+ if( sqlite3GetInt32(zRight, &nPages) ){
+ sqlite3BtreeSetAutoVacuumSlackPages(pBt, nPages);
+ }
+ }
+ break;
+ }
+#endif
+
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
/*
** PRAGMA [schema.]cache_size
diff --git a/third_party/sqlite/src/src/pragma.h b/third_party/sqlite/src/src/pragma.h
index 826516202e41..970092f1cd8d 100644
--- a/third_party/sqlite/src/src/pragma.h
+++ b/third_party/sqlite/src/src/pragma.h
@@ -7,51 +7,52 @@
/* The various pragma types */
#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_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_FUNCTION_LIST 15
-#define PragTyp_INCREMENTAL_VACUUM 16
-#define PragTyp_INDEX_INFO 17
-#define PragTyp_INDEX_LIST 18
-#define PragTyp_INTEGRITY_CHECK 19
-#define PragTyp_JOURNAL_MODE 20
-#define PragTyp_JOURNAL_SIZE_LIMIT 21
-#define PragTyp_LOCK_PROXY_FILE 22
-#define PragTyp_LOCKING_MODE 23
-#define PragTyp_PAGE_COUNT 24
-#define PragTyp_MMAP_SIZE 25
-#define PragTyp_MODULE_LIST 26
-#define PragTyp_OPTIMIZE 27
-#define PragTyp_PAGE_SIZE 28
-#define PragTyp_PRAGMA_LIST 29
-#define PragTyp_SECURE_DELETE 30
-#define PragTyp_SHRINK_MEMORY 31
-#define PragTyp_SOFT_HEAP_LIMIT 32
-#define PragTyp_SYNCHRONOUS 33
-#define PragTyp_TABLE_INFO 34
-#define PragTyp_TEMP_STORE 35
-#define PragTyp_TEMP_STORE_DIRECTORY 36
-#define PragTyp_THREADS 37
-#define PragTyp_WAL_AUTOCHECKPOINT 38
-#define PragTyp_WAL_CHECKPOINT 39
-#define PragTyp_ACTIVATE_EXTENSIONS 40
-#define PragTyp_HEXKEY 41
-#define PragTyp_KEY 42
-#define PragTyp_REKEY 43
-#define PragTyp_LOCK_STATUS 44
-#define PragTyp_PARSER_TRACE 45
-#define PragTyp_STATS 46
+#define PragTyp_AUTO_VACUUM_SLACK_PAGES 2
+#define PragTyp_FLAG 3
+#define PragTyp_BUSY_TIMEOUT 4
+#define PragTyp_CACHE_SIZE 5
+#define PragTyp_CACHE_SPILL 6
+#define PragTyp_CASE_SENSITIVE_LIKE 7
+#define PragTyp_COLLATION_LIST 8
+#define PragTyp_COMPILE_OPTIONS 9
+#define PragTyp_DATA_STORE_DIRECTORY 10
+#define PragTyp_DATABASE_LIST 11
+#define PragTyp_DEFAULT_CACHE_SIZE 12
+#define PragTyp_ENCODING 13
+#define PragTyp_FOREIGN_KEY_CHECK 14
+#define PragTyp_FOREIGN_KEY_LIST 15
+#define PragTyp_FUNCTION_LIST 16
+#define PragTyp_INCREMENTAL_VACUUM 17
+#define PragTyp_INDEX_INFO 18
+#define PragTyp_INDEX_LIST 19
+#define PragTyp_INTEGRITY_CHECK 20
+#define PragTyp_JOURNAL_MODE 21
+#define PragTyp_JOURNAL_SIZE_LIMIT 22
+#define PragTyp_LOCK_PROXY_FILE 23
+#define PragTyp_LOCKING_MODE 24
+#define PragTyp_PAGE_COUNT 25
+#define PragTyp_MMAP_SIZE 26
+#define PragTyp_MODULE_LIST 27
+#define PragTyp_OPTIMIZE 28
+#define PragTyp_PAGE_SIZE 29
+#define PragTyp_PRAGMA_LIST 30
+#define PragTyp_SECURE_DELETE 31
+#define PragTyp_SHRINK_MEMORY 32
+#define PragTyp_SOFT_HEAP_LIMIT 33
+#define PragTyp_SYNCHRONOUS 34
+#define PragTyp_TABLE_INFO 35
+#define PragTyp_TEMP_STORE 36
+#define PragTyp_TEMP_STORE_DIRECTORY 37
+#define PragTyp_THREADS 38
+#define PragTyp_WAL_AUTOCHECKPOINT 39
+#define PragTyp_WAL_CHECKPOINT 40
+#define PragTyp_ACTIVATE_EXTENSIONS 41
+#define PragTyp_HEXKEY 42
+#define PragTyp_KEY 43
+#define PragTyp_REKEY 44
+#define PragTyp_LOCK_STATUS 45
+#define PragTyp_PARSER_TRACE 46
+#define PragTyp_STATS 47
/* Property flags associated with various pragma. */
#define PragFlg_NeedSchema 0x01 /* Force schema load before running */
@@ -152,6 +153,11 @@ static const PragmaName aPragmaName[] = {
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
/* ColNames: */ 0, 0,
/* iArg: */ 0 },
+ {/* zName: */ "auto_vacuum_slack_pages",
+ /* ePragTyp: */ PragTyp_AUTO_VACUUM_SLACK_PAGES,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if !defined(SQLITE_OMIT_AUTOMATIC_INDEX)
diff --git a/third_party/sqlite/src/tool/mkpragmatab.tcl b/third_party/sqlite/src/tool/mkpragmatab.tcl
index 83a85db9d6fd..6ed2dfc8e846 100644
--- a/third_party/sqlite/src/tool/mkpragmatab.tcl
+++ b/third_party/sqlite/src/tool/mkpragmatab.tcl
@@ -387,6 +387,10 @@ set pragma_def {
TYPE: FLAG
ARG: SQLITE_LegacyAlter
IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS)
+
+ NAME: auto_vacuum_slack_pages
+ FLAG: NeedSchema Result0 SchemaReq NoColumns1
+ IF: !defined(SQLITE_OMIT_AUTOVACUUM)
}
# Open the output file
--
2.19.0