1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-01 06:27:03 +03:00

Add an incremental optimize capability to fts5. Make the 'merge' command independent of the 'automerge' settings.

FossilOrigin-Name: 556671444c03e3afca072d0f5e9bea2657de6fd3
This commit is contained in:
dan
2016-03-09 20:54:14 +00:00
parent 57ebc84a6e
commit 4dbc65b29a
10 changed files with 213 additions and 69 deletions

View File

@ -4179,13 +4179,17 @@ static void fts5IndexMergeLevel(
/*
** Do up to nPg pages of automerge work on the index.
**
** Return true if any changes were actually made, or false otherwise.
*/
static void fts5IndexMerge(
static int fts5IndexMerge(
Fts5Index *p, /* FTS5 backend object */
Fts5Structure **ppStruct, /* IN/OUT: Current structure of index */
int nPg /* Pages of work to do */
int nPg, /* Pages of work to do */
int nMin /* Minimum number of segments to merge */
){
int nRem = nPg;
int bRet = 0;
Fts5Structure *pStruct = *ppStruct;
while( nRem>0 && p->rc==SQLITE_OK ){
int iLvl; /* To iterate through levels */
@ -4216,17 +4220,17 @@ static void fts5IndexMerge(
}
#endif
if( nBest<p->pConfig->nAutomerge
&& pStruct->aLevel[iBestLvl].nMerge==0
){
if( nBest<nMin && pStruct->aLevel[iBestLvl].nMerge==0 ){
break;
}
bRet = 1;
fts5IndexMergeLevel(p, &pStruct, iBestLvl, &nRem);
if( p->rc==SQLITE_OK && pStruct->aLevel[iBestLvl].nMerge==0 ){
fts5StructurePromote(p, iBestLvl+1, pStruct);
}
}
*ppStruct = pStruct;
return bRet;
}
/*
@ -4254,7 +4258,7 @@ static void fts5IndexAutomerge(
pStruct->nWriteCounter += nLeaf;
nRem = (int)(p->nWorkUnit * nWork * pStruct->nLevel);
fts5IndexMerge(p, ppStruct, nRem);
fts5IndexMerge(p, ppStruct, nRem, p->pConfig->nAutomerge);
}
}
@ -4474,25 +4478,38 @@ static void fts5IndexFlush(Fts5Index *p){
}
}
int sqlite3Fts5IndexOptimize(Fts5Index *p){
Fts5Structure *pStruct;
static Fts5Structure *fts5IndexOptimizeStruct(
Fts5Index *p,
Fts5Structure *pStruct
){
Fts5Structure *pNew = 0;
int nSeg = 0;
int nByte = sizeof(Fts5Structure);
int nSeg = pStruct->nSegment;
int i;
assert( p->rc==SQLITE_OK );
fts5IndexFlush(p);
pStruct = fts5StructureRead(p);
if( pStruct ){
assert( pStruct->nSegment==fts5StructureCountSegments(pStruct) );
nSeg = pStruct->nSegment;
if( nSeg>1 ){
int nByte = sizeof(Fts5Structure);
nByte += (pStruct->nLevel+1) * sizeof(Fts5StructureLevel);
pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte);
/* Figure out if this structure requires optimization. A structure does
** not require optimization if either:
**
** + it consists of fewer than two segments, or
** + all segments are on the same level, or
** + all segments except one are currently inputs to a merge operation.
**
** In the first case, return NULL. In the second, increment the ref-count
** on *pStruct and return a copy of the pointer to it.
*/
if( nSeg<2 ) return 0;
for(i=0; i<pStruct->nLevel; i++){
int nThis = pStruct->aLevel[i].nSeg;
if( nThis==nSeg || (nThis==nSeg-1 && pStruct->aLevel[i].nMerge==nThis) ){
fts5StructureRef(pStruct);
return pStruct;
}
assert( pStruct->aLevel[i].nMerge<=nThis );
}
nByte += (pStruct->nLevel+1) * sizeof(Fts5StructureLevel);
pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte);
if( pNew ){
Fts5StructureLevel *pLvl;
int nByte = nSeg * sizeof(Fts5StructureSegment);
@ -4520,8 +4537,28 @@ int sqlite3Fts5IndexOptimize(Fts5Index *p){
}
}
if( pNew ){
int iLvl = pNew->nLevel-1;
return pNew;
}
int sqlite3Fts5IndexOptimize(Fts5Index *p){
Fts5Structure *pStruct;
Fts5Structure *pNew = 0;
int nSeg = 0;
assert( p->rc==SQLITE_OK );
fts5IndexFlush(p);
pStruct = fts5StructureRead(p);
if( pStruct ){
pNew = fts5IndexOptimizeStruct(p, pStruct);
}
fts5StructureRelease(pStruct);
if( pNew && pNew->nSegment>0 ){
int iLvl;
for(iLvl=0; iLvl<pNew->nLevel; iLvl++){
if( pNew->aLevel[iLvl].nSeg ) break;
}
while( p->rc==SQLITE_OK && pNew->aLevel[iLvl].nSeg>0 ){
int nRem = FTS5_OPT_WORK_UNIT;
fts5IndexMergeLevel(p, &pNew, iLvl, &nRem);
@ -4531,20 +4568,31 @@ int sqlite3Fts5IndexOptimize(Fts5Index *p){
fts5StructureRelease(pNew);
}
fts5StructureRelease(pStruct);
return fts5IndexReturn(p);
}
/*
** This is called to implement the special "VALUES('merge', $nMerge)"
** INSERT command.
*/
int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){
Fts5Structure *pStruct;
pStruct = fts5StructureRead(p);
if( pStruct && pStruct->nLevel ){
fts5IndexMerge(p, &pStruct, nMerge);
fts5StructureWrite(p, pStruct);
Fts5Structure *pStruct = fts5StructureRead(p);
if( pStruct ){
int nMin = p->pConfig->nUsermerge;
if( nMerge<0 ){
Fts5Structure *pNew = fts5IndexOptimizeStruct(p, pStruct);
fts5StructureRelease(pStruct);
pStruct = pNew;
nMin = 2;
nMerge = nMerge*-1;
}
if( pStruct && pStruct->nLevel ){
if( fts5IndexMerge(p, &pStruct, nMerge, nMin) ){
fts5StructureWrite(p, pStruct);
}
}
fts5StructureRelease(pStruct);
}
fts5StructureRelease(pStruct);
return fts5IndexReturn(p);
}