Compare commits

...

9 Commits

Author SHA1 Message Date
drh 1d60598d40 Do not let the multi-core sorter use lookaside memory, which is not
thread-safe.

FossilOrigin-Name: acdc7d1270b6aacf4612296a8d4dd596042b058c
2012-08-22 15:16:36 +00:00
drh 90c9f69892 Merge in all the latest trunk changes.
FossilOrigin-Name: 45cdc32f1e4d33959108dac94f551a4b8030424d
2012-08-21 17:46:18 +00:00
drh 3473d375e7 Changes to the thread routines to disable them when threading is turned
off using sqlite3_config().

FossilOrigin-Name: 555fc07efd1a1bc597804dcacbbcd95e88e75e90
2012-08-20 12:36:53 +00:00
drh 486e31f1b3 Attempt to use two cores to do sorting. Unfortunately, instead of making sorts
go faster as was hoped, this changes slows sorting down by about 10%.

FossilOrigin-Name: 11dd05e5984f0d5f98052458b94cbaf7d18c2e8f
2012-08-16 20:05:43 +00:00
drh e22724ee54 Update the threads branch to include all the latest trunk changes.
FossilOrigin-Name: f4125771e21f1ca29d5442b5441dacfc06b8032b
2012-08-16 11:24:22 +00:00
mistachkin a806475f86 Add an assert() to help verify the return code from the Win32 thread wait function.
FossilOrigin-Name: ed3dc7a89f3416622fcd741ae5fba437929d06d6
2012-07-23 06:47:30 +00:00
mistachkin 572df3b1e4 Enhance implementation of the Win32 thread wait function.
FossilOrigin-Name: 049b04117353c3e163ffc87916cbe121403a2821
2012-07-23 02:00:38 +00:00
mistachkin da0e47109e Add Win32 support to the internal threads interface. Also, add several asserts and fix a few typos.
FossilOrigin-Name: 793195d37109c75eba84f7190c8fe0b8722f76f7
2012-07-21 22:49:08 +00:00
drh f51446a38c Add an internal interface that allows the code to take advantage of multiple
cores by pushing subcomputations off into separate threads.  The interface
is not currently used.

