]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Break interior-node and leaf-node readers apart in loadSegment().
authorshess <shess@noemail.net>
Fri, 27 Apr 2007 22:02:57 +0000 (22:02 +0000)
committershess <shess@noemail.net>
Fri, 27 Apr 2007 22:02:57 +0000 (22:02 +0000)
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

ext/fts2/fts2.c
manifest
manifest.uuid

index e2e4dbac596505a65a3995174c6b1419e9c5d1a9..b13f252d627d66f534536820dd2197f473cf91ef 100644 (file)
@@ -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;
 
-    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);
-  }
-
-  rc = loadSegmentLeaf(v, pData, nData, pTerm, nTerm, out);
-  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;
+    }
 
-  /* 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 loadSegmentLeaves(v, iBlockid, iBlockid, pTerm, nTerm, out);
   }
-  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 ){
index c1e7fbf99c20fb84e46719d4c2448dcd4271f298..561012ca3477e3fe7f84b3f85996d4cc926d6871 100644 (file)
--- a/manifest
+++ b/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
index a93d1e8ceed7bbcf2dc0938eda5e53631acab239..28127576846426bb18592247a798347e2d65a538 100644 (file)
@@ -1 +1 @@
-ff1f4e744728c8f55afae265246797b30fe98fb0
\ No newline at end of file
+9466367d65f43d58020e709428268dc2ff98aa35
\ No newline at end of file