Break interior-node and leaf-node readers apart in loadSegment().
Previously, the code looped until the block was a leaf node as indicated by a leading NUL. Now the code loops until it finds a block in the range of leaf nodes for this segment, then reads it using LeavesReader. This will make it easier to traverse a range of leaves when doing a prefix search. (CVS 3884) FossilOrigin-Name: 9466367d65f43d58020e709428268dc2ff98aa35
This commit is contained in:
parent
d1e3a616ca
commit
8ffcadb57e
134
ext/fts2/fts2.c
134
ext/fts2/fts2.c
@ -1634,7 +1634,8 @@ static const char *const fulltext_zStatement[MAX_STMT] = {
|
||||
"select min(start_block), max(end_block) from %_segdir "
|
||||
" where level = ? and start_block <> 0",
|
||||
/* SEGDIR_DELETE */ "delete from %_segdir where level = ?",
|
||||
/* SEGDIR_SELECT_ALL */ "select root from %_segdir order by level desc, idx",
|
||||
/* SEGDIR_SELECT_ALL */
|
||||
"select root, leaves_end_block from %_segdir order by level desc, idx",
|
||||
};
|
||||
|
||||
/*
|
||||
@ -4807,6 +4808,23 @@ static int leavesReaderAtEnd(LeavesReader *pReader){
|
||||
return pReader->eof;
|
||||
}
|
||||
|
||||
/* loadSegmentLeaves() may not read all the way to SQLITE_DONE, thus
|
||||
** leaving the statement handle open, which locks the table.
|
||||
*/
|
||||
/* TODO(shess) This "solution" is not satisfactory. Really, there
|
||||
** should be check-in function for all statement handles which
|
||||
** arranges to call sqlite3_reset(). This most likely will require
|
||||
** modification to control flow all over the place, though, so for now
|
||||
** just punt.
|
||||
**
|
||||
** Note the the current system assumes that segment merges will run to
|
||||
** completion, which is why this particular probably hasn't arisen in
|
||||
** this case. Probably a brittle assumption.
|
||||
*/
|
||||
static int leavesReaderReset(LeavesReader *pReader){
|
||||
return sqlite3_reset(pReader->pStmt);
|
||||
}
|
||||
|
||||
static void leavesReaderDestroy(LeavesReader *pReader){
|
||||
leafReaderDestroy(&pReader->leafReader);
|
||||
dataBufferDestroy(&pReader->rootData);
|
||||
@ -5133,6 +5151,25 @@ static int loadSegmentLeaf(fulltext_vtab *v, const char *pData, int nData,
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
rc = loadSegmentLeavesInt(v, &reader, pTerm, nTerm, out);
|
||||
leavesReaderReset(&reader);
|
||||
leavesReaderDestroy(&reader);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Call loadSegmentLeavesInt() with the leaf nodes from iStartLeaf to
|
||||
** iEndLeaf (inclusive) as input, and merge the resulting doclist into
|
||||
** out.
|
||||
*/
|
||||
static int loadSegmentLeaves(fulltext_vtab *v,
|
||||
sqlite_int64 iStartLeaf, sqlite_int64 iEndLeaf,
|
||||
const char *pTerm, int nTerm,
|
||||
DataBuffer *out){
|
||||
LeavesReader reader;
|
||||
int rc = leavesReaderInit(v, 0, iStartLeaf, iEndLeaf, NULL, 0, &reader);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
rc = loadSegmentLeavesInt(v, &reader, pTerm, nTerm, out);
|
||||
leavesReaderReset(&reader);
|
||||
leavesReaderDestroy(&reader);
|
||||
return rc;
|
||||
}
|
||||
@ -5143,9 +5180,9 @@ static int loadSegmentLeaf(fulltext_vtab *v, const char *pData, int nData,
|
||||
** than there are terms (that block contains terms >= the last
|
||||
** interior-node term).
|
||||
*/
|
||||
static void getNextChild(const char *pData, int nData,
|
||||
const char *pTerm, int nTerm,
|
||||
sqlite_int64 *piBlockid){
|
||||
static void getChildContaining(const char *pData, int nData,
|
||||
const char *pTerm, int nTerm,
|
||||
sqlite_int64 *piBlockid){
|
||||
InteriorReader reader;
|
||||
|
||||
assert( nData>1 );
|
||||
@ -5161,53 +5198,74 @@ static void getNextChild(const char *pData, int nData,
|
||||
interiorReaderDestroy(&reader);
|
||||
}
|
||||
|
||||
/* Read block at iBlockid and pass it with other params to
|
||||
** getChildContaining().
|
||||
*/
|
||||
static int loadAndGetChildContaining(fulltext_vtab *v, sqlite_int64 iBlockid,
|
||||
const char *pTerm, int nTerm,
|
||||
sqlite_int64 *piBlockid){
|
||||
sqlite3_stmt *s = NULL;
|
||||
int rc;
|
||||
|
||||
assert( iBlockid!=0 );
|
||||
assert( pTerm!=NULL );
|
||||
assert( nTerm!=0 ); /* TODO(shess) Why not allow this? */
|
||||
assert( piBlockid!=NULL );
|
||||
|
||||
rc = sql_get_statement(v, BLOCK_SELECT_STMT, &s);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
rc = sqlite3_bind_int64(s, 1, iBlockid);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
rc = sql_step_statement(v, BLOCK_SELECT_STMT, &s);
|
||||
if( rc==SQLITE_DONE ) return SQLITE_ERROR;
|
||||
if( rc!=SQLITE_ROW ) return rc;
|
||||
|
||||
getChildContaining(sqlite3_column_blob(s, 0), sqlite3_column_bytes(s, 0),
|
||||
pTerm, nTerm, piBlockid);
|
||||
|
||||
/* We expect only one row. We must execute another sqlite3_step()
|
||||
* to complete the iteration; otherwise the table will remain
|
||||
* locked. */
|
||||
rc = sqlite3_step(s);
|
||||
if( rc==SQLITE_ROW ) return SQLITE_ERROR;
|
||||
if( rc!=SQLITE_DONE ) return rc;
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Traverse the tree represented by pData[nData] looking for
|
||||
** pTerm[nTerm], merging its doclist over *out if found (any duplicate
|
||||
** doclists read from the segment rooted at pData will overwrite those
|
||||
** in *out).
|
||||
*/
|
||||
static int loadSegment(fulltext_vtab *v, const char *pData, int nData,
|
||||
sqlite_int64 iLeavesEnd,
|
||||
const char *pTerm, int nTerm, DataBuffer *out){
|
||||
int rc;
|
||||
sqlite3_stmt *s = NULL;
|
||||
|
||||
assert( nData>1 );
|
||||
|
||||
/* This code should never be called with buffered updates. */
|
||||
assert( v->nPendingData<0 );
|
||||
|
||||
/* Process data as an interior node until we reach a leaf. */
|
||||
while( *pData!='\0' ){
|
||||
/* Special case where root is a leaf. */
|
||||
if( *pData=='\0' ){
|
||||
return loadSegmentLeaf(v, pData, nData, pTerm, nTerm, out);
|
||||
}else{
|
||||
int rc;
|
||||
sqlite_int64 iBlockid;
|
||||
getNextChild(pData, nData, pTerm, nTerm, &iBlockid);
|
||||
|
||||
rc = sql_get_statement(v, BLOCK_SELECT_STMT, &s);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
/* Process pData as an interior node, then loop down the tree
|
||||
** until we find a leaf node to scan for the term.
|
||||
*/
|
||||
getChildContaining(pData, nData, pTerm, nTerm, &iBlockid);
|
||||
while( iBlockid>iLeavesEnd ){
|
||||
rc = loadAndGetChildContaining(v, iBlockid, pTerm, nTerm, &iBlockid);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
}
|
||||
|
||||
rc = sqlite3_bind_int64(s, 1, iBlockid);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
rc = sql_step_statement(v, BLOCK_SELECT_STMT, &s);
|
||||
if( rc==SQLITE_DONE ) return SQLITE_ERROR;
|
||||
if( rc!=SQLITE_ROW ) return rc;
|
||||
|
||||
pData = sqlite3_column_blob(s, 0);
|
||||
nData = sqlite3_column_bytes(s, 0);
|
||||
return loadSegmentLeaves(v, iBlockid, iBlockid, pTerm, nTerm, out);
|
||||
}
|
||||
|
||||
rc = loadSegmentLeaf(v, pData, nData, pTerm, nTerm, out);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
/* If we selected a child node, we need to finish that select. */
|
||||
if( s!=NULL ){
|
||||
/* We expect only one row. We must execute another sqlite3_step()
|
||||
* to complete the iteration; otherwise the table will remain
|
||||
* locked. */
|
||||
rc = sqlite3_step(s);
|
||||
if( rc==SQLITE_ROW ) return SQLITE_ERROR;
|
||||
if( rc!=SQLITE_DONE ) return rc;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Scan the database and merge together the posting lists for the term
|
||||
@ -5230,8 +5288,10 @@ static int termSelect(fulltext_vtab *v, int iColumn,
|
||||
** elements for given docids overwrite older elements.
|
||||
*/
|
||||
while( (rc=sql_step_statement(v, SEGDIR_SELECT_ALL_STMT, &s))==SQLITE_ROW ){
|
||||
rc = loadSegment(v, sqlite3_column_blob(s, 0), sqlite3_column_bytes(s, 0),
|
||||
pTerm, nTerm, &doclist);
|
||||
const char *pData = sqlite3_column_blob(s, 0);
|
||||
const int nData = sqlite3_column_bytes(s, 0);
|
||||
const sqlite_int64 iLeavesEnd = sqlite3_column_int64(s, 1);
|
||||
rc = loadSegment(v, pData, nData, iLeavesEnd, pTerm, nTerm, &doclist);
|
||||
if( rc!=SQLITE_OK ) goto err;
|
||||
}
|
||||
if( rc==SQLITE_DONE ){
|
||||
|
14
manifest
14
manifest
@ -1,5 +1,5 @@
|
||||
C Internationalize\sthe\sTRIM\sfunctions.\s\sTicket\s#2323.\s(CVS\s3883)
|
||||
D 2007-04-27T21:59:53
|
||||
C Break\sinterior-node\sand\sleaf-node\sreaders\sapart\sin\sloadSegment().\nPreviously,\sthe\scode\slooped\suntil\sthe\sblock\swas\sa\sleaf\snode\sas\nindicated\sby\sa\sleading\sNUL.\s\sNow\sthe\scode\sloops\suntil\sit\sfinds\sa\sblock\nin\sthe\srange\sof\sleaf\snodes\sfor\sthis\ssegment,\sthen\sreads\sit\susing\nLeavesReader.\s\sThis\swill\smake\sit\seasier\sto\straverse\sa\srange\sof\sleaves\nwhen\sdoing\sa\sprefix\ssearch.\s(CVS\s3884)
|
||||
D 2007-04-27T22:02:58
|
||||
F Makefile.in 8cab54f7c9f5af8f22fd97ddf1ecfd1e1860de62
|
||||
F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
|
||||
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
|
||||
@ -34,7 +34,7 @@ F ext/fts1/fulltext.h 08525a47852d1d62a0be81d3fc3fe2d23b094efd
|
||||
F ext/fts1/simple_tokenizer.c 1844d72f7194c3fd3d7e4173053911bf0661b70d
|
||||
F ext/fts1/tokenizer.h 0c53421b832366d20d720d21ea3e1f6e66a36ef9
|
||||
F ext/fts2/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
|
||||
F ext/fts2/fts2.c c1e7528d9f49f1c982bb0b75f262b115a508d140
|
||||
F ext/fts2/fts2.c b45e07a23646e82525657af9bab063e10f9acffc
|
||||
F ext/fts2/fts2.h 591916a822cfb6426518fdbf6069359119bc46eb
|
||||
F ext/fts2/fts2_hash.c b3f22116d4ef0bc8f2da6e3fdc435c86d0951a9b
|
||||
F ext/fts2/fts2_hash.h e283308156018329f042816eb09334df714e105e
|
||||
@ -464,7 +464,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
|
||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
||||
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
||||
P 25935db73877c0cb132acb30c2fed2544d0e5e32
|
||||
R fdd67fb21752d8fbe0a5631485c66773
|
||||
U drh
|
||||
Z dbf7b152ffcec38cc7febead2efd96a3
|
||||
P ff1f4e744728c8f55afae265246797b30fe98fb0
|
||||
R 99c2fc3fe139fed22b3873b01510508d
|
||||
U shess
|
||||
Z 5fe07eef28bba3b5b8361756bba83b2b
|
||||
|
@ -1 +1 @@
|
||||
ff1f4e744728c8f55afae265246797b30fe98fb0
|
||||
9466367d65f43d58020e709428268dc2ff98aa35
|
Loading…
Reference in New Issue
Block a user