From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id C9F1C2DD18 for ; Mon, 29 Apr 2019 13:26:24 -0400 (EDT) Received: from turing.freelists.org ([127.0.0.1]) by localhost (turing.freelists.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id GUQWAXB4dQ8F for ; Mon, 29 Apr 2019 13:26:24 -0400 (EDT) Received: from smtp39.i.mail.ru (smtp39.i.mail.ru [94.100.177.99]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTPS id CA9A82DCD2 for ; Mon, 29 Apr 2019 13:26:23 -0400 (EDT) From: Stanislav Zudin Subject: [tarantool-patches] [PATCH 6/8] Removes the following unused macros: SQL_EXPLAIN_ESTIMATED_ROWS SQL_ENABLE_COLUMN_USED_MASK SQL_DISABLE_DIRSYNC SQL_OMIT_AUTOMATIC_INDEX SQL_DEBUG_SORTER_THREADS SQL_DEFAULT_WORKER_THREADS SQL_LIMIT_WORKER_THREADS SQL_MAX_WORKER_THREADS Date: Mon, 29 Apr 2019 20:26:09 +0300 Message-Id: In-Reply-To: References: In-Reply-To: References: Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-Help: List-Unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-Subscribe: List-Owner: List-post: List-Archive: To: tarantool-patches@freelists.org, korablev@tarantool.org Cc: Stanislav Zudin Part of #3978 --- src/box/sql/CMakeLists.txt | 3 - src/box/sql/expr.c | 14 - src/box/sql/main.c | 8 - src/box/sql/os_unix.c | 2 - src/box/sql/sqlInt.h | 21 +- src/box/sql/util.c | 5 - src/box/sql/vdbe.c | 20 -- src/box/sql/vdbeInt.h | 3 - src/box/sql/vdbesort.c | 639 +++---------------------------------- src/box/sql/where.c | 313 ------------------ src/box/sql/wherecode.c | 8 - 11 files changed, 45 insertions(+), 991 deletions(-) diff --git a/src/box/sql/CMakeLists.txt b/src/box/sql/CMakeLists.txt index b9dbe141a..f988dc3e7 100644 --- a/src/box/sql/CMakeLists.txt +++ b/src/box/sql/CMakeLists.txt @@ -10,9 +10,6 @@ set(SQL_BIN_DIR ${CMAKE_BINARY_DIR}/src/box/sql) include_directories(${SQL_SRC_DIR}) include_directories(${SQL_BIN_DIR}) -add_definitions(-DSQL_MAX_WORKER_THREADS=0) -add_definitions(-DSQL_OMIT_AUTOMATIC_INDEX) - set(TEST_DEFINITIONS SQL_NO_SYNC=1 SQL_TEST=1 diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c index 71d0cbf46..48d7185f3 100644 --- a/src/box/sql/expr.c +++ b/src/box/sql/expr.c @@ -2570,20 +2570,6 @@ sqlFindInIndex(Parse * pParse, /* Parsing context */ parts[0].sort_order; if (prRhsHasNull) { -#ifdef SQL_ENABLE_COLUMN_USED_MASK - i64 mask = - (1 << nExpr) - 1; - sqlVdbeAddOp4Dup8(v, - OP_ColumnsUsed, - iTab, - 0, - 0, - (u8 - *) - & - mask, - P4_INT64); -#endif *prRhsHasNull = ++pParse->nMem; if (nExpr == 1) { /* Tarantool: Check for null is performed on first key of the index. */ diff --git a/src/box/sql/main.c b/src/box/sql/main.c index c0c334f89..339b456df 100644 --- a/src/box/sql/main.c +++ b/src/box/sql/main.c @@ -533,7 +533,6 @@ static const int aHardLimit[] = { SQL_MAX_ATTACHED, SQL_MAX_LIKE_PATTERN_LENGTH, SQL_MAX_TRIGGER_DEPTH, - SQL_MAX_WORKER_THREADS, }; /* @@ -569,9 +568,6 @@ static const int aHardLimit[] = { #if SQL_MAX_TRIGGER_DEPTH<1 #error SQL_MAX_TRIGGER_DEPTH must be at least 1 #endif -#if SQL_MAX_WORKER_THREADS<0 || SQL_MAX_WORKER_THREADS>50 -#error SQL_MAX_WORKER_THREADS must be between 0 and 50 -#endif /* * Change the value of a limit. Report the old value. @@ -607,9 +603,6 @@ sql_limit(sql * db, int limitId, int newLimit) SQL_MAX_LIKE_PATTERN_LENGTH); assert(aHardLimit[SQL_LIMIT_TRIGGER_DEPTH] == SQL_MAX_TRIGGER_DEPTH); - assert(aHardLimit[SQL_LIMIT_WORKER_THREADS] == - SQL_MAX_WORKER_THREADS); - assert(SQL_LIMIT_WORKER_THREADS == (SQL_N_LIMIT - 1)); if (limitId < 0 || limitId >= SQL_N_LIMIT) { return -1; @@ -652,7 +645,6 @@ sql_init_db(sql **out_db) assert(sizeof(db->aLimit) == sizeof(aHardLimit)); memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit)); - db->aLimit[SQL_LIMIT_WORKER_THREADS] = SQL_DEFAULT_WORKER_THREADS; db->aLimit[SQL_LIMIT_COMPOUND_SELECT] = SQL_DEFAULT_COMPOUND_SELECT; db->szMmap = sqlGlobalConfig.szMmap; db->nMaxSorterMmap = 0x7FFFFFFF; diff --git a/src/box/sql/os_unix.c b/src/box/sql/os_unix.c index 615d539b5..f9969b447 100644 --- a/src/box/sql/os_unix.c +++ b/src/box/sql/os_unix.c @@ -1937,7 +1937,6 @@ unixDelete(sql_vfs * NotUsed, /* VFS containing this as the xDelete method */ } return rc; } -#ifndef SQL_DISABLE_DIRSYNC if ((dirSync & 1) != 0) { int fd; rc = openDirectory(zPath, &fd); @@ -1953,7 +1952,6 @@ unixDelete(sql_vfs * NotUsed, /* VFS containing this as the xDelete method */ rc = SQL_OK; } } -#endif return rc; } diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h index f019cd291..4bf94fad2 100644 --- a/src/box/sql/sqlInt.h +++ b/src/box/sql/sqlInt.h @@ -341,7 +341,6 @@ struct sql_vfs { #define SQL_LIMIT_ATTACHED 7 #define SQL_LIMIT_LIKE_PATTERN_LENGTH 8 #define SQL_LIMIT_TRIGGER_DEPTH 9 -#define SQL_LIMIT_WORKER_THREADS 10 enum sql_ret_code { /** Result of a routine is ok. */ @@ -945,17 +944,6 @@ sql_bind_parameter_lindex(sql_stmt * pStmt, const char *zName, #define SQL_DEFAULT_RECURSIVE_TRIGGERS 0 #endif -#ifndef SQL_MAX_WORKER_THREADS -#define SQL_MAX_WORKER_THREADS 8 -#endif -#ifndef SQL_DEFAULT_WORKER_THREADS -#define SQL_DEFAULT_WORKER_THREADS 0 -#endif -#if SQL_DEFAULT_WORKER_THREADS>SQL_MAX_WORKER_THREADS -#undef SQL_MAX_WORKER_THREADS -#define SQL_MAX_WORKER_THREADS SQL_DEFAULT_WORKER_THREADS -#endif - /** * Default count of allowed compound selects. * @@ -1296,7 +1284,7 @@ typedef int VList; * The number of different kinds of things that can be limited * using the sql_limit() interface. */ -#define SQL_N_LIMIT (SQL_LIMIT_WORKER_THREADS+1) +#define SQL_N_LIMIT (SQL_LIMIT_TRIGGER_DEPTH+1) /* * Lookaside malloc is a set of fixed-size buffers that can be used @@ -4858,13 +4846,6 @@ int sqlMemdebugNoType(void *, u8); #define MEMTYPE_SCRATCH 0x04 /* Scratch allocations */ #define MEMTYPE_PCACHE 0x08 /* Page cache allocations */ -/* - * Threading interface - */ -#if SQL_MAX_WORKER_THREADS>0 -int sqlThreadCreate(sqlThread **, void *(*)(void *), void *); -int sqlThreadJoin(sqlThread *, void **); -#endif int sqlExprVectorSize(Expr * pExpr); int sqlExprIsVector(Expr * pExpr); diff --git a/src/box/sql/util.c b/src/box/sql/util.c index 31378041d..39632e38d 100644 --- a/src/box/sql/util.c +++ b/src/box/sql/util.c @@ -1337,15 +1337,10 @@ sqlLogEstToInt(LogEst x) n -= 2; else if (n >= 1) n -= 1; -#if defined(SQL_EXPLAIN_ESTIMATED_ROWS) - if (x > 60) - return (u64) LARGEST_INT64; -#else /* The largest input possible to this routine is 310, * resulting in a maximum x of 31 */ assert(x <= 60); -#endif return x >= 3 ? (n + 8) << (x - 3) : (n + 8) >> (3 - x); } diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c index 624df25b8..738a0701b 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -3346,26 +3346,6 @@ case OP_Close: { break; } -#ifdef SQL_ENABLE_COLUMN_USED_MASK -/* Opcode: ColumnsUsed P1 * * P4 * - * - * This opcode (which only exists if sql was compiled with - * SQL_ENABLE_COLUMN_USED_MASK) identifies which columns of the - * table or index for cursor P1 are used. P4 is a 64-bit integer - * (P4_INT64) in which the first 63 bits are one for each of the - * first 63 columns of the table or index that are actually used - * by the cursor. The high-order bit is set if any column after - * the 64th is used. - */ -case OP_ColumnsUsed: { - VdbeCursor *pC; - pC = p->apCsr[pOp->p1]; - assert(pC->eCurType==CURTYPE_TARANTOOL); - pC->maskUsed = *(u64*)pOp->p4.pI64; - break; -} -#endif - /* Opcode: SeekGE P1 P2 P3 P4 P5 * Synopsis: key=r[P3@P4] * diff --git a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h index a5933a5e7..a070e87f8 100644 --- a/src/box/sql/vdbeInt.h +++ b/src/box/sql/vdbeInt.h @@ -116,9 +116,6 @@ struct VdbeCursor { const u8 *aRow; /* Data for the current row, if all on one page */ u32 payloadSize; /* Total number of bytes in the record */ u32 szRow; /* Byte available in aRow */ -#ifdef SQL_ENABLE_COLUMN_USED_MASK - u64 maskUsed; /* Mask of columns used by this cursor */ -#endif u32 nRowField; /* Number of fields in the current row */ /* Offsets for all fields in the record [nField+1] * Order of fields is the same as it was passes to create table statement diff --git a/src/box/sql/vdbesort.c b/src/box/sql/vdbesort.c index ddea6752c..a37fbd911 100644 --- a/src/box/sql/vdbesort.c +++ b/src/box/sql/vdbesort.c @@ -118,11 +118,6 @@ * there are already N worker threads running, the main thread does the work * itself. * - * The sorter is running in multi-threaded mode if (a) the library was built - * with pre-processor symbol SQL_MAX_WORKER_THREADS set to a value greater - * than zero, and (b) worker threads have been enabled at runtime by calling - * "PRAGMA threads=N" with some value of N greater than 0. - * * When Rewind() is called, any data remaining in memory is flushed to a * final PMA. So at this point the data is stored in some number of sorted * PMAs within temporary files on disk. @@ -159,15 +154,6 @@ #include "sqlInt.h" #include "vdbeInt.h" -/* - * If SQL_DEBUG_SORTER_THREADS is defined, this module outputs various - * messages to stderr that may be helpful in understanding the performance - * characteristics of the sorter in multi-threaded mode. - */ -#if 0 -#define SQL_DEBUG_SORTER_THREADS 1 -#endif - /* * Hard-coded maximum amount of data to accumulate in memory before flushing * to a level 0 PMA. The purpose of this limit is to prevent various integer @@ -297,18 +283,14 @@ struct MergeEngine { * * Before a background thread is launched, variable bDone is set to 0. Then, * right before it exits, the thread itself sets bDone to 1. This is used for - * two purposes: + * the following purpose: * - * 1. When flushing the contents of memory to a level-0 PMA on disk, to + * When flushing the contents of memory to a level-0 PMA on disk, to * attempt to select a SortSubtask for which there is not already an * active background thread (since doing so causes the main thread * to block until it finishes). * - * 2. If SQL_DEBUG_SORTER_THREADS is defined, to determine if a call - * to sqlThreadJoin() is likely to block. Cases that are likely to - * block provoke debugging output. - * - * In both cases, the effects of the main thread seeing (bDone==0) even + * The effects of the main thread seeing (bDone==0) even * after the thread has finished are not dire. So we don't worry about * memory barriers and such here. */ @@ -855,25 +837,6 @@ sqlVdbeSorterInit(sql * db, /* Database connection (for malloc()) */ int i; /* Used to iterate through aTask[] */ VdbeSorter *pSorter; /* The new sorter */ int rc = SQL_OK; -#if SQL_MAX_WORKER_THREADS==0 -#define nWorker 0 -#else - int nWorker; -#endif - - /* Initialize the upper limit on the number of worker threads */ -#if SQL_MAX_WORKER_THREADS>0 - nWorker = db->aLimit[SQL_LIMIT_WORKER_THREADS]; -#endif - - /* Do not allow the total number of threads (main thread + all workers) - * to exceed the maximum merge count - */ -#if SQL_MAX_WORKER_THREADS>=SORTER_MAX_MERGE_COUNT - if (nWorker >= SORTER_MAX_MERGE_COUNT) { - nWorker = SORTER_MAX_MERGE_COUNT - 1; - } -#endif assert(pCsr->key_def != NULL); assert(pCsr->eCurType == CURTYPE_SORTER); @@ -885,8 +848,8 @@ sqlVdbeSorterInit(sql * db, /* Database connection (for malloc()) */ } else { pSorter->key_def = pCsr->key_def; pSorter->pgsz = pgsz = 1024; - pSorter->nTask = nWorker + 1; - pSorter->iPrev = (u8) (nWorker - 1); + pSorter->nTask = 1; + pSorter->iPrev = (u8) (-1); pSorter->bUseThreads = (pSorter->nTask > 1); pSorter->db = db; for (i = 0; i < pSorter->nTask; i++) { @@ -927,8 +890,6 @@ sqlVdbeSorterInit(sql * db, /* Database connection (for malloc()) */ return rc; } -#undef nWorker /* Defined at the top of this function */ - /* * Free the list of sorted records starting at pRecord. */ @@ -951,18 +912,10 @@ static void vdbeSortSubtaskCleanup(sql * db, SortSubtask * pTask) { sqlDbFree(db, pTask->pUnpacked); -#if SQL_MAX_WORKER_THREADS>0 - /* pTask->list.aMemory can only be non-zero if it was handed memory - * from the main thread. That only occurs SQL_MAX_WORKER_THREADS>0 - */ - if (pTask->list.aMemory) { - sql_free(pTask->list.aMemory); - } else -#endif - { - assert(pTask->list.aMemory == 0); - vdbeSorterRecordFree(0, pTask->list.pList); - } + + assert(pTask->list.aMemory == 0); + vdbeSorterRecordFree(0, pTask->list.pList); + if (pTask->file.pFd) { sqlOsCloseFree(pTask->file.pFd); } @@ -972,116 +925,7 @@ vdbeSortSubtaskCleanup(sql * db, SortSubtask * pTask) memset(pTask, 0, sizeof(SortSubtask)); } -#ifdef SQL_DEBUG_SORTER_THREADS -static void -vdbeSorterWorkDebug(SortSubtask * pTask, const char *zEvent) -{ - i64 t; - int iTask = (pTask - pTask->pSorter->aTask); - sqlOsCurrentTimeInt64(pTask->pSorter->db->pVfs, &t); - fprintf(stderr, "%lld:%d %s\n", t, iTask, zEvent); -} - -static void -vdbeSorterRewindDebug(const char *zEvent) -{ - i64 t; - sqlOsCurrentTimeInt64(sql_vfs_find(0), &t); - fprintf(stderr, "%lld:X %s\n", t, zEvent); -} - -static void -vdbeSorterPopulateDebug(SortSubtask * pTask, const char *zEvent) -{ - i64 t; - int iTask = (pTask - pTask->pSorter->aTask); - sqlOsCurrentTimeInt64(pTask->pSorter->db->pVfs, &t); - fprintf(stderr, "%lld:bg%d %s\n", t, iTask, zEvent); -} - -static void -vdbeSorterBlockDebug(SortSubtask * pTask, int bBlocked, const char *zEvent) -{ - if (bBlocked) { - i64 t; - sqlOsCurrentTimeInt64(pTask->pSorter->db->pVfs, &t); - fprintf(stderr, "%lld:main %s\n", t, zEvent); - } -} -#else -#define vdbeSorterWorkDebug(x,y) -#define vdbeSorterRewindDebug(y) -#define vdbeSorterPopulateDebug(x,y) -#define vdbeSorterBlockDebug(x,y,z) -#endif - -#if SQL_MAX_WORKER_THREADS>0 -/* - * Join thread pTask->thread. - */ -static int -vdbeSorterJoinThread(SortSubtask * pTask) -{ - int rc = SQL_OK; - if (pTask->pThread) { -#ifdef SQL_DEBUG_SORTER_THREADS - int bDone = pTask->bDone; -#endif - void *pRet = SQL_INT_TO_PTR(SQL_ERROR); - vdbeSorterBlockDebug(pTask, !bDone, "enter"); - (void)sqlThreadJoin(pTask->pThread, &pRet); - vdbeSorterBlockDebug(pTask, !bDone, "exit"); - rc = SQL_PTR_TO_INT(pRet); - assert(pTask->bDone == 1); - pTask->bDone = 0; - pTask->pThread = 0; - } - return rc; -} - -/* - * Launch a background thread to run xTask(pIn). - */ -static int -vdbeSorterCreateThread(SortSubtask * pTask, /* Thread will use this task object */ - void *(*xTask) (void *), /* Routine to run in a separate thread */ - void *pIn /* Argument passed into xTask() */ - ) -{ - assert(pTask->pThread == 0 && pTask->bDone == 0); - return sqlThreadCreate(&pTask->pThread, xTask, pIn); -} - -/* - * Join all outstanding threads launched by SorterWrite() to create - * level-0 PMAs. - */ -static int -vdbeSorterJoinAll(VdbeSorter * pSorter, int rcin) -{ - int rc = rcin; - int i; - - /* This function is always called by the main user thread. - * - * If this function is being called after SorterRewind() has been called, - * it is possible that thread pSorter->aTask[pSorter->nTask-1].pThread - * is currently attempt to join one of the other threads. To avoid a race - * condition where this thread also attempts to join the same object, join - * thread pSorter->aTask[pSorter->nTask-1].pThread first. - */ - for (i = pSorter->nTask - 1; i >= 0; i--) { - SortSubtask *pTask = &pSorter->aTask[i]; - int rc2 = vdbeSorterJoinThread(pTask); - if (rc == SQL_OK) - rc = rc2; - } - return rc; -} -#else #define vdbeSorterJoinAll(x,rcin) (rcin) -#define vdbeSorterJoinThread(pTask) SQL_OK -#endif /* * Allocate a new MergeEngine object capable of handling up to @@ -1137,15 +981,6 @@ static void vdbeIncrFree(IncrMerger * pIncr) { if (pIncr) { -#if SQL_MAX_WORKER_THREADS>0 - if (pIncr->bUseThread) { - vdbeSorterJoinThread(pIncr->pTask); - if (pIncr->aFile[0].pFd) - sqlOsCloseFree(pIncr->aFile[0].pFd); - if (pIncr->aFile[1].pFd) - sqlOsCloseFree(pIncr->aFile[1].pFd); - } -#endif vdbeMergeEngineFree(pIncr->pMerger); sql_free(pIncr); } @@ -1160,13 +995,6 @@ sqlVdbeSorterReset(sql * db, VdbeSorter * pSorter) int i; (void)vdbeSorterJoinAll(pSorter, SQL_OK); assert(pSorter->bUseThreads || pSorter->pReader == 0); -#if SQL_MAX_WORKER_THREADS>0 - if (pSorter->pReader) { - vdbePmaReaderClear(pSorter->pReader); - sqlDbFree(db, pSorter->pReader); - pSorter->pReader = 0; - } -#endif vdbeMergeEngineFree(pSorter->pMerger); pSorter->pMerger = 0; for (i = 0; i < pSorter->nTask; i++) { @@ -1516,7 +1344,6 @@ vdbeSorterListToPMA(SortSubtask * pTask, SorterList * pList) pList->szPMA + sqlVarintLen(pList->szPMA) + pTask->file.iEof; #endif - vdbeSorterWorkDebug(pTask, "enter"); memset(&writer, 0, sizeof(PmaWriter)); assert(pList->szPMA > 0); @@ -1558,7 +1385,6 @@ vdbeSorterListToPMA(SortSubtask * pTask, SorterList * pList) rc = vdbePmaWriterFinish(&writer, &pTask->file.iEof); } - vdbeSorterWorkDebug(pTask, "exit"); assert(rc != SQL_OK || pList->pList == 0); assert(rc != SQL_OK || pTask->file.iEof == iSz); return rc; @@ -1648,22 +1474,6 @@ vdbeMergeEngineStep(MergeEngine * pMerger, /* The merge engine to advance to the return (rc == SQL_OK ? pTask->pUnpacked->errCode : rc); } -#if SQL_MAX_WORKER_THREADS>0 -/* - * The main routine for background threads that write level-0 PMAs. - */ -static void * -vdbeSorterFlushThread(void *pCtx) -{ - SortSubtask *pTask = (SortSubtask *) pCtx; - int rc; /* Return code */ - assert(pTask->bDone == 0); - rc = vdbeSorterListToPMA(pTask, &pTask->list); - pTask->bDone = 1; - return SQL_INT_TO_PTR(rc); -} -#endif /* SQL_MAX_WORKER_THREADS>0 */ - /* * Flush the current contents of VdbeSorter.list to a new PMA, possibly * using a background thread. @@ -1671,76 +1481,8 @@ vdbeSorterFlushThread(void *pCtx) static int vdbeSorterFlushPMA(VdbeSorter * pSorter) { -#if SQL_MAX_WORKER_THREADS==0 pSorter->bUsePMA = 1; return vdbeSorterListToPMA(&pSorter->aTask[0], &pSorter->list); -#else - int rc = SQL_OK; - int i; - SortSubtask *pTask = 0; /* Thread context used to create new PMA */ - int nWorker = (pSorter->nTask - 1); - - /* Set the flag to indicate that at least one PMA has been written. - * Or will be, anyhow. - */ - pSorter->bUsePMA = 1; - - /* Select a sub-task to sort and flush the current list of in-memory - * records to disk. If the sorter is running in multi-threaded mode, - * round-robin between the first (pSorter->nTask-1) tasks. Except, if - * the background thread from a sub-tasks previous turn is still running, - * skip it. If the first (pSorter->nTask-1) sub-tasks are all still busy, - * fall back to using the final sub-task. The first (pSorter->nTask-1) - * sub-tasks are prefered as they use background threads - the final - * sub-task uses the main thread. - */ - for (i = 0; i < nWorker; i++) { - int iTest = (pSorter->iPrev + i + 1) % nWorker; - pTask = &pSorter->aTask[iTest]; - if (pTask->bDone) { - rc = vdbeSorterJoinThread(pTask); - } - if (rc != SQL_OK || pTask->pThread == 0) - break; - } - - if (rc == SQL_OK) { - if (i == nWorker) { - /* Use the foreground thread for this operation */ - rc = vdbeSorterListToPMA(&pSorter->aTask[nWorker], - &pSorter->list); - } else { - /* Launch a background thread for this operation */ - u8 *aMem = pTask->list.aMemory; - void *pCtx = (void *)pTask; - - assert(pTask->pThread == 0 && pTask->bDone == 0); - assert(pTask->list.pList == 0); - assert(pTask->list.aMemory == 0 - || pSorter->list.aMemory != 0); - - pSorter->iPrev = (u8) (pTask - pSorter->aTask); - pTask->list = pSorter->list; - pSorter->list.pList = 0; - pSorter->list.szPMA = 0; - if (aMem) { - pSorter->list.aMemory = aMem; - pSorter->nMemory = sqlMallocSize(aMem); - } else if (pSorter->list.aMemory) { - pSorter->list.aMemory = - sqlMalloc(pSorter->nMemory); - if (!pSorter->list.aMemory) - return SQL_NOMEM; - } - - rc = vdbeSorterCreateThread(pTask, - vdbeSorterFlushThread, - pCtx); - } - } - - return rc; -#endif /* SQL_MAX_WORKER_THREADS!=0 */ } /* @@ -1876,8 +1618,6 @@ vdbeIncrPopulate(IncrMerger * pIncr) PmaWriter writer; assert(pIncr->bEof == 0); - vdbeSorterPopulateDebug(pTask, "enter"); - vdbePmaWriterInit(pOut->pFd, &writer, pTask->pSorter->pgsz, iStart); while (rc == SQL_OK) { int dummy; @@ -1904,36 +1644,9 @@ vdbeIncrPopulate(IncrMerger * pIncr) rc2 = vdbePmaWriterFinish(&writer, &pOut->iEof); if (rc == SQL_OK) rc = rc2; - vdbeSorterPopulateDebug(pTask, "exit"); return rc; } -#if SQL_MAX_WORKER_THREADS>0 -/* - * The main routine for background threads that populate aFile[1] of - * multi-threaded IncrMerger objects. - */ -static void * -vdbeIncrPopulateThread(void *pCtx) -{ - IncrMerger *pIncr = (IncrMerger *) pCtx; - void *pRet = SQL_INT_TO_PTR(vdbeIncrPopulate(pIncr)); - pIncr->pTask->bDone = 1; - return pRet; -} - -/* - * Launch a background thread to populate aFile[1] of pIncr. - */ -static int -vdbeIncrBgPopulate(IncrMerger * pIncr) -{ - void *p = (void *)pIncr; - assert(pIncr->bUseThread); - return vdbeSorterCreateThread(pIncr->pTask, vdbeIncrPopulateThread, p); -} -#endif - /* * This function is called when the PmaReader corresponding to pIncr has * finished reading the contents of aFile[0]. Its purpose is to "refill" @@ -1954,33 +1667,10 @@ vdbeIncrBgPopulate(IncrMerger * pIncr) static int vdbeIncrSwap(IncrMerger * pIncr) { - int rc = SQL_OK; - -#if SQL_MAX_WORKER_THREADS>0 - if (pIncr->bUseThread) { - rc = vdbeSorterJoinThread(pIncr->pTask); - - if (rc == SQL_OK) { - SorterFile f0 = pIncr->aFile[0]; - pIncr->aFile[0] = pIncr->aFile[1]; - pIncr->aFile[1] = f0; - } - - if (rc == SQL_OK) { - if (pIncr->aFile[0].iEof == pIncr->iStartOff) { - pIncr->bEof = 1; - } else { - rc = vdbeIncrBgPopulate(pIncr); - } - } - } else -#endif - { - rc = vdbeIncrPopulate(pIncr); - pIncr->aFile[0] = pIncr->aFile[1]; - if (pIncr->aFile[0].iEof == pIncr->iStartOff) { - pIncr->bEof = 1; - } + int rc = vdbeIncrPopulate(pIncr); + pIncr->aFile[0] = pIncr->aFile[1]; + if (pIncr->aFile[0].iEof == pIncr->iStartOff) { + pIncr->bEof = 1; } return rc; @@ -2015,18 +1705,6 @@ vdbeIncrMergerNew(SortSubtask * pTask, /* The thread that will be using the new return rc; } -#if SQL_MAX_WORKER_THREADS>0 -/* - * Set the "use-threads" flag on object pIncr. - */ -static void -vdbeIncrMergerSetThreads(IncrMerger * pIncr) -{ - pIncr->bUseThread = 1; - pIncr->pTask->file2.iEof -= pIncr->mxSz; -} -#endif /* SQL_MAX_WORKER_THREADS>0 */ - /* * Recompute pMerger->aTree[iOut] by comparing the next keys on the * two PmaReaders that feed that entry. Neither of the PmaReaders @@ -2077,38 +1755,20 @@ vdbeMergeEngineCompare(MergeEngine * pMerger, /* Merge engine containing PmaRead pMerger->aTree[iOut] = iRes; } -/* - * Allowed values for the eMode parameter to vdbeMergeEngineInit() - * and vdbePmaReaderIncrMergeInit(). - * - * Only INCRINIT_NORMAL is valid in single-threaded builds (when - * SQL_MAX_WORKER_THREADS==0). The other values are only used - * when there exists one or more separate worker threads. - */ -#define INCRINIT_NORMAL 0 -#define INCRINIT_TASK 1 -#define INCRINIT_ROOT 2 - /* * Forward reference required as the vdbeIncrMergeInit() and * vdbePmaReaderIncrInit() routines are called mutually recursively when * building a merge tree. */ -static int vdbePmaReaderIncrInit(PmaReader * pReadr, int eMode); +static int vdbePmaReaderIncrInit(PmaReader * pReader); /* * Initialize the MergeEngine object passed as the second argument. Once this * function returns, the first key of merged data may be read from the * MergeEngine object in the usual fashion. * - * If argument eMode is INCRINIT_ROOT, then it is assumed that any IncrMerge - * objects attached to the PmaReader objects that the merger reads from have - * already been populated, but that they have not yet populated aFile[0] and - * set the PmaReader objects up to read from it. In this case all that is - * required is to call vdbePmaReaderNext() on each PmaReader to point it at - * its first key. * - * Otherwise, if eMode is any value other than INCRINIT_ROOT, then use + * Use * vdbePmaReaderIncrMergeInit() to initialize each PmaReader that feeds data * to pMerger. * @@ -2116,36 +1776,19 @@ static int vdbePmaReaderIncrInit(PmaReader * pReadr, int eMode); */ static int vdbeMergeEngineInit(SortSubtask * pTask, /* Thread that will run pMerger */ - MergeEngine * pMerger, /* MergeEngine to initialize */ - int eMode /* One of the INCRINIT_XXX constants */ + MergeEngine * pMerger /* MergeEngine to initialize */ ) { int rc = SQL_OK; /* Return code */ int i; /* For looping over PmaReader objects */ int nTree = pMerger->nTree; - /* eMode is always INCRINIT_NORMAL in single-threaded mode */ - assert(SQL_MAX_WORKER_THREADS > 0 || eMode == INCRINIT_NORMAL); - /* Verify that the MergeEngine is assigned to a single thread */ assert(pMerger->pTask == 0); pMerger->pTask = pTask; for (i = 0; i < nTree; i++) { - if (SQL_MAX_WORKER_THREADS > 0 && eMode == INCRINIT_ROOT) { - /* PmaReaders should be normally initialized in order, as if they are - * reading from the same temp file this makes for more linear file IO. - * However, in the INCRINIT_ROOT case, if PmaReader aReadr[nTask-1] is - * in use it will block the vdbePmaReaderNext() call while it uses - * the main thread to fill its buffer. So calling PmaReaderNext() - * on this PmaReader before any of the multi-threaded PmaReaders takes - * better advantage of multi-processor hardware. - */ - rc = vdbePmaReaderNext(&pMerger->aReadr[nTree - i - 1]); - } else { - rc = vdbePmaReaderIncrInit(&pMerger->aReadr[i], - INCRINIT_NORMAL); - } + rc = vdbePmaReaderIncrInit(&pMerger->aReadr[i]); if (rc != SQL_OK) return rc; } @@ -2157,50 +1800,27 @@ vdbeMergeEngineInit(SortSubtask * pTask, /* Thread that will run pMerger */ } /* - * The PmaReader passed as the first argument is guaranteed to be an + * The PmaReader is guaranteed to be an * incremental-reader (pReadr->pIncr!=0). This function serves to open * and/or initialize the temp file related fields of the IncrMerge * object at (pReadr->pIncr). * - * If argument eMode is set to INCRINIT_NORMAL, then all PmaReaders - * in the sub-tree headed by pReadr are also initialized. Data is then + * All PmaReaders + * in the sub-tree headed by pReadr are also initialized. Data is * loaded into the buffers belonging to pReadr and it is set to point to * the first key in its range. * - * If argument eMode is set to INCRINIT_TASK, then pReadr is guaranteed - * to be a multi-threaded PmaReader and this function is being called in a - * background thread. In this case all PmaReaders in the sub-tree are - * initialized as for INCRINIT_NORMAL and the aFile[1] buffer belonging to - * pReadr is populated. However, pReadr itself is not set up to point - * to its first key. A call to vdbePmaReaderNext() is still required to do - * that. - * - * The reason this function does not call vdbePmaReaderNext() immediately - * in the INCRINIT_TASK case is that vdbePmaReaderNext() assumes that it has - * to block on thread (pTask->thread) before accessing aFile[1]. But, since - * this entire function is being run by thread (pTask->thread), that will - * lead to the current background thread attempting to join itself. - * - * Finally, if argument eMode is set to INCRINIT_ROOT, it may be assumed - * that pReadr->pIncr is a multi-threaded IncrMerge objects, and that all - * child-trees have already been initialized using IncrInit(INCRINIT_TASK). - * In this case vdbePmaReaderNext() is called on all child PmaReaders and - * the current PmaReader set to point to the first key in its range. - * * SQL_OK is returned if successful, or an sql error code otherwise. */ static int -vdbePmaReaderIncrMergeInit(PmaReader * pReadr, int eMode) +vdbePmaReaderIncrMergeInit(PmaReader * pReadr) { int rc = SQL_OK; IncrMerger *pIncr = pReadr->pIncr; SortSubtask *pTask = pIncr->pTask; sql *db = pTask->pSorter->db; - /* eMode is always INCRINIT_NORMAL in single-threaded mode */ - assert(SQL_MAX_WORKER_THREADS > 0 || eMode == INCRINIT_NORMAL); - - rc = vdbeMergeEngineInit(pTask, pIncr->pMerger, eMode); + rc = vdbeMergeEngineInit(pTask, pIncr->pMerger); /* Set up the required files for pIncr. A multi-theaded IncrMerge object * requires two temp files to itself, whereas a single-threaded object @@ -2208,74 +1828,27 @@ vdbePmaReaderIncrMergeInit(PmaReader * pReadr, int eMode) */ if (rc == SQL_OK) { int mxSz = pIncr->mxSz; -#if SQL_MAX_WORKER_THREADS>0 - if (pIncr->bUseThread) { - rc = vdbeSorterOpenTempFile(db, mxSz, - &pIncr->aFile[0].pFd); - if (rc == SQL_OK) { - rc = vdbeSorterOpenTempFile(db, mxSz, - &pIncr->aFile[1]. - pFd); - } - } else -#endif - /*if( !pIncr->bUseThread ) */ { - if (pTask->file2.pFd == 0) { - assert(pTask->file2.iEof > 0); - rc = vdbeSorterOpenTempFile(db, - pTask->file2.iEof, - &pTask->file2.pFd); - pTask->file2.iEof = 0; - } - if (rc == SQL_OK) { - pIncr->aFile[1].pFd = pTask->file2.pFd; - pIncr->iStartOff = pTask->file2.iEof; - pTask->file2.iEof += mxSz; - } - } - } -#if SQL_MAX_WORKER_THREADS>0 - if (rc == SQL_OK && pIncr->bUseThread) { - /* Use the current thread to populate aFile[1], even though this - * PmaReader is multi-threaded. If this is an INCRINIT_TASK object, - * then this function is already running in background thread - * pIncr->pTask->thread. - * - * If this is the INCRINIT_ROOT object, then it is running in the - * main VDBE thread. But that is Ok, as that thread cannot return - * control to the VDBE or proceed with anything useful until the - * first results are ready from this merger object anyway. - */ - assert(eMode == INCRINIT_ROOT || eMode == INCRINIT_TASK); - rc = vdbeIncrPopulate(pIncr); + if (pTask->file2.pFd == 0) { + assert(pTask->file2.iEof > 0); + rc = vdbeSorterOpenTempFile(db, + pTask->file2.iEof, + &pTask->file2.pFd); + pTask->file2.iEof = 0; + } + if (rc == SQL_OK) { + pIncr->aFile[1].pFd = pTask->file2.pFd; + pIncr->iStartOff = pTask->file2.iEof; + pTask->file2.iEof += mxSz; + } } -#endif - if (rc == SQL_OK - && (SQL_MAX_WORKER_THREADS == 0 || eMode != INCRINIT_TASK)) { + if (rc == SQL_OK) { rc = vdbePmaReaderNext(pReadr); } return rc; } -#if SQL_MAX_WORKER_THREADS>0 -/* - * The main routine for vdbePmaReaderIncrMergeInit() operations run in - * background threads. - */ -static void * -vdbePmaReaderBgIncrInit(void *pCtx) -{ - PmaReader *pReader = (PmaReader *) pCtx; - void *pRet = - SQL_INT_TO_PTR(vdbePmaReaderIncrMergeInit(pReader, INCRINIT_TASK) - ); - pReader->pIncr->pTask->bDone = 1; - return pRet; -} -#endif - /* * If the PmaReader passed as the first argument is not an incremental-reader * (if pReadr->pIncr==0), then this function is a no-op. Otherwise, it invokes @@ -2288,23 +1861,12 @@ vdbePmaReaderBgIncrInit(void *pCtx) * using the current thread. */ static int -vdbePmaReaderIncrInit(PmaReader * pReadr, int eMode) +vdbePmaReaderIncrInit(PmaReader * pReadr) { IncrMerger *pIncr = pReadr->pIncr; /* Incremental merger */ int rc = SQL_OK; /* Return code */ if (pIncr) { -#if SQL_MAX_WORKER_THREADS>0 - assert(pIncr->bUseThread == 0 || eMode == INCRINIT_TASK); - if (pIncr->bUseThread) { - void *pCtx = (void *)pReadr; - rc = vdbeSorterCreateThread(pIncr->pTask, - vdbePmaReaderBgIncrInit, - pCtx); - } else -#endif - { - rc = vdbePmaReaderIncrMergeInit(pReadr, eMode); - } + rc = vdbePmaReaderIncrMergeInit(pReadr); } return rc; } @@ -2451,23 +2013,10 @@ vdbeSorterMergeTreeBuild(VdbeSorter * pSorter, /* The VDBE cursor that implement int rc = SQL_OK; int iTask; -#if SQL_MAX_WORKER_THREADS>0 - /* If the sorter uses more than one task, then create the top-level - * MergeEngine here. This MergeEngine will read data from exactly - * one PmaReader per sub-task. - */ - assert(pSorter->bUseThreads || pSorter->nTask == 1); - if (pSorter->nTask > 1) { - pMain = vdbeMergeEngineNew(pSorter->nTask); - if (pMain == 0) - rc = SQL_NOMEM; - } -#endif - for (iTask = 0; rc == SQL_OK && iTask < pSorter->nTask; iTask++) { SortSubtask *pTask = &pSorter->aTask[iTask]; - assert(pTask->nPMA > 0 || SQL_MAX_WORKER_THREADS > 0); - if (SQL_MAX_WORKER_THREADS == 0 || pTask->nPMA) { + assert(pTask->nPMA > 0); + if (pTask->nPMA) { MergeEngine *pRoot = 0; /* Root node of tree for this task */ int nDepth = vdbeSorterTreeDepth(pTask->nPMA); i64 iReadOff = 0; @@ -2505,18 +2054,8 @@ vdbeSorterMergeTreeBuild(VdbeSorter * pSorter, /* The VDBE cursor that implement } if (rc == SQL_OK) { -#if SQL_MAX_WORKER_THREADS>0 - if (pMain != 0) { - rc = vdbeIncrMergerNew(pTask, pRoot, - &pMain-> - aReadr[iTask]. - pIncr); - } else -#endif - { - assert(pMain == 0); - pMain = pRoot; - } + assert(pMain == 0); + pMain = pRoot; } else { vdbeMergeEngineFree(pRoot); } @@ -2546,88 +2085,12 @@ vdbeSorterSetupMerge(VdbeSorter * pSorter) int rc; /* Return code */ SortSubtask *pTask0 = &pSorter->aTask[0]; MergeEngine *pMain = 0; -#if SQL_MAX_WORKER_THREADS - sql *db = pTask0->pSorter->db; - int i; - SorterCompare xCompare = vdbeSorterGetCompare(pSorter); - for (i = 0; i < pSorter->nTask; i++) { - pSorter->aTask[i].xCompare = xCompare; - } -#endif rc = vdbeSorterMergeTreeBuild(pSorter, &pMain); if (rc == SQL_OK) { -#if SQL_MAX_WORKER_THREADS - assert(pSorter->bUseThreads == 0 || pSorter->nTask > 1); - if (pSorter->bUseThreads) { - int iTask; - PmaReader *pReadr = 0; - SortSubtask *pLast = - &pSorter->aTask[pSorter->nTask - 1]; - rc = vdbeSortAllocUnpacked(pLast); - if (rc == SQL_OK) { - pReadr = - (PmaReader *) sqlDbMallocZero(db, - sizeof - (PmaReader)); - pSorter->pReader = pReadr; - if (pReadr == 0) - rc = SQL_NOMEM; - } - if (rc == SQL_OK) { - rc = vdbeIncrMergerNew(pLast, pMain, - &pReadr->pIncr); - if (rc == SQL_OK) { - vdbeIncrMergerSetThreads(pReadr->pIncr); - for (iTask = 0; - iTask < (pSorter->nTask - 1); - iTask++) { - IncrMerger *pIncr; - if ((pIncr = - pMain->aReadr[iTask]. - pIncr)) { - vdbeIncrMergerSetThreads - (pIncr); - assert(pIncr->pTask != - pLast); - } - } - for (iTask = 0; - rc == SQL_OK - && iTask < pSorter->nTask; - iTask++) { - /* Check that: - * - * a) The incremental merge object is configured to use the - * right task, and - * b) If it is using task (nTask-1), it is configured to run - * in single-threaded mode. This is important, as the - * root merge (INCRINIT_ROOT) will be using the same task - * object. - */ - PmaReader *p = - &pMain->aReadr[iTask]; - assert(p->pIncr == 0 || ((p->pIncr->pTask == &pSorter->aTask[iTask]) /* a */ - &&(iTask != pSorter->nTask - 1 || p->pIncr->bUseThread == 0) /* b */ - )); - rc = vdbePmaReaderIncrInit(p, - INCRINIT_TASK); - } - } - pMain = 0; - } - if (rc == SQL_OK) { - rc = vdbePmaReaderIncrMergeInit(pReadr, - INCRINIT_ROOT); - } - } else -#endif - { - rc = vdbeMergeEngineInit(pTask0, pMain, - INCRINIT_NORMAL); - pSorter->pMerger = pMain; - pMain = 0; - } + rc = vdbeMergeEngineInit(pTask0, pMain); + pSorter->pMerger = pMain; + pMain = 0; } if (rc != SQL_OK) { @@ -2676,8 +2139,6 @@ sqlVdbeSorterRewind(const VdbeCursor * pCsr, int *pbEof) /* Join all threads */ rc = vdbeSorterJoinAll(pSorter, rc); - vdbeSorterRewindDebug("rewind"); - /* Assuming no errors have occurred, set up a merger structure to * incrementally read and merge all remaining PMAs. */ @@ -2687,7 +2148,6 @@ sqlVdbeSorterRewind(const VdbeCursor * pCsr, int *pbEof) *pbEof = 0; } - vdbeSorterRewindDebug("rewinddone"); return rc; } @@ -2708,12 +2168,6 @@ sqlVdbeSorterNext(sql * db, const VdbeCursor * pCsr, int *pbEof) assert(pSorter->pReader == 0 || pSorter->pMerger == 0); assert(pSorter->bUseThreads == 0 || pSorter->pReader); assert(pSorter->bUseThreads == 1 || pSorter->pMerger); -#if SQL_MAX_WORKER_THREADS>0 - if (pSorter->bUseThreads) { - rc = vdbePmaReaderNext(pSorter->pReader); - *pbEof = (pSorter->pReader->pFd == 0); - } else -#endif /*if( !pSorter->bUseThreads ) */ { assert(pSorter->pMerger != 0); assert(pSorter->pMerger->pTask == (&pSorter->aTask[0])); @@ -2743,11 +2197,6 @@ vdbeSorterRowkey(const VdbeSorter * pSorter, /* Sorter object */ void *pKey; if (pSorter->bUsePMA) { PmaReader *pReader; -#if SQL_MAX_WORKER_THREADS>0 - if (pSorter->bUseThreads) { - pReader = pSorter->pReader; - } else -#endif /*if( !pSorter->bUseThreads ) */ { pReader = &pSorter->pMerger->aReadr[pSorter->pMerger-> diff --git a/src/box/sql/where.c b/src/box/sql/where.c index efd4f4f4b..c38b60b0f 100644 --- a/src/box/sql/where.c +++ b/src/box/sql/where.c @@ -684,225 +684,6 @@ translateColumnToCopy(Vdbe * v, /* The VDBE containing code to translate */ } } -#ifndef SQL_OMIT_AUTOMATIC_INDEX -/* - * Return TRUE if the WHERE clause term pTerm is of a form where it - * could be used with an index to access pSrc, assuming an appropriate - * index existed. - */ -static int -termCanDriveIndex(WhereTerm * pTerm, /* WHERE clause term to check */ - struct SrcList_item *pSrc, /* Table we are trying to access */ - Bitmask notReady /* Tables in outer loops of the join */ - ) -{ - if (pTerm->leftCursor != pSrc->iCursor) - return 0; - if ((pTerm->eOperator & WO_EQ) == 0) - return 0; - if ((pTerm->prereqRight & notReady) != 0) - return 0; - if (pTerm->u.leftColumn < 0) - return 0; - enum field_type type = pSrc->pTab->def->fields[pTerm->u.leftColumn].type; - enum field_type expr_type = expr_cmp_mutual_type(pTerm->pExpr); - if (!field_type1_contains_type2(expr_type, type)) - return 0; - return 1; -} -#endif - -#ifndef SQL_OMIT_AUTOMATIC_INDEX -/* - * Generate code to construct the Index object for an automatic index - * and to set up the WhereLevel object pLevel so that the code generator - * makes use of the automatic index. - */ -static void -constructAutomaticIndex(Parse * pParse, /* The parsing context */ - WhereClause * pWC, /* The WHERE clause */ - struct SrcList_item *pSrc, /* The FROM clause term to get the next index */ - Bitmask notReady, /* Mask of cursors that are not available */ - WhereLevel * pLevel) /* Write new index here */ -{ - int nKeyCol; /* Number of columns in the constructed index */ - WhereTerm *pTerm; /* A single term of the WHERE clause */ - WhereTerm *pWCEnd; /* End of pWC->a[] */ - Index *pIdx; /* Object describing the transient index */ - Vdbe *v; /* Prepared statement under construction */ - int addrInit; /* Address of the initialization bypass jump */ - Table *pTable; /* The table being indexed */ - int addrTop; /* Top of the index fill loop */ - int regRecord; /* Register holding an index record */ - int n; /* Column counter */ - int i; /* Loop counter */ - int mxBitCol; /* Maximum column in pSrc->colUsed */ - struct coll *pColl; /* Collating sequence to on a column */ - WhereLoop *pLoop; /* The Loop object */ - char *zNotUsed; /* Extra space on the end of pIdx */ - Bitmask idxCols; /* Bitmap of columns used for indexing */ - Bitmask extraCols; /* Bitmap of additional columns */ - u8 sentWarning = 0; /* True if a warnning has been issued */ - int iContinue = 0; /* Jump here to skip excluded rows */ - struct SrcList_item *pTabItem; /* FROM clause term being indexed */ - int addrCounter = 0; /* Address where integer counter is initialized */ - int regBase; /* Array of registers where record is assembled */ - - /* Generate code to skip over the creation and initialization of the - * transient index on 2nd and subsequent iterations of the loop. - */ - v = pParse->pVdbe; - assert(v != 0); - addrInit = sqlVdbeAddOp0(v, OP_Once); - VdbeCoverage(v); - - /* Count the number of columns that will be added to the index - * and used to match WHERE clause constraints - */ - nKeyCol = 0; - pTable = pSrc->pTab; - pWCEnd = &pWC->a[pWC->nTerm]; - pLoop = pLevel->pWLoop; - idxCols = 0; - for (pTerm = pWC->a; pTerm < pWCEnd; pTerm++) { - if (termCanDriveIndex(pTerm, pSrc, notReady)) { - int iCol = pTerm->u.leftColumn; - Bitmask cMask = - iCol >= BMS ? MASKBIT(BMS - 1) : MASKBIT(iCol); - testcase(iCol == BMS); - testcase(iCol == BMS - 1); - if (!sentWarning) { - sql_log(SQL_WARNING_AUTOINDEX, - "automatic index on %s(%s)", - pTable->def->name, - pTable->aCol[iCol].zName); - sentWarning = 1; - } - if ((idxCols & cMask) == 0) { - if (whereLoopResize - (pParse->db, pLoop, nKeyCol + 1)) { - goto end_auto_index_create; - } - pLoop->aLTerm[nKeyCol++] = pTerm; - idxCols |= cMask; - } - } - } - assert(nKeyCol > 0); - pLoop->nEq = pLoop->nLTerm = nKeyCol; - pLoop->wsFlags = WHERE_COLUMN_EQ | WHERE_IDX_ONLY | WHERE_INDEXED - | WHERE_AUTO_INDEX; - - /* Count the number of additional columns needed to create a - * covering index. A "covering index" is an index that contains all - * columns that are needed by the query. With a covering index, the - * original table never needs to be accessed. Automatic indices must - * be a covering index because the index will not be updated if the - * original table changes and the index and table cannot both be used - * if they go out of sync. - */ - extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS - 1)); - mxBitCol = MIN(BMS - 1, pTable->def->field_count); - testcase(pTable->def->field_count == BMS - 1); - testcase(pTable->def->field_count == BMS - 2); - for (i = 0; i < mxBitCol; i++) { - if (extraCols & MASKBIT(i)) - nKeyCol++; - } - if (pSrc->colUsed & MASKBIT(BMS - 1)) { - nKeyCol += pTable->def->field_count - BMS + 1; - } - - /* Construct the Index object to describe this index */ - pIdx = sqlDbMallocZero(pParse->db, sizeof(*pIdx)); - if (pIdx == 0) - goto end_auto_index_create; - pLoop->pIndex = pIdx; - pIdx->zName = "auto-index"; - pIdx->pTable = pTable; - n = 0; - idxCols = 0; - for (pTerm = pWC->a; pTerm < pWCEnd; pTerm++) { - if (termCanDriveIndex(pTerm, pSrc, notReady)) { - int iCol = pTerm->u.leftColumn; - Bitmask cMask = - iCol >= BMS ? MASKBIT(BMS - 1) : MASKBIT(iCol); - testcase(iCol == BMS - 1); - testcase(iCol == BMS); - if ((idxCols & cMask) == 0) { - Expr *pX = pTerm->pExpr; - idxCols |= cMask; - pIdx->aiColumn[n] = pTerm->u.leftColumn; - n++; - } - } - } - assert((u32) n == pLoop->nEq); - - /* Add additional columns needed to make the automatic index into - * a covering index - */ - for (i = 0; i < mxBitCol; i++) { - if (extraCols & MASKBIT(i)) { - pIdx->aiColumn[n] = i; - n++; - } - } - if (pSrc->colUsed & MASKBIT(BMS - 1)) { - for (i = BMS - 1; i < (int)pTable->def->field_count; i++) { - pIdx->aiColumn[n] = i; - n++; - } - } - assert(n == nKeyCol); - pIdx->aiColumn[n] = XN_ROWID; - - /* Create the automatic index */ - assert(pLevel->iIdxCur >= 0); - pLevel->iIdxCur = pParse->nTab++; - sqlVdbeAddOp2(v, OP_OpenAutoindex, pLevel->iIdxCur, nKeyCol + 1); - sql_vdbe_set_p4_key_def(pParse, pIdx->key_def); - VdbeComment((v, "for %s", pTable->def->name)); - - /* Fill the automatic index with content */ - sqlExprCachePush(pParse); - pTabItem = &pWC->pWInfo->pTabList->a[pLevel->iFrom]; - if (pTabItem->fg.viaCoroutine) { - int regYield = pTabItem->regReturn; - addrCounter = sqlVdbeAddOp2(v, OP_Integer, 0, 0); - sqlVdbeAddOp3(v, OP_InitCoroutine, regYield, 0, - pTabItem->addrFillSub); - addrTop = sqlVdbeAddOp1(v, OP_Yield, regYield); - VdbeCoverage(v); - VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName)); - } else { - addrTop = sqlVdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); - VdbeCoverage(v); - } - regRecord = sqlGetTempReg(pParse); - regBase = sql_generate_index_key(pParse, pIdx, pLevel->iTabCur, - regRecord, NULL, 0); - sqlVdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord); - if (pTabItem->fg.viaCoroutine) { - sqlVdbeChangeP2(v, addrCounter, regBase + n); - translateColumnToCopy(v, addrTop, pLevel->iTabCur, - pTabItem->regResult, 1); - sqlVdbeGoto(v, addrTop); - pTabItem->fg.viaCoroutine = 0; - } else { - sqlVdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop + 1); - VdbeCoverage(v); - } - sqlVdbeChangeP5(v, SQL_STMTSTATUS_AUTOINDEX); - sqlVdbeJumpHere(v, addrTop); - sqlReleaseTempReg(pParse, regRecord); - sqlExprCachePop(pParse); - - /* Jump here when skipping the initialization */ - sqlVdbeJumpHere(v, addrInit); -} -#endif /* SQL_OMIT_AUTOMATIC_INDEX */ - /* * Estimate the location of a particular key among all keys in an * index. Store the results in aStat as follows: @@ -2828,61 +2609,6 @@ tnt_error: probe = fake_index; } -#ifndef SQL_OMIT_AUTOMATIC_INDEX - /* Automatic indexes */ - LogEst rSize = pTab->nRowLogEst; - LogEst rLogSize = estLog(rSize); - struct session *user_session = current_session(); - if (!pBuilder->pOrSet /* Not part of an OR optimization */ - && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE) == 0 && (user_session->sql_flags & SQL_AutoIndex) != 0 && pSrc->pIBIndex == 0 /* Has no INDEXED BY clause */ - && !pSrc->fg.notIndexed /* Has no NOT INDEXED clause */ - && HasRowid(pTab) /* Not WITHOUT ROWID table. (FIXME: Why not?) */ - &&!pSrc->fg.isCorrelated /* Not a correlated subquery */ - && !pSrc->fg.isRecursive /* Not a recursive common table expression. */ - ) { - /* Generate auto-index WhereLoops */ - WhereTerm *pTerm; - WhereTerm *pWCEnd = pWC->a + pWC->nTerm; - for (pTerm = pWC->a; rc == SQL_OK && pTerm < pWCEnd; pTerm++) { - if (pTerm->prereqRight & pNew->maskSelf) - continue; - if (termCanDriveIndex(pTerm, pSrc, 0)) { - pNew->nEq = 1; - pNew->nSkip = 0; - pNew->pIndex = 0; - pNew->nLTerm = 1; - pNew->aLTerm[0] = pTerm; - /* TUNING: One-time cost for computing the automatic index is - * estimated to be X*N*log2(N) where N is the number of rows in - * the table being indexed and where X is 7 (LogEst=28) for normal - * tables or 1.375 (LogEst=4) for views and subqueries. The value - * of X is smaller for views and subqueries so that the query planner - * will be more aggressive about generating automatic indexes for - * those objects, since there is no opportunity to add schema - * indexes on subqueries and views. - */ - pNew->rSetup = rLogSize + rSize + 4; - if (!pTab->def->opts.is_view && - pTab->def->id == 0) - pNew->rSetup += 24; - if (pNew->rSetup < 0) - pNew->rSetup = 0; - /* TUNING: Each index lookup yields 20 rows in the table. This - * is more than the usual guess of 10 rows, since we have no way - * of knowing how selective the index will ultimately be. It would - * not be unreasonable to make this value much larger. - */ - pNew->nOut = 43; - assert(43 == sqlLogEst(20)); - pNew->rRun = - sqlLogEstAdd(rLogSize, pNew->nOut); - pNew->wsFlags = WHERE_AUTO_INDEX; - pNew->prereq = mPrereq | pTerm->prereqRight; - rc = whereLoopInsert(pBuilder, pNew); - } - } - } -#endif /* SQL_OMIT_AUTOMATIC_INDEX */ /* * If there was an INDEXED BY clause, then only that one * index is considered. @@ -4561,12 +4287,6 @@ sqlWhereBegin(Parse * pParse, /* The parser context */ VdbeComment((v, "%s", space->def->name)); assert(pTabItem->iCursor == pLevel->iTabCur); sqlVdbeChangeP5(v, bFordelete); -#ifdef SQL_ENABLE_COLUMN_USED_MASK - sqlVdbeAddOp4Dup8(v, OP_ColumnsUsed, - pTabItem->iCursor, 0, 0, - (const u8 *)&pTabItem->colUsed, - P4_INT64); -#endif } if (pLoop->wsFlags & WHERE_INDEXED) { struct index_def *idx_def = pLoop->index_def; @@ -4641,30 +4361,6 @@ sqlWhereBegin(Parse * pParse, /* The parser context */ sqlVdbeChangeP5(v, OPFLAG_SEEKEQ); /* Hint to COMDB2 */ } VdbeComment((v, "%s", idx_def->name)); -#ifdef SQL_ENABLE_COLUMN_USED_MASK - { - u64 colUsed = 0; - int ii, jj; - for (ii = 0; ii < pIx->nColumn; ii++) { - jj = pIx->aiColumn[ii]; - if (jj < 0) - continue; - if (jj > 63) - jj = 63; - if ((pTabItem-> - colUsed & MASKBIT(jj)) == - 0) - continue; - colUsed |= - ((u64) 1) << (ii < - 63 ? ii : 63); - } - sqlVdbeAddOp4Dup8(v, OP_ColumnsUsed, - iIndexCur, 0, 0, - (u8 *) & colUsed, - P4_INT64); - } -#endif /* SQL_ENABLE_COLUMN_USED_MASK */ } } } @@ -4679,15 +4375,6 @@ sqlWhereBegin(Parse * pParse, /* The parser context */ notReady = ~(Bitmask) 0; for (ii = 0; ii < nTabList; ii++) { pLevel = &pWInfo->a[ii]; -#ifndef SQL_OMIT_AUTOMATIC_INDEX - if ((pLevel->pWLoop->wsFlags & WHERE_AUTO_INDEX) != 0) { - constructAutomaticIndex(pParse, &pWInfo->sWC, - &pTabList->a[pLevel->iFrom], - notReady, pLevel); - if (db->mallocFailed) - goto whereBeginError; - } -#endif sqlWhereExplainOneScan(pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags); pLevel->addrBody = sqlVdbeCurrentAddr(v); diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c index 4dedb38a7..01fa138f6 100644 --- a/src/box/sql/wherecode.c +++ b/src/box/sql/wherecode.c @@ -253,14 +253,6 @@ sqlWhereExplainOneScan(Parse * pParse, /* Parse context */ " USING INTEGER PRIMARY KEY (rowid%s?)", zRangeOp); } -#ifdef SQL_EXPLAIN_ESTIMATED_ROWS - if (pLoop->nOut >= 10) { - sqlXPrintf(&str, " (~%llu rows)", - sqlLogEstToInt(pLoop->nOut)); - } else { - sqlStrAccumAppend(&str, " (~1 row)", 9); - } -#endif zMsg = sqlStrAccumFinish(&str); ret = sqlVdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg, -- 2.17.1