1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Reduce the number of calls to malloc() made by fts5.

FossilOrigin-Name: 898618ccf61d3ad166d9fc742e132d518338b5c3
This commit is contained in:
dan
2015-07-09 19:02:19 +00:00
parent a90579db99
commit 3dbd2397f4
8 changed files with 99 additions and 48 deletions

View File

@@ -36,6 +36,7 @@ typedef sqlite3_uint64 u64;
#define NEVER(x) 0
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
#define MAX(x,y) (((x) > (y)) ? (x) : (y))
#endif

View File

@@ -605,6 +605,21 @@ struct Fts5BtreeIter {
};
/*
** The first argument passed to this macro is a pointer to an Fts5Buffer
** object.
*/
#define fts5BufferSize(pBuf,n) { \
if( pBuf->nSpace<n ) { \
u8 *pNew = sqlite3_realloc(pBuf->p, n); \
if( pNew==0 ){ \
sqlite3_free(pBuf->p); \
} \
pBuf->nSpace = n; \
pBuf->p = pNew; \
} \
}
static void fts5PutU16(u8 *aOut, u16 iVal){
aOut[0] = (iVal>>8);
aOut[1] = (iVal&0xFF);
@@ -724,16 +739,20 @@ static Fts5Data *fts5DataReadOrBuffer(
u8 *aOut; /* Read blob data into this buffer */
int nByte = sqlite3_blob_bytes(p->pReader);
if( pBuf ){
fts5BufferZero(pBuf);
fts5BufferGrow(&rc, pBuf, nByte);
aOut = pBuf->p;
fts5BufferSize(pBuf, MAX(nByte, p->pConfig->pgsz) + 20);
pBuf->n = nByte;
aOut = pBuf->p;
if( aOut==0 ){
rc = SQLITE_NOMEM;
}
}else{
int nSpace = nByte + FTS5_DATA_ZERO_PADDING;
pRet = (Fts5Data*)sqlite3Fts5MallocZero(&rc, nSpace+sizeof(Fts5Data));
pRet = (Fts5Data*)sqlite3_malloc(nSpace+sizeof(Fts5Data));
if( pRet ){
pRet->n = nByte;
aOut = pRet->p = (u8*)&pRet[1];
}else{
rc = SQLITE_NOMEM;
}
}
@@ -1019,18 +1038,20 @@ static void fts5StructureExtendLevel(
static Fts5Structure *fts5StructureRead(Fts5Index *p){
Fts5Config *pConfig = p->pConfig;
Fts5Structure *pRet = 0; /* Object to return */
Fts5Data *pData; /* %_data entry containing structure record */
int iCookie; /* Configuration cookie */
Fts5Buffer buf = {0, 0, 0};
pData = fts5DataRead(p, FTS5_STRUCTURE_ROWID);
if( !pData ) return 0;
p->rc = fts5StructureDecode(pData->p, pData->n, &iCookie, &pRet);
fts5DataBuffer(p, &buf, FTS5_STRUCTURE_ROWID);
if( buf.p==0 ) return 0;
assert( buf.nSpace>=(buf.n + FTS5_DATA_ZERO_PADDING) );
memset(&buf.p[buf.n], 0, FTS5_DATA_ZERO_PADDING);
p->rc = fts5StructureDecode(buf.p, buf.n, &iCookie, &pRet);
if( p->rc==SQLITE_OK && pConfig->iCookie!=iCookie ){
p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie);
}
fts5DataRelease(pData);
fts5BufferFree(&buf);
if( p->rc!=SQLITE_OK ){
fts5StructureRelease(pRet);
pRet = 0;
@@ -2028,7 +2049,7 @@ static void fts5SegIterLoadDlidx(Fts5Index *p, Fts5SegIter *pIter){
#ifdef SQLITE_DEBUG
static void fts5AssertNodeSeekOk(
Fts5Data *pNode,
Fts5Buffer *pNode,
const u8 *pTerm, int nTerm, /* Term to search for */
int iExpectPg,
int bExpectDlidx
@@ -2070,7 +2091,7 @@ static void fts5AssertNodeSeekOk(
** returned child page number has a doclist-index. Or left as is otherwise.
*/
static int fts5NodeSeek(
Fts5Data *pNode, /* Node to search */
Fts5Buffer *pNode, /* Node to search */
const u8 *pTerm, int nTerm, /* Term to search for */
int *pbDlidx /* OUT: True if dlidx flag is set */
){
@@ -2094,6 +2115,7 @@ static int fts5NodeSeek(
*pbDlidx = (*pPtr==0x01);
pPtr++;
pPtr += fts5GetVarint32(pPtr, nEmpty);
if( pPtr>=pEnd ) break;
}
/* Read the next "term" pointer. Set nKeep to the number of bytes to
@@ -2230,7 +2252,10 @@ static void fts5LeafSeek(
/* Skip past position list */
fts5IndexGetVarint32(a, iOff, nPos);
iOff += (nPos >> 1);
if( iOff>=n ) goto search_failed;
if( iOff>=(n-1) ){
iOff = n;
goto search_failed;
}
/* If this is the end of the doclist, break out of the loop */
if( a[iOff]==0x00 ){
@@ -2287,6 +2312,7 @@ static void fts5LeafSeek(
*/
static void fts5SegIterSeekInit(
Fts5Index *p, /* FTS5 backend */
Fts5Buffer *pBuf, /* Buffer to use for loading pages */
const u8 *pTerm, int nTerm, /* Term to seek to */
int flags, /* Mask of FTS5INDEX_XXX flags */
Fts5StructureSegment *pSeg, /* Description of segment */
@@ -2298,6 +2324,9 @@ static void fts5SegIterSeekInit(
int bDlidx = 0; /* True if there is a doclist-index */
Fts5Data *pLeaf;
static int nCall = 0;
nCall++;
assert( bGe==0 || (flags & FTS5INDEX_QUERY_DESC)==0 );
assert( pTerm && nTerm );
memset(pIter, 0, sizeof(*pIter));
@@ -2307,11 +2336,9 @@ static void fts5SegIterSeekInit(
** contain term (pTerm/nTerm), if it is present in the segment. */
for(h=pSeg->nHeight-1; h>0; h--){
i64 iRowid = FTS5_SEGMENT_ROWID(pSeg->iSegid, h, iPg);
Fts5Data *pNode = fts5DataRead(p, iRowid);
if( pNode==0 ) break;
iPg = fts5NodeSeek(pNode, pTerm, nTerm, &bDlidx);
fts5DataRelease(pNode);
fts5DataBuffer(p, pBuf, iRowid);
if( p->rc ) break;
iPg = fts5NodeSeek(pBuf, pTerm, nTerm, &bDlidx);
}
if( iPg<pSeg->pgnoFirst ){
@@ -2340,6 +2367,20 @@ static void fts5SegIterSeekInit(
}
}
}
/* Either:
**
** 1) an error has occurred, or
** 2) the iterator points to EOF, or
** 3) the iterator points to an entry with term (pTerm/nTerm), or
** 4) the FTS5INDEX_QUERY_SCAN flag was set and the iterator points
** to an entry with a term greater than or equal to (pTerm/nTerm).
*/
assert( p->rc!=SQLITE_OK /* 1 */
|| pIter->pLeaf==0 /* 2 */
|| fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)==0 /* 3 */
|| (bGe && fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)>0) /* 4 */
);
}
/*
@@ -2795,6 +2836,7 @@ static void fts5MultiIterNew(
int nSeg = 0; /* Number of segment-iters in use */
int iIter = 0; /* */
int iSeg; /* Used to iterate through segments */
Fts5Buffer buf = {0,0,0}; /* Buffer used by fts5SegIterSeekInit() */
Fts5StructureLevel *pLvl;
Fts5IndexIter *pNew;
@@ -2832,7 +2874,7 @@ static void fts5MultiIterNew(
if( pTerm==0 ){
fts5SegIterInit(p, pSeg, pIter);
}else{
fts5SegIterSeekInit(p, pTerm, nTerm, flags, pSeg, pIter);
fts5SegIterSeekInit(p, &buf, pTerm, nTerm, flags, pSeg, pIter);
}
}
}
@@ -2866,6 +2908,7 @@ static void fts5MultiIterNew(
fts5MultiIterFree(p, pNew);
*ppOut = 0;
}
fts5BufferFree(&buf);
}
/*
@@ -5391,7 +5434,7 @@ static void fts5DebugStructure(
for(iLvl=0; iLvl<p->nLevel; iLvl++){
Fts5StructureLevel *pLvl = &p->aLevel[iLvl];
sqlite3Fts5BufferAppendPrintf(pRc, pBuf,
" {lvl=%d nMerge=%d", iLvl, pLvl->nMerge
" {lvl=%d nMerge=%d nSeg=%d", iLvl, pLvl->nMerge, pLvl->nSeg
);
for(iSeg=0; iSeg<pLvl->nSeg; iSeg++){
Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg];

View File

@@ -124,7 +124,7 @@ proc fts5_level_segs {tbl} {
set sql "SELECT fts5_decode(rowid,block) aS r FROM ${tbl}_data WHERE rowid=10"
set ret [list]
foreach L [lrange [db one $sql] 1 end] {
lappend ret [expr [llength $L] - 2]
lappend ret [expr [llength $L] - 3]
}
set ret
}
@@ -134,7 +134,7 @@ proc fts5_level_segids {tbl} {
set ret [list]
foreach L [lrange [db one $sql] 1 end] {
set lvl [list]
foreach S [lrange $L 2 end] {
foreach S [lrange $L 3 end] {
regexp {id=([1234567890]*)} $S -> segid
lappend lvl $segid
}

View File

@@ -49,7 +49,7 @@ do_execsql_test 2.1 {
}
do_test 2.2 {
execsql { SELECT fts5_decode(id, block) FROM t1_data WHERE id==10 }
} {/{\(structure\) {lvl=0 nMerge=0 {id=[0123456789]* h=1 leaves=1..1}}}/}
} {/{\(structure\) {lvl=0 nMerge=0 nSeg=1 {id=[0123456789]* h=1 leaves=1..1}}}/}
foreach w {a b c d e f} {
do_execsql_test 2.3.$w.asc {

View File

@@ -71,7 +71,8 @@ do_execsql_test 2.3 {
} $res
do_execsql_test 2.4 {
UPDATE x1_data SET block = X'';
SELECT count(fts5_decode(rowid, block)) FROM x1_data;
-- SELECT count(fts5_decode(rowid, block)) FROM x1_data;
SELECT count(*) FROM x1_data;
} $res
do_execsql_test 2.5 {
@@ -83,10 +84,12 @@ set res [db one {SELECT count(*) FROM x1_data}]
do_execsql_test 2.6 {
SELECT count(fts5_decode(rowid, block)) FROM x1_data;
} $res
do_execsql_test 2.7 {
UPDATE x1_data SET block = X'';
SELECT count(fts5_decode(rowid, block)) FROM x1_data;
} $res
# This is really a corruption test...
#do_execsql_test 2.7 {
# UPDATE x1_data SET block = X'';
# SELECT count(fts5_decode(rowid, block)) FROM x1_data;
#} $res
#-------------------------------------------------------------------------
# Tests with very large tokens.

View File

@@ -1,28 +1,32 @@
#-------------------------------------------------------------------------
# Process command line arguments.
#
proc usage {} {
puts stderr "usage: $::argv0 database table"
puts stderr ""
exit 1
}
set o(vtab) fts5
set o(tok) ""
set o(limit) 0
set o(automerge) -1
set o(crisismerge) -1
if {[llength $argv]!=2} usage
set database [lindex $argv 0]
set tbl [lindex $argv 1]
#-------------------------------------------------------------------------
# Start of main program.
#
sqlite3 db $database
catch { load_static_extension db fts5 }
db eval "SELECT fts5_decode(rowid, block) AS d FROM ${tbl}_data WHERE id=10" {
foreach lvl [lrange $d 1 end] {
puts $lvl
puts [lrange $lvl 0 2]
foreach seg [lrange $lvl 3 end] {
puts " $seg"
}
}
}