Improve performance in single-threaded mode by having the final merge pass keys directly to the VDBE, instead of going via a final PMA.
FossilOrigin-Name: 02610cd9b77caa2c181210056088beb3ad6ce30f
diff --git a/manifest b/manifest
index eb0882e..08cf12e 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Minor\sfixes\sso\sthat\sbuilds\swith\sSQLITE_MAX_WORKER_THREADS=0\swork.
-D 2014-04-14T08:45:32.394
+C Improve\sperformance\sin\ssingle-threaded\smode\sby\shaving\sthe\sfinal\smerge\spass\skeys\sdirectly\sto\sthe\sVDBE,\sinstead\sof\sgoing\svia\sa\sfinal\sPMA.
+D 2014-04-14T18:41:21.894
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in ad0921c4b2780d01868cf69b419a4f102308d125
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -286,7 +286,7 @@
F src/vdbeaux.c d8dc38965507a34b0e150c0d7fc82b02f8cf25ea
F src/vdbeblob.c 15377abfb59251bccedd5a9c7d014a895f0c04aa
F src/vdbemem.c 6fc77594c60f6155404f3f8d71bf36d1fdeb4447
-F src/vdbesort.c 364cb94cf1eaefa1f79d86b7b1e4778c58192e1c
+F src/vdbesort.c 15f59dc56c7c4509b4783ad20fb25479ac63d267
F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767
F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
F src/wal.c 76e7fc6de229bea8b30bb2539110f03a494dc3a8
@@ -1163,7 +1163,7 @@
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
-P e1bdc4b810907cc0e55e0c923c8ebc777068cfe0
-R 15b762d2cb0315f25703d6fa43b514ac
+P e400bbbf26cdfe88f6cb231e96cdcddb9a6bcc0f
+R b74f7a073d8c77e32a2dce332520aa10
U dan
-Z 8e0f4aca92a8e556e8d49ca399252be9
+Z cd43207b847b4088208c6c3dd9c99bf8
diff --git a/manifest.uuid b/manifest.uuid
index bd230a5..0cd782f 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-e400bbbf26cdfe88f6cb231e96cdcddb9a6bcc0f
\ No newline at end of file
+02610cd9b77caa2c181210056088beb3ad6ce30f
\ No newline at end of file
diff --git a/src/vdbesort.c b/src/vdbesort.c
index 870e4e2..857b7ba 100644
--- a/src/vdbesort.c
+++ b/src/vdbesort.c
@@ -280,21 +280,17 @@
struct VdbeSorter {
int mnPmaSize; /* Minimum PMA size, in bytes */
int mxPmaSize; /* Maximum PMA size, in bytes. 0==no limit */
- int bUsePMA; /* True if one or more PMAs created */
- int bUseThreads; /* True if one or more PMAs created */
PmaReader *pReader; /* Read data from here after Rewind() */
+ MergeEngine *pMerger; /* Or here, if bUseThreads==0 */
int mxKeysize; /* Largest serialized key seen so far */
UnpackedRecord *pUnpacked; /* Used by VdbeSorterCompare() */
-#if 0
- int nInMemory; /* Current size of pRecord list as PMA */
- SorterRecord *pRecord; /* Head of in-memory record list */
- u8 *aMemory; /* Block of memory to alloc records from */
-#endif
- SorterList list;
- int iMemory; /* Offset of first free byte in aMemory */
- int nMemory; /* Size of aMemory allocation in bytes */
- int iPrev; /* Previous thread used to flush PMA */
- int nTask; /* Size of aTask[] array */
+ SorterList list; /* List of in-memory records */
+ int iMemory; /* Offset of free space in list.aMemory */
+ int nMemory; /* Size of list.aMemory allocation in bytes */
+ u8 bUsePMA; /* True if one or more PMAs created */
+ u8 bUseThreads; /* True to use background threads */
+ u8 iPrev; /* Previous thread used to flush PMA */
+ u8 nTask; /* Size of aTask[] array */
SortSubtask aTask[1]; /* One or more subtasks */
};
@@ -1005,6 +1001,8 @@
sqlite3DbFree(db, pSorter->pReader);
pSorter->pReader = 0;
}
+ vdbeMergeEngineFree(pSorter->pMerger);
+ pSorter->pMerger = 0;
for(i=0; i<pSorter->nTask; i++){
SortSubtask *pTask = &pSorter->aTask[i];
vdbeSortSubtaskCleanup(db, pTask);
@@ -1713,22 +1711,39 @@
#define INCRINIT2_NORMAL 0
#define INCRINIT2_TASK 1
#define INCRINIT2_ROOT 2
+
+static int vdbeIncrInit2(PmaReader *pIter, int eMode);
+
+static int vdbeIncrInitMerger(
+ SortSubtask *pTask,
+ MergeEngine *pMerger,
+ int eMode
+){
+ int i;
+ int rc = SQLITE_OK;
+
+ for(i=0; rc==SQLITE_OK && i<pMerger->nTree; i++){
+ if( eMode==INCRINIT2_ROOT ){
+ rc = vdbePmaReaderNext(&pMerger->aIter[i]);
+ }else{
+ rc = vdbeIncrInit2(&pMerger->aIter[i], INCRINIT2_NORMAL);
+ }
+ }
+
+ for(i=pMerger->nTree-1; rc==SQLITE_OK && i>0; i--){
+ rc = vdbeSorterDoCompare(pTask, pMerger, i);
+ }
+
+ return rc;
+}
+
static int vdbeIncrInit2(PmaReader *pIter, int eMode){
int rc = SQLITE_OK;
IncrMerger *pIncr = pIter->pIncr;
if( pIncr ){
SortSubtask *pTask = pIncr->pTask;
- int i;
- MergeEngine *pMerger = pIncr->pMerger;
- for(i=0; rc==SQLITE_OK && i<pMerger->nTree; i++){
- IncrMerger *p;
- if( eMode==INCRINIT2_ROOT ){
- rc = vdbePmaReaderNext(&pMerger->aIter[i]);
- }else{
- rc = vdbeIncrInit2(&pMerger->aIter[i], INCRINIT2_NORMAL);
- }
- }
+ rc = vdbeIncrInitMerger(pTask, pIncr->pMerger, eMode);
/* Set up the required files for pIncr */
if( rc==SQLITE_OK ){
@@ -1754,10 +1769,6 @@
}
}
- for(i=pMerger->nTree-1; rc==SQLITE_OK && i>0; i--){
- rc = vdbeSorterDoCompare(pIncr->pTask, pMerger, i);
- }
-
if( rc==SQLITE_OK && pIncr->bUseThread ){
/* Use the current thread */
assert( eMode==INCRINIT2_ROOT || eMode==INCRINIT2_TASK );
@@ -1871,7 +1882,7 @@
** Populate iterator *pIter so that it may be used to iterate through all
** keys stored in all PMAs created by this sorter.
*/
-static int vdbePmaReaderIncrInit(VdbeSorter *pSorter, PmaReader *pIter){
+static int vdbePmaReaderIncrInit(VdbeSorter *pSorter){
SortSubtask *pTask0 = &pSorter->aTask[0];
MergeEngine *pMain = 0;
sqlite3 *db = pTask0->db;
@@ -1943,39 +1954,49 @@
}
if( rc==SQLITE_OK ){
- SortSubtask *pLast = &pSorter->aTask[pSorter->nTask-1];
-
- rc = vdbeSortAllocUnpacked(pLast);
- if( rc==SQLITE_OK ){
- pIter->pIncr = vdbeIncrNew(pLast, pMain);
- if( pIter->pIncr==0 ){
- rc = SQLITE_NOMEM;
+#if SQLITE_MAX_WORKER_THREADS
+ if( pSorter->bUseThreads ){
+ PmaReader *pIter;
+ SortSubtask *pLast = &pSorter->aTask[pSorter->nTask-1];
+ rc = vdbeSortAllocUnpacked(pLast);
+ if( rc==SQLITE_OK ){
+ pIter = (PmaReader*)sqlite3DbMallocZero(db, sizeof(PmaReader));
+ pSorter->pReader = pIter;
}
-#if SQLITE_MAX_WORKER_THREADS>0
- else{
- vdbeIncrSetThreads(pIter->pIncr, pSorter->bUseThreads);
- for(iTask=0; iTask<(pSorter->nTask-1); iTask++){
- IncrMerger *pIncr;
- if( (pIncr = pMain->aIter[iTask].pIncr) ){
- vdbeIncrSetThreads(pIncr, pSorter->bUseThreads);
- assert( pIncr->pTask!=pLast );
- }
+ if( rc==SQLITE_OK ){
+ pIter->pIncr = vdbeIncrNew(pLast, pMain);
+ if( pIter->pIncr==0 ){
+ rc = SQLITE_NOMEM;
}
- if( pSorter->nTask>1 ){
- for(iTask=0; rc==SQLITE_OK && iTask<pSorter->nTask; iTask++){
- PmaReader *p = &pMain->aIter[iTask];
- assert( p->pIncr==0 || p->pIncr->pTask==&pSorter->aTask[iTask] );
- if( p->pIncr ){ rc = vdbeIncrBgInit2(p); }
+ else{
+ vdbeIncrSetThreads(pIter->pIncr, pSorter->bUseThreads);
+ for(iTask=0; iTask<(pSorter->nTask-1); iTask++){
+ IncrMerger *pIncr;
+ if( (pIncr = pMain->aIter[iTask].pIncr) ){
+ vdbeIncrSetThreads(pIncr, pSorter->bUseThreads);
+ assert( pIncr->pTask!=pLast );
+ }
+ }
+ if( pSorter->nTask>1 ){
+ for(iTask=0; rc==SQLITE_OK && iTask<pSorter->nTask; iTask++){
+ PmaReader *p = &pMain->aIter[iTask];
+ assert( p->pIncr==0 || p->pIncr->pTask==&pSorter->aTask[iTask] );
+ if( p->pIncr ){ rc = vdbeIncrBgInit2(p); }
+ }
}
}
}
+ if( rc==SQLITE_OK ){
+ int eMode = (pSorter->nTask>1 ? INCRINIT2_ROOT : INCRINIT2_NORMAL);
+ rc = vdbeIncrInit2(pIter, eMode);
+ }
+ }else
#endif
+ {
+ pSorter->pMerger = pMain;
+ rc = vdbeIncrInitMerger(pTask0, pMain, INCRINIT2_NORMAL);
}
}
- if( rc==SQLITE_OK ){
- int eMode = (pSorter->nTask>1 ? INCRINIT2_ROOT : INCRINIT2_NORMAL);
- rc = vdbeIncrInit2(pIter, eMode);
- }
sqlite3_free(aMerge);
return rc;
@@ -2020,11 +2041,7 @@
** incrementally read and merge all remaining PMAs. */
assert( pSorter->pReader==0 );
if( rc==SQLITE_OK ){
- PmaReader *pReader;
- pReader = (PmaReader*)sqlite3DbMallocZero(db, sizeof(PmaReader));
- pSorter->pReader = pReader;
- rc = vdbePmaReaderIncrInit(pSorter, pReader);
- assert( rc!=SQLITE_OK || pReader->pFile );
+ rc = vdbePmaReaderIncrInit(pSorter);
*pbEof = 0;
}
@@ -2039,9 +2056,17 @@
VdbeSorter *pSorter = pCsr->pSorter;
int rc; /* Return code */
- if( pSorter->pReader ){
- rc = vdbePmaReaderNext(pSorter->pReader);
- *pbEof = (pSorter->pReader->pFile==0);
+ assert( pSorter->bUsePMA || (pSorter->pReader==0 && pSorter->pMerger==0) );
+ if( pSorter->bUsePMA ){
+ assert( pSorter->pReader==0 || pSorter->pMerger==0 );
+ assert( pSorter->bUseThreads==0 || pSorter->pReader );
+ assert( pSorter->bUseThreads==1 || pSorter->pMerger );
+ if( pSorter->bUseThreads ){
+ rc = vdbePmaReaderNext(pSorter->pReader);
+ *pbEof = (pSorter->pReader->pFile==0);
+ }else{
+ rc = vdbeSorterNext(&pSorter->aTask[0], pSorter->pMerger, pbEof);
+ }
}else{
SorterRecord *pFree = pSorter->list.pList;
pSorter->list.pList = pFree->u.pNext;
@@ -2062,9 +2087,12 @@
int *pnKey /* OUT: Size of current key in bytes */
){
void *pKey;
- if( pSorter->pReader ){
- *pnKey = pSorter->pReader->nKey;
- pKey = pSorter->pReader->aKey;
+ if( pSorter->bUsePMA ){
+ PmaReader *pReader = (pSorter->bUseThreads ?
+ pSorter->pReader : &pSorter->pMerger->aIter[pSorter->pMerger->aTree[1]]
+ );
+ *pnKey = pReader->nKey;
+ pKey = pReader->aKey;
}else{
*pnKey = pSorter->list.pList->nVal;
pKey = SRVAL(pSorter->list.pList);