FossilOrigin-Name: 0e4d977a4a07d6de50acbf022c7dd947998b8d96
2012-07-21 19:40:42 +00:00
14 changed files with 451 additions and 104 deletions
+5 -1
View File
@@ -176,7 +176,7 @@ LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \
notify.lo opcodes.lo os.lo os_unix.lo os_win.lo \
pager.lo parse.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \
random.lo resolve.lo rowset.lo rtree.lo select.lo status.lo \
table.lo tokenize.lo trigger.lo \
table.lo threads.lo tokenize.lo trigger.lo \
update.lo util.lo vacuum.lo \
vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \
vdbetrace.lo wal.lo walker.lo where.lo utf.lo vtab.lo
@@ -260,6 +260,7 @@ SRC = \
$(TOP)/src/sqliteInt.h \
$(TOP)/src/sqliteLimit.h \
$(TOP)/src/table.c \
$(TOP)/src/threads.c \
$(TOP)/src/tclsqlite.c \
$(TOP)/src/tokenize.c \
$(TOP)/src/trigger.c \
@@ -708,6 +709,9 @@ status.lo: $(TOP)/src/status.c $(HDR)
table.lo: $(TOP)/src/table.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/table.c
threads.lo: $(TOP)/src/threads.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/threads.c
tokenize.lo: $(TOP)/src/tokenize.c keywordhash.h $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/tokenize.c
+5 -1
View File
@@ -390,7 +390,7 @@ LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \
notify.lo opcodes.lo os.lo os_unix.lo os_win.lo \
pager.lo parse.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \
random.lo resolve.lo rowset.lo rtree.lo select.lo status.lo \
table.lo tokenize.lo trigger.lo \
table.lo threads.o tokenize.lo trigger.lo \
update.lo util.lo vacuum.lo \
vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \
vdbetrace.lo wal.lo walker.lo where.lo utf.lo vtab.lo
@@ -477,6 +477,7 @@ SRC = \
$(TOP)\src\sqliteInt.h \
$(TOP)\src\sqliteLimit.h \
$(TOP)\src\table.c \
$(TOP)\src\threads.c \
$(TOP)\src\tclsqlite.c \
$(TOP)\src\tokenize.c \
$(TOP)\src\trigger.c \
@@ -910,6 +911,9 @@ status.lo: $(TOP)\src\status.c $(HDR)
table.lo: $(TOP)\src\table.c $(HDR)
$(LTCOMPILE) -c $(TOP)\src\table.c
threads.lo: $(TOP)\src\threads.c $(HDR)
$(LTCOMPILE) -c $(TOP)\src\threads.c
tokenize.lo: $(TOP)\src\tokenize.c keywordhash.h $(HDR)
$(LTCOMPILE) -c $(TOP)\src\tokenize.c
+2 -1
View File
@@ -64,7 +64,7 @@ LIBOBJ+= alter.o analyze.o attach.o auth.o \
notify.o opcodes.o os.o os_unix.o os_win.o \
pager.o parse.o pcache.o pcache1.o pragma.o prepare.o printf.o \
random.o resolve.o rowset.o rtree.o select.o status.o \
table.o tokenize.o trigger.o \
table.o threads.o tokenize.o trigger.o \
update.o util.o vacuum.o \
vdbe.o vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o vdbesort.o \
vdbetrace.o wal.o walker.o where.o utf.o vtab.o
@@ -142,6 +142,7 @@ SRC = \
$(TOP)/src/sqliteLimit.h \
$(TOP)/src/table.c \
$(TOP)/src/tclsqlite.c \
$(TOP)/src/threads.c \
$(TOP)/src/tokenize.c \
$(TOP)/src/trigger.c \
$(TOP)/src/utf.c \
+17 -16
View File
@@ -1,9 +1,9 @@
C Update\sthe\sspellfix\svirtual\stable\sso\sthat\sall\sOOM\serrors\sare\sreported\sout\nto\sthe\sapplication.
D 2012-08-21T17:44:05.685
C Do\snot\slet\sthe\smulti-core\ssorter\suse\slookaside\smemory,\swhich\sis\snot\nthread-safe.
D 2012-08-22T15:16:36.722
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in abd5c10d21d1395f140d9e50ea999df8fa4d6376
F Makefile.in adec39f15a9c7000f634b87a535b95279b0cbd09
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F Makefile.msc e89bdb795a841e58169ef9e26e543096dfc17c24
F Makefile.msc d2f83cd5e74d54f9e3bcd7a505ca5b356d7e7c68
F Makefile.vxworks 879f034a64062a364b21000266bbd5bc6e0c19b9
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
F VERSION a71848df48082f1d6585d4b0819d530fc455485d
@@ -103,7 +103,7 @@ F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F main.mk 72026405046ed5b1f0368943b89c0aa29ad558b6
F main.mk a463acdf2898fed3ccd716ece9d3c5d28450c852
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac
@@ -163,7 +163,7 @@ F src/os.c e1acdc09ff3ac2412945cca9766e2dcf4675f31c
F src/os.h 027491c77d2404c0a678bb3fb06286f331eb9b57
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
F src/os_unix.c b5149a3343a6acd6c9df4e3acf5085a6501c1f68
F src/os_win.c b8fc659987a678c7924796585f5ae293ba5c896d
F src/os_win.c a7878531bf2c592218266f139d152cbe648fcc05
F src/pager.c e381c118b77dc22021a1a59d3fec24815e91df78
F src/pager.h 8b8c9bc065a3c66769df8724dfdf492ee1aab3c5
F src/parse.y f29df90bd3adc64b33114ab1de9fb7768fcf2099
@@ -180,7 +180,7 @@ F src/select.c a365da6d7a6d7d8a10ad60ca71837ab5e9369466
F src/shell.c 076e1c90d594644f36027c8ecff9a392cf2d3a06
F src/sqlite.h.in f664797c68ced43c2ea2c541d4ec8e1e04ec68ac
F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477
F src/sqliteInt.h c8169801f8bbfdf5873cc6fa45cb5df720c04db4
F src/sqliteInt.h 1ef5f8b64d204fe5deec83c58297493b2f5fbfa0
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 35939e7e03abf1b7577ce311f48f682c40de3208
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -231,20 +231,21 @@ F src/test_vfs.c c6260ef238c1142c8f8bd402db02216afd182ae3
F src/test_vfstrace.c 6b28adb2a0e8ecd0f2e3581482e1f658b11b4067
F src/test_wholenumber.c 3d2b9ed1505c40ad5c5ca2ad16ae7a289d6cc251
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c cde9d885fd562b5427f89a42a8829085f88b17df
F src/tokenize.c 1e86210d3976717a19238ea7b047fac481fe8c12
F src/trigger.c ee7e178fb9188f44b532cebd449a7c1df90fb684
F src/update.c d3076782c887c10e882996550345da9c4c9f9dea
F src/utf.c 890c67dcfcc7a74623c95baac7535aadfe265e84
F src/util.c 0af2e515dc0dabacec931bca39525f6c3f1c5455
F src/vacuum.c 587a52bb8833d7ac15af8916f25437e2575028bd
F src/vdbe.c 75da79cdcd58481825a06f045bc2f5ea3966eeae
F src/vdbe.c 1a451790e5abd4df1c0ad0c39d5d6398888b473f
F src/vdbe.h 18f581cac1f4339ec3299f3e0cc6e11aec654cdb
F src/vdbeInt.h 986b6b11a13c517337355009e5438703ba5b0a40
F src/vdbeInt.h 3c238336fc5b186b193553dbac4e1979d91e0c0d
F src/vdbeapi.c 88ea823bbcb4320f5a6607f39cd7c2d3cc4c26b1
F src/vdbeaux.c dce80038c3c41f2680e5ab4dd0f7e0d8b7ff9071
F src/vdbeaux.c 84bd15358329f4005a7bceefafc1e798592e987d
F src/vdbeblob.c 32f2a4899d67f69634ea4dd93e3f651936d732cb
F src/vdbemem.c cb55e84b8e2c15704968ee05f0fae25883299b74
F src/vdbesort.c 0dc1b274dcb4d4c8e71b0b2b15261f286caba39b
F src/vdbesort.c acaefad52f6345a06fcfe2ec7da0c7d7d2569c39
F src/vdbetrace.c 8bd5da325fc90f28464335e4cc4ad1407fe30835
F src/vtab.c bb8ea3a26608bb1357538a5d2fc72beba6638998
F src/wal.c 9294df6f96aae5909ae1a9b733fd1e1b4736978b
@@ -982,8 +983,8 @@ F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc
F tool/mkkeywordhash.c bb52064aa614e1426445e4b2b9b00eeecd23cc79
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
F tool/mksqlite3c-noext.tcl 8bce31074e4cbe631bb7676526a048335f4c9f02
F tool/mksqlite3c.tcl 589c7f44e990be1b8443cfe4808dce392b0327fa
F tool/mksqlite3c-noext.tcl 752f1a9d3287f6c0ef5738b1c4add0b96fbe0854
F tool/mksqlite3c.tcl d4923e8e75b7710ddbe4eb37f83dda5eadef63d8
F tool/mksqlite3h.tcl 78013ad79a5e492e5f764f3c7a8ef834255061f8
F tool/mksqlite3internalh.tcl 3dca7bb5374cee003379b8cbac73714f610ef795
F tool/mkvsix.tcl 19b2ab9ea16445953a76568a5bbe4cb864f92dfe
@@ -1011,7 +1012,7 @@ F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
F tool/win/sqlite.vsix 67d8a99aceb56384a81b3f30d6c71743146d2cc9
P e799222f3b8246e65657a758437914ece7069ba9
R 5e828b4451d9abd5424b5fdb18a303b8
P 45cdc32f1e4d33959108dac94f551a4b8030424d
R fe69bbfbdf0f9035e48cc3502476a4c4
U drh
Z 86d779defb1a86a95d6cf62943de67e6
Z cf3f449e5e4dc5f0a36f059aada3751c
+1 -1
View File
@@ -1 +1 @@
573770f5a66fa4d708931b30350149eb739da607
acdc7d1270b6aacf4612296a8d4dd596042b058c
+7
View File
@@ -954,6 +954,13 @@ void sqlite3_win32_sleep(DWORD milliseconds){
#endif
}
DWORD sqlite3Win32Wait(HANDLE hObject){
DWORD rc;
while( (rc = osWaitForSingleObjectEx(hObject, INFINITE,
TRUE))==WAIT_IO_COMPLETION ){}
return rc;
}
/*
** Return true (non-zero) if we are running under WinNT, Win2K, WinXP,
** or WinCE. Return false (zero) for Win95, Win98, or WinME.
+14
View File
@@ -661,6 +661,7 @@ typedef struct Parse Parse;
typedef struct RowSet RowSet;
typedef struct Savepoint Savepoint;
typedef struct Select Select;
typedef struct SQLiteThread SQLiteThread;
typedef struct SrcList SrcList;
typedef struct StrAccum StrAccum;
typedef struct Table Table;
@@ -3309,4 +3310,17 @@ SQLITE_EXTERN void (*sqlite3IoTrace)(const char*,...);
#define MEMTYPE_PCACHE 0x08 /* Page cache allocations */
#define MEMTYPE_DB 0x10 /* Uses sqlite3DbMalloc, not sqlite_malloc */
/*
** Threading interface
*/
int sqlite3ThreadCreate(SQLiteThread**,void*(*)(void*),void*);
int sqlite3ThreadJoin(SQLiteThread*, void**);
/*
** Win32 interface
*/
#if SQLITE_OS_WIN
DWORD sqlite3Win32Wait(HANDLE hObject);
#endif
#endif /* _SQLITEINT_H_ */
+217
View File
@@ -0,0 +1,217 @@
/*
** 2012 July 21
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
******************************************************************************
**
** This file presents a simple cross-platform threading interface for
** use internally by SQLite.
**
** A "thread" can be created using sqlite3ThreadCreate(). This thread
** runs independently of its creator until it is joined using
** sqlite3ThreadJoin(), at which point it terminates.
**
** Threads do not have to be real. It could be that the work of the
** "thread" is done by the main thread at either the sqlite3ThreadCreate()
** or sqlite3ThreadJoin() call. This is, in fact, what happens in
** single threaded systems. Nothing in SQLite requires multiple threads.
** This interface exists so that applications that want to take advantage
** of multiple cores can do so, while also allowing applications to stay
** single-threaded if desired.
*/
#include "sqliteInt.h"
/********************************* Unix Pthreads ****************************/
#if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS)
#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */
#include <pthread.h>
/* A running thread */
struct SQLiteThread {
pthread_t tid;
int done;
void *pOut;
};
/* Create a new thread */
int sqlite3ThreadCreate(
SQLiteThread **ppThread, /* OUT: Write the thread object here */
void *(*xTask)(void*), /* Routine to run in a separate thread */
void *pIn /* Argument passed into xTask() */
){
SQLiteThread *p;
assert( ppThread!=0 );
assert( xTask!=0 );
*ppThread = 0;
p = sqlite3Malloc(sizeof(*p));
if( p==0 ) return SQLITE_NOMEM;
memset(p, 0, sizeof(*p));
if( sqlite3GlobalConfig.bCoreMutex==0
|| pthread_create(&p->tid, 0, xTask, pIn)!=0
){
p->done = 1;
p->pOut = xTask(pIn);
}
*ppThread = p;
return SQLITE_OK;
}
/* Get the results of the thread */
int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
int rc;
assert( ppOut!=0 );
if( p==0 ) return SQLITE_NOMEM;
if( p->done ){
*ppOut = p->pOut;
rc = SQLITE_OK;
}else{
rc = pthread_join(p->tid, ppOut);
}
sqlite3_free(p);
return rc ? SQLITE_ERROR : SQLITE_OK;
}
#endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */
/******************************** End Unix Pthreads *************************/
/********************************* Win32 Threads ****************************/
#if SQLITE_OS_WIN && !SQLITE_OS_WINRT
#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */
#include <process.h>
/* A running thread */
struct SQLiteThread {
uintptr_t tid; /* The thread handle */
void *(*xTask)(void*); /* The routine to run as a thread */
void *pIn; /* Argument to xTask */
void *pResult; /* Result of xTask */
};
/* Thread procedure Win32 compatibility shim */
static void sqlite3ThreadProc(
void *pArg /* IN: Pointer to the SQLiteThread structure */
){
SQLiteThread *p = (SQLiteThread *)pArg;
assert( p!=0 );
assert( p->xTask!=0 );
p->pResult = p->xTask(p->pIn);
_endthread();
}
/* Create a new thread */
int sqlite3ThreadCreate(
SQLiteThread **ppThread, /* OUT: Write the thread object here */
void *(*xTask)(void*), /* Routine to run in a separate thread */
void *pIn /* Argument passed into xTask() */
){
SQLiteThread *p;
assert( ppThread!=0 );
assert( xTask!=0 );
*ppThread = 0;
p = sqlite3Malloc(sizeof(*p));
if( p==0 ) return SQLITE_NOMEM;
if( sqlite3GlobalConfig.bCoreMutex==0 ){
memset(p, 0, sizeof(*p));
}else{
p->xTask = xTask;
p->pIn = pIn;
p->tid = _beginthread(sqlite3ThreadProc, 0, p);
if( p->tid==(uintptr_t)-1 ){
memset(p, 0, sizeof(*p));
}
}
if( p->xTask==0 ){
p->pResult = xTask(pIn);
}
*ppThread = p;
return SQLITE_OK;
}
/* Get the results of the thread */
int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
DWORD rc;
assert( ppOut!=0 );
if( p==0 ) return SQLITE_NOMEM;
if( p->xTask==0 ){
rc = WAIT_OBJECT_O;
}else{
rc = sqlite3Win32Wait((HANDLE)p->tid);
assert( rc!=WAIT_IO_COMPLETION );
}
if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult;
sqlite3_free(p);
return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR;
}
#endif /* SQLITE_OS_WIN && !SQLITE_OS_WINRT */
/******************************** End Win32 Threads *************************/
/********************************* Single-Threaded **************************/
#ifndef SQLITE_THREADS_IMPLEMENTED
/*
** This implementation does not actually create a new thread. It does the
** work of the thread in the main thread, when either the thread is created
** or when it is joined
*/
/* A running thread */
struct SQLiteThread {
void *(*xTask)(void*); /* The routine to run as a thread */
void *pIn; /* Argument to xTask */
void *pResult; /* Result of xTask */
};
/* Create a new thread */
int sqlite3ThreadCreate(
SQLiteThread **ppThread, /* OUT: Write the thread object here */
void *(*xTask)(void*), /* Routine to run in a separate thread */
void *pIn /* Argument passed into xTask() */
){
SQLiteThread *p;
assert( ppThread!=0 );
assert( xTask!=0 );
*ppThread = 0;
p = sqlite3Malloc(sizeof(*p));
if( p==0 ) return SQLITE_NOMEM;
if( (SQLITE_PTR_TO_INT(p)/17)&1 ){
p->xTask = xTask;
p->pIn = pIn;
}else{
p->xTask = 0;
p->pResult = xTask(pIn);
}
*ppThread = p;
return SQLITE_OK;
}
/* Get the results of the thread */
int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
assert( ppOut!=0 );
if( p==0 ) return SQLITE_NOMEM;
if( p->xTask ){
*ppOut = p->xTask(p->pIn);
}else{
*ppOut = p->pResult;
}
sqlite3_free(p);
return SQLITE_OK;
}
#endif /* !defined(SQLITE_THREADS_IMPLEMENTED) */
/****************************** End Single-Threaded *************************/
+3 -3
View File
@@ -4405,7 +4405,7 @@ case OP_Rewind: { /* jump */
assert( pC->isSorter==(pOp->opcode==OP_SorterSort) );
res = 1;
if( isSorter(pC) ){
rc = sqlite3VdbeSorterRewind(db, pC, &res);
rc = sqlite3VdbeSorterRewind(pC, &res);
}else{
pCrsr = pC->pCursor;
assert( pCrsr );
@@ -4474,7 +4474,7 @@ case OP_Next: { /* jump */
assert( pC->isSorter==(pOp->opcode==OP_SorterNext) );
if( isSorter(pC) ){
assert( pOp->opcode==OP_SorterNext );
rc = sqlite3VdbeSorterNext(db, pC, &res);
rc = sqlite3VdbeSorterNext(pC, &res);
}else{
res = 1;
assert( pC->deferredMoveto==0 );
@@ -4530,7 +4530,7 @@ case OP_IdxInsert: { /* in2 */
rc = ExpandBlob(pIn2);
if( rc==SQLITE_OK ){
if( isSorter(pC) ){
rc = sqlite3VdbeSorterWrite(db, pC, pIn2);
rc = sqlite3VdbeSorterWrite(pC, pIn2);
}else{
nKey = pIn2->n;
zKey = pIn2->z;
+9 -9
View File
@@ -422,19 +422,19 @@ int sqlite3VdbeTransferError(Vdbe *p);
#ifdef SQLITE_OMIT_MERGE_SORT
# define sqlite3VdbeSorterInit(Y,Z) SQLITE_OK
# define sqlite3VdbeSorterWrite(X,Y,Z) SQLITE_OK
# define sqlite3VdbeSorterClose(Y,Z)
# define sqlite3VdbeSorterWrite(Y,Z) SQLITE_OK
# define sqlite3VdbeSorterClose(Z)
# define sqlite3VdbeSorterRowkey(Y,Z) SQLITE_OK
# define sqlite3VdbeSorterRewind(X,Y,Z) SQLITE_OK
# define sqlite3VdbeSorterNext(X,Y,Z) SQLITE_OK
# define sqlite3VdbeSorterCompare(X,Y,Z) SQLITE_OK
# define sqlite3VdbeSorterRewind(Y,Z) SQLITE_OK
# define sqlite3VdbeSorterNext(Y,Z) SQLITE_OK
# define sqlite3VdbeSorterCompare(Y,Z) SQLITE_OK
#else
int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *);
void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *);
void sqlite3VdbeSorterClose(VdbeCursor *);
int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *);
int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *);
int sqlite3VdbeSorterRewind(sqlite3 *, const VdbeCursor *, int *);
int sqlite3VdbeSorterWrite(sqlite3 *, const VdbeCursor *, Mem *);
int sqlite3VdbeSorterNext(const VdbeCursor *, int *);
int sqlite3VdbeSorterRewind(const VdbeCursor *, int *);
int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *);
int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int *);
#endif
+1 -1
View File
@@ -1575,7 +1575,7 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
if( pCx==0 ){
return;
}
sqlite3VdbeSorterClose(p->db, pCx);
sqlite3VdbeSorterClose(pCx);
if( pCx->pBt ){
sqlite3BtreeClose(pCx->pBt);
/* The pCx->pCursor will be close automatically, if it exists, by
+168 -71
View File
@@ -105,7 +105,10 @@ struct VdbeSorter {
int *aTree; /* Current state of incremental merge */
sqlite3_file *pTemp1; /* PMA file 1 */
SorterRecord *pRecord; /* Head of in-memory record list */
int nRecord; /* Number of elements on the pRecord list */
UnpackedRecord *pUnpacked; /* Used to unpack keys */
KeyInfo *pKeyInfo; /* Copy of cursor KeyInfo without db ptr */
sqlite3 *db; /* Database connection */
};
/*
@@ -115,6 +118,7 @@ struct VdbeSorter {
struct VdbeSorterIter {
i64 iReadOff; /* Current read offset */
i64 iEof; /* 1 byte past EOF for this iterator */
sqlite3 *db; /* Corresponding database connection */
int nAlloc; /* Bytes of space at aAlloc */
int nKey; /* Number of bytes in key */
sqlite3_file *pFile; /* File iterator is reading from */
@@ -177,7 +181,6 @@ static void vdbeSorterIterZero(sqlite3 *db, VdbeSorterIter *pIter){
** next call to this function.
*/
static int vdbeSorterIterRead(
sqlite3 *db, /* Database handle (for malloc) */
VdbeSorterIter *p, /* Iterator */
int nByte, /* Bytes of data to read */
u8 **ppOut /* OUT: Pointer to buffer containing data */
@@ -222,7 +225,7 @@ static int vdbeSorterIterRead(
if( p->nAlloc<nByte ){
int nNew = p->nAlloc*2;
while( nByte>nNew ) nNew = nNew*2;
p->aAlloc = sqlite3DbReallocOrFree(db, p->aAlloc, nNew);
p->aAlloc = sqlite3DbReallocOrFree(p->db, p->aAlloc, nNew);
if( !p->aAlloc ) return SQLITE_NOMEM;
p->nAlloc = nNew;
}
@@ -242,7 +245,7 @@ static int vdbeSorterIterRead(
nCopy = nRem;
if( nRem>p->nBuffer ) nCopy = p->nBuffer;
rc = vdbeSorterIterRead(db, p, nCopy, &aNext);
rc = vdbeSorterIterRead(p, nCopy, &aNext);
if( rc!=SQLITE_OK ) return rc;
assert( aNext!=p->aAlloc );
memcpy(&p->aAlloc[nByte - nRem], aNext, nCopy);
@@ -259,7 +262,7 @@ static int vdbeSorterIterRead(
** Read a varint from the stream of data accessed by p. Set *pnOut to
** the value read.
*/
static int vdbeSorterIterVarint(sqlite3 *db, VdbeSorterIter *p, u64 *pnOut){
static int vdbeSorterIterVarint(VdbeSorterIter *p, u64 *pnOut){
int iBuf;
iBuf = p->iReadOff % p->nBuffer;
@@ -269,7 +272,7 @@ static int vdbeSorterIterVarint(sqlite3 *db, VdbeSorterIter *p, u64 *pnOut){
u8 aVarint[16], *a;
int i = 0, rc;
do{
rc = vdbeSorterIterRead(db, p, 1, &a);
rc = vdbeSorterIterRead(p, 1, &a);
if( rc ) return rc;
aVarint[(i++)&0xf] = a[0];
}while( (a[0]&0x80)!=0 );
@@ -285,11 +288,11 @@ static int vdbeSorterIterVarint(sqlite3 *db, VdbeSorterIter *p, u64 *pnOut){
** no error occurs, or an SQLite error code if one does.
*/
static int vdbeSorterIterNext(
sqlite3 *db, /* Database handle (for sqlite3DbMalloc() ) */
VdbeSorterIter *pIter /* Iterator to advance */
){
int rc; /* Return Code */
u64 nRec = 0; /* Size of record in bytes */
sqlite3 *db = pIter->db; /* Database connection */
if( pIter->iReadOff>=pIter->iEof ){
/* This is an EOF condition */
@@ -297,10 +300,10 @@ static int vdbeSorterIterNext(
return SQLITE_OK;
}
rc = vdbeSorterIterVarint(db, pIter, &nRec);
rc = vdbeSorterIterVarint(pIter, &nRec);
if( rc==SQLITE_OK ){
pIter->nKey = (int)nRec;
rc = vdbeSorterIterRead(db, pIter, (int)nRec, &pIter->aKey);
rc = vdbeSorterIterRead(pIter, (int)nRec, &pIter->aKey);
}
return rc;
@@ -313,7 +316,6 @@ static int vdbeSorterIterNext(
** PMA is empty).
*/
static int vdbeSorterIterInit(
sqlite3 *db, /* Database handle */
const VdbeSorter *pSorter, /* Sorter object */
i64 iStart, /* Start offset in pFile */
VdbeSorterIter *pIter, /* Iterator to populate */
@@ -321,6 +323,7 @@ static int vdbeSorterIterInit(
){
int rc = SQLITE_OK;
int nBuf;
sqlite3 *db = pSorter->db;
nBuf = sqlite3BtreeGetPageSize(db->aDb[0].pBt);
@@ -329,6 +332,7 @@ static int vdbeSorterIterInit(
assert( pIter->aBuffer==0 );
pIter->pFile = pSorter->pTemp1;
pIter->iReadOff = iStart;
pIter->db = db;
pIter->nAlloc = 128;
pIter->aAlloc = (u8 *)sqlite3DbMallocRaw(db, pIter->nAlloc);
pIter->nBuffer = nBuf;
@@ -354,14 +358,14 @@ static int vdbeSorterIterInit(
if( rc==SQLITE_OK ){
u64 nByte; /* Size of PMA in bytes */
pIter->iEof = pSorter->iWriteOff;
rc = vdbeSorterIterVarint(db, pIter, &nByte);
rc = vdbeSorterIterVarint(pIter, &nByte);
pIter->iEof = pIter->iReadOff + nByte;
*pnByte += nByte;
}
}
if( rc==SQLITE_OK ){
rc = vdbeSorterIterNext(db, pIter);
rc = vdbeSorterIterNext(pIter);
}
return rc;
}
@@ -383,18 +387,18 @@ static int vdbeSorterIterInit(
** has been allocated and contains an unpacked record that is used as key2.
*/
static void vdbeSorterCompare(
const VdbeCursor *pCsr, /* Cursor object (for pKeyInfo) */
VdbeSorter *pSorter, /* The sorter */
int bOmitRowid, /* Ignore rowid field at end of keys */
const void *pKey1, int nKey1, /* Left side of comparison */
const void *pKey2, int nKey2, /* Right side of comparison */
int *pRes /* OUT: Result of comparison */
int *pRes, /* OUT: Result of comparison */
UnpackedRecord *r2 /* Space to hold the unpacked Key2 record */
){
KeyInfo *pKeyInfo = pCsr->pKeyInfo;
VdbeSorter *pSorter = pCsr->pSorter;
UnpackedRecord *r2 = pSorter->pUnpacked;
KeyInfo *pKeyInfo = pSorter->pKeyInfo;
int i;
if( pKey2 ){
assert( r2!=0 );
sqlite3VdbeRecordUnpack(pKeyInfo, nKey2, pKey2, r2);
}
@@ -418,8 +422,7 @@ static void vdbeSorterCompare(
** multiple b-tree segments. Parameter iOut is the index of the aTree[]
** value to recalculate.
*/
static int vdbeSorterDoCompare(const VdbeCursor *pCsr, int iOut){
VdbeSorter *pSorter = pCsr->pSorter;
static int vdbeSorterDoCompare(VdbeSorter *pSorter, int iOut){
int i1;
int i2;
int iRes;
@@ -445,9 +448,9 @@ static int vdbeSorterDoCompare(const VdbeCursor *pCsr, int iOut){
iRes = i1;
}else{
int res;
assert( pCsr->pSorter->pUnpacked!=0 ); /* allocated in vdbeSorterMerge() */
vdbeSorterCompare(
pCsr, 0, p1->aKey, p1->nKey, p2->aKey, p2->nKey, &res
pSorter, 0, p1->aKey, p1->nKey, p2->aKey, p2->nKey, &res,
pSorter->pUnpacked
);
if( res<=0 ){
iRes = i1;
@@ -468,17 +471,32 @@ int sqlite3VdbeSorterInit(sqlite3 *db, VdbeCursor *pCsr){
int mxCache; /* Cache size */
VdbeSorter *pSorter; /* The new sorter */
char *d; /* Dummy */
int nByte; /* Bytes in pKeyInfo */
assert( pCsr->pKeyInfo && pCsr->pBt==0 );
pCsr->pSorter = pSorter = sqlite3DbMallocZero(db, sizeof(VdbeSorter));
if( pSorter==0 ){
return SQLITE_NOMEM;
}
pSorter->db = db;
pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pCsr->pKeyInfo, 0, 0, &d);
if( pSorter->pUnpacked==0 ) return SQLITE_NOMEM;
assert( pSorter->pUnpacked==(UnpackedRecord *)d );
/* pSorter->pKeyInfo is a copy of pCsr->pKeyInfo with the db field set to
** zero. We use this modified pKeyInfo for sorting so that no lookaside
** memory will be used, so that sorting can proceed in parallel in multiple
** threads.
*/
nByte = sizeof(KeyInfo) + (pCsr->pKeyInfo->nField - 1)*sizeof(CollSeq*);
pSorter->pKeyInfo = sqlite3DbMallocRaw(db, nByte);
if( pSorter->pKeyInfo==0 ){
return SQLITE_NOMEM;
}
memcpy(pSorter->pKeyInfo, pCsr->pKeyInfo, nByte);
pSorter->pKeyInfo->db = 0;
if( !sqlite3TempInMemory(db) ){
pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt);
pSorter->mnPmaSize = SORTER_MIN_WORKING * pgsz;
@@ -505,9 +523,10 @@ static void vdbeSorterRecordFree(sqlite3 *db, SorterRecord *pRecord){
/*
** Free any cursor components allocated by sqlite3VdbeSorterXXX routines.
*/
void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){
void sqlite3VdbeSorterClose(VdbeCursor *pCsr){
VdbeSorter *pSorter = pCsr->pSorter;
if( pSorter ){
sqlite3 *db = pSorter->db;
if( pSorter->aIter ){
int i;
for(i=0; i<pSorter->nTree; i++){
@@ -520,6 +539,7 @@ void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){
}
vdbeSorterRecordFree(db, pSorter->pRecord);
sqlite3DbFree(db, pSorter->pUnpacked);
sqlite3DbFree(db, pSorter->pKeyInfo);
sqlite3DbFree(db, pSorter);
pCsr->pSorter = 0;
}
@@ -544,10 +564,11 @@ static int vdbeSorterOpenTempFile(sqlite3 *db, sqlite3_file **ppFile){
** Set *ppOut to the head of the new list.
*/
static void vdbeSorterMerge(
const VdbeCursor *pCsr, /* For pKeyInfo */
VdbeSorter *pSorter, /* The sorter object */
SorterRecord *p1, /* First list to merge */
SorterRecord *p2, /* Second list to merge */
SorterRecord **ppOut /* OUT: Head of merged list */
SorterRecord **ppOut, /* OUT: Head of merged list */
UnpackedRecord *pUnpacked /* Space to hold an unpacked record */
){
SorterRecord *pFinal = 0;
SorterRecord **pp = &pFinal;
@@ -555,7 +576,8 @@ static void vdbeSorterMerge(
while( p1 && p2 ){
int res;
vdbeSorterCompare(pCsr, 0, p1->pVal, p1->nVal, pVal2, p2->nVal, &res);
vdbeSorterCompare(pSorter, 0, p1->pVal, p1->nVal, pVal2, p2->nVal, &res,
pUnpacked);
if( res<=0 ){
*pp = p1;
pp = &p1->pNext;
@@ -573,42 +595,112 @@ static void vdbeSorterMerge(
*ppOut = pFinal;
}
/*
** Background sorting task
*/
typedef struct SortTask {
VdbeSorter *pSorter; /* The sorter for which this task works */
UnpackedRecord *pUnpacked; /* Space to hold an unpacked key */
SorterRecord *pList; /* List of elements to be sorted */
SorterRecord **apSlot; /* Temp memory for the merge sort */
} SortTask;
/*
** Do a sort in a background thread
*/
void *vdbeSorterBackgroundSort(SortTask *pTask){
SorterRecord *p = pTask->pList;
SorterRecord **a = pTask->apSlot;
int i;
for(i=0; i<64; i++) a[i] = 0;
while( p ){
SorterRecord *pNext = p->pNext;
p->pNext = 0;
for(i=0; a[i]; i++){
if( a[i]==0 ) break;
vdbeSorterMerge(pTask->pSorter, a[i], p, &p, pTask->pUnpacked);
a[i] = 0;
}
a[i] = p;
p = pNext;
}
p = 0;
for(i=0; i<64; i++){
vdbeSorterMerge(pTask->pSorter, a[i], p, &p, pTask->pUnpacked);
}
pTask->pList = p;
return p;
}
/*
** Divide a linked list of SorterRecord objects into two separate
** linked lists
*/
static void vdbeSorterDivideList(
SorterRecord *pIn, /* The list to be divided */
SorterRecord **ppOut1, /* Write the first list here */
SorterRecord **ppOut2 /* Write the second list here */
){
int i = 0;
*ppOut1 = *ppOut2 = 0;
while( pIn ){
SorterRecord *pNext = pIn->pNext;
pIn->pNext = 0;
if( i & 1 ){
*ppOut1 = pIn;
ppOut1 = &pIn->pNext;
}else{
*ppOut2 = pIn;
ppOut2 = &pIn->pNext;
}
i++;
pIn = pNext;
}
}
/*
** Sort the linked list of records headed at pCsr->pRecord. Return SQLITE_OK
** if successful, or an SQLite error code (i.e. SQLITE_NOMEM) if an error
** occurs.
*/
static int vdbeSorterSort(const VdbeCursor *pCsr){
int i;
SorterRecord **aSlot;
SorterRecord *p;
VdbeSorter *pSorter = pCsr->pSorter;
static int vdbeSorterSort(VdbeSorter *pSorter){
int rc;
char *pDummy = 0;
int nByteA, nByteB;
SortTask aTask[2];
SQLiteThread *pThread;
aSlot = (SorterRecord **)sqlite3MallocZero(64 * sizeof(SorterRecord *));
if( !aSlot ){
nByteA = 64*sizeof(SorterRecord*);
nByteB = ROUND8(sizeof(UnpackedRecord));
nByteB += sizeof(Mem)*(pSorter->pKeyInfo->nField+1);
aTask[0].apSlot = (SorterRecord **)sqlite3MallocZero(2*(nByteA + nByteB));
if( !aTask[0].apSlot ){
return SQLITE_NOMEM;
}
aTask[0].pSorter = pSorter;
aTask[0].pUnpacked = sqlite3VdbeAllocUnpackedRecord(pSorter->pKeyInfo,
(char*)&aTask[0].apSlot[64], nByteB, &pDummy);
assert( pDummy==0 );
aTask[1].apSlot = (SorterRecord**)((nByteA+nByteB)+(char*)aTask[0].apSlot);
aTask[1].pSorter = pSorter;
aTask[1].pUnpacked = sqlite3VdbeAllocUnpackedRecord(pSorter->pKeyInfo,
(char*)&aTask[1].apSlot[64], nByteB, &pDummy);
assert( pDummy==0 );
p = pSorter->pRecord;
while( p ){
SorterRecord *pNext = p->pNext;
p->pNext = 0;
for(i=0; aSlot[i]; i++){
vdbeSorterMerge(pCsr, p, aSlot[i], &p);
aSlot[i] = 0;
}
aSlot[i] = p;
p = pNext;
vdbeSorterDivideList(pSorter->pRecord, &aTask[0].pList, &aTask[1].pList);
rc = sqlite3ThreadCreate(&pThread,
(void*(*)(void*))vdbeSorterBackgroundSort, &aTask[0]);
vdbeSorterBackgroundSort(&aTask[1]);
if( rc==SQLITE_NOMEM ){
vdbeSorterBackgroundSort(&aTask[0]);
}else{
rc = sqlite3ThreadJoin(pThread, (void**)&pDummy);
}
p = 0;
for(i=0; i<64; i++){
vdbeSorterMerge(pCsr, p, aSlot[i], &p);
}
pSorter->pRecord = p;
sqlite3_free(aSlot);
return SQLITE_OK;
vdbeSorterMerge(pSorter, aTask[0].pList, aTask[1].pList, &pSorter->pRecord,
pSorter->pUnpacked);
sqlite3_free(aTask[0].apSlot);
return rc;
}
/*
@@ -710,19 +802,20 @@ static void fileWriterWriteVarint(FileWriter *p, u64 iVal){
** Each record consists of a varint followed by a blob of data (the
** key). The varint is the number of bytes in the blob of data.
*/
static int vdbeSorterListToPMA(sqlite3 *db, const VdbeCursor *pCsr){
static int vdbeSorterListToPMA(VdbeSorter *pSorter){
int rc = SQLITE_OK; /* Return code */
VdbeSorter *pSorter = pCsr->pSorter;
FileWriter writer;
sqlite3 *db = pSorter->db;
memset(&writer, 0, sizeof(FileWriter));
if( pSorter->nInMemory==0 ){
assert( pSorter->pRecord==0 );
assert( pSorter->nRecord==0 );
return rc;
}
rc = vdbeSorterSort(pCsr);
rc = vdbeSorterSort(pSorter);
/* If the first temporary PMA file has not been opened, open it now. */
if( rc==SQLITE_OK && pSorter->pTemp1==0 ){
@@ -745,7 +838,8 @@ static int vdbeSorterListToPMA(sqlite3 *db, const VdbeCursor *pCsr){
fileWriterWrite(&writer, p->pVal, p->nVal);
sqlite3DbFree(db, p);
}
pSorter->pRecord = p;
pSorter->pRecord = 0;
pSorter->nRecord = 0;
rc = fileWriterFinish(db, &writer, &pSorter->iWriteOff);
}
@@ -756,11 +850,11 @@ static int vdbeSorterListToPMA(sqlite3 *db, const VdbeCursor *pCsr){
** Add a record to the sorter.
*/
int sqlite3VdbeSorterWrite(
sqlite3 *db, /* Database handle */
const VdbeCursor *pCsr, /* Sorter cursor */
const VdbeCursor *pCsr, /* Sorter cursor */
Mem *pVal /* Memory cell containing record */
){
VdbeSorter *pSorter = pCsr->pSorter;
sqlite3 *db = pSorter->db;
int rc = SQLITE_OK; /* Return Code */
SorterRecord *pNew; /* New list element */
@@ -776,6 +870,7 @@ int sqlite3VdbeSorterWrite(
pNew->nVal = pVal->n;
pNew->pNext = pSorter->pRecord;
pSorter->pRecord = pNew;
pSorter->nRecord++;
}
/* See if the contents of the sorter should now be written out. They
@@ -796,7 +891,7 @@ int sqlite3VdbeSorterWrite(
+ sqlite3VarintLen(pSorter->nInMemory)
+ pSorter->nInMemory;
#endif
rc = vdbeSorterListToPMA(db, pCsr);
rc = vdbeSorterListToPMA(pSorter);
pSorter->nInMemory = 0;
assert( rc!=SQLITE_OK || (nExpect==pSorter->iWriteOff) );
}
@@ -808,11 +903,9 @@ int sqlite3VdbeSorterWrite(
** Helper function for sqlite3VdbeSorterRewind().
*/
static int vdbeSorterInitMerge(
sqlite3 *db, /* Database handle */
const VdbeCursor *pCsr, /* Cursor handle for this sorter */
VdbeSorter *pSorter, /* The sorter */
i64 *pnByte /* Sum of bytes in all opened PMAs */
){
VdbeSorter *pSorter = pCsr->pSorter;
int rc = SQLITE_OK; /* Return code */
int i; /* Used to iterator through aIter[] */
i64 nByte = 0; /* Total bytes in all opened PMAs */
@@ -820,7 +913,7 @@ static int vdbeSorterInitMerge(
/* Initialize the iterators. */
for(i=0; i<SORTER_MAX_MERGE_COUNT; i++){
VdbeSorterIter *pIter = &pSorter->aIter[i];
rc = vdbeSorterIterInit(db, pSorter, pSorter->iReadOff, pIter, &nByte);
rc = vdbeSorterIterInit(pSorter, pSorter->iReadOff, pIter, &nByte);
pSorter->iReadOff = pIter->iEof;
assert( rc!=SQLITE_OK || pSorter->iReadOff<=pSorter->iWriteOff );
if( rc!=SQLITE_OK || pSorter->iReadOff>=pSorter->iWriteOff ) break;
@@ -828,7 +921,7 @@ static int vdbeSorterInitMerge(
/* Initialize the aTree[] array. */
for(i=pSorter->nTree-1; rc==SQLITE_OK && i>0; i--){
rc = vdbeSorterDoCompare(pCsr, i);
rc = vdbeSorterDoCompare(pSorter, i);
}
*pnByte = nByte;
@@ -839,8 +932,9 @@ static int vdbeSorterInitMerge(
** Once the sorter has been populated, this function is called to prepare
** for iterating through its contents in sorted order.
*/
int sqlite3VdbeSorterRewind(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){
VdbeSorter *pSorter = pCsr->pSorter;
sqlite3 *db = pSorter->db;
int rc; /* Return code */
sqlite3_file *pTemp2 = 0; /* Second temp file to use */
i64 iWrite2 = 0; /* Write offset for pTemp2 */
@@ -856,11 +950,11 @@ int sqlite3VdbeSorterRewind(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
if( pSorter->nPMA==0 ){
*pbEof = !pSorter->pRecord;
assert( pSorter->aTree==0 );
return vdbeSorterSort(pCsr);
return vdbeSorterSort(pSorter);
}
/* Write the current in-memory list to a PMA. */
rc = vdbeSorterListToPMA(db, pCsr);
rc = vdbeSorterListToPMA(pSorter);
if( rc!=SQLITE_OK ) return rc;
/* Allocate space for aIter[] and aTree[]. */
@@ -896,7 +990,7 @@ int sqlite3VdbeSorterRewind(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
** initialize interators for SORTER_MAX_MERGE_COUNT of them. These PMAs
** are merged into a single PMA that is written to file pTemp2.
*/
rc = vdbeSorterInitMerge(db, pCsr, &nWrite);
rc = vdbeSorterInitMerge(pSorter, &nWrite);
assert( rc!=SQLITE_OK || pSorter->aIter[ pSorter->aTree[1] ].pFile );
if( rc!=SQLITE_OK || pSorter->nPMA<=SORTER_MAX_MERGE_COUNT ){
break;
@@ -918,7 +1012,7 @@ int sqlite3VdbeSorterRewind(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
fileWriterWriteVarint(&writer, pIter->nKey);
fileWriterWrite(&writer, pIter->aKey, pIter->nKey);
rc = sqlite3VdbeSorterNext(db, pCsr, &bEof);
rc = sqlite3VdbeSorterNext(pCsr, &bEof);
}
rc2 = fileWriterFinish(db, &writer, &iWrite2);
if( rc==SQLITE_OK ) rc = rc2;
@@ -948,23 +1042,25 @@ int sqlite3VdbeSorterRewind(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
/*
** Advance to the next element in the sorter.
*/
int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
int sqlite3VdbeSorterNext(const VdbeCursor *pCsr, int *pbEof){
VdbeSorter *pSorter = pCsr->pSorter;
sqlite3 *db = pSorter->db;
int rc; /* Return code */
if( pSorter->aTree ){
int iPrev = pSorter->aTree[1];/* Index of iterator to advance */
int i; /* Index of aTree[] to recalculate */
rc = vdbeSorterIterNext(db, &pSorter->aIter[iPrev]);
rc = vdbeSorterIterNext(&pSorter->aIter[iPrev]);
for(i=(pSorter->nTree+iPrev)/2; rc==SQLITE_OK && i>0; i=i/2){
rc = vdbeSorterDoCompare(pCsr, i);
rc = vdbeSorterDoCompare(pSorter, i);
}
*pbEof = (pSorter->aIter[pSorter->aTree[1]].pFile==0);
}else{
SorterRecord *pFree = pSorter->pRecord;
pSorter->pRecord = pFree->pNext;
pSorter->nRecord--;
pFree->pNext = 0;
vdbeSorterRecordFree(db, pFree);
*pbEof = !pSorter->pRecord;
@@ -1031,7 +1127,8 @@ int sqlite3VdbeSorterCompare(
void *pKey; int nKey; /* Sorter key to compare pVal with */
pKey = vdbeSorterRowkey(pSorter, &nKey);
vdbeSorterCompare(pCsr, 1, pVal->z, pVal->n, pKey, nKey, pRes);
vdbeSorterCompare(pSorter, 1, pVal->z, pVal->n, pKey, nKey, pRes,
pSorter->pUnpacked);
return SQLITE_OK;
}
+1
View File
@@ -237,6 +237,7 @@ foreach file {
malloc.c
printf.c
random.c
threads.c
utf.c
util.c
hash.c
+1
View File
@@ -242,6 +242,7 @@ foreach file {
malloc.c
printf.c
random.c
threads.c
utf.c
util.c
hash.c