Merge remote-tracking branch 'origin/3.0' into feature/config
This commit is contained in:
commit
e5606ccf38
|
@ -589,7 +589,7 @@ SOperatorInfo* createTableSeqScanOperatorInfo(void* pTsdbQueryHandle, SQueryRunt
|
|||
SOperatorInfo* createAggregateOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SOperatorInfo* upstream, SExprInfo* pExpr, int32_t numOfOutput);
|
||||
SOperatorInfo* createProjectOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SOperatorInfo* upstream, SExprInfo* pExpr, int32_t numOfOutput);
|
||||
SOperatorInfo* createLimitOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SOperatorInfo* upstream);
|
||||
SOperatorInfo* createTimeIntervalOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SOperatorInfo* upstream, SExprInfo* pExpr, int32_t numOfOutput);
|
||||
SOperatorInfo* createIntervalOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SOperatorInfo* upstream, SExprInfo* pExpr, int32_t numOfOutput);
|
||||
SOperatorInfo* createAllTimeIntervalOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SOperatorInfo* upstream, SExprInfo* pExpr, int32_t numOfOutput);
|
||||
SOperatorInfo* createSWindowOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SOperatorInfo* upstream, SExprInfo* pExpr, int32_t numOfOutput);
|
||||
SOperatorInfo* createFillOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SOperatorInfo* upstream, SExprInfo* pExpr, int32_t numOfOutput, bool multigroupResult);
|
||||
|
|
|
@ -2166,7 +2166,7 @@ static int32_t setupQueryRuntimeEnv(SQueryRuntimeEnv *pRuntimeEnv, int32_t numOf
|
|||
}
|
||||
case OP_TimeWindow: {
|
||||
pRuntimeEnv->proot =
|
||||
createTimeIntervalOperatorInfo(pRuntimeEnv, pRuntimeEnv->proot, pQueryAttr->pExpr1, pQueryAttr->numOfOutput);
|
||||
createIntervalOperatorInfo(pRuntimeEnv, pRuntimeEnv->proot, pQueryAttr->pExpr1, pQueryAttr->numOfOutput);
|
||||
int32_t opType = pRuntimeEnv->proot->upstream[0]->operatorType;
|
||||
if (opType != OP_DummyInput && opType != OP_Join) {
|
||||
setTableScanFilterOperatorInfo(pRuntimeEnv->proot->upstream[0]->info, pRuntimeEnv->proot);
|
||||
|
@ -6756,7 +6756,7 @@ SOperatorInfo* createLimitOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SOperatorI
|
|||
return pOperator;
|
||||
}
|
||||
|
||||
SOperatorInfo* createTimeIntervalOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SOperatorInfo* upstream, SExprInfo* pExpr, int32_t numOfOutput) {
|
||||
SOperatorInfo* createIntervalOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SOperatorInfo* upstream, SExprInfo* pExpr, int32_t numOfOutput) {
|
||||
STableIntervalOperatorInfo* pInfo = calloc(1, sizeof(STableIntervalOperatorInfo));
|
||||
|
||||
pInfo->pCtx = createSQLFunctionCtx(pRuntimeEnv, pExpr, numOfOutput, &pInfo->rowCellInfoOffset);
|
||||
|
|
|
@ -18,9 +18,6 @@ typedef struct SBlockOrderInfo {
|
|||
int32_t order;
|
||||
int32_t colIndex;
|
||||
SColumnInfoData *pColData;
|
||||
// int32_t type;
|
||||
// int32_t bytes;
|
||||
// bool hasNull;
|
||||
} SBlockOrderInfo;
|
||||
|
||||
int taosGetFqdnPortFromEp(const char *ep, SEp *pEp);
|
||||
|
@ -67,15 +64,15 @@ static FORCE_INLINE bool colDataIsNull(const SColumnInfoData* pColumnInfoData, u
|
|||
}
|
||||
}
|
||||
|
||||
#define colDataGet(p1_, r_) \
|
||||
((IS_VAR_DATA_TYPE((p1_)->info.type)) ? ((p1_)->pData + (p1_)->varmeta.offset[(r_)]) \
|
||||
: ((p1_)->pData + ((r_) * (p1_)->info.bytes)))
|
||||
#define colDataGetData(p1_, r_) \
|
||||
((IS_VAR_DATA_TYPE((p1_)->info.type)) ? (p1_)->pData + (p1_)->varmeta.offset[(r_)] \
|
||||
: (p1_)->pData + ((r_) * (p1_)->info.bytes))
|
||||
|
||||
int32_t colDataAppend(SColumnInfoData* pColumnInfoData, uint32_t currentRow, const char* pData, bool isNull);
|
||||
int32_t colDataMergeCol(SColumnInfoData* pColumnInfoData, uint32_t numOfRow1, const SColumnInfoData* pSource, uint32_t numOfRow2);
|
||||
int32_t blockDataUpdateTsWindow(SSDataBlock* pDataBlock);
|
||||
|
||||
int32_t colDataGetSize(const SColumnInfoData* pColumnInfoData, int32_t numOfRows);
|
||||
int32_t colDataGetLength(const SColumnInfoData* pColumnInfoData, int32_t numOfRows);
|
||||
void colDataTrim(SColumnInfoData* pColumnInfoData);
|
||||
|
||||
size_t colDataGetNumOfCols(const SSDataBlock* pBlock);
|
||||
|
@ -93,13 +90,15 @@ size_t blockDataGetRowSize(const SSDataBlock* pBlock);
|
|||
double blockDataGetSerialRowSize(const SSDataBlock* pBlock);
|
||||
size_t blockDataGetSerialMetaSize(const SSDataBlock* pBlock);
|
||||
|
||||
size_t blockDataNumOfRowsForSerialize(const SSDataBlock* pBlock, int32_t blockSize);
|
||||
SSchema* blockDataExtractSchema(const SSDataBlock* pBlock, int32_t* numOfCols);
|
||||
|
||||
int32_t blockDataSort(SSDataBlock* pDataBlock, SArray* pOrderInfo, bool nullFirst);
|
||||
int32_t blockDataSort_rv(SSDataBlock* pDataBlock, SArray* pOrderInfo, bool nullFirst);
|
||||
|
||||
int32_t blockDataEnsureCapacity(SSDataBlock* pDataBlock, uint32_t numOfRows);
|
||||
void blockDataClearup(SSDataBlock* pDataBlock, bool hasVarCol);
|
||||
SSDataBlock* createOneDataBlock(const SSDataBlock* pDataBlock);
|
||||
size_t blockDataGetCapacityInRow(const SSDataBlock* pBlock, size_t pageSize);
|
||||
void *blockDataDestroy(SSDataBlock *pBlock);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -31,6 +31,7 @@ typedef struct SReadHandle {
|
|||
void* reader;
|
||||
void* meta;
|
||||
} SReadHandle;
|
||||
|
||||
/**
|
||||
* Create the exec task for streaming mode
|
||||
* @param pMsg
|
||||
|
@ -40,13 +41,23 @@ typedef struct SReadHandle {
|
|||
qTaskInfo_t qCreateStreamExecTaskInfo(void *msg, void* streamReadHandle);
|
||||
|
||||
/**
|
||||
*
|
||||
* Set the input data block for the stream scan.
|
||||
* @param tinfo
|
||||
* @param input
|
||||
* @return
|
||||
*/
|
||||
int32_t qSetStreamInput(qTaskInfo_t tinfo, const void* input);
|
||||
|
||||
/**
|
||||
* Update the table id list, add or remove.
|
||||
*
|
||||
* @param tinfo
|
||||
* @param id
|
||||
* @param isAdd
|
||||
* @return
|
||||
*/
|
||||
int32_t qUpdateQualifiedTableId(qTaskInfo_t tinfo, SArray* tableIdList, bool isAdd);
|
||||
|
||||
/**
|
||||
* Create the exec task object according to task json
|
||||
* @param readHandle
|
||||
|
|
|
@ -138,8 +138,10 @@ extern SFunctionFpSet fpSet[1];
|
|||
|
||||
// sql function runtime context
|
||||
typedef struct SqlFunctionCtx {
|
||||
int32_t startRow;
|
||||
int32_t size; // number of rows
|
||||
void * pInput; // input data buffer
|
||||
SColumnInfoData* pInput;
|
||||
|
||||
uint32_t order; // asc|desc
|
||||
int16_t inputType;
|
||||
int16_t inputBytes;
|
||||
|
|
|
@ -47,5 +47,6 @@ OP_ENUM_MACRO(AllTimeWindow)
|
|||
OP_ENUM_MACRO(AllMultiTableTimeInterval)
|
||||
OP_ENUM_MACRO(Order)
|
||||
OP_ENUM_MACRO(Exchange)
|
||||
OP_ENUM_MACRO(SortedMerge)
|
||||
|
||||
//OP_ENUM_MACRO(TableScan)
|
||||
|
|
|
@ -42,8 +42,8 @@ extern "C" {
|
|||
|
||||
typedef struct SArray {
|
||||
size_t size;
|
||||
size_t capacity;
|
||||
size_t elemSize;
|
||||
uint32_t capacity;
|
||||
uint32_t elemSize;
|
||||
void* pData;
|
||||
} SArray;
|
||||
|
||||
|
|
|
@ -29,10 +29,9 @@ typedef struct SPageInfo SPageInfo;
|
|||
typedef struct SDiskbasedBuf SDiskbasedBuf;
|
||||
|
||||
#define DEFAULT_INTERN_BUF_PAGE_SIZE (1024L) // in bytes
|
||||
#define DEFAULT_PAGE_SIZE (16384L)
|
||||
|
||||
typedef struct SFilePage {
|
||||
int64_t num;
|
||||
int32_t num;
|
||||
char data[];
|
||||
} SFilePage;
|
||||
|
||||
|
@ -54,8 +53,7 @@ typedef struct SDiskbasedBufStatis {
|
|||
* @param handle
|
||||
* @return
|
||||
*/
|
||||
int32_t createDiskbasedBuffer(SDiskbasedBuf** pBuf, int32_t pagesize, int32_t inMemBufSize, uint64_t qId,
|
||||
const char* dir);
|
||||
int32_t createDiskbasedBuf(SDiskbasedBuf** pBuf, int32_t pagesize, int32_t inMemBufSize, uint64_t qId, const char* dir);
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -64,7 +62,7 @@ int32_t createDiskbasedBuffer(SDiskbasedBuf** pBuf, int32_t pagesize, int32_t in
|
|||
* @param pageId
|
||||
* @return
|
||||
*/
|
||||
SFilePage* getNewDataBuf(SDiskbasedBuf* pBuf, int32_t groupId, int32_t* pageId);
|
||||
void* getNewBufPage(SDiskbasedBuf* pBuf, int32_t groupId, int32_t* pageId);
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -80,7 +78,7 @@ SIDList getDataBufPagesIdList(SDiskbasedBuf* pBuf, int32_t groupId);
|
|||
* @param id
|
||||
* @return
|
||||
*/
|
||||
SFilePage* getBufPage(SDiskbasedBuf* pBuf, int32_t id);
|
||||
void* getBufPage(SDiskbasedBuf* pBuf, int32_t id);
|
||||
|
||||
/**
|
||||
* release the referenced buf pages
|
||||
|
@ -108,13 +106,13 @@ size_t getTotalBufSize(const SDiskbasedBuf* pBuf);
|
|||
* @param pBuf
|
||||
* @return
|
||||
*/
|
||||
size_t getNumOfResultBufGroupId(const SDiskbasedBuf* pBuf);
|
||||
size_t getNumOfBufGroupId(const SDiskbasedBuf* pBuf);
|
||||
|
||||
/**
|
||||
* destroy result buffer
|
||||
* @param pBuf
|
||||
*/
|
||||
void destroyResultBuf(SDiskbasedBuf* pBuf);
|
||||
void destroyDiskbasedBuf(SDiskbasedBuf* pBuf);
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -137,6 +135,11 @@ int32_t getPageId(const SPageInfo* pPgInfo);
|
|||
*/
|
||||
int32_t getBufPageSize(const SDiskbasedBuf* pBuf);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param pBuf
|
||||
* @return
|
||||
*/
|
||||
int32_t getNumOfInMemBufPages(const SDiskbasedBuf* pBuf);
|
||||
|
||||
/**
|
||||
|
@ -148,22 +151,43 @@ bool isAllDataInMemBuf(const SDiskbasedBuf* pBuf);
|
|||
|
||||
/**
|
||||
* Set the buffer page is dirty, and needs to be flushed to disk when swap out.
|
||||
* @param pPageInfo
|
||||
* @param pPage
|
||||
* @param dirty
|
||||
*/
|
||||
void setBufPageDirty(SFilePage* pPageInfo, bool dirty);
|
||||
void setBufPageDirty(void* pPage, bool dirty);
|
||||
|
||||
/**
|
||||
* Set the compress/ no-compress flag for paged buffer, when flushing data in disk.
|
||||
* @param pBuf
|
||||
*/
|
||||
void setBufPageCompressOnDisk(SDiskbasedBuf* pBuf, bool comp);
|
||||
|
||||
/**
|
||||
* Set the pageId page buffer is not need
|
||||
* @param pBuf
|
||||
* @param pageId
|
||||
*/
|
||||
void dBufSetBufPageRecycled(SDiskbasedBuf *pBuf, void* pPage);
|
||||
|
||||
/**
|
||||
* Print the statistics when closing this buffer
|
||||
* @param pBuf
|
||||
*/
|
||||
void printStatisBeforeClose(SDiskbasedBuf* pBuf);
|
||||
void dBufSetPrintInfo(SDiskbasedBuf* pBuf);
|
||||
|
||||
/**
|
||||
* return buf statistics.
|
||||
* Return buf statistics.
|
||||
* @param pBuf
|
||||
* @return
|
||||
*/
|
||||
SDiskbasedBufStatis getDBufStatis(const SDiskbasedBuf* pBuf);
|
||||
|
||||
/**
|
||||
* Print the buffer statistics information
|
||||
* @param pBuf
|
||||
*/
|
||||
void dBufPrintStatis(const SDiskbasedBuf* pBuf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -53,8 +53,10 @@ TEST(testCase, driverInit_Test) {
|
|||
// taos_init();
|
||||
}
|
||||
|
||||
#if 0
|
||||
#if 1
|
||||
TEST(testCase, connect_Test) {
|
||||
// taos_options(TSDB_OPTION_CONFIGDIR, "/home/ubuntu/first/cfg");
|
||||
|
||||
TAOS* pConn = taos_connect("localhost", "root", "taosdata", NULL, 0);
|
||||
if (pConn == NULL) {
|
||||
printf("failed to connect to server, reason:%s\n", taos_errstr(NULL));
|
||||
|
|
|
@ -63,7 +63,7 @@ SEpSet getEpSet_s(SCorEpSet *pEpSet) {
|
|||
|
||||
#define BitmapLen(_n) (((_n) + ((1<<NBIT)-1)) >> NBIT)
|
||||
|
||||
int32_t colDataGetSize(const SColumnInfoData* pColumnInfoData, int32_t numOfRows) {
|
||||
int32_t colDataGetLength(const SColumnInfoData* pColumnInfoData, int32_t numOfRows) {
|
||||
ASSERT(pColumnInfoData != NULL);
|
||||
if (IS_VAR_DATA_TYPE(pColumnInfoData->info.type)) {
|
||||
return pColumnInfoData->varmeta.length;
|
||||
|
@ -127,6 +127,7 @@ int32_t colDataAppend(SColumnInfoData* pColumnInfoData, uint32_t currentRow, con
|
|||
case TSDB_DATA_TYPE_USMALLINT: {*(int16_t*) p = *(int16_t*) pData;break;}
|
||||
case TSDB_DATA_TYPE_INT:
|
||||
case TSDB_DATA_TYPE_UINT: {*(int32_t*) p = *(int32_t*) pData;break;}
|
||||
case TSDB_DATA_TYPE_TIMESTAMP:
|
||||
case TSDB_DATA_TYPE_BIGINT:
|
||||
case TSDB_DATA_TYPE_UBIGINT: {*(int64_t*) p = *(int64_t*) pData;break;}
|
||||
default:
|
||||
|
@ -249,8 +250,8 @@ int32_t blockDataUpdateTsWindow(SSDataBlock* pDataBlock) {
|
|||
}
|
||||
|
||||
ASSERT(pColInfoData->nullbitmap == NULL);
|
||||
pDataBlock->info.window.skey = *(TSKEY*) colDataGet(pColInfoData, 0);
|
||||
pDataBlock->info.window.ekey = *(TSKEY*) colDataGet(pColInfoData, (pDataBlock->info.rows - 1));
|
||||
pDataBlock->info.window.skey = *(TSKEY*) colDataGetData(pColInfoData, 0);
|
||||
pDataBlock->info.window.ekey = *(TSKEY*) colDataGetData(pColInfoData, (pDataBlock->info.rows - 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -262,8 +263,8 @@ int32_t blockDataMerge(SSDataBlock* pDest, const SSDataBlock* pSrc) {
|
|||
SColumnInfoData* pCol2 = taosArrayGet(pDest->pDataBlock, i);
|
||||
SColumnInfoData* pCol1 = taosArrayGet(pSrc->pDataBlock, i);
|
||||
|
||||
uint32_t oldLen = colDataGetSize(pCol2, pDest->info.rows);
|
||||
uint32_t newLen = colDataGetSize(pCol1, pSrc->info.rows);
|
||||
uint32_t oldLen = colDataGetLength(pCol2, pDest->info.rows);
|
||||
uint32_t newLen = colDataGetLength(pCol1, pSrc->info.rows);
|
||||
|
||||
int32_t newSize = oldLen + newLen;
|
||||
char* tmp = realloc(pCol2->pData, newSize);
|
||||
|
@ -287,7 +288,7 @@ size_t blockDataGetSize(const SSDataBlock* pBlock) {
|
|||
|
||||
for(int32_t i = 0; i < numOfCols; ++i) {
|
||||
SColumnInfoData* pColInfoData = taosArrayGet(pBlock->pDataBlock, i);
|
||||
total += colDataGetSize(pColInfoData, pBlock->info.rows);
|
||||
total += colDataGetLength(pColInfoData, pBlock->info.rows);
|
||||
|
||||
if (IS_VAR_DATA_TYPE(pColInfoData->info.type)) {
|
||||
total += sizeof(int32_t) * pBlock->info.rows;
|
||||
|
@ -336,7 +337,7 @@ int32_t blockDataSplitRows(SSDataBlock* pBlock, bool hasVarCol, int32_t startInd
|
|||
if (isNull) {
|
||||
// do nothing
|
||||
} else {
|
||||
char* p = colDataGet(pColInfoData, j);
|
||||
char* p = colDataGetData(pColInfoData, j);
|
||||
size += varDataTLen(p);
|
||||
}
|
||||
|
||||
|
@ -401,7 +402,7 @@ SSDataBlock* blockDataExtractBlock(SSDataBlock* pBlock, int32_t startIndex, int3
|
|||
|
||||
for (int32_t j = startIndex; j < (startIndex + rowCount); ++j) {
|
||||
bool isNull = colDataIsNull(pColData, pBlock->info.rows, j, pBlock->pBlockAgg);
|
||||
char* p = colDataGet(pColData, j);
|
||||
char* p = colDataGetData(pColData, j);
|
||||
|
||||
colDataAppend(pDstCol, j - startIndex, p, isNull);
|
||||
}
|
||||
|
@ -411,7 +412,6 @@ SSDataBlock* blockDataExtractBlock(SSDataBlock* pBlock, int32_t startIndex, int3
|
|||
return pDst;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* +------------------+---------------+--------------------+
|
||||
|
@ -444,7 +444,7 @@ int32_t blockDataToBuf(char* buf, const SSDataBlock* pBlock) {
|
|||
pStart += BitmapLen(pBlock->info.rows);
|
||||
}
|
||||
|
||||
uint32_t dataSize = colDataGetSize(pCol, numOfRows);
|
||||
uint32_t dataSize = colDataGetLength(pCol, numOfRows);
|
||||
|
||||
*(int32_t*) pStart = dataSize;
|
||||
pStart += sizeof(int32_t);
|
||||
|
@ -522,6 +522,22 @@ size_t blockDataGetSerialMetaSize(const SSDataBlock* pBlock) {
|
|||
return sizeof(int32_t) + pBlock->info.numOfCols * sizeof(int32_t);
|
||||
}
|
||||
|
||||
SSchema* blockDataExtractSchema(const SSDataBlock* pBlock, int32_t* numOfCols) {
|
||||
SSchema* pSchema = calloc(pBlock->info.numOfCols, sizeof(SSchema));
|
||||
for(int32_t i = 0; i < pBlock->info.numOfCols; ++i) {
|
||||
SColumnInfoData* pColInfoData = taosArrayGet(pBlock->pDataBlock, i);
|
||||
pSchema[i].bytes = pColInfoData->info.bytes;
|
||||
pSchema[i].type = pColInfoData->info.type;
|
||||
pSchema[i].colId = pColInfoData->info.colId;
|
||||
}
|
||||
|
||||
if (numOfCols != NULL) {
|
||||
*numOfCols = pBlock->info.numOfCols;
|
||||
}
|
||||
|
||||
return pSchema;
|
||||
}
|
||||
|
||||
double blockDataGetSerialRowSize(const SSDataBlock* pBlock) {
|
||||
ASSERT(pBlock != NULL);
|
||||
double rowSize = 0;
|
||||
|
@ -577,8 +593,8 @@ int32_t dataBlockCompar(const void* p1, const void* p2, const void* param) {
|
|||
}
|
||||
}
|
||||
|
||||
void* left1 = colDataGet(pColInfoData, left);
|
||||
void* right1 = colDataGet(pColInfoData, right);
|
||||
void* left1 = colDataGetData(pColInfoData, left);
|
||||
void* right1 = colDataGetData(pColInfoData, right);
|
||||
|
||||
switch(pColInfoData->info.type) {
|
||||
case TSDB_DATA_TYPE_INT: {
|
||||
|
@ -617,7 +633,7 @@ static int32_t doAssignOneTuple(SColumnInfoData* pDstCols, int32_t numOfRows, co
|
|||
return code;
|
||||
}
|
||||
} else {
|
||||
char* p = colDataGet(pSrc, tupleIndex);
|
||||
char* p = colDataGetData(pSrc, tupleIndex);
|
||||
code = colDataAppend(pDst, numOfRows, p, false);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
return code;
|
||||
|
@ -956,8 +972,8 @@ int32_t dataBlockCompar_rv(const void* p1, const void* p2, const void* param) {
|
|||
// }
|
||||
// }
|
||||
|
||||
// void* left1 = colDataGet(pColInfoData, left);
|
||||
// void* right1 = colDataGet(pColInfoData, right);
|
||||
// void* left1 = colDataGetData(pColInfoData, left);
|
||||
// void* right1 = colDataGetData(pColInfoData, right);
|
||||
|
||||
// switch(pColInfoData->info.type) {
|
||||
// case TSDB_DATA_TYPE_INT: {
|
||||
|
@ -1099,3 +1115,24 @@ void* blockDataDestroy(SSDataBlock* pBlock) {
|
|||
tfree(pBlock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SSDataBlock* createOneDataBlock(const SSDataBlock* pDataBlock) {
|
||||
int32_t numOfCols = pDataBlock->info.numOfCols;
|
||||
|
||||
SSDataBlock* pBlock = calloc(1, sizeof(SSDataBlock));
|
||||
pBlock->pDataBlock = taosArrayInit(numOfCols, sizeof(SColumnInfoData));
|
||||
pBlock->info.numOfCols = numOfCols;
|
||||
|
||||
for(int32_t i = 0; i < numOfCols; ++i) {
|
||||
SColumnInfoData colInfo = {0};
|
||||
SColumnInfoData* p = taosArrayGet(pDataBlock->pDataBlock, i);
|
||||
colInfo.info = p->info;
|
||||
taosArrayPush(pBlock->pDataBlock, &colInfo);
|
||||
}
|
||||
|
||||
return pBlock;
|
||||
}
|
||||
|
||||
size_t blockDataGetCapacityInRow(const SSDataBlock* pBlock, size_t pageSize) {
|
||||
return pageSize / (blockDataGetSerialRowSize(pBlock) + blockDataGetSerialMetaSize(pBlock));
|
||||
}
|
|
@ -162,7 +162,7 @@ TEST(testCase, Datablock_test) {
|
|||
ASSERT_EQ(colDataGetNumOfCols(b), 2);
|
||||
ASSERT_EQ(colDataGetNumOfRows(b), 40);
|
||||
|
||||
char* pData = colDataGet(p1, 3);
|
||||
char* pData = colDataGetData(p1, 3);
|
||||
printf("the second row of binary:%s, length:%d\n", (char*)varDataVal(pData), varDataLen(pData));
|
||||
|
||||
SArray* pOrderInfo = taosArrayInit(3, sizeof(SBlockOrderInfo));
|
||||
|
|
|
@ -216,13 +216,15 @@ static FORCE_INLINE void tqReadHandleSetColIdList(STqReadHandle *pReadHandle, SA
|
|||
static FORCE_INLINE int tqReadHandleSetTbUidList(STqReadHandle *pHandle, const SArray *tbUidList) {
|
||||
pHandle->tbIdHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BIGINT), true, HASH_NO_LOCK);
|
||||
if (pHandle->tbIdHash == NULL) {
|
||||
terrno = TSDB_CODE_OUT_OF_MEMORY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < taosArrayGetSize(tbUidList); i++) {
|
||||
int64_t *pKey = (int64_t *)taosArrayGet(tbUidList, i);
|
||||
taosHashPut(pHandle->tbIdHash, pKey, sizeof(int64_t), NULL, 0);
|
||||
// pHandle->tbUid = tbUid;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ typedef struct STableCheckInfo {
|
|||
int32_t compSize;
|
||||
int32_t numOfBlocks:29; // number of qualified data blocks not the original blocks
|
||||
uint8_t chosen:2; // indicate which iterator should move forward
|
||||
bool initBuf; // whether to initialize the in-memory skip list iterator or not
|
||||
bool initBuf:1; // whether to initialize the in-memory skip list iterator or not
|
||||
SSkipListIterator* iter; // mem buffer skip list iterator
|
||||
SSkipListIterator* iiter; // imem buffer skip list iterator
|
||||
} STableCheckInfo;
|
||||
|
|
|
@ -68,9 +68,10 @@ typedef struct SResultRow {
|
|||
} SResultRow;
|
||||
|
||||
typedef struct SResultRowInfo {
|
||||
SResultRow *pCurResult; // current active result row info
|
||||
SResultRow** pResult; // result list
|
||||
int16_t type:8; // data type for hash key
|
||||
int32_t size:24; // number of result set
|
||||
// int16_t type:8; // data type for hash key
|
||||
int32_t size; // number of result set
|
||||
int32_t capacity; // max capacity
|
||||
int32_t curPos; // current active result row index of pResult list
|
||||
} SResultRowInfo;
|
||||
|
@ -95,7 +96,7 @@ struct SUdfInfo;
|
|||
int32_t getOutputInterResultBufSize(struct STaskAttr* pQueryAttr);
|
||||
|
||||
size_t getResultRowSize(SArray* pExprInfo);
|
||||
int32_t initResultRowInfo(SResultRowInfo* pResultRowInfo, int32_t size, int16_t type);
|
||||
int32_t initResultRowInfo(SResultRowInfo* pResultRowInfo, int32_t size);
|
||||
void cleanupResultRowInfo(SResultRowInfo* pResultRowInfo);
|
||||
|
||||
void resetResultRowInfo(struct STaskRuntimeEnv* pRuntimeEnv, SResultRowInfo* pResultRowInfo);
|
||||
|
@ -105,7 +106,7 @@ void closeAllResultRows(SResultRowInfo* pResultRowInfo);
|
|||
int32_t initResultRow(SResultRow *pResultRow);
|
||||
void closeResultRow(SResultRowInfo* pResultRowInfo, int32_t slot);
|
||||
bool isResultRowClosed(SResultRowInfo *pResultRowInfo, int32_t slot);
|
||||
void clearResultRow(struct STaskRuntimeEnv* pRuntimeEnv, SResultRow* pResultRow, int16_t type);
|
||||
void clearResultRow(struct STaskRuntimeEnv* pRuntimeEnv, SResultRow* pResultRow);
|
||||
|
||||
struct SResultRowEntryInfo* getResultCell(const SResultRow* pRow, int32_t index, int32_t* offset);
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#ifndef TDENGINE_EXECUTORIMPL_H
|
||||
#define TDENGINE_EXECUTORIMPL_H
|
||||
|
||||
#include "tsort.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -444,16 +445,32 @@ typedef struct SOptrBasicInfo {
|
|||
int32_t capacity;
|
||||
} SOptrBasicInfo;
|
||||
|
||||
typedef struct SOptrBasicInfo STableIntervalOperatorInfo;
|
||||
|
||||
typedef struct SAggOperatorInfo {
|
||||
SOptrBasicInfo binfo;
|
||||
SDiskbasedBuf *pResultBuf; // query result buffer based on blocked-wised disk file
|
||||
typedef struct SAggSupporter {
|
||||
SHashObj* pResultRowHashTable; // quick locate the window object for each result
|
||||
SHashObj* pResultRowListSet; // used to check if current ResultRowInfo has ResultRow object or not
|
||||
SArray* pResultRowArrayList; // The array list that contains the Result rows
|
||||
char* keyBuf; // window key buffer
|
||||
SResultRowPool *pool; // The window result objects pool, all the resultRow Objects are allocated and managed by this object.
|
||||
} SAggSupporter;
|
||||
|
||||
typedef struct STableIntervalOperatorInfo {
|
||||
SOptrBasicInfo binfo;
|
||||
SDiskbasedBuf *pResultBuf; // query result buffer based on blocked-wised disk file
|
||||
SGroupResInfo groupResInfo;
|
||||
SInterval interval;
|
||||
STimeWindow win;
|
||||
int32_t precision;
|
||||
bool timeWindowInterpo;
|
||||
char **pRow;
|
||||
SAggSupporter aggSup;
|
||||
STableQueryInfo *pCurrent;
|
||||
int32_t order;
|
||||
} STableIntervalOperatorInfo;
|
||||
|
||||
typedef struct SAggOperatorInfo {
|
||||
SOptrBasicInfo binfo;
|
||||
SDiskbasedBuf *pResultBuf; // query result buffer based on blocked-wised disk file
|
||||
SAggSupporter aggSup;
|
||||
STableQueryInfo *current;
|
||||
uint32_t groupId;
|
||||
SGroupResInfo groupResInfo;
|
||||
|
@ -549,49 +566,42 @@ typedef struct SDistinctOperatorInfo {
|
|||
SArray* pDistinctDataInfo;
|
||||
} SDistinctOperatorInfo;
|
||||
|
||||
struct SGlobalMerger;
|
||||
|
||||
typedef struct SMultiwayMergeInfo {
|
||||
struct SGlobalMerger* pMerge;
|
||||
typedef struct SSortedMergeOperatorInfo {
|
||||
SOptrBasicInfo binfo;
|
||||
int32_t bufCapacity;
|
||||
int64_t seed;
|
||||
char** prevRow;
|
||||
SArray* orderColumnList;
|
||||
int32_t resultRowFactor;
|
||||
bool hasVarCol;
|
||||
|
||||
bool hasGroupColData;
|
||||
char** currentGroupColData;
|
||||
SArray* groupColumnList;
|
||||
bool hasDataBlockForNewGroup;
|
||||
SSDataBlock* pExistBlock;
|
||||
|
||||
SArray* udfInfo;
|
||||
bool hasPrev;
|
||||
bool multiGroupResults;
|
||||
} SMultiwayMergeInfo;
|
||||
|
||||
typedef struct SMsortComparParam {
|
||||
struct SExternalMemSource **pSources;
|
||||
int32_t numOfSources;
|
||||
SArray *orderInfo; // SArray<SBlockOrderInfo>
|
||||
bool nullFirst;
|
||||
} SMsortComparParam;
|
||||
int32_t numOfSources;
|
||||
|
||||
SSortHandle *pSortHandle;
|
||||
|
||||
int32_t bufPageSize;
|
||||
uint32_t sortBufSize; // max buffer size for in-memory sort
|
||||
|
||||
int32_t resultRowFactor;
|
||||
bool hasGroupVal;
|
||||
|
||||
SDiskbasedBuf *pTupleStore; // keep the final results
|
||||
int32_t numOfResPerPage;
|
||||
|
||||
char** groupVal;
|
||||
SArray *groupInfo;
|
||||
SAggSupporter aggSup;
|
||||
} SSortedMergeOperatorInfo;
|
||||
|
||||
typedef struct SOrderOperatorInfo {
|
||||
int32_t sourceId;
|
||||
uint32_t sortBufSize; // max buffer size for in-memory sort
|
||||
SSDataBlock *pDataBlock;
|
||||
bool hasVarCol; // has variable length column, such as binary/varchar/nchar
|
||||
int32_t numOfCompleted;
|
||||
SDiskbasedBuf *pSortInternalBuf;
|
||||
SMultiwayMergeTreeInfo *pMergeTree;
|
||||
SArray *pSources; // SArray<SExternalMemSource*>
|
||||
SArray *orderInfo;
|
||||
bool nullFirst;
|
||||
SSortHandle *pSortHandle;
|
||||
|
||||
int32_t bufPageSize;
|
||||
int32_t numOfRowsInRes;
|
||||
|
||||
SMsortComparParam cmpParam;
|
||||
|
||||
// TODO extact struct
|
||||
int64_t startTs; // sort start time
|
||||
uint64_t sortElapsed; // sort elapsed time, time to flush to disk not included.
|
||||
uint64_t totalSize; // total load bytes from remote
|
||||
|
@ -608,8 +618,8 @@ SOperatorInfo* createMultiTableAggOperatorInfo(SOperatorInfo* downstream, SArray
|
|||
SOperatorInfo* createProjectOperatorInfo(STaskRuntimeEnv* pRuntimeEnv, SOperatorInfo* downstream, SExprInfo* pExpr,
|
||||
int32_t numOfOutput);
|
||||
SOperatorInfo* createLimitOperatorInfo(STaskRuntimeEnv* pRuntimeEnv, SOperatorInfo* downstream);
|
||||
SOperatorInfo* createTimeIntervalOperatorInfo(STaskRuntimeEnv* pRuntimeEnv, SOperatorInfo* downstream, SExprInfo* pExpr,
|
||||
int32_t numOfOutput);
|
||||
SOperatorInfo* createIntervalOperatorInfo(SOperatorInfo* downstream, SArray* pExprInfo, SExecTaskInfo* pTaskInfo);
|
||||
|
||||
SOperatorInfo* createAllTimeIntervalOperatorInfo(STaskRuntimeEnv* pRuntimeEnv, SOperatorInfo* downstream,
|
||||
SExprInfo* pExpr, int32_t numOfOutput);
|
||||
SOperatorInfo* createSWindowOperatorInfo(STaskRuntimeEnv* pRuntimeEnv, SOperatorInfo* downstream, SExprInfo* pExpr,
|
||||
|
@ -641,9 +651,8 @@ SOperatorInfo* createFilterOperatorInfo(STaskRuntimeEnv* pRuntimeEnv, SOperatorI
|
|||
|
||||
SOperatorInfo* createJoinOperatorInfo(SOperatorInfo** pdownstream, int32_t numOfDownstream, SSchema* pSchema,
|
||||
int32_t numOfOutput);
|
||||
SOperatorInfo* createOrderOperatorInfo(SOperatorInfo* downstream, SArray* pExprInfo, SArray* pOrderVal);
|
||||
SOperatorInfo* createMergeSortOperatorInfo(SOperatorInfo* downstream, SExprInfo* pExpr, int32_t numOfOutput,
|
||||
SOrder* pOrderVal);
|
||||
SOperatorInfo* createOrderOperatorInfo(SOperatorInfo* downstream, SArray* pExprInfo, SArray* pOrderVal, SExecTaskInfo* pTaskInfo);
|
||||
SOperatorInfo* createSortedMergeOperatorInfo(SOperatorInfo** downstream, int32_t numOfDownstream, SArray* pExprInfo, SArray* pOrderVal, SArray* pGroupInfo, SExecTaskInfo* pTaskInfo);
|
||||
|
||||
// SSDataBlock* doGlobalAggregate(void* param, bool* newgroup);
|
||||
// SSDataBlock* doMultiwayMergeSort(void* param, bool* newgroup);
|
||||
|
@ -691,9 +700,6 @@ int32_t checkForQueryBuf(size_t numOfTables);
|
|||
bool checkNeedToCompressQueryCol(SQInfo* pQInfo);
|
||||
void setQueryStatus(STaskRuntimeEnv* pRuntimeEnv, int8_t status);
|
||||
|
||||
bool onlyQueryTags(STaskAttr* pQueryAttr);
|
||||
// void destroyUdfInfo(struct SUdfInfo* pUdfInfo);
|
||||
|
||||
int32_t doDumpQueryResult(SQInfo* pQInfo, char* data, int8_t compressed, int32_t* compLen);
|
||||
|
||||
size_t getResultSize(SQInfo* pQInfo, int64_t* numOfRows);
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* This program is free software: you can use, redistribute, and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3
|
||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TDENGINE_TLINEARHASH_H
|
||||
#define TDENGINE_TLINEARHASH_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "thash.h"
|
||||
|
||||
enum {
|
||||
LINEAR_HASH_STATIS = 0x1,
|
||||
LINEAR_HASH_DATA = 0x2,
|
||||
};
|
||||
|
||||
typedef struct SLHashObj SLHashObj;
|
||||
|
||||
SLHashObj* tHashInit(int32_t inMemPages, int32_t pageSize, _hash_fn_t fn, int32_t numOfTuplePerPage);
|
||||
void* tHashCleanup(SLHashObj* pHashObj);
|
||||
|
||||
int32_t tHashPut(SLHashObj* pHashObj, const void *key, size_t keyLen, void *data, size_t size);
|
||||
char* tHashGet(SLHashObj* pHashObj, const void *key, size_t keyLen);
|
||||
int32_t tHashRemove(SLHashObj* pHashObj, const void *key, size_t keyLen);
|
||||
|
||||
void tHashPrint(const SLHashObj* pHashObj, int32_t type);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // TDENGINE_TLINEARHASH_H
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* This program is free software: you can use, redistribute, and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3
|
||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TDENGINE_TSORT_H
|
||||
#define TDENGINE_TSORT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
#include "os.h"
|
||||
|
||||
enum {
|
||||
SORT_MULTISOURCE_MERGE = 0x1,
|
||||
SORT_SINGLESOURCE_SORT = 0x2,
|
||||
};
|
||||
|
||||
typedef struct SMultiMergeSource {
|
||||
int32_t type;
|
||||
int32_t rowIndex;
|
||||
SSDataBlock *pBlock;
|
||||
} SMultiMergeSource;
|
||||
|
||||
typedef struct SExternalMemSource {
|
||||
SMultiMergeSource src;
|
||||
SArray* pageIdList;
|
||||
int32_t pageIndex;
|
||||
} SExternalMemSource;
|
||||
|
||||
typedef struct SGenericSource {
|
||||
SMultiMergeSource src;
|
||||
void *param;
|
||||
} SGenericSource;
|
||||
|
||||
typedef struct SMsortComparParam {
|
||||
void **pSources;
|
||||
int32_t numOfSources;
|
||||
SArray *orderInfo; // SArray<SBlockOrderInfo>
|
||||
bool nullFirst;
|
||||
} SMsortComparParam;
|
||||
|
||||
typedef struct SSortHandle SSortHandle;
|
||||
typedef struct STupleHandle STupleHandle;
|
||||
|
||||
typedef SSDataBlock* (*_sort_fetch_block_fn_t)(void* param);
|
||||
typedef int32_t (*_sort_merge_compar_fn_t)(const void* p1, const void* p2, void* param);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
SSortHandle* tsortCreateSortHandle(SArray* pOrderInfo, bool nullFirst, int32_t type, int32_t pageSize, int32_t numOfPages, SSchema* pSchema, int32_t numOfCols, const char* idstr);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param pSortHandle
|
||||
*/
|
||||
void tsortDestroySortHandle(SSortHandle* pSortHandle);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param pHandle
|
||||
* @return
|
||||
*/
|
||||
int32_t tsortOpen(SSortHandle* pHandle);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param pHandle
|
||||
* @return
|
||||
*/
|
||||
int32_t tsortClose(SSortHandle* pHandle);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
int32_t tsortSetFetchRawDataFp(SSortHandle* pHandle, _sort_fetch_block_fn_t fp);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param pHandle
|
||||
* @param fp
|
||||
* @return
|
||||
*/
|
||||
int32_t tsortSetComparFp(SSortHandle* pHandle, _sort_merge_compar_fn_t fp);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param pHandle
|
||||
* @param pSource
|
||||
* @return success or failed
|
||||
*/
|
||||
int32_t tsortAddSource(SSortHandle* pSortHandle, void* pSource);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param pHandle
|
||||
* @return
|
||||
*/
|
||||
STupleHandle* tsortNextTuple(SSortHandle* pHandle);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param pHandle
|
||||
* @param colIndex
|
||||
* @return
|
||||
*/
|
||||
bool tsortIsNullVal(STupleHandle* pVHandle, int32_t colIndex);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param pHandle
|
||||
* @param colIndex
|
||||
* @return
|
||||
*/
|
||||
void* tsortGetValue(STupleHandle* pVHandle, int32_t colIndex);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // TDENGINE_TSORT_H
|
|
@ -53,8 +53,7 @@ int32_t getOutputInterResultBufSize(STaskAttr* pQueryAttr) {
|
|||
return size;
|
||||
}
|
||||
|
||||
int32_t initResultRowInfo(SResultRowInfo *pResultRowInfo, int32_t size, int16_t type) {
|
||||
pResultRowInfo->type = type;
|
||||
int32_t initResultRowInfo(SResultRowInfo *pResultRowInfo, int32_t size) {
|
||||
pResultRowInfo->size = 0;
|
||||
pResultRowInfo->curPos = -1;
|
||||
pResultRowInfo->capacity = size;
|
||||
|
@ -93,7 +92,7 @@ void resetResultRowInfo(STaskRuntimeEnv *pRuntimeEnv, SResultRowInfo *pResultRow
|
|||
|
||||
for (int32_t i = 0; i < pResultRowInfo->size; ++i) {
|
||||
SResultRow *pWindowRes = pResultRowInfo->pResult[i];
|
||||
clearResultRow(pRuntimeEnv, pWindowRes, pResultRowInfo->type);
|
||||
clearResultRow(pRuntimeEnv, pWindowRes);
|
||||
|
||||
int32_t groupIndex = 0;
|
||||
int64_t uid = 0;
|
||||
|
@ -136,7 +135,7 @@ void closeResultRow(SResultRowInfo *pResultRowInfo, int32_t slot) {
|
|||
getResultRow(pResultRowInfo, slot)->closed = true;
|
||||
}
|
||||
|
||||
void clearResultRow(STaskRuntimeEnv *pRuntimeEnv, SResultRow *pResultRow, int16_t type) {
|
||||
void clearResultRow(STaskRuntimeEnv *pRuntimeEnv, SResultRow *pResultRow) {
|
||||
if (pResultRow == NULL) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -93,3 +93,25 @@ qTaskInfo_t qCreateStreamExecTaskInfo(void* msg, void* streamReadHandle) {
|
|||
|
||||
return pTaskInfo;
|
||||
}
|
||||
|
||||
int32_t qUpdateQualifiedTableId(qTaskInfo_t tinfo, SArray* tableIdList, bool isAdd) {
|
||||
SExecTaskInfo* pTaskInfo = (SExecTaskInfo* )tinfo;
|
||||
|
||||
// traverse to the streamscan node to add this table id
|
||||
SOperatorInfo* pInfo = pTaskInfo->pRoot;
|
||||
while(pInfo->operatorType != OP_StreamScan) {
|
||||
pInfo = pInfo->pDownstream[0];
|
||||
}
|
||||
|
||||
SStreamBlockScanInfo* pScanInfo = pInfo->info;
|
||||
if (isAdd) {
|
||||
int32_t code = tqReadHandleSetTbUidList(pScanInfo->readerHandle, tableIdList);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
return code;
|
||||
}
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,427 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* This program is free software: you can use, redistribute, and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3
|
||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "tlinearhash.h"
|
||||
#include "tcfg.h"
|
||||
#include "taoserror.h"
|
||||
#include "tpagedbuf.h"
|
||||
|
||||
#define LHASH_CAP_RATIO 0.85
|
||||
|
||||
// Always located in memory
|
||||
typedef struct SLHashBucket {
|
||||
SArray *pPageIdList;
|
||||
int32_t size; // the number of element in this entry
|
||||
} SLHashBucket;
|
||||
|
||||
typedef struct SLHashObj {
|
||||
SDiskbasedBuf *pBuf;
|
||||
_hash_fn_t hashFn;
|
||||
int32_t tuplesPerPage;
|
||||
SLHashBucket **pBucket; // entry list
|
||||
int32_t numOfAlloc; // number of allocated bucket ptr slot
|
||||
int32_t bits; // the number of bits used in hash
|
||||
int32_t numOfBuckets; // the number of buckets
|
||||
int64_t size; // the number of total items
|
||||
} SLHashObj;
|
||||
|
||||
/**
|
||||
* the data struct for each hash node
|
||||
* +-----------+-------+--------+
|
||||
* | SLHashNode| key | data |
|
||||
* +-----------+-------+--------+
|
||||
*/
|
||||
typedef struct SLHashNode {
|
||||
uint16_t keyLen;
|
||||
uint16_t dataLen;
|
||||
} SLHashNode;
|
||||
|
||||
#define GET_LHASH_NODE_KEY(_n) (((char*)(_n)) + sizeof(SLHashNode))
|
||||
#define GET_LHASH_NODE_DATA(_n) ((char*)(_n) + sizeof(SLHashNode) + ((SLHashNode*)(_n))->keyLen)
|
||||
#define GET_LHASH_NODE_LEN(_n) (sizeof(SLHashNode) + ((SLHashNode*)(_n))->keyLen + ((SLHashNode*)(_n))->dataLen)
|
||||
|
||||
static int32_t doAddNewBucket(SLHashObj* pHashObj);
|
||||
|
||||
static int32_t doGetBucketIdFromHashVal(int32_t hashv, int32_t bits) {
|
||||
return hashv & ((1ul << (bits)) - 1);
|
||||
}
|
||||
|
||||
static int32_t doGetAlternativeBucketId(int32_t bucketId, int32_t bits, int32_t numOfBuckets) {
|
||||
int32_t v = bucketId - (1ul << (bits - 1));
|
||||
ASSERT(v < numOfBuckets);
|
||||
return v;
|
||||
}
|
||||
|
||||
static int32_t doGetRelatedSplitBucketId(int32_t bucketId, int32_t bits) {
|
||||
int32_t splitBucketId = (1ul << (bits - 1)) ^ bucketId;
|
||||
return splitBucketId;
|
||||
}
|
||||
|
||||
static void doCopyObject(char* p, const void* key, int32_t keyLen, const void* data, int32_t size) {
|
||||
*(uint16_t*) p = keyLen;
|
||||
p += sizeof(uint16_t);
|
||||
*(uint16_t*) p = size;
|
||||
p += sizeof(uint16_t);
|
||||
|
||||
memcpy(p, key, keyLen);
|
||||
p += keyLen;
|
||||
|
||||
memcpy(p, data, size);
|
||||
}
|
||||
|
||||
static int32_t doAddToBucket(SLHashObj* pHashObj, SLHashBucket* pBucket, int32_t index, const void* key, int32_t keyLen,
|
||||
const void* data, int32_t size) {
|
||||
int32_t pageId = *(int32_t*)taosArrayGetLast(pBucket->pPageIdList);
|
||||
|
||||
SFilePage* pPage = getBufPage(pHashObj->pBuf, pageId);
|
||||
ASSERT (pPage != NULL);
|
||||
|
||||
// put to current buf page
|
||||
size_t nodeSize = sizeof(SLHashNode) + keyLen + size;
|
||||
ASSERT(nodeSize + sizeof(SFilePage) <= getBufPageSize(pHashObj->pBuf));
|
||||
|
||||
if (pPage->num + nodeSize > getBufPageSize(pHashObj->pBuf)) {
|
||||
releaseBufPage(pHashObj->pBuf, pPage);
|
||||
|
||||
// allocate the overflow buffer page to hold this k/v.
|
||||
int32_t newPageId = -1;
|
||||
SFilePage* pNewPage = getNewBufPage(pHashObj->pBuf, 0, &newPageId);
|
||||
if (pNewPage == NULL) {
|
||||
return TSDB_CODE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
taosArrayPush(pBucket->pPageIdList, &newPageId);
|
||||
|
||||
doCopyObject(pNewPage->data, key, keyLen, data, size);
|
||||
pNewPage->num = sizeof(SFilePage) + nodeSize;
|
||||
|
||||
setBufPageDirty(pNewPage, true);
|
||||
releaseBufPage(pHashObj->pBuf, pNewPage);
|
||||
} else {
|
||||
char* p = (char*) pPage + pPage->num;
|
||||
doCopyObject(p, key, keyLen, data, size);
|
||||
pPage->num += nodeSize;
|
||||
setBufPageDirty(pPage, true);
|
||||
releaseBufPage(pHashObj->pBuf, pPage);
|
||||
}
|
||||
|
||||
pBucket->size += 1;
|
||||
// printf("===> add to bucket:0x%x, num:%d, key:%d\n", index, pBucket->size, *(int*) key);
|
||||
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static void doRemoveFromBucket(SFilePage* pPage, SLHashNode* pNode, SLHashBucket* pBucket) {
|
||||
ASSERT(pPage != NULL && pNode != NULL && pBucket->size >= 1);
|
||||
|
||||
int32_t len = GET_LHASH_NODE_LEN(pNode);
|
||||
char* p = (char*) pNode + len;
|
||||
|
||||
char* pEnd = (char*)pPage + pPage->num;
|
||||
memmove(pNode, p, (pEnd - p));
|
||||
|
||||
pPage->num -= len;
|
||||
if (pPage->num == 0) {
|
||||
// this page is empty, could be recycle in the future.
|
||||
}
|
||||
|
||||
setBufPageDirty(pPage, true);
|
||||
|
||||
pBucket->size -= 1;
|
||||
}
|
||||
|
||||
static void doCompressBucketPages(SLHashObj *pHashObj, SLHashBucket* pBucket) {
|
||||
size_t numOfPages = taosArrayGetSize(pBucket->pPageIdList);
|
||||
if (numOfPages <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t* firstPage = taosArrayGet(pBucket->pPageIdList, 0);
|
||||
SFilePage* pFirst = getBufPage(pHashObj->pBuf, *firstPage);
|
||||
|
||||
int32_t* pageId = taosArrayGetLast(pBucket->pPageIdList);
|
||||
SFilePage* pLast = getBufPage(pHashObj->pBuf, *pageId);
|
||||
|
||||
if (pLast->num <= sizeof(SFilePage)) {
|
||||
// this is empty
|
||||
dBufSetBufPageRecycled(pHashObj->pBuf, pLast);
|
||||
releaseBufPage(pHashObj->pBuf, pFirst);
|
||||
taosArrayRemove(pBucket->pPageIdList, numOfPages - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
char* pStart = pLast->data;
|
||||
int32_t nodeSize = GET_LHASH_NODE_LEN(pStart);
|
||||
while (1) {
|
||||
if (pFirst->num + nodeSize < getBufPageSize(pHashObj->pBuf)) {
|
||||
char* p = ((char*)pFirst) + pFirst->num;
|
||||
|
||||
SLHashNode* pNode = (SLHashNode*)pStart;
|
||||
doCopyObject(p, GET_LHASH_NODE_KEY(pStart), pNode->keyLen, GET_LHASH_NODE_DATA(pStart), pNode->dataLen);
|
||||
|
||||
setBufPageDirty(pFirst, true);
|
||||
setBufPageDirty(pLast, true);
|
||||
|
||||
ASSERT(pLast->num >= nodeSize + sizeof(SFilePage));
|
||||
|
||||
pFirst->num += nodeSize;
|
||||
pLast->num -= nodeSize;
|
||||
|
||||
pStart += nodeSize;
|
||||
if (pLast->num <= sizeof(SFilePage)) {
|
||||
// this is empty
|
||||
dBufSetBufPageRecycled(pHashObj->pBuf, pLast);
|
||||
releaseBufPage(pHashObj->pBuf, pFirst);
|
||||
taosArrayRemove(pBucket->pPageIdList, numOfPages - 1);
|
||||
break;
|
||||
}
|
||||
|
||||
nodeSize = GET_LHASH_NODE_LEN(pStart);
|
||||
} else { // move to the front of pLast page
|
||||
if (pStart != pLast->data) {
|
||||
memmove(pLast->data, pStart, (((char*)pLast) + pLast->num - pStart));
|
||||
setBufPageDirty(pLast, true);
|
||||
}
|
||||
|
||||
releaseBufPage(pHashObj->pBuf, pLast);
|
||||
releaseBufPage(pHashObj->pBuf, pFirst);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t doAddNewBucket(SLHashObj* pHashObj) {
|
||||
if (pHashObj->numOfBuckets + 1 > pHashObj->numOfAlloc) {
|
||||
int32_t newLen = pHashObj->numOfAlloc * 1.25;
|
||||
if (newLen == pHashObj->numOfAlloc) {
|
||||
newLen += 4;
|
||||
}
|
||||
|
||||
char* p = realloc(pHashObj->pBucket, POINTER_BYTES * newLen);
|
||||
if (p == NULL) {
|
||||
return TSDB_CODE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
memset(p + POINTER_BYTES * pHashObj->numOfBuckets, 0, newLen - pHashObj->numOfBuckets);
|
||||
pHashObj->pBucket = (SLHashBucket**) p;
|
||||
pHashObj->numOfAlloc = newLen;
|
||||
}
|
||||
|
||||
SLHashBucket* pBucket = calloc(1, sizeof(SLHashBucket));
|
||||
pHashObj->pBucket[pHashObj->numOfBuckets] = pBucket;
|
||||
|
||||
pBucket->pPageIdList = taosArrayInit(2, sizeof(int32_t));
|
||||
if (pBucket->pPageIdList == NULL || pBucket == NULL) {
|
||||
return TSDB_CODE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
int32_t pageId = -1;
|
||||
SFilePage* p = getNewBufPage(pHashObj->pBuf, 0, &pageId);
|
||||
p->num = sizeof(SFilePage);
|
||||
setBufPageDirty(p, true);
|
||||
|
||||
releaseBufPage(pHashObj->pBuf, p);
|
||||
taosArrayPush(pBucket->pPageIdList, &pageId);
|
||||
|
||||
pHashObj->numOfBuckets += 1;
|
||||
// printf("---------------add new bucket, id:0x%x, total:%d\n", pHashObj->numOfBuckets - 1, pHashObj->numOfBuckets);
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
SLHashObj* tHashInit(int32_t inMemPages, int32_t pageSize, _hash_fn_t fn, int32_t numOfTuplePerPage) {
|
||||
SLHashObj* pHashObj = calloc(1, sizeof(SLHashObj));
|
||||
if (pHashObj == NULL) {
|
||||
terrno = TSDB_CODE_OUT_OF_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int32_t code = createDiskbasedBuf(&pHashObj->pBuf, pageSize, inMemPages * pageSize, 0, "/tmp");
|
||||
if (code != 0) {
|
||||
terrno = code;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
setBufPageCompressOnDisk(pHashObj->pBuf, false);
|
||||
|
||||
/**
|
||||
* The number of bits in the hash value, which is used to decide the exact bucket where the object should be located in.
|
||||
* The initial value is 0.
|
||||
*/
|
||||
pHashObj->bits = 0;
|
||||
pHashObj->hashFn = fn;
|
||||
pHashObj->tuplesPerPage = numOfTuplePerPage;
|
||||
|
||||
pHashObj->numOfAlloc = 4; // initial allocated array list
|
||||
pHashObj->pBucket = calloc(pHashObj->numOfAlloc, POINTER_BYTES);
|
||||
|
||||
code = doAddNewBucket(pHashObj);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
destroyDiskbasedBuf(pHashObj->pBuf);
|
||||
tfree(pHashObj);
|
||||
terrno = code;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pHashObj;
|
||||
}
|
||||
|
||||
void* tHashCleanup(SLHashObj* pHashObj) {
|
||||
destroyDiskbasedBuf(pHashObj->pBuf);
|
||||
for(int32_t i = 0; i < pHashObj->numOfBuckets; ++i) {
|
||||
taosArrayDestroy(pHashObj->pBucket[i]->pPageIdList);
|
||||
tfree(pHashObj->pBucket[i]);
|
||||
}
|
||||
|
||||
tfree(pHashObj->pBucket);
|
||||
tfree(pHashObj);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int32_t tHashPut(SLHashObj* pHashObj, const void *key, size_t keyLen, void *data, size_t size) {
|
||||
ASSERT(pHashObj != NULL && key != NULL);
|
||||
|
||||
if (pHashObj->bits == 0) {
|
||||
SLHashBucket* pBucket = pHashObj->pBucket[0];
|
||||
doAddToBucket(pHashObj, pBucket, 0, key, keyLen, data, size);
|
||||
} else {
|
||||
int32_t hashVal = pHashObj->hashFn(key, keyLen);
|
||||
int32_t v = doGetBucketIdFromHashVal(hashVal, pHashObj->bits);
|
||||
|
||||
if (v >= pHashObj->numOfBuckets) {
|
||||
int32_t newBucketId = doGetAlternativeBucketId(v, pHashObj->bits, pHashObj->numOfBuckets);
|
||||
// printf("bucketId: 0x%x not exists, put it into 0x%x instead\n", v, newBucketId);
|
||||
v = newBucketId;
|
||||
}
|
||||
|
||||
SLHashBucket* pBucket = pHashObj->pBucket[v];
|
||||
int32_t code = doAddToBucket(pHashObj, pBucket, v, key, keyLen, data, size);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
pHashObj->size += 1;
|
||||
|
||||
// Too many records, needs to bucket split
|
||||
if ((pHashObj->numOfBuckets * LHASH_CAP_RATIO * pHashObj->tuplesPerPage) < pHashObj->size) {
|
||||
int32_t newBucketId = pHashObj->numOfBuckets;
|
||||
|
||||
int32_t code = doAddNewBucket(pHashObj);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
return code;
|
||||
}
|
||||
|
||||
int32_t numOfBits = ceil(log(pHashObj->numOfBuckets) / log(2));
|
||||
if (numOfBits > pHashObj->bits) {
|
||||
// printf("extend the bits from %d to %d, new bucket:%d\n", pHashObj->bits, numOfBits, newBucketId);
|
||||
ASSERT(numOfBits == pHashObj->bits + 1);
|
||||
pHashObj->bits = numOfBits;
|
||||
}
|
||||
|
||||
int32_t splitBucketId = doGetRelatedSplitBucketId(newBucketId, pHashObj->bits);
|
||||
|
||||
// load all data in this bucket and check if the data needs to relocated into the new bucket
|
||||
SLHashBucket* pBucket = pHashObj->pBucket[splitBucketId];
|
||||
// printf("split %d items' bucket:0x%x to new bucket:0x%x\n", pBucket->size, splitBucketId, newBucketId);
|
||||
|
||||
for (int32_t i = 0; i < taosArrayGetSize(pBucket->pPageIdList); ++i) {
|
||||
int32_t pageId = *(int32_t*)taosArrayGet(pBucket->pPageIdList, i);
|
||||
SFilePage* p = getBufPage(pHashObj->pBuf, pageId);
|
||||
|
||||
char* pStart = p->data;
|
||||
while (pStart - ((char*) p) < p->num) {
|
||||
SLHashNode* pNode = (SLHashNode*)pStart;
|
||||
ASSERT(pNode->keyLen > 0 && pNode->dataLen >= 0);
|
||||
|
||||
char* k = GET_LHASH_NODE_KEY(pNode);
|
||||
int32_t hashv = pHashObj->hashFn(k, pNode->keyLen);
|
||||
int32_t v1 = doGetBucketIdFromHashVal(hashv, pHashObj->bits);
|
||||
|
||||
if (v1 != splitBucketId) { // place it into the new bucket
|
||||
ASSERT(v1 == newBucketId);
|
||||
// printf("move key:%d to 0x%x bucket, remain items:%d\n", *(int32_t*)k, v1, pBucket->size - 1);
|
||||
|
||||
SLHashBucket* pNewBucket = pHashObj->pBucket[newBucketId];
|
||||
doAddToBucket(pHashObj, pNewBucket, newBucketId, (void*)GET_LHASH_NODE_KEY(pNode), pNode->keyLen,
|
||||
GET_LHASH_NODE_KEY(pNode), pNode->dataLen);
|
||||
doRemoveFromBucket(p, pNode, pBucket);
|
||||
} else {
|
||||
// printf("check key:%d, located into: %d, skip it\n", *(int*) k, v1);
|
||||
|
||||
int32_t nodeSize = GET_LHASH_NODE_LEN(pStart);
|
||||
pStart += nodeSize;
|
||||
}
|
||||
}
|
||||
releaseBufPage(pHashObj->pBuf, p);
|
||||
}
|
||||
|
||||
doCompressBucketPages(pHashObj, pBucket);
|
||||
}
|
||||
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
char* tHashGet(SLHashObj* pHashObj, const void *key, size_t keyLen) {
|
||||
ASSERT(pHashObj != NULL && key != NULL && keyLen > 0);
|
||||
int32_t hashv = pHashObj->hashFn(key, keyLen);
|
||||
|
||||
int32_t bucketId = doGetBucketIdFromHashVal(hashv, pHashObj->bits);
|
||||
if (bucketId >= pHashObj->numOfBuckets) {
|
||||
bucketId = doGetAlternativeBucketId(bucketId, pHashObj->bits, pHashObj->numOfBuckets);
|
||||
}
|
||||
|
||||
SLHashBucket* pBucket = pHashObj->pBucket[bucketId];
|
||||
for (int32_t i = 0; i < taosArrayGetSize(pBucket->pPageIdList); ++i) {
|
||||
int32_t pageId = *(int32_t*)taosArrayGet(pBucket->pPageIdList, i);
|
||||
SFilePage* p = getBufPage(pHashObj->pBuf, pageId);
|
||||
|
||||
char* pStart = p->data;
|
||||
while (pStart - p->data < p->num) {
|
||||
SLHashNode* pNode = (SLHashNode*)pStart;
|
||||
|
||||
char* k = GET_LHASH_NODE_KEY(pNode);
|
||||
if (pNode->keyLen == keyLen && (memcmp(key, k, keyLen) == 0)) {
|
||||
releaseBufPage(pHashObj->pBuf, p);
|
||||
return GET_LHASH_NODE_DATA(pNode);
|
||||
} else {
|
||||
pStart += GET_LHASH_NODE_LEN(pStart);
|
||||
}
|
||||
}
|
||||
|
||||
releaseBufPage(pHashObj->pBuf, p);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int32_t tHashRemove(SLHashObj* pHashObj, const void *key, size_t keyLen) {
|
||||
// todo
|
||||
}
|
||||
|
||||
void tHashPrint(const SLHashObj* pHashObj, int32_t type) {
|
||||
printf("==================== linear hash ====================\n");
|
||||
printf("total bucket:%d, size:%ld, ratio:%.2f\n", pHashObj->numOfBuckets, pHashObj->size, LHASH_CAP_RATIO);
|
||||
|
||||
dBufSetPrintInfo(pHashObj->pBuf);
|
||||
|
||||
if (type == LINEAR_HASH_DATA) {
|
||||
for (int32_t i = 0; i < pHashObj->numOfBuckets; ++i) {
|
||||
// printf("bucket: 0x%x, obj:%d, page:%d\n", i, pHashObj->pBucket[i]->size,
|
||||
// (int)taosArrayGetSize(pHashObj->pBucket[i]->pPageIdList));
|
||||
}
|
||||
} else {
|
||||
dBufPrintStatis(pHashObj->pBuf);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,679 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* This program is free software: you can use, redistribute, and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3
|
||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "query.h"
|
||||
|
||||
#include "tsort.h"
|
||||
#include "tep.h"
|
||||
#include "tcfg.h"
|
||||
#include "tlosertree.h"
|
||||
#include "tpagedbuf.h"
|
||||
#include "tutil.h"
|
||||
|
||||
typedef struct STupleHandle {
|
||||
SSDataBlock* pBlock;
|
||||
int32_t rowIndex;
|
||||
} STupleHandle;
|
||||
|
||||
typedef struct SSortHandle {
|
||||
int32_t type;
|
||||
|
||||
int32_t pageSize;
|
||||
int32_t numOfPages;
|
||||
SDiskbasedBuf *pBuf;
|
||||
|
||||
SArray *pOrderInfo;
|
||||
bool nullFirst;
|
||||
bool hasVarCol;
|
||||
SArray *pOrderedSource;
|
||||
|
||||
_sort_fetch_block_fn_t fetchfp;
|
||||
_sort_merge_compar_fn_t comparFn;
|
||||
|
||||
void *pParam;
|
||||
SMultiwayMergeTreeInfo *pMergeTree;
|
||||
int32_t numOfCols;
|
||||
|
||||
int64_t startTs;
|
||||
uint64_t sortElapsed;
|
||||
uint64_t totalElapsed;
|
||||
|
||||
int32_t sourceId;
|
||||
SSDataBlock *pDataBlock;
|
||||
SMsortComparParam cmpParam;
|
||||
int32_t numOfCompletedSources;
|
||||
bool opened;
|
||||
const char *idStr;
|
||||
|
||||
bool inMemSort;
|
||||
bool needAdjust;
|
||||
STupleHandle tupleHandle;
|
||||
} SSortHandle;
|
||||
|
||||
static int32_t msortComparFn(const void *pLeft, const void *pRight, void *param);
|
||||
|
||||
static SSDataBlock* createDataBlock_rv(SSchema* pSchema, int32_t numOfCols) {
|
||||
SSDataBlock* pBlock = calloc(1, sizeof(SSDataBlock));
|
||||
pBlock->pDataBlock = taosArrayInit(numOfCols, sizeof(SColumnInfoData));
|
||||
pBlock->info.numOfCols = numOfCols;
|
||||
|
||||
for(int32_t i = 0; i < numOfCols; ++i) {
|
||||
SColumnInfoData colInfo = {0};
|
||||
|
||||
colInfo.info.type = pSchema[i].type;
|
||||
colInfo.info.bytes = pSchema[i].bytes;
|
||||
colInfo.info.colId = pSchema[i].colId;
|
||||
taosArrayPush(pBlock->pDataBlock, &colInfo);
|
||||
}
|
||||
|
||||
return pBlock;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
SSortHandle* tsortCreateSortHandle(SArray* pOrderInfo, bool nullFirst, int32_t type, int32_t pageSize, int32_t numOfPages, SSchema* pSchema, int32_t numOfCols, const char* idstr) {
|
||||
SSortHandle* pSortHandle = calloc(1, sizeof(SSortHandle));
|
||||
|
||||
pSortHandle->type = type;
|
||||
pSortHandle->pageSize = pageSize;
|
||||
pSortHandle->numOfPages = numOfPages;
|
||||
pSortHandle->pOrderedSource = taosArrayInit(4, POINTER_BYTES);
|
||||
pSortHandle->pOrderInfo = pOrderInfo;
|
||||
pSortHandle->nullFirst = nullFirst;
|
||||
pSortHandle->cmpParam.orderInfo = pOrderInfo;
|
||||
|
||||
pSortHandle->pDataBlock = createDataBlock_rv(pSchema, numOfCols);
|
||||
tsortSetComparFp(pSortHandle, msortComparFn);
|
||||
|
||||
if (idstr != NULL) {
|
||||
pSortHandle->idStr = strdup(idstr);
|
||||
}
|
||||
|
||||
return pSortHandle;
|
||||
}
|
||||
|
||||
void tsortDestroySortHandle(SSortHandle* pSortHandle) {
|
||||
tsortClose(pSortHandle);
|
||||
if (pSortHandle->pMergeTree != NULL) {
|
||||
tMergeTreeDestroy(pSortHandle->pMergeTree);
|
||||
}
|
||||
|
||||
destroyDiskbasedBuf(pSortHandle->pBuf);
|
||||
tfree(pSortHandle->idStr);
|
||||
tfree(pSortHandle);
|
||||
}
|
||||
|
||||
int32_t tsortAddSource(SSortHandle* pSortHandle, void* pSource) {
|
||||
taosArrayPush(pSortHandle->pOrderedSource, &pSource);
|
||||
}
|
||||
|
||||
static int32_t doAddNewExternalMemSource(SDiskbasedBuf *pBuf, SArray* pAllSources, SSDataBlock* pBlock, int32_t* sourceId) {
|
||||
SExternalMemSource* pSource = calloc(1, sizeof(SExternalMemSource));
|
||||
if (pSource == NULL) {
|
||||
return TSDB_CODE_QRY_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
pSource->pageIdList = getDataBufPagesIdList(pBuf, (*sourceId));
|
||||
pSource->src.pBlock = pBlock;
|
||||
|
||||
taosArrayPush(pAllSources, &pSource);
|
||||
|
||||
(*sourceId) += 1;
|
||||
|
||||
int32_t rowSize = blockDataGetSerialRowSize(pSource->src.pBlock);
|
||||
int32_t numOfRows = (getBufPageSize(pBuf) - blockDataGetSerialMetaSize(pBlock))/rowSize;
|
||||
|
||||
return blockDataEnsureCapacity(pSource->src.pBlock, numOfRows);
|
||||
}
|
||||
|
||||
static int32_t doAddToBuf(SSDataBlock* pDataBlock, SSortHandle* pHandle) {
|
||||
int32_t start = 0;
|
||||
|
||||
if (pHandle->pBuf == NULL) {
|
||||
int32_t code = createDiskbasedBuf(&pHandle->pBuf, pHandle->pageSize, pHandle->numOfPages * pHandle->pageSize, 0, "/tmp");
|
||||
dBufSetPrintInfo(pHandle->pBuf);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
while(start < pDataBlock->info.rows) {
|
||||
int32_t stop = 0;
|
||||
blockDataSplitRows(pDataBlock, pHandle->hasVarCol, start, &stop, pHandle->pageSize);
|
||||
SSDataBlock* p = blockDataExtractBlock(pDataBlock, start, stop - start + 1);
|
||||
if (p == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
|
||||
int32_t pageId = -1;
|
||||
SFilePage* pPage = getNewBufPage(pHandle->pBuf, pHandle->sourceId, &pageId);
|
||||
if (pPage == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
|
||||
int32_t size = blockDataGetSize(p) + sizeof(int32_t) + p->info.numOfCols * sizeof(int32_t);
|
||||
assert(size <= getBufPageSize(pHandle->pBuf));
|
||||
|
||||
blockDataToBuf(pPage->data, p);
|
||||
|
||||
setBufPageDirty(pPage, true);
|
||||
releaseBufPage(pHandle->pBuf, pPage);
|
||||
|
||||
blockDataDestroy(p);
|
||||
start = stop + 1;
|
||||
}
|
||||
|
||||
blockDataClearup(pDataBlock, pHandle->hasVarCol);
|
||||
|
||||
SSDataBlock* pBlock = createOneDataBlock(pDataBlock);
|
||||
int32_t code = doAddNewExternalMemSource(pHandle->pBuf, pHandle->pOrderedSource, pBlock, &pHandle->sourceId);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t sortComparInit(SMsortComparParam* cmpParam, SArray* pSources, int32_t startIndex, int32_t endIndex, SSortHandle* pHandle) {
|
||||
cmpParam->pSources = taosArrayGet(pSources, startIndex);
|
||||
cmpParam->numOfSources = (endIndex - startIndex + 1);
|
||||
|
||||
int32_t code = 0;
|
||||
|
||||
if (pHandle->type == SORT_SINGLESOURCE_SORT) {
|
||||
for (int32_t i = 0; i < cmpParam->numOfSources; ++i) {
|
||||
SExternalMemSource* pSource = cmpParam->pSources[i];
|
||||
SPageInfo* pPgInfo = *(SPageInfo**)taosArrayGet(pSource->pageIdList, pSource->pageIndex);
|
||||
|
||||
SFilePage* pPage = getBufPage(pHandle->pBuf, getPageId(pPgInfo));
|
||||
code = blockDataFromBuf(pSource->src.pBlock, pPage->data);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
return code;
|
||||
}
|
||||
|
||||
releaseBufPage(pHandle->pBuf, pPage);
|
||||
}
|
||||
} else {
|
||||
// multi-pass internal merge sort is required
|
||||
if (pHandle->pBuf == NULL) {
|
||||
code = createDiskbasedBuf(&pHandle->pBuf, pHandle->pageSize, pHandle->numOfPages * pHandle->pageSize, 0, "/tmp");
|
||||
dBufSetPrintInfo(pHandle->pBuf);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < cmpParam->numOfSources; ++i) {
|
||||
SGenericSource* pSource = cmpParam->pSources[i];
|
||||
pSource->src.pBlock = pHandle->fetchfp(pSource->param);
|
||||
}
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t sortComparClearup(SMsortComparParam* cmpParam) {
|
||||
for(int32_t i = 0; i < cmpParam->numOfSources; ++i) {
|
||||
SExternalMemSource* pSource = cmpParam->pSources[i];
|
||||
blockDataDestroy(pSource->src.pBlock);
|
||||
tfree(pSource);
|
||||
}
|
||||
|
||||
cmpParam->numOfSources = 0;
|
||||
}
|
||||
|
||||
static void appendOneRowToDataBlock(SSDataBlock *pBlock, const SSDataBlock* pSource, int32_t* rowIndex) {
|
||||
for (int32_t i = 0; i < pBlock->info.numOfCols; ++i) {
|
||||
SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, i);
|
||||
|
||||
SColumnInfoData* pSrcColInfo = taosArrayGet(pSource->pDataBlock, i);
|
||||
bool isNull = colDataIsNull(pSrcColInfo, pSource->info.rows, *rowIndex, NULL);
|
||||
|
||||
if (isNull) {
|
||||
colDataAppend(pColInfo, pBlock->info.rows, NULL, true);
|
||||
} else {
|
||||
char* pData = colDataGetData(pSrcColInfo, *rowIndex);
|
||||
colDataAppend(pColInfo, pBlock->info.rows, pData, false);
|
||||
}
|
||||
}
|
||||
|
||||
pBlock->info.rows += 1;
|
||||
*rowIndex += 1;
|
||||
}
|
||||
|
||||
static int32_t adjustMergeTreeForNextTuple(SExternalMemSource *pSource, SMultiwayMergeTreeInfo *pTree, SSortHandle *pHandle, int32_t* numOfCompleted) {
|
||||
/*
|
||||
* load a new SDataBlock into memory of a given intermediate data-set source,
|
||||
* since it's last record in buffer has been chosen to be processed, as the winner of loser-tree
|
||||
*/
|
||||
if (pSource->src.rowIndex >= pSource->src.pBlock->info.rows) {
|
||||
pSource->src.rowIndex = 0;
|
||||
|
||||
if (pHandle->type == SORT_SINGLESOURCE_SORT) {
|
||||
if (pSource->pageIndex >= taosArrayGetSize(pSource->pageIdList)) {
|
||||
(*numOfCompleted) += 1;
|
||||
pSource->src.rowIndex = -1;
|
||||
pSource->pageIndex = -1;
|
||||
pSource->src.pBlock = blockDataDestroy(pSource->src.pBlock);
|
||||
} else {
|
||||
SPageInfo* pPgInfo = *(SPageInfo**)taosArrayGet(pSource->pageIdList, pSource->pageIndex);
|
||||
|
||||
SFilePage* pPage = getBufPage(pHandle->pBuf, getPageId(pPgInfo));
|
||||
int32_t code = blockDataFromBuf(pSource->src.pBlock, pPage->data);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
return code;
|
||||
}
|
||||
|
||||
releaseBufPage(pHandle->pBuf, pPage);
|
||||
}
|
||||
} else {
|
||||
pSource->src.pBlock = pHandle->fetchfp(((SGenericSource*)pSource)->param);
|
||||
if (pSource->src.pBlock == NULL) {
|
||||
(*numOfCompleted) += 1;
|
||||
pSource->src.rowIndex = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjust loser tree otherwise, according to new candidate data
|
||||
* if the loser tree is rebuild completed, we do not need to adjust
|
||||
*/
|
||||
int32_t leafNodeIndex = tMergeTreeGetAdjustIndex(pTree);
|
||||
|
||||
#ifdef _DEBUG_VIEW
|
||||
printf("before adjust:\t");
|
||||
tMergeTreePrint(pTree);
|
||||
#endif
|
||||
|
||||
tMergeTreeAdjust(pTree, leafNodeIndex);
|
||||
|
||||
#ifdef _DEBUG_VIEW
|
||||
printf("\nafter adjust:\t");
|
||||
tMergeTreePrint(pTree);
|
||||
#endif
|
||||
}
|
||||
|
||||
static SSDataBlock* getSortedBlockData(SSortHandle* pHandle, SMsortComparParam* cmpParam, int32_t capacity) {
|
||||
blockDataClearup(pHandle->pDataBlock, pHandle->hasVarCol);
|
||||
|
||||
while(1) {
|
||||
if (cmpParam->numOfSources == pHandle->numOfCompletedSources) {
|
||||
break;
|
||||
}
|
||||
|
||||
int32_t index = tMergeTreeGetChosenIndex(pHandle->pMergeTree);
|
||||
|
||||
SExternalMemSource *pSource = (*cmpParam).pSources[index];
|
||||
appendOneRowToDataBlock(pHandle->pDataBlock, pSource->src.pBlock, &pSource->src.rowIndex);
|
||||
|
||||
int32_t code = adjustMergeTreeForNextTuple(pSource, pHandle->pMergeTree, pHandle, &pHandle->numOfCompletedSources);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
terrno = code;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pHandle->pDataBlock->info.rows >= capacity) {
|
||||
return pHandle->pDataBlock;
|
||||
}
|
||||
}
|
||||
|
||||
return (pHandle->pDataBlock->info.rows > 0)? pHandle->pDataBlock:NULL;
|
||||
}
|
||||
|
||||
int32_t msortComparFn(const void *pLeft, const void *pRight, void *param) {
|
||||
int32_t pLeftIdx = *(int32_t *)pLeft;
|
||||
int32_t pRightIdx = *(int32_t *)pRight;
|
||||
|
||||
SMsortComparParam *pParam = (SMsortComparParam *)param;
|
||||
|
||||
SArray *pInfo = pParam->orderInfo;
|
||||
|
||||
SExternalMemSource* pLeftSource = pParam->pSources[pLeftIdx];
|
||||
SExternalMemSource* pRightSource = pParam->pSources[pRightIdx];
|
||||
|
||||
// this input is exhausted, set the special value to denote this
|
||||
if (pLeftSource->src.rowIndex == -1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (pRightSource->src.rowIndex == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSDataBlock* pLeftBlock = pLeftSource->src.pBlock;
|
||||
SSDataBlock* pRightBlock = pRightSource->src.pBlock;
|
||||
|
||||
for(int32_t i = 0; i < pInfo->size; ++i) {
|
||||
SBlockOrderInfo* pOrder = TARRAY_GET_ELEM(pInfo, i);
|
||||
|
||||
SColumnInfoData* pLeftColInfoData = TARRAY_GET_ELEM(pLeftBlock->pDataBlock, pOrder->colIndex);
|
||||
|
||||
bool leftNull = false;
|
||||
if (pLeftColInfoData->hasNull) {
|
||||
leftNull = colDataIsNull(pLeftColInfoData, pLeftBlock->info.rows, pLeftSource->src.rowIndex, pLeftBlock->pBlockAgg);
|
||||
}
|
||||
|
||||
SColumnInfoData* pRightColInfoData = TARRAY_GET_ELEM(pRightBlock->pDataBlock, pOrder->colIndex);
|
||||
bool rightNull = false;
|
||||
if (pRightColInfoData->hasNull) {
|
||||
rightNull = colDataIsNull(pRightColInfoData, pRightBlock->info.rows, pRightSource->src.rowIndex, pRightBlock->pBlockAgg);
|
||||
}
|
||||
|
||||
if (leftNull && rightNull) {
|
||||
continue; // continue to next slot
|
||||
}
|
||||
|
||||
if (rightNull) {
|
||||
return pParam->nullFirst? 1:-1;
|
||||
}
|
||||
|
||||
if (leftNull) {
|
||||
return pParam->nullFirst? -1:1;
|
||||
}
|
||||
|
||||
void* left1 = colDataGetData(pLeftColInfoData, pLeftSource->src.rowIndex);
|
||||
void* right1 = colDataGetData(pRightColInfoData, pRightSource->src.rowIndex);
|
||||
|
||||
switch(pLeftColInfoData->info.type) {
|
||||
case TSDB_DATA_TYPE_INT: {
|
||||
int32_t leftv = *(int32_t*)left1;
|
||||
int32_t rightv = *(int32_t*)right1;
|
||||
|
||||
if (leftv == rightv) {
|
||||
break;
|
||||
} else {
|
||||
if (pOrder->order == TSDB_ORDER_ASC) {
|
||||
return leftv < rightv? -1 : 1;
|
||||
} else {
|
||||
return leftv < rightv? 1 : -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t doInternalMergeSort(SSortHandle* pHandle) {
|
||||
size_t numOfSources = taosArrayGetSize(pHandle->pOrderedSource);
|
||||
|
||||
// Calculate the I/O counts to complete the data sort.
|
||||
double sortPass = floorl(log2(numOfSources) / log2(pHandle->numOfPages));
|
||||
|
||||
pHandle->totalElapsed = taosGetTimestampUs() - pHandle->startTs;
|
||||
qDebug("%s %d rounds mergesort required to complete the sort, first-round sorted data size:%"PRIzu", sort:%"PRId64", total elapsed:%"PRId64,
|
||||
pHandle->idStr, (int32_t) (sortPass + 1), getTotalBufSize(pHandle->pBuf), pHandle->sortElapsed, pHandle->totalElapsed);
|
||||
|
||||
size_t pgSize = pHandle->pageSize;
|
||||
int32_t numOfRows = (pgSize - blockDataGetSerialMetaSize(pHandle->pDataBlock))/ blockDataGetSerialRowSize(pHandle->pDataBlock);
|
||||
|
||||
blockDataEnsureCapacity(pHandle->pDataBlock, numOfRows);
|
||||
|
||||
size_t numOfSorted = taosArrayGetSize(pHandle->pOrderedSource);
|
||||
for(int32_t t = 0; t < sortPass; ++t) {
|
||||
int64_t st = taosGetTimestampUs();
|
||||
|
||||
SArray* pResList = taosArrayInit(4, POINTER_BYTES);
|
||||
|
||||
int32_t numOfInputSources = pHandle->numOfPages;
|
||||
int32_t sortGroup = (numOfSorted + numOfInputSources - 1) / numOfInputSources;
|
||||
|
||||
// Only *numOfInputSources* can be loaded into buffer to perform the external sort.
|
||||
for(int32_t i = 0; i < sortGroup; ++i) {
|
||||
pHandle->sourceId += 1;
|
||||
|
||||
int32_t end = (i + 1) * numOfInputSources - 1;
|
||||
if (end > numOfSorted - 1) {
|
||||
end = numOfSorted - 1;
|
||||
}
|
||||
|
||||
pHandle->cmpParam.numOfSources = end - i * numOfInputSources + 1;
|
||||
|
||||
int32_t code = sortComparInit(&pHandle->cmpParam, pHandle->pOrderedSource, i * numOfInputSources, end, pHandle);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
return code;
|
||||
}
|
||||
|
||||
code = tMergeTreeCreate(&pHandle->pMergeTree, pHandle->cmpParam.numOfSources, &pHandle->cmpParam, pHandle->comparFn);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
return code;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
SSDataBlock* pDataBlock = getSortedBlockData(pHandle, &pHandle->cmpParam, numOfRows);
|
||||
if (pDataBlock == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
int32_t pageId = -1;
|
||||
SFilePage* pPage = getNewBufPage(pHandle->pBuf, pHandle->sourceId, &pageId);
|
||||
if (pPage == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
|
||||
int32_t size = blockDataGetSize(pDataBlock) + sizeof(int32_t) + pDataBlock->info.numOfCols * sizeof(int32_t);
|
||||
assert(size <= getBufPageSize(pHandle->pBuf));
|
||||
|
||||
blockDataToBuf(pPage->data, pDataBlock);
|
||||
|
||||
setBufPageDirty(pPage, true);
|
||||
releaseBufPage(pHandle->pBuf, pPage);
|
||||
|
||||
blockDataClearup(pDataBlock, pHandle->hasVarCol);
|
||||
}
|
||||
|
||||
tMergeTreeDestroy(pHandle->pMergeTree);
|
||||
pHandle->numOfCompletedSources = 0;
|
||||
|
||||
SSDataBlock* pBlock = createOneDataBlock(pHandle->pDataBlock);
|
||||
code = doAddNewExternalMemSource(pHandle->pBuf, pResList, pBlock, &pHandle->sourceId);
|
||||
if (code != 0) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
sortComparClearup(&pHandle->cmpParam);
|
||||
|
||||
taosArrayClear(pHandle->pOrderedSource);
|
||||
taosArrayAddAll(pHandle->pOrderedSource, pResList);
|
||||
taosArrayDestroy(pResList);
|
||||
|
||||
numOfSorted = taosArrayGetSize(pHandle->pOrderedSource);
|
||||
|
||||
int64_t el = taosGetTimestampUs() - st;
|
||||
pHandle->totalElapsed += el;
|
||||
|
||||
SDiskbasedBufStatis statis = getDBufStatis(pHandle->pBuf);
|
||||
qDebug("%s %d round mergesort, elapsed:%"PRId64" readDisk:%.2f Kb, flushDisk:%.2f Kb", pHandle->idStr, t + 1, el, statis.loadBytes/1024.0,
|
||||
statis.flushBytes/1024.0);
|
||||
|
||||
if (pHandle->type == SORT_MULTISOURCE_MERGE) {
|
||||
pHandle->type = SORT_SINGLESOURCE_SORT;
|
||||
pHandle->comparFn = msortComparFn;
|
||||
}
|
||||
}
|
||||
|
||||
pHandle->cmpParam.numOfSources = taosArrayGetSize(pHandle->pOrderedSource);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t createInitialSortedMultiSources(SSortHandle* pHandle) {
|
||||
size_t sortBufSize = pHandle->numOfPages * pHandle->pageSize;
|
||||
|
||||
if (pHandle->type == SORT_SINGLESOURCE_SORT) {
|
||||
SGenericSource* source = taosArrayGetP(pHandle->pOrderedSource, 0);
|
||||
taosArrayClear(pHandle->pOrderedSource);
|
||||
|
||||
while (1) {
|
||||
SSDataBlock* pBlock = pHandle->fetchfp(source->param);
|
||||
if (pBlock == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (pHandle->pDataBlock == NULL) {
|
||||
pHandle->pDataBlock = createOneDataBlock(pBlock);
|
||||
}
|
||||
|
||||
int32_t code = blockDataMerge(pHandle->pDataBlock, pBlock);
|
||||
if (code != 0) {
|
||||
return code;
|
||||
}
|
||||
|
||||
size_t size = blockDataGetSize(pHandle->pDataBlock);
|
||||
if (size > sortBufSize) {
|
||||
// Perform the in-memory sort and then flush data in the buffer into disk.
|
||||
int64_t p = taosGetTimestampUs();
|
||||
blockDataSort(pHandle->pDataBlock, pHandle->pOrderInfo, pHandle->nullFirst);
|
||||
|
||||
int64_t el = taosGetTimestampUs() - p;
|
||||
pHandle->sortElapsed += el;
|
||||
|
||||
doAddToBuf(pHandle->pDataBlock, pHandle);
|
||||
}
|
||||
}
|
||||
|
||||
if (pHandle->pDataBlock->info.rows > 0) {
|
||||
size_t size = blockDataGetSize(pHandle->pDataBlock);
|
||||
|
||||
// Perform the in-memory sort and then flush data in the buffer into disk.
|
||||
blockDataSort(pHandle->pDataBlock, pHandle->pOrderInfo, pHandle->nullFirst);
|
||||
|
||||
// All sorted data can fit in memory, external memory sort is not needed. Return to directly
|
||||
if (size <= sortBufSize) {
|
||||
pHandle->cmpParam.numOfSources = 1;
|
||||
pHandle->inMemSort = true;
|
||||
|
||||
pHandle->tupleHandle.rowIndex = -1;
|
||||
pHandle->tupleHandle.pBlock = pHandle->pDataBlock;
|
||||
return 0;
|
||||
} else {
|
||||
doAddToBuf(pHandle->pDataBlock, pHandle);
|
||||
}
|
||||
}
|
||||
|
||||
tfree(source);
|
||||
}
|
||||
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t tsortOpen(SSortHandle* pHandle) {
|
||||
if (pHandle->opened) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pHandle->fetchfp == NULL || pHandle->comparFn == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pHandle->opened = true;
|
||||
|
||||
int32_t code = createInitialSortedMultiSources(pHandle);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
return code;
|
||||
}
|
||||
|
||||
// do internal sort
|
||||
code = doInternalMergeSort(pHandle);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
return code;
|
||||
}
|
||||
|
||||
int32_t numOfSources = taosArrayGetSize(pHandle->pOrderedSource);
|
||||
if (pHandle->pBuf != NULL) {
|
||||
ASSERT(numOfSources <= getNumOfInMemBufPages(pHandle->pBuf));
|
||||
}
|
||||
|
||||
code = sortComparInit(&pHandle->cmpParam, pHandle->pOrderedSource, 0, numOfSources - 1, pHandle);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
return code;
|
||||
}
|
||||
|
||||
code = tMergeTreeCreate(&pHandle->pMergeTree, pHandle->cmpParam.numOfSources, &pHandle->cmpParam, pHandle->comparFn);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t tsortClose(SSortHandle* pHandle) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
int32_t tsortSetFetchRawDataFp(SSortHandle* pHandle, _sort_fetch_block_fn_t fp) {
|
||||
pHandle->fetchfp = fp;
|
||||
}
|
||||
|
||||
int32_t tsortSetComparFp(SSortHandle* pHandle, _sort_merge_compar_fn_t fp) {
|
||||
pHandle->comparFn = fp;
|
||||
}
|
||||
|
||||
STupleHandle* tsortNextTuple(SSortHandle* pHandle) {
|
||||
if (pHandle->cmpParam.numOfSources == pHandle->numOfCompletedSources) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// All the data are hold in the buffer, no external sort is invoked.
|
||||
if (pHandle->inMemSort) {
|
||||
pHandle->tupleHandle.rowIndex += 1;
|
||||
if (pHandle->tupleHandle.rowIndex == pHandle->pDataBlock->info.rows) {
|
||||
pHandle->numOfCompletedSources = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &pHandle->tupleHandle;
|
||||
}
|
||||
|
||||
int32_t index = tMergeTreeGetChosenIndex(pHandle->pMergeTree);
|
||||
SExternalMemSource *pSource = pHandle->cmpParam.pSources[index];
|
||||
|
||||
if (pHandle->needAdjust) {
|
||||
int32_t code = adjustMergeTreeForNextTuple(pSource, pHandle->pMergeTree, pHandle, &pHandle->numOfCompletedSources);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
terrno = code;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (pHandle->cmpParam.numOfSources == pHandle->numOfCompletedSources) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get the adjusted value after the loser tree is updated.
|
||||
index = tMergeTreeGetChosenIndex(pHandle->pMergeTree);
|
||||
pSource = pHandle->cmpParam.pSources[index];
|
||||
|
||||
assert(pSource->src.pBlock != NULL);
|
||||
|
||||
pHandle->tupleHandle.rowIndex = pSource->src.rowIndex;
|
||||
pHandle->tupleHandle.pBlock = pSource->src.pBlock;
|
||||
|
||||
pHandle->needAdjust = true;
|
||||
pSource->src.rowIndex += 1;
|
||||
|
||||
return &pHandle->tupleHandle;
|
||||
}
|
||||
|
||||
bool tsortIsNullVal(STupleHandle* pVHandle, int32_t colIndex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void* tsortGetValue(STupleHandle* pVHandle, int32_t colIndex) {
|
||||
SColumnInfoData* pColInfo = TARRAY_GET_ELEM(pVHandle->pBlock->pDataBlock, colIndex);
|
||||
return colDataGetData(pColInfo, pVHandle->rowIndex);
|
||||
}
|
|
@ -14,6 +14,7 @@
|
|||
*/
|
||||
|
||||
#include <executorimpl.h>
|
||||
#include <function.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <tglobal.h>
|
||||
#include <iostream>
|
||||
|
@ -37,22 +38,30 @@
|
|||
|
||||
namespace {
|
||||
|
||||
enum {
|
||||
data_rand = 0x1,
|
||||
data_asc = 0x2,
|
||||
data_desc = 0x3,
|
||||
};
|
||||
|
||||
typedef struct SDummyInputInfo {
|
||||
int32_t max;
|
||||
int32_t totalPages; // numOfPages
|
||||
int32_t current;
|
||||
int32_t startVal;
|
||||
int32_t type;
|
||||
int32_t numOfRowsPerPage;
|
||||
int32_t numOfCols; // number of columns
|
||||
int64_t tsStart;
|
||||
SSDataBlock* pBlock;
|
||||
} SDummyInputInfo;
|
||||
|
||||
SSDataBlock* getDummyBlock(void* param, bool* newgroup) {
|
||||
SOperatorInfo* pOperator = static_cast<SOperatorInfo*>(param);
|
||||
SDummyInputInfo* pInfo = static_cast<SDummyInputInfo*>(pOperator->info);
|
||||
if (pInfo->current >= pInfo->max) {
|
||||
if (pInfo->current >= pInfo->totalPages) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int32_t numOfRows = 1000;
|
||||
|
||||
if (pInfo->pBlock == NULL) {
|
||||
pInfo->pBlock = static_cast<SSDataBlock*>(calloc(1, sizeof(SSDataBlock)));
|
||||
|
||||
|
@ -62,8 +71,8 @@ SSDataBlock* getDummyBlock(void* param, bool* newgroup) {
|
|||
colInfo.info.type = TSDB_DATA_TYPE_INT;
|
||||
colInfo.info.bytes = sizeof(int32_t);
|
||||
colInfo.info.colId = 1;
|
||||
colInfo.pData = static_cast<char*>(calloc(numOfRows, sizeof(int32_t)));
|
||||
colInfo.nullbitmap = static_cast<char*>(calloc(1, (numOfRows + 7) / 8));
|
||||
colInfo.pData = static_cast<char*>(calloc(pInfo->numOfRowsPerPage, sizeof(int32_t)));
|
||||
colInfo.nullbitmap = static_cast<char*>(calloc(1, (pInfo->numOfRowsPerPage + 7) / 8));
|
||||
|
||||
taosArrayPush(pInfo->pBlock->pDataBlock, &colInfo);
|
||||
|
||||
|
@ -85,10 +94,18 @@ SSDataBlock* getDummyBlock(void* param, bool* newgroup) {
|
|||
|
||||
char buf[128] = {0};
|
||||
char b1[128] = {0};
|
||||
for(int32_t i = 0; i < numOfRows; ++i) {
|
||||
int32_t v = 0;
|
||||
for(int32_t i = 0; i < pInfo->numOfRowsPerPage; ++i) {
|
||||
SColumnInfoData* pColInfo = static_cast<SColumnInfoData*>(TARRAY_GET_ELEM(pBlock->pDataBlock, 0));
|
||||
|
||||
int32_t v = (--pInfo->startVal);
|
||||
if (pInfo->type == data_desc) {
|
||||
v = (--pInfo->startVal);
|
||||
} else if (pInfo->type == data_asc) {
|
||||
v = ++pInfo->startVal;
|
||||
} else if (pInfo->type == data_rand) {
|
||||
v = random();
|
||||
}
|
||||
|
||||
colDataAppend(pColInfo, i, reinterpret_cast<const char*>(&v), false);
|
||||
|
||||
// sprintf(buf, "this is %d row", i);
|
||||
|
@ -98,21 +115,103 @@ SSDataBlock* getDummyBlock(void* param, bool* newgroup) {
|
|||
// colDataAppend(pColInfo2, i, b1, false);
|
||||
}
|
||||
|
||||
pBlock->info.rows = numOfRows;
|
||||
pBlock->info.rows = pInfo->numOfRowsPerPage;
|
||||
pBlock->info.numOfCols = 1;
|
||||
|
||||
pInfo->current += 1;
|
||||
return pBlock;
|
||||
}
|
||||
|
||||
SOperatorInfo* createDummyOperator(int32_t numOfBlocks) {
|
||||
SSDataBlock* get2ColsDummyBlock(void* param, bool* newgroup) {
|
||||
SOperatorInfo* pOperator = static_cast<SOperatorInfo*>(param);
|
||||
SDummyInputInfo* pInfo = static_cast<SDummyInputInfo*>(pOperator->info);
|
||||
if (pInfo->current >= pInfo->totalPages) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pInfo->pBlock == NULL) {
|
||||
pInfo->pBlock = static_cast<SSDataBlock*>(calloc(1, sizeof(SSDataBlock)));
|
||||
|
||||
pInfo->pBlock->pDataBlock = taosArrayInit(4, sizeof(SColumnInfoData));
|
||||
|
||||
SColumnInfoData colInfo = {0};
|
||||
colInfo.info.type = TSDB_DATA_TYPE_TIMESTAMP;
|
||||
colInfo.info.bytes = sizeof(int64_t);
|
||||
colInfo.info.colId = 1;
|
||||
colInfo.pData = static_cast<char*>(calloc(pInfo->numOfRowsPerPage, sizeof(int64_t)));
|
||||
// colInfo.nullbitmap = static_cast<char*>(calloc(1, (pInfo->numOfRowsPerPage + 7) / 8));
|
||||
|
||||
taosArrayPush(pInfo->pBlock->pDataBlock, &colInfo);
|
||||
|
||||
SColumnInfoData colInfo1 = {0};
|
||||
colInfo1.info.type = TSDB_DATA_TYPE_INT;
|
||||
colInfo1.info.bytes = 4;
|
||||
colInfo1.info.colId = 2;
|
||||
|
||||
colInfo1.pData = static_cast<char*>(calloc(pInfo->numOfRowsPerPage, sizeof(int32_t)));
|
||||
colInfo1.nullbitmap = static_cast<char*>(calloc(1, (pInfo->numOfRowsPerPage + 7) / 8));
|
||||
|
||||
taosArrayPush(pInfo->pBlock->pDataBlock, &colInfo1);
|
||||
} else {
|
||||
blockDataClearup(pInfo->pBlock, false);
|
||||
}
|
||||
|
||||
SSDataBlock* pBlock = pInfo->pBlock;
|
||||
|
||||
char buf[128] = {0};
|
||||
char b1[128] = {0};
|
||||
int64_t ts = 0;
|
||||
int32_t v = 0;
|
||||
for(int32_t i = 0; i < pInfo->numOfRowsPerPage; ++i) {
|
||||
SColumnInfoData* pColInfo = static_cast<SColumnInfoData*>(TARRAY_GET_ELEM(pBlock->pDataBlock, 0));
|
||||
|
||||
ts = (++pInfo->tsStart);
|
||||
colDataAppend(pColInfo, i, reinterpret_cast<const char*>(&ts), false);
|
||||
|
||||
SColumnInfoData* pColInfo1 = static_cast<SColumnInfoData*>(TARRAY_GET_ELEM(pBlock->pDataBlock, 1));
|
||||
if (pInfo->type == data_desc) {
|
||||
v = (--pInfo->startVal);
|
||||
} else if (pInfo->type == data_asc) {
|
||||
v = ++pInfo->startVal;
|
||||
} else if (pInfo->type == data_rand) {
|
||||
v = random();
|
||||
}
|
||||
|
||||
colDataAppend(pColInfo1, i, reinterpret_cast<const char*>(&v), false);
|
||||
|
||||
// sprintf(buf, "this is %d row", i);
|
||||
// STR_TO_VARSTR(b1, buf);
|
||||
//
|
||||
// SColumnInfoData* pColInfo2 = static_cast<SColumnInfoData*>(TARRAY_GET_ELEM(pBlock->pDataBlock, 1));
|
||||
// colDataAppend(pColInfo2, i, b1, false);
|
||||
}
|
||||
|
||||
pBlock->info.rows = pInfo->numOfRowsPerPage;
|
||||
pBlock->info.numOfCols = 1;
|
||||
|
||||
pInfo->current += 1;
|
||||
|
||||
blockDataUpdateTsWindow(pBlock);
|
||||
return pBlock;
|
||||
|
||||
}
|
||||
|
||||
SOperatorInfo* createDummyOperator(int32_t startVal, int32_t numOfBlocks, int32_t rowsPerPage, int32_t type, int32_t numOfCols) {
|
||||
SOperatorInfo* pOperator = static_cast<SOperatorInfo*>(calloc(1, sizeof(SOperatorInfo)));
|
||||
pOperator->name = "dummyInputOpertor4Test";
|
||||
|
||||
if (numOfCols == 1) {
|
||||
pOperator->exec = getDummyBlock;
|
||||
} else {
|
||||
pOperator->exec = get2ColsDummyBlock;
|
||||
}
|
||||
|
||||
SDummyInputInfo *pInfo = (SDummyInputInfo*) calloc(1, sizeof(SDummyInputInfo));
|
||||
pInfo->max = numOfBlocks;
|
||||
pInfo->startVal = 1500000;
|
||||
pInfo->totalPages = numOfBlocks;
|
||||
pInfo->startVal = startVal;
|
||||
pInfo->numOfRowsPerPage = rowsPerPage;
|
||||
pInfo->type = type;
|
||||
pInfo->tsStart = 1620000000000;
|
||||
|
||||
pOperator->info = pInfo;
|
||||
return pOperator;
|
||||
|
@ -123,6 +222,7 @@ int main(int argc, char** argv) {
|
|||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
||||
#if 0
|
||||
TEST(testCase, build_executor_tree_Test) {
|
||||
const char* msg = "{\n"
|
||||
"\t\"Id\":\t{\n"
|
||||
|
@ -218,34 +318,34 @@ TEST(testCase, build_executor_tree_Test) {
|
|||
// int32_t code = qCreateExecTask(&handle, 2, 1, NULL, (void**) &pTaskInfo, &sinkHandle);
|
||||
}
|
||||
|
||||
//TEST(testCase, inMem_sort_Test) {
|
||||
// SArray* pOrderVal = taosArrayInit(4, sizeof(SOrder));
|
||||
// SOrder o = {.order = TSDB_ORDER_ASC};
|
||||
// o.col.info.colId = 1;
|
||||
// o.col.info.type = TSDB_DATA_TYPE_INT;
|
||||
// taosArrayPush(pOrderVal, &o);
|
||||
//
|
||||
// SArray* pExprInfo = taosArrayInit(4, sizeof(SExprInfo));
|
||||
// SExprInfo *exp = static_cast<SExprInfo*>(calloc(1, sizeof(SExprInfo)));
|
||||
// exp->base.resSchema = createSchema(TSDB_DATA_TYPE_INT, sizeof(int32_t), 1, "res");
|
||||
// taosArrayPush(pExprInfo, &exp);
|
||||
//
|
||||
// SExprInfo *exp1 = static_cast<SExprInfo*>(calloc(1, sizeof(SExprInfo)));
|
||||
// exp1->base.resSchema = createSchema(TSDB_DATA_TYPE_BINARY, 40, 2, "res1");
|
||||
// taosArrayPush(pExprInfo, &exp1);
|
||||
//
|
||||
// SOperatorInfo* pOperator = createOrderOperatorInfo(createDummyOperator(5), pExprInfo, pOrderVal);
|
||||
//
|
||||
// bool newgroup = false;
|
||||
// SSDataBlock* pRes = pOperator->exec(pOperator, &newgroup);
|
||||
//
|
||||
// SColumnInfoData* pCol1 = static_cast<SColumnInfoData*>(taosArrayGet(pRes->pDataBlock, 0));
|
||||
// SColumnInfoData* pCol2 = static_cast<SColumnInfoData*>(taosArrayGet(pRes->pDataBlock, 1));
|
||||
// for(int32_t i = 0; i < pRes->info.rows; ++i) {
|
||||
// char* p = colDataGet(pCol2, i);
|
||||
// printf("%d: %d, %s\n", i, ((int32_t*)pCol1->pData)[i], (char*)varDataVal(p));
|
||||
// }
|
||||
//}
|
||||
TEST(testCase, inMem_sort_Test) {
|
||||
SArray* pOrderVal = taosArrayInit(4, sizeof(SOrder));
|
||||
SOrder o = {.order = TSDB_ORDER_ASC};
|
||||
o.col.info.colId = 1;
|
||||
o.col.info.type = TSDB_DATA_TYPE_INT;
|
||||
taosArrayPush(pOrderVal, &o);
|
||||
|
||||
SArray* pExprInfo = taosArrayInit(4, sizeof(SExprInfo));
|
||||
SExprInfo *exp = static_cast<SExprInfo*>(calloc(1, sizeof(SExprInfo)));
|
||||
exp->base.resSchema = createSchema(TSDB_DATA_TYPE_INT, sizeof(int32_t), 1, "res");
|
||||
taosArrayPush(pExprInfo, &exp);
|
||||
|
||||
SExprInfo *exp1 = static_cast<SExprInfo*>(calloc(1, sizeof(SExprInfo)));
|
||||
exp1->base.resSchema = createSchema(TSDB_DATA_TYPE_BINARY, 40, 2, "res1");
|
||||
taosArrayPush(pExprInfo, &exp1);
|
||||
|
||||
SOperatorInfo* pOperator = createOrderOperatorInfo(createDummyOperator(5), pExprInfo, pOrderVal, NULL);
|
||||
|
||||
bool newgroup = false;
|
||||
SSDataBlock* pRes = pOperator->exec(pOperator, &newgroup);
|
||||
|
||||
SColumnInfoData* pCol1 = static_cast<SColumnInfoData*>(taosArrayGet(pRes->pDataBlock, 0));
|
||||
SColumnInfoData* pCol2 = static_cast<SColumnInfoData*>(taosArrayGet(pRes->pDataBlock, 1));
|
||||
for(int32_t i = 0; i < pRes->info.rows; ++i) {
|
||||
char* p = colDataGetData(pCol2, i);
|
||||
printf("%d: %d, %s\n", i, ((int32_t*)pCol1->pData)[i], (char*)varDataVal(p));
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct su {
|
||||
int32_t v;
|
||||
|
@ -300,7 +400,7 @@ TEST(testCase, external_sort_Test) {
|
|||
exp1->base.resSchema = createSchema(TSDB_DATA_TYPE_BINARY, 40, 2, "res1");
|
||||
// taosArrayPush(pExprInfo, &exp1);
|
||||
|
||||
SOperatorInfo* pOperator = createOrderOperatorInfo(createDummyOperator(1500), pExprInfo, pOrderVal);
|
||||
SOperatorInfo* pOperator = createOrderOperatorInfo(createDummyOperator(1500), pExprInfo, pOrderVal, NULL);
|
||||
|
||||
bool newgroup = false;
|
||||
SSDataBlock* pRes = NULL;
|
||||
|
@ -326,14 +426,12 @@ TEST(testCase, external_sort_Test) {
|
|||
SColumnInfoData* pCol1 = static_cast<SColumnInfoData*>(taosArrayGet(pRes->pDataBlock, 0));
|
||||
// SColumnInfoData* pCol2 = static_cast<SColumnInfoData*>(taosArrayGet(pRes->pDataBlock, 1));
|
||||
for (int32_t i = 0; i < pRes->info.rows; ++i) {
|
||||
// char* p = colDataGet(pCol2, i);
|
||||
// char* p = colDataGetData(pCol2, i);
|
||||
printf("%d: %d\n", total++, ((int32_t*)pCol1->pData)[i]);
|
||||
// printf("%d: %d, %s\n", total++, ((int32_t*)pCol1->pData)[i], (char*)varDataVal(p));
|
||||
}
|
||||
}
|
||||
|
||||
printStatisBeforeClose(((SOrderOperatorInfo*) pOperator->info)->pSortInternalBuf);
|
||||
|
||||
int64_t s2 = taosGetTimestampUs();
|
||||
printf("total:%ld\n", s2 - s1);
|
||||
|
||||
|
@ -343,4 +441,153 @@ TEST(testCase, external_sort_Test) {
|
|||
taosArrayDestroy(pExprInfo);
|
||||
taosArrayDestroy(pOrderVal);
|
||||
}
|
||||
|
||||
TEST(testCase, sorted_merge_Test) {
|
||||
srand(time(NULL));
|
||||
|
||||
SArray* pOrderVal = taosArrayInit(4, sizeof(SOrder));
|
||||
SOrder o = {0};
|
||||
o.order = TSDB_ORDER_ASC;
|
||||
o.col.info.colId = 1;
|
||||
o.col.info.type = TSDB_DATA_TYPE_INT;
|
||||
taosArrayPush(pOrderVal, &o);
|
||||
|
||||
SArray* pExprInfo = taosArrayInit(4, sizeof(SExprInfo));
|
||||
SExprInfo *exp = static_cast<SExprInfo*>(calloc(1, sizeof(SExprInfo)));
|
||||
exp->base.resSchema = createSchema(TSDB_DATA_TYPE_BIGINT, sizeof(int64_t), 1, "count_result");
|
||||
exp->base.pColumns = static_cast<SColumn*>(calloc(1, sizeof(SColumn)));
|
||||
exp->base.pColumns->flag = TSDB_COL_NORMAL;
|
||||
exp->base.pColumns->info = (SColumnInfo) {.colId = 1, .type = TSDB_DATA_TYPE_INT, .bytes = 4};
|
||||
exp->base.numOfCols = 1;
|
||||
|
||||
taosArrayPush(pExprInfo, &exp);
|
||||
|
||||
SExprInfo *exp1 = static_cast<SExprInfo*>(calloc(1, sizeof(SExprInfo)));
|
||||
exp1->base.resSchema = createSchema(TSDB_DATA_TYPE_BINARY, 40, 2, "res1");
|
||||
// taosArrayPush(pExprInfo, &exp1);
|
||||
|
||||
int32_t numOfSources = 10;
|
||||
SOperatorInfo** plist = (SOperatorInfo**) calloc(numOfSources, sizeof(void*));
|
||||
for(int32_t i = 0; i < numOfSources; ++i) {
|
||||
plist[i] = createDummyOperator(1, 1, 1, data_asc);
|
||||
}
|
||||
|
||||
SOperatorInfo* pOperator = createSortedMergeOperatorInfo(plist, numOfSources, pExprInfo, pOrderVal, NULL, NULL);
|
||||
|
||||
bool newgroup = false;
|
||||
SSDataBlock* pRes = NULL;
|
||||
|
||||
int32_t total = 1;
|
||||
|
||||
int64_t s1 = taosGetTimestampUs();
|
||||
int32_t t = 1;
|
||||
|
||||
while(1) {
|
||||
int64_t s = taosGetTimestampUs();
|
||||
pRes = pOperator->exec(pOperator, &newgroup);
|
||||
|
||||
int64_t e = taosGetTimestampUs();
|
||||
if (t++ == 1) {
|
||||
printf("---------------elapsed:%ld\n", e - s);
|
||||
}
|
||||
|
||||
if (pRes == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
SColumnInfoData* pCol1 = static_cast<SColumnInfoData*>(taosArrayGet(pRes->pDataBlock, 0));
|
||||
// SColumnInfoData* pCol2 = static_cast<SColumnInfoData*>(taosArrayGet(pRes->pDataBlock, 1));
|
||||
for (int32_t i = 0; i < pRes->info.rows; ++i) {
|
||||
// char* p = colDataGetData(pCol2, i);
|
||||
printf("%d: %ld\n", total++, ((int64_t*)pCol1->pData)[i]);
|
||||
// printf("%d: %d, %s\n", total++, ((int32_t*)pCol1->pData)[i], (char*)varDataVal(p));
|
||||
}
|
||||
}
|
||||
|
||||
int64_t s2 = taosGetTimestampUs();
|
||||
printf("total:%ld\n", s2 - s1);
|
||||
|
||||
pOperator->cleanupFn(pOperator->info, 2);
|
||||
tfree(exp);
|
||||
tfree(exp1);
|
||||
taosArrayDestroy(pExprInfo);
|
||||
taosArrayDestroy(pOrderVal);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
TEST(testCase, time_interval_Operator_Test) {
|
||||
srand(time(NULL));
|
||||
|
||||
SArray* pOrderVal = taosArrayInit(4, sizeof(SOrder));
|
||||
SOrder o = {0};
|
||||
o.order = TSDB_ORDER_ASC;
|
||||
o.col.info.colId = 1;
|
||||
o.col.info.type = TSDB_DATA_TYPE_INT;
|
||||
taosArrayPush(pOrderVal, &o);
|
||||
|
||||
SArray* pExprInfo = taosArrayInit(4, sizeof(SExprInfo));
|
||||
SExprInfo *exp = static_cast<SExprInfo*>(calloc(1, sizeof(SExprInfo)));
|
||||
exp->base.resSchema = createSchema(TSDB_DATA_TYPE_TIMESTAMP, sizeof(int64_t), 1, "ts");
|
||||
exp->base.pColumns = static_cast<SColumn*>(calloc(1, sizeof(SColumn)));
|
||||
exp->base.pColumns->flag = TSDB_COL_NORMAL;
|
||||
exp->base.pColumns->info = (SColumnInfo) {.colId = 1, .type = TSDB_DATA_TYPE_TIMESTAMP, .bytes = 8};
|
||||
exp->base.numOfCols = 1;
|
||||
|
||||
taosArrayPush(pExprInfo, &exp);
|
||||
|
||||
SExprInfo *exp1 = static_cast<SExprInfo*>(calloc(1, sizeof(SExprInfo)));
|
||||
exp1->base.resSchema = createSchema(TSDB_DATA_TYPE_BIGINT, 8, 2, "res1");
|
||||
exp1->base.pColumns = static_cast<SColumn*>(calloc(1, sizeof(SColumn)));
|
||||
exp1->base.pColumns->flag = TSDB_COL_NORMAL;
|
||||
exp1->base.pColumns->info = (SColumnInfo) {.colId = 1, .type = TSDB_DATA_TYPE_INT, .bytes = 4};
|
||||
exp1->base.numOfCols = 1;
|
||||
|
||||
taosArrayPush(pExprInfo, &exp1);
|
||||
|
||||
SOperatorInfo* p = createDummyOperator(1, 1, 2000, data_asc, 2);
|
||||
|
||||
SExecTaskInfo ti = {0};
|
||||
SOperatorInfo* pOperator = createIntervalOperatorInfo(p, pExprInfo, &ti);
|
||||
|
||||
bool newgroup = false;
|
||||
SSDataBlock* pRes = NULL;
|
||||
|
||||
int32_t total = 1;
|
||||
|
||||
int64_t s1 = taosGetTimestampUs();
|
||||
int32_t t = 1;
|
||||
|
||||
while(1) {
|
||||
int64_t s = taosGetTimestampUs();
|
||||
pRes = pOperator->exec(pOperator, &newgroup);
|
||||
|
||||
int64_t e = taosGetTimestampUs();
|
||||
if (t++ == 1) {
|
||||
printf("---------------elapsed:%ld\n", e - s);
|
||||
}
|
||||
|
||||
if (pRes == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
SColumnInfoData* pCol1 = static_cast<SColumnInfoData*>(taosArrayGet(pRes->pDataBlock, 0));
|
||||
// SColumnInfoData* pCol2 = static_cast<SColumnInfoData*>(taosArrayGet(pRes->pDataBlock, 1));
|
||||
for (int32_t i = 0; i < pRes->info.rows; ++i) {
|
||||
// char* p = colDataGetData(pCol2, i);
|
||||
printf("%d: %ld\n", total++, ((int64_t*)pCol1->pData)[i]);
|
||||
// printf("%d: %d, %s\n", total++, ((int32_t*)pCol1->pData)[i], (char*)varDataVal(p));
|
||||
}
|
||||
}
|
||||
|
||||
int64_t s2 = taosGetTimestampUs();
|
||||
printf("total:%ld\n", s2 - s1);
|
||||
|
||||
pOperator->cleanupFn(pOperator->info, 2);
|
||||
tfree(exp);
|
||||
tfree(exp1);
|
||||
taosArrayDestroy(pExprInfo);
|
||||
taosArrayDestroy(pOrderVal);
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* This program is free software: you can use, redistribute, and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3
|
||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <iostream>
|
||||
#include "executorimpl.h"
|
||||
#include "tlinearhash.h"
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wwrite-strings"
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
#pragma GCC diagnostic ignored "-Wsign-compare"
|
||||
|
||||
TEST(testCase, linear_hash_Tests) {
|
||||
srand(time(NULL));
|
||||
|
||||
_hash_fn_t fn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_INT);
|
||||
#if 0
|
||||
SLHashObj* pHashObj = tHashInit(256, 4096, fn, 320);
|
||||
for(int32_t i = 0; i < 5000000; ++i) {
|
||||
int32_t code = tHashPut(pHashObj, &i, sizeof(i), &i, sizeof(i));
|
||||
assert(code == 0);
|
||||
}
|
||||
|
||||
// tHashPrint(pHashObj, LINEAR_HASH_STATIS);
|
||||
|
||||
// for(int32_t i = 0; i < 10000; ++i) {
|
||||
// char* v = tHashGet(pHashObj, &i, sizeof(i));
|
||||
// if (v != NULL) {
|
||||
//// printf("find value: %d, key:%d\n", *(int32_t*) v, i);
|
||||
// } else {
|
||||
// printf("failed to found key:%d in hash\n", i);
|
||||
// }
|
||||
// }
|
||||
|
||||
tHashPrint(pHashObj, LINEAR_HASH_STATIS);
|
||||
tHashCleanup(pHashObj);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
SHashObj* pHashObj = taosHashInit(1000, fn, false, HASH_NO_LOCK);
|
||||
for(int32_t i = 0; i < 1000000; ++i) {
|
||||
taosHashPut(pHashObj, &i, sizeof(i), &i, sizeof(i));
|
||||
}
|
||||
|
||||
for(int32_t i = 0; i < 10000; ++i) {
|
||||
void* v = taosHashGet(pHashObj, &i, sizeof(i));
|
||||
}
|
||||
taosHashCleanup(pHashObj);
|
||||
#endif
|
||||
|
||||
}
|
|
@ -0,0 +1,280 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* This program is free software: you can use, redistribute, and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3
|
||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <executorimpl.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <tglobal.h>
|
||||
#include <tsort.h>
|
||||
#include <iostream>
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wwrite-strings"
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
#pragma GCC diagnostic ignored "-Wsign-compare"
|
||||
#include "os.h"
|
||||
|
||||
#include "executor.h"
|
||||
#include "stub.h"
|
||||
#include "taos.h"
|
||||
#include "tdef.h"
|
||||
#include "tep.h"
|
||||
#include "trpc.h"
|
||||
#include "tvariant.h"
|
||||
|
||||
namespace {
|
||||
typedef struct {
|
||||
int32_t startVal;
|
||||
int32_t count;
|
||||
int32_t pageRows;
|
||||
} _info;
|
||||
|
||||
SSDataBlock* getSingleColDummyBlock(void* param) {
|
||||
_info* pInfo = (_info*) param;
|
||||
if (--pInfo->count < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SSDataBlock* pBlock = static_cast<SSDataBlock*>(calloc(1, sizeof(SSDataBlock)));
|
||||
pBlock->pDataBlock = taosArrayInit(4, sizeof(SColumnInfoData));
|
||||
|
||||
SColumnInfoData colInfo = {0};
|
||||
colInfo.info.type = TSDB_DATA_TYPE_INT;
|
||||
colInfo.info.bytes = sizeof(int32_t);
|
||||
colInfo.info.colId = 1;
|
||||
colInfo.pData = static_cast<char*>(calloc(pInfo->pageRows, sizeof(int32_t)));
|
||||
colInfo.nullbitmap = static_cast<char*>(calloc(1, (pInfo->pageRows + 7) / 8));
|
||||
|
||||
taosArrayPush(pBlock->pDataBlock, &colInfo);
|
||||
|
||||
for (int32_t i = 0; i < pInfo->pageRows; ++i) {
|
||||
SColumnInfoData* pColInfo = static_cast<SColumnInfoData*>(TARRAY_GET_ELEM(pBlock->pDataBlock, 0));
|
||||
|
||||
int32_t v = ++pInfo->startVal;
|
||||
colDataAppend(pColInfo, i, reinterpret_cast<const char*>(&v), false);
|
||||
}
|
||||
|
||||
pBlock->info.rows = pInfo->pageRows;
|
||||
pBlock->info.numOfCols = 1;
|
||||
return pBlock;
|
||||
}
|
||||
|
||||
int32_t docomp(const void* p1, const void* p2, void* param) {
|
||||
int32_t pLeftIdx = *(int32_t *)p1;
|
||||
int32_t pRightIdx = *(int32_t *)p2;
|
||||
|
||||
SMsortComparParam *pParam = (SMsortComparParam *)param;
|
||||
SGenericSource** px = reinterpret_cast<SGenericSource**>(pParam->pSources);
|
||||
|
||||
SArray *pInfo = pParam->orderInfo;
|
||||
|
||||
SGenericSource* pLeftSource = px[pLeftIdx];
|
||||
SGenericSource* pRightSource = px[pRightIdx];
|
||||
|
||||
// this input is exhausted, set the special value to denote this
|
||||
if (pLeftSource->src.rowIndex == -1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (pRightSource->src.rowIndex == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSDataBlock* pLeftBlock = pLeftSource->src.pBlock;
|
||||
SSDataBlock* pRightBlock = pRightSource->src.pBlock;
|
||||
|
||||
for(int32_t i = 0; i < pInfo->size; ++i) {
|
||||
SBlockOrderInfo* pOrder = (SBlockOrderInfo*)TARRAY_GET_ELEM(pInfo, i);
|
||||
|
||||
SColumnInfoData* pLeftColInfoData = (SColumnInfoData*)TARRAY_GET_ELEM(pLeftBlock->pDataBlock, pOrder->colIndex);
|
||||
|
||||
bool leftNull = false;
|
||||
if (pLeftColInfoData->hasNull) {
|
||||
leftNull = colDataIsNull(pLeftColInfoData, pLeftBlock->info.rows, pLeftSource->src.rowIndex, pLeftBlock->pBlockAgg);
|
||||
}
|
||||
|
||||
SColumnInfoData* pRightColInfoData = (SColumnInfoData*) TARRAY_GET_ELEM(pRightBlock->pDataBlock, pOrder->colIndex);
|
||||
bool rightNull = false;
|
||||
if (pRightColInfoData->hasNull) {
|
||||
rightNull = colDataIsNull(pRightColInfoData, pRightBlock->info.rows, pRightSource->src.rowIndex, pRightBlock->pBlockAgg);
|
||||
}
|
||||
|
||||
if (leftNull && rightNull) {
|
||||
continue; // continue to next slot
|
||||
}
|
||||
|
||||
if (rightNull) {
|
||||
return pParam->nullFirst? 1:-1;
|
||||
}
|
||||
|
||||
if (leftNull) {
|
||||
return pParam->nullFirst? -1:1;
|
||||
}
|
||||
|
||||
void* left1 = colDataGetData(pLeftColInfoData, pLeftSource->src.rowIndex);
|
||||
void* right1 = colDataGetData(pRightColInfoData, pRightSource->src.rowIndex);
|
||||
|
||||
switch(pLeftColInfoData->info.type) {
|
||||
case TSDB_DATA_TYPE_INT: {
|
||||
int32_t leftv = *(int32_t*)left1;
|
||||
int32_t rightv = *(int32_t*)right1;
|
||||
|
||||
if (leftv == rightv) {
|
||||
break;
|
||||
} else {
|
||||
if (pOrder->order == TSDB_ORDER_ASC) {
|
||||
return leftv < rightv? -1 : 1;
|
||||
} else {
|
||||
return leftv < rightv? 1 : -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
#if 0
|
||||
TEST(testCase, inMem_sort_Test) {
|
||||
SArray* pOrderVal = taosArrayInit(4, sizeof(SOrder));
|
||||
SOrder o = {.order = TSDB_ORDER_ASC};
|
||||
o.col.info.colId = 1;
|
||||
o.col.info.type = TSDB_DATA_TYPE_INT;
|
||||
taosArrayPush(pOrderVal, &o);
|
||||
|
||||
int32_t numOfRows = 1000;
|
||||
SBlockOrderInfo oi = {0};
|
||||
oi.order = TSDB_ORDER_ASC;
|
||||
oi.colIndex = 0;
|
||||
SArray* orderInfo = taosArrayInit(1, sizeof(SBlockOrderInfo));
|
||||
taosArrayPush(orderInfo, &oi);
|
||||
|
||||
SSchema s = {.type = TSDB_DATA_TYPE_INT, .colId = 1, .bytes = 4, };
|
||||
SSortHandle* phandle = tsortCreateSortHandle(orderInfo, false, SORT_SINGLESOURCE_SORT, 1024, 5, &s, 1, "test_abc");
|
||||
tsortSetFetchRawDataFp(phandle, getSingleColDummyBlock);
|
||||
tsortAddSource(phandle, &numOfRows);
|
||||
|
||||
int32_t code = tsortOpen(phandle);
|
||||
int32_t row = 1;
|
||||
|
||||
while(1) {
|
||||
STupleHandle* pTupleHandle = tsortNextTuple(phandle);
|
||||
if (pTupleHandle == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
void* v = tsortGetValue(pTupleHandle, 0);
|
||||
printf("%d: %d\n", row++, *(int32_t*) v);
|
||||
|
||||
}
|
||||
tsortDestroySortHandle(phandle);
|
||||
}
|
||||
|
||||
TEST(testCase, external_mem_sort_Test) {
|
||||
SArray* pOrderVal = taosArrayInit(4, sizeof(SOrder));
|
||||
SOrder o = {.order = TSDB_ORDER_ASC};
|
||||
o.col.info.colId = 1;
|
||||
o.col.info.type = TSDB_DATA_TYPE_INT;
|
||||
taosArrayPush(pOrderVal, &o);
|
||||
|
||||
SBlockOrderInfo oi = {0};
|
||||
oi.order = TSDB_ORDER_ASC;
|
||||
oi.colIndex = 0;
|
||||
SArray* orderInfo = taosArrayInit(1, sizeof(SBlockOrderInfo));
|
||||
taosArrayPush(orderInfo, &oi);
|
||||
|
||||
SSchema s = {.type = TSDB_DATA_TYPE_INT, .colId = 1, .bytes = 4, };
|
||||
SSortHandle* phandle = tsortCreateSortHandle(orderInfo, false, SORT_SINGLESOURCE_SORT, 1024, 5, &s, 1, "test_abc");
|
||||
tsortSetFetchRawDataFp(phandle, getSingleColDummyBlock);
|
||||
|
||||
_info* pInfo = (_info*) calloc(1, sizeof(_info));
|
||||
pInfo->startVal = 100000;
|
||||
pInfo->pageRows = 1000;
|
||||
pInfo->count = 50;
|
||||
|
||||
SGenericSource* ps = static_cast<SGenericSource*>(calloc(1, sizeof(SGenericSource)));
|
||||
ps->param = pInfo;
|
||||
|
||||
tsortAddSource(phandle, ps);
|
||||
|
||||
int32_t code = tsortOpen(phandle);
|
||||
int32_t row = 1;
|
||||
|
||||
while(1) {
|
||||
STupleHandle* pTupleHandle = tsortNextTuple(phandle);
|
||||
if (pTupleHandle == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
void* v = tsortGetValue(pTupleHandle, 0);
|
||||
printf("%d: %d\n", row++, *(int32_t*) v);
|
||||
|
||||
}
|
||||
tsortDestroySortHandle(phandle);
|
||||
}
|
||||
|
||||
TEST(testCase, ordered_merge_sort_Test) {
|
||||
SArray* pOrderVal = taosArrayInit(4, sizeof(SOrder));
|
||||
SOrder o = {.order = TSDB_ORDER_ASC};
|
||||
o.col.info.colId = 1;
|
||||
o.col.info.type = TSDB_DATA_TYPE_INT;
|
||||
taosArrayPush(pOrderVal, &o);
|
||||
|
||||
int32_t numOfRows = 1000;
|
||||
SBlockOrderInfo oi = {0};
|
||||
oi.order = TSDB_ORDER_ASC;
|
||||
oi.colIndex = 0;
|
||||
SArray* orderInfo = taosArrayInit(1, sizeof(SBlockOrderInfo));
|
||||
taosArrayPush(orderInfo, &oi);
|
||||
|
||||
SSchema s = {.type = TSDB_DATA_TYPE_INT, .colId = 1, .bytes = 4};
|
||||
SSortHandle* phandle = tsortCreateSortHandle(orderInfo, false, SORT_MULTISOURCE_MERGE, 1024, 5, &s, 1,"test_abc");
|
||||
tsortSetFetchRawDataFp(phandle, getSingleColDummyBlock);
|
||||
tsortSetComparFp(phandle, docomp);
|
||||
|
||||
for(int32_t i = 0; i < 10; ++i) {
|
||||
SGenericSource* p = static_cast<SGenericSource*>(calloc(1, sizeof(SGenericSource)));
|
||||
_info* c = static_cast<_info*>(calloc(1, sizeof(_info)));
|
||||
c->count = 1;
|
||||
c->pageRows = 1000;
|
||||
c->startVal = 0;
|
||||
|
||||
p->param = c;
|
||||
tsortAddSource(phandle, p);
|
||||
}
|
||||
|
||||
int32_t code = tsortOpen(phandle);
|
||||
int32_t row = 1;
|
||||
|
||||
while(1) {
|
||||
STupleHandle* pTupleHandle = tsortNextTuple(phandle);
|
||||
if (pTupleHandle == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
void* v = tsortGetValue(pTupleHandle, 0);
|
||||
printf("%d: %d\n", row++, *(int32_t*) v);
|
||||
|
||||
}
|
||||
tsortDestroySortHandle(phandle);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#pragma GCC diagnostic pop
|
|
@ -29,9 +29,10 @@
|
|||
#include "tcompression.h"
|
||||
//#include "queryLog.h"
|
||||
#include "tudf.h"
|
||||
#include "tep.h"
|
||||
|
||||
#define GET_INPUT_DATA_LIST(x) ((char *)((x)->pInput))
|
||||
#define GET_INPUT_DATA(x, y) (GET_INPUT_DATA_LIST(x) + (y) * (x)->inputBytes)
|
||||
#define GET_INPUT_DATA(x, y) ((char*) colDataGetData((x)->pInput, (y)))
|
||||
|
||||
#define GET_TS_LIST(x) ((TSKEY*)((x)->ptsList))
|
||||
#define GET_TS_DATA(x, y) (GET_TS_LIST(x)[(y)])
|
||||
|
@ -3818,7 +3819,7 @@ static void interp_function_impl(SqlFunctionCtx *pCtx) {
|
|||
skey = ekey;
|
||||
}
|
||||
}
|
||||
assignVal(pCtx->pOutput, pCtx->pInput, pCtx->resDataInfo.bytes, pCtx->inputType);
|
||||
// assignVal(pCtx->pOutput, pCtx->pInput, pCtx->resDataInfo.bytes, pCtx->inputType);
|
||||
} else if (type == TSDB_FILL_NEXT) {
|
||||
TSKEY ekey = skey;
|
||||
char* val = NULL;
|
||||
|
@ -4395,7 +4396,7 @@ SFunctionFpSet fpSet[1] = {
|
|||
.addInput = count_function,
|
||||
.finalize = doFinalizer,
|
||||
.combine = count_func_merge,
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
SAggFunctionInfo aggFunc[35] = {{
|
||||
|
|
|
@ -222,7 +222,7 @@ tMemBucket *tMemBucketCreate(int16_t nElemSize, int16_t dataType, double minval,
|
|||
}
|
||||
|
||||
pBucket->numOfSlots = DEFAULT_NUM_OF_SLOT;
|
||||
pBucket->bufPageSize = DEFAULT_PAGE_SIZE * 4; // 4k per page
|
||||
pBucket->bufPageSize = 16384 * 4; // 16k per page
|
||||
|
||||
pBucket->type = dataType;
|
||||
pBucket->bytes = nElemSize;
|
||||
|
@ -255,7 +255,7 @@ tMemBucket *tMemBucketCreate(int16_t nElemSize, int16_t dataType, double minval,
|
|||
|
||||
resetSlotInfo(pBucket);
|
||||
|
||||
int32_t ret = createDiskbasedBuffer(&pBucket->pBuffer, pBucket->bufPageSize, pBucket->bufPageSize * 512, 1, tsTempDir);
|
||||
int32_t ret = createDiskbasedBuf(&pBucket->pBuffer, pBucket->bufPageSize, pBucket->bufPageSize * 512, 1, "/tmp");
|
||||
if (ret != 0) {
|
||||
tMemBucketDestroy(pBucket);
|
||||
return NULL;
|
||||
|
@ -270,7 +270,7 @@ void tMemBucketDestroy(tMemBucket *pBucket) {
|
|||
return;
|
||||
}
|
||||
|
||||
destroyResultBuf(pBucket->pBuffer);
|
||||
destroyDiskbasedBuf(pBucket->pBuffer);
|
||||
tfree(pBucket->pSlots);
|
||||
tfree(pBucket);
|
||||
}
|
||||
|
@ -348,7 +348,7 @@ int32_t tMemBucketPut(tMemBucket *pBucket, const void *data, size_t size) {
|
|||
pSlot->info.data = NULL;
|
||||
}
|
||||
|
||||
pSlot->info.data = getNewDataBuf(pBucket->pBuffer, groupId, &pageId);
|
||||
pSlot->info.data = getNewBufPage(pBucket->pBuffer, groupId, &pageId);
|
||||
pSlot->info.pageId = pageId;
|
||||
}
|
||||
|
||||
|
|
|
@ -230,7 +230,7 @@ int32_t getExprFunctionId(SExprInfo *pExprInfo) {
|
|||
}
|
||||
|
||||
void assignExprInfo(SExprInfo* dst, const SExprInfo* src) {
|
||||
assert(dst != NULL && src != NULL);
|
||||
assert(dst != NULL && src != NULL/* && src->base.numOfCols > 0*/);
|
||||
|
||||
*dst = *src;
|
||||
#if 0
|
||||
|
@ -241,8 +241,12 @@ void assignExprInfo(SExprInfo* dst, const SExprInfo* src) {
|
|||
#endif
|
||||
|
||||
dst->pExpr = exprdup(src->pExpr);
|
||||
if (src->base.numOfCols > 0) {
|
||||
dst->base.pColumns = calloc(src->base.numOfCols, sizeof(SColumn));
|
||||
memcpy(dst->base.pColumns, src->base.pColumns, sizeof(SColumn) * src->base.numOfCols);
|
||||
} else {
|
||||
dst->base.pColumns = NULL;
|
||||
}
|
||||
|
||||
memset(dst->base.param, 0, sizeof(SVariant) * tListLen(dst->base.param));
|
||||
for (int32_t j = 0; j < src->base.numOfParams; ++j) {
|
||||
|
|
|
@ -306,7 +306,7 @@ typedef struct SFilterInfo {
|
|||
#define FILTER_GET_COL_FIELD_ID(fi) (((SColumnNode *)((fi)->desc))->colId)
|
||||
#define FILTER_GET_COL_FIELD_SLOT_ID(fi) (((SColumnNode *)((fi)->desc))->slotId)
|
||||
#define FILTER_GET_COL_FIELD_DESC(fi) ((SColumnNode *)((fi)->desc))
|
||||
#define FILTER_GET_COL_FIELD_DATA(fi, ri) (colDataGet(((SColumnInfoData *)(fi)->data), (ri)))
|
||||
#define FILTER_GET_COL_FIELD_DATA(fi, ri) (colDataGetData(((SColumnInfoData *)(fi)->data), (ri)))
|
||||
#define FILTER_GET_VAL_FIELD_TYPE(fi) (((SValueNode *)((fi)->desc))->node.resType.type)
|
||||
#define FILTER_GET_VAL_FIELD_DATA(fi) ((char *)(fi)->data)
|
||||
#define FILTER_GET_JSON_VAL_FIELD_DATA(fi) ((char *)(fi)->desc)
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "tcompare.h"
|
||||
#include "filterInt.h"
|
||||
#include "filter.h"
|
||||
#include "tep.h"
|
||||
|
||||
OptrStr gOptrStr[] = {
|
||||
{0, "invalid"},
|
||||
|
@ -2776,7 +2777,7 @@ bool filterExecuteBasedOnStatisImpl(void *pinfo, int32_t numOfRows, int8_t** p,
|
|||
uint32_t unitNum = *(unitIdx++);
|
||||
for (uint32_t u = 0; u < unitNum; ++u) {
|
||||
SFilterComUnit *cunit = &info->cunits[*(unitIdx + u)];
|
||||
void *colData = colDataGet((SColumnInfoData *)cunit->colData, i);
|
||||
void *colData = colDataGetData((SColumnInfoData *)cunit->colData, i);
|
||||
|
||||
//if (FILTER_UNIT_GET_F(info, uidx)) {
|
||||
// p[i] = FILTER_UNIT_GET_R(info, uidx);
|
||||
|
@ -2874,7 +2875,7 @@ static FORCE_INLINE bool filterExecuteImplIsNull(void *pinfo, int32_t numOfRows,
|
|||
|
||||
for (int32_t i = 0; i < numOfRows; ++i) {
|
||||
uint32_t uidx = info->groups[0].unitIdxs[0];
|
||||
void *colData = colDataGet((SColumnInfoData *)info->cunits[uidx].colData, i);
|
||||
void *colData = colDataGetData((SColumnInfoData *)info->cunits[uidx].colData, i);
|
||||
if(info->cunits[uidx].dataType == TSDB_DATA_TYPE_JSON){
|
||||
if (!colData){ // for json->'key' is null
|
||||
(*p)[i] = 1;
|
||||
|
@ -2908,7 +2909,7 @@ static FORCE_INLINE bool filterExecuteImplNotNull(void *pinfo, int32_t numOfRows
|
|||
|
||||
for (int32_t i = 0; i < numOfRows; ++i) {
|
||||
uint32_t uidx = info->groups[0].unitIdxs[0];
|
||||
void *colData = colDataGet((SColumnInfoData *)info->cunits[uidx].colData, i);
|
||||
void *colData = colDataGetData((SColumnInfoData *)info->cunits[uidx].colData, i);
|
||||
|
||||
if(info->cunits[uidx].dataType == TSDB_DATA_TYPE_JSON){
|
||||
if (!colData) { // for json->'key' is not null
|
||||
|
@ -2949,7 +2950,7 @@ bool filterExecuteImplRange(void *pinfo, int32_t numOfRows, int8_t** p, SColumnD
|
|||
}
|
||||
|
||||
for (int32_t i = 0; i < numOfRows; ++i) {
|
||||
void *colData = colDataGet((SColumnInfoData *)info->cunits[0].colData, i);
|
||||
void *colData = colDataGetData((SColumnInfoData *)info->cunits[0].colData, i);
|
||||
|
||||
if (colData == NULL || isNull(colData, info->cunits[0].dataType)) {
|
||||
all = false;
|
||||
|
@ -2980,7 +2981,7 @@ bool filterExecuteImplMisc(void *pinfo, int32_t numOfRows, int8_t** p, SColumnDa
|
|||
|
||||
for (int32_t i = 0; i < numOfRows; ++i) {
|
||||
uint32_t uidx = info->groups[0].unitIdxs[0];
|
||||
void *colData = colDataGet((SColumnInfoData *)info->cunits[uidx].colData, i);
|
||||
void *colData = colDataGetData((SColumnInfoData *)info->cunits[uidx].colData, i);
|
||||
if (colData == NULL || isNull(colData, info->cunits[uidx].dataType)) {
|
||||
(*p)[i] = 0;
|
||||
all = false;
|
||||
|
@ -3031,7 +3032,7 @@ bool filterExecuteImpl(void *pinfo, int32_t numOfRows, int8_t** p, SColumnDataAg
|
|||
for (uint32_t u = 0; u < group->unitNum; ++u) {
|
||||
uint32_t uidx = group->unitIdxs[u];
|
||||
SFilterComUnit *cunit = &info->cunits[uidx];
|
||||
void *colData = colDataGet((SColumnInfoData *)(cunit->colData), i);
|
||||
void *colData = colDataGetData((SColumnInfoData *)(cunit->colData), i);
|
||||
|
||||
//if (FILTER_UNIT_GET_F(info, uidx)) {
|
||||
// p[i] = FILTER_UNIT_GET_R(info, uidx);
|
||||
|
|
|
@ -226,7 +226,7 @@ void* getVectorValueAddr_default(void *src, int32_t index) {
|
|||
return src;
|
||||
}
|
||||
void* getVectorValueAddr_VAR(void *src, int32_t index) {
|
||||
return colDataGet((SColumnInfoData *)src, index);
|
||||
return colDataGetData((SColumnInfoData *)src, index);
|
||||
}
|
||||
|
||||
_getValueAddr_fn_t getVectorValueAddrFn(int32_t srcType) {
|
||||
|
|
|
@ -1,18 +1,3 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* This program is free software: you can use, redistribute, and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3
|
||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define _DEFAULT_SOURCE
|
||||
#include "tpagedbuf.h"
|
||||
#include "taoserror.h"
|
||||
|
@ -23,27 +8,22 @@
|
|||
#define GET_DATA_PAYLOAD(_p) ((char*)(_p)->pData + POINTER_BYTES)
|
||||
#define NO_IN_MEM_AVAILABLE_PAGES(_b) (listNEles((_b)->lruList) >= (_b)->inMemPages)
|
||||
|
||||
typedef struct SFreeListItem {
|
||||
int32_t offset;
|
||||
int32_t len;
|
||||
} SFreeListItem;
|
||||
|
||||
typedef struct SPageDiskInfo {
|
||||
int64_t offset;
|
||||
int32_t length;
|
||||
} SPageDiskInfo;
|
||||
} SPageDiskInfo, SFreeListItem;
|
||||
|
||||
typedef struct SPageInfo {
|
||||
SListNode* pn; // point to list node
|
||||
struct SPageInfo {
|
||||
SListNode* pn; // point to list node struct
|
||||
void* pData;
|
||||
int64_t offset;
|
||||
int32_t pageId;
|
||||
int32_t length : 30;
|
||||
int32_t length : 29;
|
||||
bool used : 1; // set current page is in used
|
||||
bool dirty : 1; // set current buffer page is dirty or not
|
||||
} SPageInfo;
|
||||
};
|
||||
|
||||
typedef struct SDiskbasedBuf {
|
||||
struct SDiskbasedBuf {
|
||||
int32_t numOfPages;
|
||||
int64_t totalBufSize;
|
||||
uint64_t fileSize; // disk file size
|
||||
|
@ -52,7 +32,8 @@ typedef struct SDiskbasedBuf {
|
|||
char* path; // file path
|
||||
int32_t pageSize; // current used page size
|
||||
int32_t inMemPages; // numOfPages that are allocated in memory
|
||||
SHashObj* groupSet; // id hash table
|
||||
SList* freePgList; // free page list
|
||||
SHashObj* groupSet; // id hash table, todo remove it
|
||||
SHashObj* all;
|
||||
SList* lruList;
|
||||
void* emptyDummyIdList; // dummy id list
|
||||
|
@ -64,51 +45,7 @@ typedef struct SDiskbasedBuf {
|
|||
uint64_t qId; // for debug purpose
|
||||
bool printStatis; // Print statistics info when closing this buffer.
|
||||
SDiskbasedBufStatis statis;
|
||||
} SDiskbasedBuf;
|
||||
|
||||
static void printStatisData(const SDiskbasedBuf* pBuf);
|
||||
|
||||
int32_t createDiskbasedBuffer(SDiskbasedBuf** pBuf, int32_t pagesize, int32_t inMemBufSize, uint64_t qId,
|
||||
const char* dir) {
|
||||
*pBuf = calloc(1, sizeof(SDiskbasedBuf));
|
||||
|
||||
SDiskbasedBuf* pResBuf = *pBuf;
|
||||
if (pResBuf == NULL) {
|
||||
return TSDB_CODE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
pResBuf->pageSize = pagesize;
|
||||
pResBuf->numOfPages = 0; // all pages are in buffer in the first place
|
||||
pResBuf->totalBufSize = 0;
|
||||
pResBuf->inMemPages = inMemBufSize / pagesize; // maximum allowed pages, it is a soft limit.
|
||||
pResBuf->allocateId = -1;
|
||||
pResBuf->comp = true;
|
||||
pResBuf->pFile = NULL;
|
||||
pResBuf->qId = qId;
|
||||
pResBuf->fileSize = 0;
|
||||
|
||||
// at least more than 2 pages must be in memory
|
||||
assert(inMemBufSize >= pagesize * 2);
|
||||
|
||||
pResBuf->lruList = tdListNew(POINTER_BYTES);
|
||||
|
||||
// init id hash table
|
||||
pResBuf->groupSet = taosHashInit(10, taosGetDefaultHashFunction(TSDB_DATA_TYPE_INT), true, false);
|
||||
pResBuf->assistBuf = malloc(pResBuf->pageSize + 2); // EXTRA BYTES
|
||||
pResBuf->all = taosHashInit(10, taosGetDefaultHashFunction(TSDB_DATA_TYPE_INT), true, false);
|
||||
|
||||
char path[PATH_MAX] = {0};
|
||||
taosGetTmpfilePath(dir, "qbuf", path);
|
||||
pResBuf->path = strdup(path);
|
||||
|
||||
pResBuf->emptyDummyIdList = taosArrayInit(1, sizeof(int32_t));
|
||||
|
||||
// qDebug("QInfo:0x%"PRIx64" create resBuf for output, page size:%d, inmem buf pages:%d, file:%s", qId,
|
||||
// pResBuf->pageSize,
|
||||
// pResBuf->inMemPages, pResBuf->path);
|
||||
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
};
|
||||
|
||||
static int32_t createDiskFile(SDiskbasedBuf* pBuf) {
|
||||
// pBuf->file = fopen(pBuf->path, "wb+");
|
||||
|
@ -139,8 +76,7 @@ static char* doDecompressData(void* data, int32_t srcSize, int32_t* dst, SDiskba
|
|||
return data;
|
||||
}
|
||||
|
||||
*dst = tsDecompressString(data, srcSize, 1, pBuf->assistBuf, pBuf->pageSize + sizeof(SFilePage), ONE_STAGE_COMP, NULL,
|
||||
0);
|
||||
*dst = tsDecompressString(data, srcSize, 1, pBuf->assistBuf, pBuf->pageSize, ONE_STAGE_COMP, NULL, 0);
|
||||
if (*dst > 0) {
|
||||
memcpy(data, pBuf->assistBuf, *dst);
|
||||
}
|
||||
|
@ -156,10 +92,10 @@ static uint64_t allocatePositionInFile(SDiskbasedBuf* pBuf, size_t size) {
|
|||
size_t num = taosArrayGetSize(pBuf->pFree);
|
||||
for (int32_t i = 0; i < num; ++i) {
|
||||
SFreeListItem* pi = taosArrayGet(pBuf->pFree, i);
|
||||
if (pi->len >= size) {
|
||||
if (pi->length >= size) {
|
||||
offset = pi->offset;
|
||||
pi->offset += (int32_t)size;
|
||||
pi->len -= (int32_t)size;
|
||||
pi->length -= (int32_t)size;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
@ -170,17 +106,31 @@ static uint64_t allocatePositionInFile(SDiskbasedBuf* pBuf, size_t size) {
|
|||
}
|
||||
}
|
||||
|
||||
static void setPageNotInBuf(SPageInfo* pPageInfo) { pPageInfo->pData = NULL; }
|
||||
|
||||
static FORCE_INLINE size_t getAllocPageSize(int32_t pageSize) { return pageSize + POINTER_BYTES + 2; }
|
||||
|
||||
/**
|
||||
* +--------------------------+-------------------+--------------+
|
||||
* | PTR to SPageInfo (8bytes)| Payload (PageSize)| 2 Extra Bytes|
|
||||
* +--------------------------+-------------------+--------------+
|
||||
* @param pBuf
|
||||
* @param pg
|
||||
* @return
|
||||
*/
|
||||
static char* doFlushPageToDisk(SDiskbasedBuf* pBuf, SPageInfo* pg) {
|
||||
assert(!pg->used && pg->pData != NULL);
|
||||
|
||||
int32_t size = -1;
|
||||
int32_t size = pBuf->pageSize;
|
||||
char* t = NULL;
|
||||
if (pg->offset == -1 || pg->dirty) {
|
||||
SFilePage* pPage = (SFilePage*)GET_DATA_PAYLOAD(pg);
|
||||
t = doCompressData(pPage->data, pBuf->pageSize, &size, pBuf);
|
||||
void* payload = GET_DATA_PAYLOAD(pg);
|
||||
t = doCompressData(payload, pBuf->pageSize, &size, pBuf);
|
||||
assert(size >= 0);
|
||||
}
|
||||
|
||||
// this page is flushed to disk for the first time
|
||||
if (pg->dirty) {
|
||||
if (pg->offset == -1) {
|
||||
assert(pg->dirty == true);
|
||||
|
||||
|
@ -205,7 +155,7 @@ static char* doFlushPageToDisk(SDiskbasedBuf* pBuf, SPageInfo* pg) {
|
|||
|
||||
pBuf->statis.flushBytes += size;
|
||||
pBuf->statis.flushPages += 1;
|
||||
} else if (pg->dirty) {
|
||||
} else {
|
||||
// length becomes greater, current space is not enough, allocate new place, otherwise, do nothing
|
||||
if (pg->length < size) {
|
||||
// 1. add current space to free list
|
||||
|
@ -237,14 +187,19 @@ static char* doFlushPageToDisk(SDiskbasedBuf* pBuf, SPageInfo* pg) {
|
|||
pBuf->statis.flushBytes += size;
|
||||
pBuf->statis.flushPages += 1;
|
||||
}
|
||||
} else { // NOTE: the size may be -1, the this recycle page has not been flushed to disk yet.
|
||||
size = pg->length;
|
||||
if (size == -1) {
|
||||
printf("----\n");
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(size > 0 || (pg->offset == -1 && pg->length == -1));
|
||||
|
||||
char* pDataBuf = pg->pData;
|
||||
memset(pDataBuf, 0, pBuf->pageSize + sizeof(SFilePage));
|
||||
|
||||
pg->pData = NULL; // this means the data is not in buffer
|
||||
pg->length = size;
|
||||
pg->dirty = false;
|
||||
memset(pDataBuf, 0, getAllocPageSize(pBuf->pageSize));
|
||||
|
||||
pg->length = size; // on disk size
|
||||
return pDataBuf;
|
||||
}
|
||||
|
||||
|
@ -259,7 +214,11 @@ static char* flushPageToDisk(SDiskbasedBuf* pBuf, SPageInfo* pg) {
|
|||
}
|
||||
}
|
||||
|
||||
return doFlushPageToDisk(pBuf, pg);
|
||||
char* p = doFlushPageToDisk(pBuf, pg);
|
||||
setPageNotInBuf(pg);
|
||||
pg->dirty = false;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
// load file block data in disk
|
||||
|
@ -270,8 +229,8 @@ static int32_t loadPageFromDisk(SDiskbasedBuf* pBuf, SPageInfo* pg) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
SFilePage* pPage = (SFilePage*)GET_DATA_PAYLOAD(pg);
|
||||
ret = (int32_t)taosReadFile(pBuf->pFile, pPage->data, pg->length);
|
||||
void* pPage = (void*)GET_DATA_PAYLOAD(pg);
|
||||
ret = (int32_t)taosReadFile(pBuf->pFile, pPage, pg->length);
|
||||
if (ret != pg->length) {
|
||||
ret = TAOS_SYSTEM_ERROR(errno);
|
||||
return ret;
|
||||
|
@ -281,7 +240,7 @@ static int32_t loadPageFromDisk(SDiskbasedBuf* pBuf, SPageInfo* pg) {
|
|||
pBuf->statis.loadPages += 1;
|
||||
|
||||
int32_t fullSize = 0;
|
||||
doDecompressData(pPage->data, pg->length, &fullSize, pBuf);
|
||||
doDecompressData(pPage, pg->length, &fullSize, pBuf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -307,7 +266,7 @@ static SPageInfo* registerPage(SDiskbasedBuf* pBuf, int32_t groupId, int32_t pag
|
|||
|
||||
pBuf->numOfPages += 1;
|
||||
|
||||
SPageInfo* ppi = malloc(sizeof(SPageInfo)); //{ .info = PAGE_INFO_INITIALIZER, .pageId = pageId, .pn = NULL};
|
||||
SPageInfo* ppi = malloc(sizeof(SPageInfo));
|
||||
|
||||
ppi->pageId = pageId;
|
||||
ppi->pData = NULL;
|
||||
|
@ -325,16 +284,27 @@ static SListNode* getEldestUnrefedPage(SDiskbasedBuf* pBuf) {
|
|||
|
||||
SListNode* pn = NULL;
|
||||
while ((pn = tdListNext(&iter)) != NULL) {
|
||||
assert(pn != NULL);
|
||||
|
||||
SPageInfo* pageInfo = *(SPageInfo**)pn->data;
|
||||
assert(pageInfo->pageId >= 0 && pageInfo->pn == pn);
|
||||
|
||||
if (!pageInfo->used) {
|
||||
// printf("%d is chosen\n", pageInfo->pageId);
|
||||
break;
|
||||
} else {
|
||||
// printf("page %d is used, dirty:%d\n", pageInfo->pageId, pageInfo->dirty);
|
||||
}
|
||||
}
|
||||
|
||||
// int32_t pos = listNEles(pBuf->lruList);
|
||||
// SListIter iter1 = {0};
|
||||
// tdListInitIter(pBuf->lruList, &iter1, TD_LIST_BACKWARD);
|
||||
// SListNode* pn1 = NULL;
|
||||
// while((pn1 = tdListNext(&iter1)) != NULL) {
|
||||
// SPageInfo* pageInfo = *(SPageInfo**) pn1->data;
|
||||
// printf("page %d is used, dirty:%d, pos:%d\n", pageInfo->pageId, pageInfo->dirty, pos - 1);
|
||||
// pos -= 1;
|
||||
// }
|
||||
|
||||
return pn;
|
||||
}
|
||||
|
||||
|
@ -378,11 +348,60 @@ static void lruListMoveToFront(SList* pList, SPageInfo* pi) {
|
|||
tdListPrependNode(pList, pi->pn);
|
||||
}
|
||||
|
||||
static FORCE_INLINE size_t getAllocPageSize(int32_t pageSize) {
|
||||
return pageSize + POINTER_BYTES + 2 + sizeof(SFilePage);
|
||||
static SPageInfo* getPageInfoFromPayload(void* page) {
|
||||
int32_t offset = offsetof(SPageInfo, pData);
|
||||
char* p = page - offset;
|
||||
|
||||
SPageInfo* ppi = ((SPageInfo**)p)[0];
|
||||
return ppi;
|
||||
}
|
||||
|
||||
SFilePage* getNewDataBuf(SDiskbasedBuf* pBuf, int32_t groupId, int32_t* pageId) {
|
||||
int32_t createDiskbasedBuf(SDiskbasedBuf** pBuf, int32_t pagesize, int32_t inMemBufSize, uint64_t qId,
|
||||
const char* dir) {
|
||||
*pBuf = calloc(1, sizeof(SDiskbasedBuf));
|
||||
|
||||
SDiskbasedBuf* pPBuf = *pBuf;
|
||||
if (pPBuf == NULL) {
|
||||
return TSDB_CODE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
pPBuf->pageSize = pagesize;
|
||||
pPBuf->numOfPages = 0; // all pages are in buffer in the first place
|
||||
pPBuf->totalBufSize = 0;
|
||||
pPBuf->inMemPages = inMemBufSize / pagesize; // maximum allowed pages, it is a soft limit.
|
||||
pPBuf->allocateId = -1;
|
||||
pPBuf->comp = true;
|
||||
pPBuf->pFile = NULL;
|
||||
pPBuf->qId = qId;
|
||||
pPBuf->fileSize = 0;
|
||||
pPBuf->pFree = taosArrayInit(4, sizeof(SFreeListItem));
|
||||
pPBuf->freePgList = tdListNew(POINTER_BYTES);
|
||||
|
||||
// at least more than 2 pages must be in memory
|
||||
assert(inMemBufSize >= pagesize * 2);
|
||||
|
||||
pPBuf->lruList = tdListNew(POINTER_BYTES);
|
||||
|
||||
// init id hash table
|
||||
_hash_fn_t fn = taosGetDefaultHashFunction(TSDB_DATA_TYPE_INT);
|
||||
pPBuf->groupSet = taosHashInit(10, fn, true, false);
|
||||
pPBuf->assistBuf = malloc(pPBuf->pageSize + 2); // EXTRA BYTES
|
||||
pPBuf->all = taosHashInit(10, fn, true, false);
|
||||
|
||||
char path[PATH_MAX] = {0};
|
||||
taosGetTmpfilePath(dir, "paged-buf", path);
|
||||
pPBuf->path = strdup(path);
|
||||
|
||||
pPBuf->emptyDummyIdList = taosArrayInit(1, sizeof(int32_t));
|
||||
|
||||
// qDebug("QInfo:0x%"PRIx64" create resBuf for output, page size:%d, inmem buf pages:%d, file:%s", qId,
|
||||
// pPBuf->pageSize,
|
||||
// pPBuf->inMemPages, pPBuf->path);
|
||||
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
void* getNewBufPage(SDiskbasedBuf* pBuf, int32_t groupId, int32_t* pageId) {
|
||||
pBuf->statis.getPages += 1;
|
||||
|
||||
char* availablePage = NULL;
|
||||
|
@ -391,23 +410,34 @@ SFilePage* getNewDataBuf(SDiskbasedBuf* pBuf, int32_t groupId, int32_t* pageId)
|
|||
|
||||
// Failed to allocate a new buffer page, and there is an error occurs.
|
||||
if (availablePage == NULL) {
|
||||
assert(0);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
SPageInfo* pi = NULL;
|
||||
if (listNEles(pBuf->freePgList) != 0) {
|
||||
SListNode* pItem = tdListPopHead(pBuf->freePgList);
|
||||
pi = *(SPageInfo**)pItem->data;
|
||||
pi->used = true;
|
||||
*pageId = pi->pageId;
|
||||
tfree(pItem);
|
||||
} else { // create a new pageinfo
|
||||
// register new id in this group
|
||||
*pageId = (++pBuf->allocateId);
|
||||
|
||||
// register page id info
|
||||
SPageInfo* pi = registerPage(pBuf, groupId, *pageId);
|
||||
pi = registerPage(pBuf, groupId, *pageId);
|
||||
|
||||
// add to hash map
|
||||
taosHashPut(pBuf->all, pageId, sizeof(int32_t), &pi, POINTER_BYTES);
|
||||
pBuf->totalBufSize += pBuf->pageSize;
|
||||
}
|
||||
|
||||
// add to LRU list
|
||||
assert(listNEles(pBuf->lruList) < pBuf->inMemPages && pBuf->inMemPages > 0);
|
||||
lruListPushFront(pBuf->lruList, pi);
|
||||
|
||||
// add to hash map
|
||||
taosHashPut(pBuf->all, pageId, sizeof(int32_t), &pi, POINTER_BYTES);
|
||||
|
||||
// allocate buf
|
||||
if (availablePage == NULL) {
|
||||
pi->pData = calloc(1, getAllocPageSize(pBuf->pageSize)); // add extract bytes in case of zipped buffer increased.
|
||||
|
@ -415,15 +445,11 @@ SFilePage* getNewDataBuf(SDiskbasedBuf* pBuf, int32_t groupId, int32_t* pageId)
|
|||
pi->pData = availablePage;
|
||||
}
|
||||
|
||||
pBuf->totalBufSize += pBuf->pageSize;
|
||||
|
||||
((void**)pi->pData)[0] = pi;
|
||||
pi->used = true;
|
||||
|
||||
return (void*)(GET_DATA_PAYLOAD(pi));
|
||||
}
|
||||
|
||||
SFilePage* getBufPage(SDiskbasedBuf* pBuf, int32_t id) {
|
||||
void* getBufPage(SDiskbasedBuf* pBuf, int32_t id) {
|
||||
assert(pBuf != NULL && id >= 0);
|
||||
pBuf->statis.getPages += 1;
|
||||
|
||||
|
@ -444,7 +470,6 @@ SFilePage* getBufPage(SDiskbasedBuf* pBuf, int32_t id) {
|
|||
(*pi)->used = true;
|
||||
|
||||
return (void*)(GET_DATA_PAYLOAD(*pi));
|
||||
|
||||
} else { // not in memory
|
||||
assert((*pi)->pData == NULL && (*pi)->pn == NULL && (*pi)->length >= 0 && (*pi)->offset >= 0);
|
||||
|
||||
|
@ -462,6 +487,7 @@ SFilePage* getBufPage(SDiskbasedBuf* pBuf, int32_t id) {
|
|||
(*pi)->pData = availablePage;
|
||||
}
|
||||
|
||||
// set the ptr to the new SPageInfo
|
||||
((void**)((*pi)->pData))[0] = (*pi);
|
||||
|
||||
lruListPushFront(pBuf->lruList, *pi);
|
||||
|
@ -478,21 +504,18 @@ SFilePage* getBufPage(SDiskbasedBuf* pBuf, int32_t id) {
|
|||
|
||||
void releaseBufPage(SDiskbasedBuf* pBuf, void* page) {
|
||||
assert(pBuf != NULL && page != NULL);
|
||||
int32_t offset = offsetof(SPageInfo, pData);
|
||||
char* p = page - offset;
|
||||
|
||||
SPageInfo* ppi = ((SPageInfo**)p)[0];
|
||||
SPageInfo* ppi = getPageInfoFromPayload(page);
|
||||
releaseBufPageInfo(pBuf, ppi);
|
||||
}
|
||||
|
||||
void releaseBufPageInfo(SDiskbasedBuf* pBuf, SPageInfo* pi) {
|
||||
assert(pi->pData != NULL && pi->used);
|
||||
assert(pi->pData != NULL && pi->used == true);
|
||||
|
||||
pi->used = false;
|
||||
pBuf->statis.releasePages += 1;
|
||||
}
|
||||
|
||||
size_t getNumOfResultBufGroupId(const SDiskbasedBuf* pBuf) { return taosHashGetSize(pBuf->groupSet); }
|
||||
size_t getNumOfBufGroupId(const SDiskbasedBuf* pBuf) { return taosHashGetSize(pBuf->groupSet); }
|
||||
|
||||
size_t getTotalBufSize(const SDiskbasedBuf* pBuf) { return (size_t)pBuf->totalBufSize; }
|
||||
|
||||
|
@ -507,12 +530,12 @@ SIDList getDataBufPagesIdList(SDiskbasedBuf* pBuf, int32_t groupId) {
|
|||
}
|
||||
}
|
||||
|
||||
void destroyResultBuf(SDiskbasedBuf* pBuf) {
|
||||
void destroyDiskbasedBuf(SDiskbasedBuf* pBuf) {
|
||||
if (pBuf == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
printStatisData(pBuf);
|
||||
dBufPrintStatis(pBuf);
|
||||
|
||||
if (pBuf->pFile != NULL) {
|
||||
uDebug(
|
||||
|
@ -553,7 +576,11 @@ void destroyResultBuf(SDiskbasedBuf* pBuf) {
|
|||
}
|
||||
|
||||
tdListFree(pBuf->lruList);
|
||||
tdListFree(pBuf->freePgList);
|
||||
|
||||
taosArrayDestroy(pBuf->emptyDummyIdList);
|
||||
taosArrayDestroy(pBuf->pFree);
|
||||
|
||||
taosHashCleanup(pBuf->groupSet);
|
||||
taosHashCleanup(pBuf->all);
|
||||
|
||||
|
@ -578,19 +605,32 @@ int32_t getNumOfInMemBufPages(const SDiskbasedBuf* pBuf) { return pBuf->inMemPag
|
|||
|
||||
bool isAllDataInMemBuf(const SDiskbasedBuf* pBuf) { return pBuf->fileSize == 0; }
|
||||
|
||||
void setBufPageDirty(SFilePage* pPage, bool dirty) {
|
||||
int32_t offset = offsetof(SPageInfo, pData); // todo extract method
|
||||
char* p = (char*)pPage - offset;
|
||||
|
||||
SPageInfo* ppi = ((SPageInfo**)p)[0];
|
||||
void setBufPageDirty(void* pPage, bool dirty) {
|
||||
SPageInfo* ppi = getPageInfoFromPayload(pPage);
|
||||
ppi->dirty = dirty;
|
||||
}
|
||||
|
||||
void printStatisBeforeClose(SDiskbasedBuf* pBuf) { pBuf->printStatis = true; }
|
||||
void setBufPageCompressOnDisk(SDiskbasedBuf* pBuf, bool comp) { pBuf->comp = comp; }
|
||||
|
||||
void dBufSetBufPageRecycled(SDiskbasedBuf* pBuf, void* pPage) {
|
||||
SPageInfo* ppi = getPageInfoFromPayload(pPage);
|
||||
|
||||
ppi->used = false;
|
||||
ppi->dirty = false;
|
||||
|
||||
// add this pageinfo into the free page info list
|
||||
SListNode* pNode = tdListPopNode(pBuf->lruList, ppi->pn);
|
||||
tfree(ppi->pData);
|
||||
tfree(pNode);
|
||||
|
||||
tdListAppend(pBuf->freePgList, &ppi);
|
||||
}
|
||||
|
||||
void dBufSetPrintInfo(SDiskbasedBuf* pBuf) { pBuf->printStatis = true; }
|
||||
|
||||
SDiskbasedBufStatis getDBufStatis(const SDiskbasedBuf* pBuf) { return pBuf->statis; }
|
||||
|
||||
void printStatisData(const SDiskbasedBuf* pBuf) {
|
||||
void dBufPrintStatis(const SDiskbasedBuf* pBuf) {
|
||||
if (!pBuf->printStatis) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -13,144 +13,144 @@ namespace {
|
|||
// simple test
|
||||
void simpleTest() {
|
||||
SDiskbasedBuf* pResultBuf = NULL;
|
||||
int32_t ret = createDiskbasedBuffer(&pResultBuf, 1024, 4096, 1, "/tmp/");
|
||||
int32_t ret = createDiskbasedBuf(&pResultBuf, 1024, 4096, 1, "/tmp/");
|
||||
|
||||
int32_t pageId = 0;
|
||||
int32_t groupId = 0;
|
||||
|
||||
SFilePage* pBufPage = getNewDataBuf(pResultBuf, groupId, &pageId);
|
||||
SFilePage* pBufPage = static_cast<SFilePage*>(getNewBufPage(pResultBuf, groupId, &pageId));
|
||||
ASSERT_TRUE(pBufPage != NULL);
|
||||
|
||||
ASSERT_EQ(getTotalBufSize(pResultBuf), 1024);
|
||||
|
||||
SIDList list = getDataBufPagesIdList(pResultBuf, groupId);
|
||||
ASSERT_EQ(taosArrayGetSize(list), 1);
|
||||
ASSERT_EQ(getNumOfResultBufGroupId(pResultBuf), 1);
|
||||
ASSERT_EQ(getNumOfBufGroupId(pResultBuf), 1);
|
||||
|
||||
releaseBufPage(pResultBuf, pBufPage);
|
||||
|
||||
SFilePage* pBufPage1 = getNewDataBuf(pResultBuf, groupId, &pageId);
|
||||
SFilePage* pBufPage1 = static_cast<SFilePage*>(getNewBufPage(pResultBuf, groupId, &pageId));
|
||||
|
||||
SFilePage* t = getBufPage(pResultBuf, pageId);
|
||||
SFilePage* t = static_cast<SFilePage*>(getBufPage(pResultBuf, pageId));
|
||||
ASSERT_TRUE(t == pBufPage1);
|
||||
|
||||
SFilePage* pBufPage2 = getNewDataBuf(pResultBuf, groupId, &pageId);
|
||||
SFilePage* t1 = getBufPage(pResultBuf, pageId);
|
||||
SFilePage* pBufPage2 = static_cast<SFilePage*>(getNewBufPage(pResultBuf, groupId, &pageId));
|
||||
SFilePage* t1 = static_cast<SFilePage*>(getBufPage(pResultBuf, pageId));
|
||||
ASSERT_TRUE(t1 == pBufPage2);
|
||||
|
||||
SFilePage* pBufPage3 = getNewDataBuf(pResultBuf, groupId, &pageId);
|
||||
SFilePage* t2 = getBufPage(pResultBuf, pageId);
|
||||
SFilePage* pBufPage3 = static_cast<SFilePage*>(getNewBufPage(pResultBuf, groupId, &pageId));
|
||||
SFilePage* t2 = static_cast<SFilePage*>(getBufPage(pResultBuf, pageId));
|
||||
ASSERT_TRUE(t2 == pBufPage3);
|
||||
|
||||
SFilePage* pBufPage4 = getNewDataBuf(pResultBuf, groupId, &pageId);
|
||||
SFilePage* t3 = getBufPage(pResultBuf, pageId);
|
||||
SFilePage* pBufPage4 = static_cast<SFilePage*>(getNewBufPage(pResultBuf, groupId, &pageId));
|
||||
SFilePage* t3 = static_cast<SFilePage*>(getBufPage(pResultBuf, pageId));
|
||||
ASSERT_TRUE(t3 == pBufPage4);
|
||||
|
||||
SFilePage* pBufPage5 = getNewDataBuf(pResultBuf, groupId, &pageId);
|
||||
SFilePage* t4 = getBufPage(pResultBuf, pageId);
|
||||
SFilePage* pBufPage5 = static_cast<SFilePage*>(getNewBufPage(pResultBuf, groupId, &pageId));
|
||||
SFilePage* t4 = static_cast<SFilePage*>(getBufPage(pResultBuf, pageId));
|
||||
ASSERT_TRUE(t4 == pBufPage5);
|
||||
|
||||
destroyResultBuf(pResultBuf);
|
||||
destroyDiskbasedBuf(pResultBuf);
|
||||
}
|
||||
|
||||
void writeDownTest() {
|
||||
SDiskbasedBuf* pResultBuf = NULL;
|
||||
int32_t ret = createDiskbasedBuffer(&pResultBuf, 1024, 4*1024, 1, "/tmp/");
|
||||
int32_t ret = createDiskbasedBuf(&pResultBuf, 1024, 4*1024, 1, "/tmp/");
|
||||
|
||||
int32_t pageId = 0;
|
||||
int32_t writePageId = 0;
|
||||
int32_t groupId = 0;
|
||||
int32_t nx = 12345;
|
||||
|
||||
SFilePage* pBufPage = getNewDataBuf(pResultBuf, groupId, &pageId);
|
||||
SFilePage* pBufPage = static_cast<SFilePage*>(getNewBufPage(pResultBuf, groupId, &pageId));
|
||||
ASSERT_TRUE(pBufPage != NULL);
|
||||
|
||||
*(int32_t*)(pBufPage->data) = nx;
|
||||
writePageId = pageId;
|
||||
releaseBufPage(pResultBuf, pBufPage);
|
||||
|
||||
SFilePage* pBufPage1 = getNewDataBuf(pResultBuf, groupId, &pageId);
|
||||
SFilePage* t1 = getBufPage(pResultBuf, pageId);
|
||||
SFilePage* pBufPage1 = static_cast<SFilePage*>(getNewBufPage(pResultBuf, groupId, &pageId));
|
||||
SFilePage* t1 = static_cast<SFilePage*>(getBufPage(pResultBuf, pageId));
|
||||
ASSERT_TRUE(t1 == pBufPage1);
|
||||
ASSERT_TRUE(pageId == 1);
|
||||
|
||||
SFilePage* pBufPage2 = getNewDataBuf(pResultBuf, groupId, &pageId);
|
||||
SFilePage* t2 = getBufPage(pResultBuf, pageId);
|
||||
SFilePage* pBufPage2 = static_cast<SFilePage*>(getNewBufPage(pResultBuf, groupId, &pageId));
|
||||
SFilePage* t2 = static_cast<SFilePage*>(getBufPage(pResultBuf, pageId));
|
||||
ASSERT_TRUE(t2 == pBufPage2);
|
||||
ASSERT_TRUE(pageId == 2);
|
||||
|
||||
SFilePage* pBufPage3 = getNewDataBuf(pResultBuf, groupId, &pageId);
|
||||
SFilePage* t3 = getBufPage(pResultBuf, pageId);
|
||||
SFilePage* pBufPage3 = static_cast<SFilePage*>(getNewBufPage(pResultBuf, groupId, &pageId));
|
||||
SFilePage* t3 = static_cast<SFilePage*>(getBufPage(pResultBuf, pageId));
|
||||
ASSERT_TRUE(t3 == pBufPage3);
|
||||
ASSERT_TRUE(pageId == 3);
|
||||
|
||||
SFilePage* pBufPage4 = getNewDataBuf(pResultBuf, groupId, &pageId);
|
||||
SFilePage* t4 = getBufPage(pResultBuf, pageId);
|
||||
SFilePage* pBufPage4 = static_cast<SFilePage*>(getNewBufPage(pResultBuf, groupId, &pageId));
|
||||
SFilePage* t4 = static_cast<SFilePage*>(getBufPage(pResultBuf, pageId));
|
||||
ASSERT_TRUE(t4 == pBufPage4);
|
||||
ASSERT_TRUE(pageId == 4);
|
||||
releaseBufPage(pResultBuf, t4);
|
||||
|
||||
// flush the written page to disk, and read it out again
|
||||
SFilePage* pBufPagex = getBufPage(pResultBuf, writePageId);
|
||||
SFilePage* pBufPagex = static_cast<SFilePage*>(getBufPage(pResultBuf, writePageId));
|
||||
ASSERT_EQ(*(int32_t*)pBufPagex->data, nx);
|
||||
|
||||
SArray* pa = getDataBufPagesIdList(pResultBuf, groupId);
|
||||
ASSERT_EQ(taosArrayGetSize(pa), 5);
|
||||
|
||||
destroyResultBuf(pResultBuf);
|
||||
destroyDiskbasedBuf(pResultBuf);
|
||||
}
|
||||
|
||||
void recyclePageTest() {
|
||||
SDiskbasedBuf* pResultBuf = NULL;
|
||||
int32_t ret = createDiskbasedBuffer(&pResultBuf, 1024, 4*1024, 1, "/tmp/");
|
||||
int32_t ret = createDiskbasedBuf(&pResultBuf, 1024, 4*1024, 1, "/tmp/");
|
||||
|
||||
int32_t pageId = 0;
|
||||
int32_t writePageId = 0;
|
||||
int32_t groupId = 0;
|
||||
int32_t nx = 12345;
|
||||
|
||||
SFilePage* pBufPage = getNewDataBuf(pResultBuf, groupId, &pageId);
|
||||
SFilePage* pBufPage = static_cast<SFilePage*>(getNewBufPage(pResultBuf, groupId, &pageId));
|
||||
ASSERT_TRUE(pBufPage != NULL);
|
||||
releaseBufPage(pResultBuf, pBufPage);
|
||||
|
||||
SFilePage* pBufPage1 = getNewDataBuf(pResultBuf, groupId, &pageId);
|
||||
SFilePage* t1 = getBufPage(pResultBuf, pageId);
|
||||
SFilePage* pBufPage1 = static_cast<SFilePage*>(getNewBufPage(pResultBuf, groupId, &pageId));
|
||||
SFilePage* t1 = static_cast<SFilePage*>(getBufPage(pResultBuf, pageId));
|
||||
ASSERT_TRUE(t1 == pBufPage1);
|
||||
ASSERT_TRUE(pageId == 1);
|
||||
|
||||
SFilePage* pBufPage2 = getNewDataBuf(pResultBuf, groupId, &pageId);
|
||||
SFilePage* t2 = getBufPage(pResultBuf, pageId);
|
||||
SFilePage* pBufPage2 = static_cast<SFilePage*>(getNewBufPage(pResultBuf, groupId, &pageId));
|
||||
SFilePage* t2 = static_cast<SFilePage*>(getBufPage(pResultBuf, pageId));
|
||||
ASSERT_TRUE(t2 == pBufPage2);
|
||||
ASSERT_TRUE(pageId == 2);
|
||||
|
||||
SFilePage* pBufPage3 = getNewDataBuf(pResultBuf, groupId, &pageId);
|
||||
SFilePage* t3 = getBufPage(pResultBuf, pageId);
|
||||
SFilePage* pBufPage3 = static_cast<SFilePage*>(getNewBufPage(pResultBuf, groupId, &pageId));
|
||||
SFilePage* t3 = static_cast<SFilePage*>(getBufPage(pResultBuf, pageId));
|
||||
ASSERT_TRUE(t3 == pBufPage3);
|
||||
ASSERT_TRUE(pageId == 3);
|
||||
|
||||
SFilePage* pBufPage4 = getNewDataBuf(pResultBuf, groupId, &pageId);
|
||||
SFilePage* t4 = getBufPage(pResultBuf, pageId);
|
||||
SFilePage* pBufPage4 = static_cast<SFilePage*>(getNewBufPage(pResultBuf, groupId, &pageId));
|
||||
SFilePage* t4 = static_cast<SFilePage*>(getBufPage(pResultBuf, pageId));
|
||||
ASSERT_TRUE(t4 == pBufPage4);
|
||||
ASSERT_TRUE(pageId == 4);
|
||||
releaseBufPage(pResultBuf, t4);
|
||||
|
||||
SFilePage* pBufPage5 = getNewDataBuf(pResultBuf, groupId, &pageId);
|
||||
SFilePage* t5 = getBufPage(pResultBuf, pageId);
|
||||
SFilePage* pBufPage5 = static_cast<SFilePage*>(getNewBufPage(pResultBuf, groupId, &pageId));
|
||||
SFilePage* t5 = static_cast<SFilePage*>(getBufPage(pResultBuf, pageId));
|
||||
ASSERT_TRUE(t5 == pBufPage5);
|
||||
ASSERT_TRUE(pageId == 5);
|
||||
|
||||
// flush the written page to disk, and read it out again
|
||||
SFilePage* pBufPagex = getBufPage(pResultBuf, writePageId);
|
||||
SFilePage* pBufPagex = static_cast<SFilePage*>(getBufPage(pResultBuf, writePageId));
|
||||
*(int32_t*)(pBufPagex->data) = nx;
|
||||
writePageId = pageId; // update the data
|
||||
releaseBufPage(pResultBuf, pBufPagex);
|
||||
|
||||
SFilePage* pBufPagex1 = getBufPage(pResultBuf, 1);
|
||||
SFilePage* pBufPagex1 = static_cast<SFilePage*>(getBufPage(pResultBuf, 1));
|
||||
|
||||
SArray* pa = getDataBufPagesIdList(pResultBuf, groupId);
|
||||
ASSERT_EQ(taosArrayGetSize(pa), 6);
|
||||
|
||||
destroyResultBuf(pResultBuf);
|
||||
destroyDiskbasedBuf(pResultBuf);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
|
Loading…
Reference in New Issue