Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1d60598d40 | |||
| 90c9f69892 | |||
| 3473d375e7 | |||
| 486e31f1b3 | |||
| e22724ee54 | |||
| a806475f86 | |||
| 572df3b1e4 | |||
| da0e47109e | |||
| f51446a38c |
+5
-1
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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
@@ -1 +1 @@
|
||||
573770f5a66fa4d708931b30350149eb739da607
|
||||
acdc7d1270b6aacf4612296a8d4dd596042b058c
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -237,6 +237,7 @@ foreach file {
|
||||
malloc.c
|
||||
printf.c
|
||||
random.c
|
||||
threads.c
|
||||
utf.c
|
||||
util.c
|
||||
hash.c
|
||||
|
||||
@@ -242,6 +242,7 @@ foreach file {
|
||||
malloc.c
|
||||
printf.c
|
||||
random.c
|
||||
threads.c
|
||||
utf.c
|
||||
util.c
|
||||
hash.c
|
||||
|
||||
Reference in New Issue
Block a user