Merge branch 'develop' into hotfix/crash
This commit is contained in:
commit
84a6e47f1c
|
@ -1321,7 +1321,6 @@ int tsParseSql(SSqlObj *pSql, bool initialParse) {
|
|||
int32_t ret = TSDB_CODE_SUCCESS;
|
||||
SSqlCmd* pCmd = &pSql->cmd;
|
||||
|
||||
tscTrace("------------------%p, initial:%d, sqlstr:%s", pSql, initialParse, pSql->sqlstr);
|
||||
if (!pCmd->parseFinished) {
|
||||
tscTrace("%p resume to parse sql: %s", pSql, pCmd->curSql);
|
||||
}
|
||||
|
|
|
@ -1853,18 +1853,17 @@ static void multiVnodeInsertFinalize(void* param, TAOS_RES* tres, int numOfRows)
|
|||
SSubqueryState* pState = pSupporter->pState;
|
||||
|
||||
// record the total inserted rows
|
||||
if (numOfRows > 0) {
|
||||
if (tres != pParentObj) {
|
||||
if (numOfRows > 0 && tres != pParentObj) {
|
||||
pParentObj->res.numOfRows += numOfRows;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
|
||||
if (taos_errno(tres) != 0) {
|
||||
SSqlObj* pSql = (SSqlObj*) tres;
|
||||
assert(pSql != NULL && pSql->res.code == numOfRows);
|
||||
|
||||
pParentObj->res.code = pSql->res.code;
|
||||
}
|
||||
|
||||
|
||||
// it is not the initial sqlObj, free it
|
||||
if (tres != pParentObj) {
|
||||
taos_free_result(tres);
|
||||
|
@ -1902,7 +1901,6 @@ int32_t tscHandleMultivnodeInsert(SSqlObj *pSql) {
|
|||
tscTrace("%p submit data to %d vnode(s)", pSql, pDataBlocks->nSize);
|
||||
SSubqueryState *pState = calloc(1, sizeof(SSubqueryState));
|
||||
pState->numOfTotal = pSql->numOfSubs;
|
||||
|
||||
pState->numOfRemain = pSql->numOfSubs;
|
||||
|
||||
pRes->code = TSDB_CODE_SUCCESS;
|
||||
|
@ -1916,6 +1914,7 @@ int32_t tscHandleMultivnodeInsert(SSqlObj *pSql) {
|
|||
pSql->pSubs[0] = pSql; // the first sub insert points back to itself
|
||||
tscTrace("%p sub:%p create subObj success. orderOfSub:%d", pSql, pSql, 0);
|
||||
|
||||
int32_t numOfSub = 1;
|
||||
int32_t code = tscCopyDataBlockToPayload(pSql, pDataBlocks->pData[0]);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
tscTrace("%p prepare submit data block failed in async insertion, vnodeIdx:%d, total:%d, code:%d", pSql, 0,
|
||||
|
@ -1923,15 +1922,14 @@ int32_t tscHandleMultivnodeInsert(SSqlObj *pSql) {
|
|||
goto _error;
|
||||
}
|
||||
|
||||
int32_t i = 1;
|
||||
for (; i < pSql->numOfSubs; ++i) {
|
||||
for (; numOfSub < pSql->numOfSubs; ++numOfSub) {
|
||||
SInsertSupporter* pSupporter1 = calloc(1, sizeof(SInsertSupporter));
|
||||
pSupporter1->pSql = pSql;
|
||||
pSupporter1->pState = pState;
|
||||
|
||||
SSqlObj *pNew = createSubqueryObj(pSql, 0, multiVnodeInsertFinalize, pSupporter, TSDB_SQL_INSERT, NULL);
|
||||
SSqlObj *pNew = createSubqueryObj(pSql, 0, multiVnodeInsertFinalize, pSupporter1, TSDB_SQL_INSERT, NULL);
|
||||
if (pNew == NULL) {
|
||||
tscError("%p failed to malloc buffer for subObj, orderOfSub:%d, reason:%s", pSql, i, strerror(errno));
|
||||
tscError("%p failed to malloc buffer for subObj, orderOfSub:%d, reason:%s", pSql, numOfSub, strerror(errno));
|
||||
goto _error;
|
||||
}
|
||||
|
||||
|
@ -1940,26 +1938,25 @@ int32_t tscHandleMultivnodeInsert(SSqlObj *pSql) {
|
|||
* the callback function (multiVnodeInsertFinalize) correctly.
|
||||
*/
|
||||
pNew->fetchFp = pNew->fp;
|
||||
pSql->pSubs[i] = pNew;
|
||||
pSql->pSubs[numOfSub] = pNew;
|
||||
|
||||
code = tscCopyDataBlockToPayload(pNew, pDataBlocks->pData[i]);
|
||||
code = tscCopyDataBlockToPayload(pNew, pDataBlocks->pData[numOfSub]);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
tscTrace("%p prepare submit data block failed in async insertion, vnodeIdx:%d, total:%d, code:%d", pSql, i,
|
||||
tscTrace("%p prepare submit data block failed in async insertion, vnodeIdx:%d, total:%d, code:%d", pSql, numOfSub,
|
||||
pDataBlocks->nSize, code);
|
||||
goto _error;
|
||||
} else {
|
||||
tscTrace("%p sub:%p create subObj success. orderOfSub:%d", pSql, pNew, i);
|
||||
tscTrace("%p sub:%p create subObj success. orderOfSub:%d", pSql, pNew, numOfSub);
|
||||
}
|
||||
}
|
||||
|
||||
if (i < pSql->numOfSubs) {
|
||||
if (numOfSub < pSql->numOfSubs) {
|
||||
tscError("%p failed to prepare subObj structure and launch sub-insertion", pSql);
|
||||
pRes->code = TSDB_CODE_TSC_OUT_OF_MEMORY;
|
||||
return pRes->code; // free all allocated resource
|
||||
}
|
||||
|
||||
// use the local variable
|
||||
int32_t numOfSub = pSql->numOfSubs;
|
||||
for (int32_t j = 0; j < numOfSub; ++j) {
|
||||
SSqlObj *pSub = pSql->pSubs[j];
|
||||
tscTrace("%p sub:%p launch sub insert, orderOfSub:%d", pSql, pSub, j);
|
||||
|
@ -1971,11 +1968,12 @@ int32_t tscHandleMultivnodeInsert(SSqlObj *pSql) {
|
|||
_error:
|
||||
// restore the udf fp
|
||||
pSql->fp = pSql->fetchFp;
|
||||
pSql->pSubs[0] = NULL;
|
||||
|
||||
tfree(pState);
|
||||
tfree(pSql->param);
|
||||
|
||||
for(int32_t j = 1; j < i; ++j) {
|
||||
for(int32_t j = 1; j < numOfSub; ++j) {
|
||||
tfree(pSql->pSubs[j]->param);
|
||||
taos_free_result(pSql->pSubs[j]);
|
||||
}
|
||||
|
|
|
@ -69,8 +69,8 @@ typedef struct {
|
|||
int version; // version
|
||||
int numOfCols; // Number of columns appended
|
||||
int tlen; // maximum length of a SDataRow without the header part
|
||||
uint16_t flen; // First part length in a SDataRow after the header part
|
||||
uint16_t vlen; // pure value part length, excluded the overhead
|
||||
uint16_t flen; // First part length in a SDataRow after the header part
|
||||
uint16_t vlen; // pure value part length, excluded the overhead
|
||||
STColumn columns[];
|
||||
} STSchema;
|
||||
|
||||
|
@ -83,8 +83,8 @@ typedef struct {
|
|||
#define tdFreeSchema(s) tfree((s))
|
||||
|
||||
STSchema *tdDupSchema(STSchema *pSchema);
|
||||
void * tdEncodeSchema(void *dst, STSchema *pSchema);
|
||||
STSchema *tdDecodeSchema(void **psrc);
|
||||
int tdEncodeSchema(void **buf, STSchema *pSchema);
|
||||
void * tdDecodeSchema(void *buf, STSchema **pRSchema);
|
||||
|
||||
static FORCE_INLINE int comparColId(const void *key1, const void *key2) {
|
||||
if (*(int16_t *)key1 > ((STColumn *)key2)->colId) {
|
||||
|
@ -107,8 +107,8 @@ typedef struct {
|
|||
int tCols;
|
||||
int nCols;
|
||||
int tlen;
|
||||
uint16_t flen;
|
||||
uint16_t vlen;
|
||||
uint16_t flen;
|
||||
uint16_t vlen;
|
||||
int version;
|
||||
STColumn *columns;
|
||||
} STSchemaBuilder;
|
||||
|
@ -288,7 +288,7 @@ typedef struct {
|
|||
|
||||
SKVRow tdKVRowDup(SKVRow row);
|
||||
int tdSetKVRowDataOfCol(SKVRow *orow, int16_t colId, int8_t type, void *value);
|
||||
void * tdEncodeKVRow(void *buf, SKVRow row);
|
||||
int tdEncodeKVRow(void **buf, SKVRow row);
|
||||
void * tdDecodeKVRow(void *buf, SKVRow *row);
|
||||
|
||||
static FORCE_INLINE int comparTagId(const void *key1, const void *key2) {
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
*/
|
||||
#include "tdataformat.h"
|
||||
#include "talgo.h"
|
||||
#include "tcoding.h"
|
||||
#include "wchar.h"
|
||||
|
||||
/**
|
||||
|
@ -33,50 +34,50 @@ STSchema *tdDupSchema(STSchema *pSchema) {
|
|||
/**
|
||||
* Encode a schema to dst, and return the next pointer
|
||||
*/
|
||||
void *tdEncodeSchema(void *dst, STSchema *pSchema) {
|
||||
int tdEncodeSchema(void **buf, STSchema *pSchema) {
|
||||
int tlen = 0;
|
||||
tlen += taosEncodeFixedI32(buf, schemaVersion(pSchema));
|
||||
tlen += taosEncodeFixedI32(buf, schemaNCols(pSchema));
|
||||
|
||||
T_APPEND_MEMBER(dst, pSchema, STSchema, version);
|
||||
T_APPEND_MEMBER(dst, pSchema, STSchema, numOfCols);
|
||||
for (int i = 0; i < schemaNCols(pSchema); i++) {
|
||||
STColumn *pCol = schemaColAt(pSchema, i);
|
||||
T_APPEND_MEMBER(dst, pCol, STColumn, type);
|
||||
T_APPEND_MEMBER(dst, pCol, STColumn, colId);
|
||||
T_APPEND_MEMBER(dst, pCol, STColumn, bytes);
|
||||
tlen += taosEncodeFixedI8(buf, colType(pCol));
|
||||
tlen += taosEncodeFixedI16(buf, colColId(pCol));
|
||||
tlen += taosEncodeFixedI32(buf, colBytes(pCol));
|
||||
}
|
||||
|
||||
return dst;
|
||||
return tlen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a schema from a binary.
|
||||
*/
|
||||
STSchema *tdDecodeSchema(void **psrc) {
|
||||
int totalCols = 0;
|
||||
void *tdDecodeSchema(void *buf, STSchema **pRSchema) {
|
||||
int version = 0;
|
||||
STSchemaBuilder schemaBuilder = {0};
|
||||
int numOfCols = 0;
|
||||
STSchemaBuilder schemaBuilder;
|
||||
|
||||
T_READ_MEMBER(*psrc, int, version);
|
||||
T_READ_MEMBER(*psrc, int, totalCols);
|
||||
buf = taosDecodeFixedI32(buf, &version);
|
||||
buf = taosDecodeFixedI32(buf, &numOfCols);
|
||||
|
||||
if (tdInitTSchemaBuilder(&schemaBuilder, version) < 0) return NULL;
|
||||
|
||||
for (int i = 0; i < totalCols; i++) {
|
||||
for (int i = 0; i < numOfCols; i++) {
|
||||
int8_t type = 0;
|
||||
int16_t colId = 0;
|
||||
int32_t bytes = 0;
|
||||
T_READ_MEMBER(*psrc, int8_t, type);
|
||||
T_READ_MEMBER(*psrc, int16_t, colId);
|
||||
T_READ_MEMBER(*psrc, int32_t, bytes);
|
||||
|
||||
buf = taosDecodeFixedI8(buf, &type);
|
||||
buf = taosDecodeFixedI16(buf, &colId);
|
||||
buf = taosDecodeFixedI32(buf, &bytes);
|
||||
if (tdAddColToSchema(&schemaBuilder, type, colId, bytes) < 0) {
|
||||
tdDestroyTSchemaBuilder(&schemaBuilder);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
STSchema *pSchema = tdGetSchemaFromBuilder(&schemaBuilder);
|
||||
*pRSchema = tdGetSchemaFromBuilder(&schemaBuilder);
|
||||
tdDestroyTSchemaBuilder(&schemaBuilder);
|
||||
return pSchema;
|
||||
return buf;
|
||||
}
|
||||
|
||||
int tdInitTSchemaBuilder(STSchemaBuilder *pBuilder, int32_t version) {
|
||||
|
@ -605,14 +606,19 @@ int tdSetKVRowDataOfCol(SKVRow *orow, int16_t colId, int8_t type, void *value) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void *tdEncodeKVRow(void *buf, SKVRow row) {
|
||||
int tdEncodeKVRow(void **buf, SKVRow row) {
|
||||
// May change the encode purpose
|
||||
kvRowCpy(buf, row);
|
||||
return POINTER_SHIFT(buf, kvRowLen(row));
|
||||
if (buf != NULL) {
|
||||
kvRowCpy(*buf, row);
|
||||
*buf = POINTER_SHIFT(*buf, kvRowLen(row));
|
||||
}
|
||||
|
||||
return kvRowLen(row);
|
||||
}
|
||||
|
||||
void *tdDecodeKVRow(void *buf, SKVRow *row) {
|
||||
*row = tdKVRowDup(buf);
|
||||
if (*row == NULL) return NULL;
|
||||
return POINTER_SHIFT(buf, kvRowLen(*row));
|
||||
}
|
||||
|
||||
|
|
|
@ -183,8 +183,8 @@ TAOS_DEFINE_ERROR(TSDB_CODE_VND_NO_WRITE_AUTH, 0, 0x0214, "vnode no w
|
|||
|
||||
// tsdb
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_TDB_INVALID_TABLE_ID, 0, 0x0600, "tsdb invalid table id")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_TDB_INVALID_TABLE_TYPE, 0, 0x0601, "tsdb invalid table schema version")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_TDB_TABLE_SCHEMA_VERSION, 0, 0x0602, "tsdb invalid table schema version")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_TDB_INVALID_TABLE_TYPE, 0, 0x0601, "tsdb invalid table type")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_TDB_IVD_TB_SCHEMA_VERSION, 0, 0x0602, "tsdb invalid table schema version")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_TDB_TABLE_ALREADY_EXIST, 0, 0x0603, "tsdb table already exist")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_TDB_INVALID_CONFIG, 0, 0x0604, "tsdb invalid configuration")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_TDB_INIT_FAILED, 0, 0x0605, "tsdb init failed")
|
||||
|
@ -194,6 +194,11 @@ TAOS_DEFINE_ERROR(TSDB_CODE_TDB_FILE_CORRUPTED, 0, 0x0608, "tsdb file
|
|||
TAOS_DEFINE_ERROR(TSDB_CODE_TDB_OUT_OF_MEMORY, 0, 0x0609, "tsdb out of memory")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_TDB_TAG_VER_OUT_OF_DATE, 0, 0x060A, "tsdb tag version is out of date")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_TDB_TIMESTAMP_OUT_OF_RANGE, 0, 0x060B, "tsdb timestamp is out of range")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_TDB_SUBMIT_MSG_MSSED_UP, 0, 0x060C, "tsdb submit message is messed up")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_TDB_INVALID_ACTION, 0, 0x060D, "tsdb invalid action")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_TDB_INVALID_CREATE_TB_MSG, 0, 0x060E, "tsdb invalid create table message")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_TDB_NO_TABLE_DATA_IN_MEM, 0, 0x060F, "tsdb no table data in memory skiplist")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_TDB_FILE_ALREADY_EXISTS, 0, 0x0610, "tsdb file already exists")
|
||||
|
||||
// query
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_QRY_INVALID_QHANDLE, 0, 0x0700, "query invalid handle")
|
||||
|
|
|
@ -19,11 +19,11 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "tdataformat.h"
|
||||
#include "tname.h"
|
||||
#include "taosdef.h"
|
||||
#include "taosmsg.h"
|
||||
#include "tarray.h"
|
||||
#include "tdataformat.h"
|
||||
#include "tname.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -35,7 +35,7 @@ extern "C" {
|
|||
#define TSDB_INVALID_SUPER_TABLE_ID -1
|
||||
|
||||
#define TSDB_STATUS_COMMIT_START 1
|
||||
#define TSDB_STATUS_COMMIT_OVER 2
|
||||
#define TSDB_STATUS_COMMIT_OVER 2
|
||||
|
||||
// --------- TSDB APPLICATION HANDLE DEFINITION
|
||||
typedef struct {
|
||||
|
@ -53,9 +53,9 @@ typedef struct {
|
|||
int32_t tsdbId;
|
||||
int32_t cacheBlockSize;
|
||||
int32_t totalBlocks;
|
||||
int32_t maxTables; // maximum number of tables this repository can have
|
||||
int32_t daysPerFile; // day per file sharding policy
|
||||
int32_t keep; // day of data to keep
|
||||
int32_t maxTables; // maximum number of tables this repository can have
|
||||
int32_t daysPerFile; // day per file sharding policy
|
||||
int32_t keep; // day of data to keep
|
||||
int32_t keep1;
|
||||
int32_t keep2;
|
||||
int32_t minRowsPerFileBlock; // minimum rows per file block
|
||||
|
@ -72,19 +72,16 @@ typedef struct {
|
|||
int64_t pointsWritten; // total data points written
|
||||
} STsdbStat;
|
||||
|
||||
typedef void TsdbRepoT; // use void to hide implementation details from outside
|
||||
typedef void TSDB_REPO_T; // use void to hide implementation details from outside
|
||||
|
||||
void tsdbSetDefaultCfg(STsdbCfg *pCfg);
|
||||
STsdbCfg *tsdbCreateDefaultCfg();
|
||||
void tsdbFreeCfg(STsdbCfg *pCfg);
|
||||
STsdbCfg *tsdbGetCfg(const TsdbRepoT *repo);
|
||||
STsdbCfg *tsdbGetCfg(const TSDB_REPO_T *repo);
|
||||
|
||||
// --------- TSDB REPOSITORY DEFINITION
|
||||
int tsdbCreateRepo(char *rootDir, STsdbCfg *pCfg, void *limiter);
|
||||
int32_t tsdbDropRepo(TsdbRepoT *repo);
|
||||
TsdbRepoT *tsdbOpenRepo(char *rootDir, STsdbAppH *pAppH);
|
||||
int32_t tsdbCloseRepo(TsdbRepoT *repo, int toCommit);
|
||||
int32_t tsdbConfigRepo(TsdbRepoT *repo, STsdbCfg *pCfg);
|
||||
int tsdbCreateRepo(char *rootDir, STsdbCfg *pCfg);
|
||||
int32_t tsdbDropRepo(char *rootDir);
|
||||
TSDB_REPO_T *tsdbOpenRepo(char *rootDir, STsdbAppH *pAppH);
|
||||
void tsdbCloseRepo(TSDB_REPO_T *repo, int toCommit);
|
||||
int32_t tsdbConfigRepo(TSDB_REPO_T *repo, STsdbCfg *pCfg);
|
||||
|
||||
// --------- TSDB TABLE DEFINITION
|
||||
typedef struct {
|
||||
|
@ -106,28 +103,19 @@ typedef struct {
|
|||
char * sql;
|
||||
} STableCfg;
|
||||
|
||||
int tsdbInitTableCfg(STableCfg *config, ETableType type, uint64_t uid, int32_t tid);
|
||||
int tsdbTableSetSuperUid(STableCfg *config, uint64_t uid);
|
||||
int tsdbTableSetSchema(STableCfg *config, STSchema *pSchema, bool dup);
|
||||
int tsdbTableSetTagSchema(STableCfg *config, STSchema *pSchema, bool dup);
|
||||
int tsdbTableSetTagValue(STableCfg *config, SKVRow row, bool dup);
|
||||
int tsdbTableSetName(STableCfg *config, char *name, bool dup);
|
||||
int tsdbTableSetSName(STableCfg *config, char *sname, bool dup);
|
||||
int tsdbTableSetStreamSql(STableCfg *config, char *sql, bool dup);
|
||||
void tsdbClearTableCfg(STableCfg *config);
|
||||
|
||||
void* tsdbGetTableTagVal(TsdbRepoT* repo, const STableId* id, int32_t colId, int16_t type, int16_t bytes);
|
||||
char* tsdbGetTableName(TsdbRepoT *repo, const STableId *id);
|
||||
void * tsdbGetTableTagVal(TSDB_REPO_T *repo, const STableId *id, int32_t colId, int16_t type, int16_t bytes);
|
||||
char * tsdbGetTableName(TSDB_REPO_T *repo, const STableId *id);
|
||||
STableCfg *tsdbCreateTableCfgFromMsg(SMDCreateTableMsg *pMsg);
|
||||
|
||||
int tsdbCreateTable(TsdbRepoT *repo, STableCfg *pCfg);
|
||||
int tsdbDropTable(TsdbRepoT *pRepo, STableId tableId);
|
||||
int tsdbAlterTable(TsdbRepoT *repo, STableCfg *pCfg);
|
||||
int tsdbUpdateTagValue(TsdbRepoT *repo, SUpdateTableTagValMsg *pMsg);
|
||||
TSKEY tsdbGetTableLastKey(TsdbRepoT *repo, uint64_t uid);
|
||||
void tsdbStartStream(TsdbRepoT *repo);
|
||||
int tsdbCreateTable(TSDB_REPO_T *repo, STableCfg *pCfg);
|
||||
int tsdbDropTable(TSDB_REPO_T *pRepo, STableId tableId);
|
||||
int tsdbUpdateTagValue(TSDB_REPO_T *repo, SUpdateTableTagValMsg *pMsg);
|
||||
TSKEY tsdbGetTableLastKey(TSDB_REPO_T *repo, uint64_t uid);
|
||||
void tsdbStartStream(TSDB_REPO_T *repo);
|
||||
|
||||
uint32_t tsdbGetFileInfo(TsdbRepoT *repo, char *name, uint32_t *index, uint32_t eindex, int32_t *size);
|
||||
uint32_t tsdbGetFileInfo(TSDB_REPO_T *repo, char *name, uint32_t *index, uint32_t eindex, int32_t *size);
|
||||
|
||||
// the TSDB repository info
|
||||
typedef struct STsdbRepoInfo {
|
||||
|
@ -137,7 +125,7 @@ typedef struct STsdbRepoInfo {
|
|||
int64_t tsdbTotalDiskSize; // the total disk size taken by this TSDB repository
|
||||
// TODO: Other informations to add
|
||||
} STsdbRepoInfo;
|
||||
STsdbRepoInfo *tsdbGetStatus(TsdbRepoT *pRepo);
|
||||
STsdbRepoInfo *tsdbGetStatus(TSDB_REPO_T *pRepo);
|
||||
|
||||
// the meter information report structure
|
||||
typedef struct {
|
||||
|
@ -146,7 +134,7 @@ typedef struct {
|
|||
int64_t tableTotalDataSize; // In bytes
|
||||
int64_t tableTotalDiskSize; // In bytes
|
||||
} STableInfo;
|
||||
STableInfo *tsdbGetTableInfo(TsdbRepoT *pRepo, STableId tid);
|
||||
STableInfo *tsdbGetTableInfo(TSDB_REPO_T *pRepo, STableId tid);
|
||||
|
||||
// -- FOR INSERT DATA
|
||||
/**
|
||||
|
@ -156,7 +144,7 @@ STableInfo *tsdbGetTableInfo(TsdbRepoT *pRepo, STableId tid);
|
|||
*
|
||||
* @return the number of points inserted, -1 for failure and the error number is set
|
||||
*/
|
||||
int32_t tsdbInsertData(TsdbRepoT *repo, SSubmitMsg *pMsg, SShellSubmitRspMsg * pRsp) ;
|
||||
int32_t tsdbInsertData(TSDB_REPO_T *repo, SSubmitMsg *pMsg, SShellSubmitRspMsg *pRsp);
|
||||
|
||||
// -- FOR QUERY TIME SERIES DATA
|
||||
|
||||
|
@ -164,10 +152,10 @@ typedef void *TsdbQueryHandleT; // Use void to hide implementation details
|
|||
|
||||
// query condition to build vnode iterator
|
||||
typedef struct STsdbQueryCond {
|
||||
STimeWindow twindow;
|
||||
int32_t order; // desc|asc order to iterate the data block
|
||||
int32_t numOfCols;
|
||||
SColumnInfo *colList;
|
||||
STimeWindow twindow;
|
||||
int32_t order; // desc|asc order to iterate the data block
|
||||
int32_t numOfCols;
|
||||
SColumnInfo *colList;
|
||||
} STsdbQueryCond;
|
||||
|
||||
typedef struct SDataBlockInfo {
|
||||
|
@ -199,7 +187,7 @@ typedef void *TsdbPosT;
|
|||
* @param qinfo query info handle from query processor
|
||||
* @return
|
||||
*/
|
||||
TsdbQueryHandleT *tsdbQueryTables(TsdbRepoT *tsdb, STsdbQueryCond *pCond, STableGroupInfo *groupInfo, void* qinfo);
|
||||
TsdbQueryHandleT *tsdbQueryTables(TSDB_REPO_T *tsdb, STsdbQueryCond *pCond, STableGroupInfo *groupInfo, void *qinfo);
|
||||
|
||||
/**
|
||||
* Get the last row of the given query time window for all the tables in STableGroupInfo object.
|
||||
|
@ -207,15 +195,17 @@ TsdbQueryHandleT *tsdbQueryTables(TsdbRepoT *tsdb, STsdbQueryCond *pCond, STable
|
|||
* all tables in this group.
|
||||
*
|
||||
* @param tsdb tsdb handle
|
||||
* @param pCond query condition, including time window, result set order, and basic required columns for each block
|
||||
* @param pCond query condition, including time window, result set order, and basic required columns for each
|
||||
* block
|
||||
* @param groupInfo tableId list.
|
||||
* @return
|
||||
*/
|
||||
TsdbQueryHandleT tsdbQueryLastRow(TsdbRepoT *tsdb, STsdbQueryCond *pCond, STableGroupInfo *groupInfo, void* qinfo);
|
||||
TsdbQueryHandleT tsdbQueryLastRow(TSDB_REPO_T *tsdb, STsdbQueryCond *pCond, STableGroupInfo *groupInfo, void *qinfo);
|
||||
|
||||
SArray* tsdbGetQueriedTableIdList(TsdbQueryHandleT *pHandle);
|
||||
SArray *tsdbGetQueriedTableIdList(TsdbQueryHandleT *pHandle);
|
||||
|
||||
TsdbQueryHandleT tsdbQueryRowsInExternalWindow(TsdbRepoT *tsdb, STsdbQueryCond* pCond, STableGroupInfo *groupList, void* qinfo);
|
||||
TsdbQueryHandleT tsdbQueryRowsInExternalWindow(TSDB_REPO_T *tsdb, STsdbQueryCond *pCond, STableGroupInfo *groupList,
|
||||
void *qinfo);
|
||||
|
||||
/**
|
||||
* move to next block if exists
|
||||
|
@ -293,7 +283,7 @@ SArray *tsdbGetTableList(TsdbQueryHandleT *pQueryHandle);
|
|||
* @param stableid. super table sid
|
||||
* @param pTagCond. tag query condition
|
||||
*/
|
||||
int32_t tsdbQuerySTableByTagCond(TsdbRepoT *tsdb, uint64_t uid, const char *pTagCond, size_t len,
|
||||
int32_t tsdbQuerySTableByTagCond(TSDB_REPO_T *tsdb, uint64_t uid, const char *pTagCond, size_t len,
|
||||
int16_t tagNameRelType, const char *tbnameCond, STableGroupInfo *pGroupList,
|
||||
SColIndex *pColIndex, int32_t numOfCols);
|
||||
|
||||
|
@ -305,7 +295,7 @@ int32_t tsdbQuerySTableByTagCond(TsdbRepoT *tsdb, uint64_t uid, const char *pTag
|
|||
* @param pGroupInfo the generated result
|
||||
* @return
|
||||
*/
|
||||
int32_t tsdbGetOneTableGroup(TsdbRepoT *tsdb, uint64_t uid, STableGroupInfo *pGroupInfo);
|
||||
int32_t tsdbGetOneTableGroup(TSDB_REPO_T *tsdb, uint64_t uid, STableGroupInfo *pGroupInfo);
|
||||
|
||||
/**
|
||||
* clean up the query handle
|
||||
|
|
|
@ -774,7 +774,7 @@ static void tQueryIndexlessColumn(SSkipList* pSkipList, tQueryInfo* pQueryInfo,
|
|||
char * pData = SL_GET_NODE_DATA(pNode);
|
||||
|
||||
// todo refactor:
|
||||
tstr *name = ((STableIndexElem *)pData)->pTable->name;
|
||||
tstr *name = (*(STable **)pData)->name;
|
||||
// todo speed up by using hash
|
||||
if (pQueryInfo->colIndex == TSDB_TBNAME_COLUMN_INDEX) {
|
||||
if (pQueryInfo->optr == TSDB_RELATION_IN) {
|
||||
|
|
|
@ -15,13 +15,16 @@
|
|||
#ifndef _TD_TSDB_MAIN_H_
|
||||
#define _TD_TSDB_MAIN_H_
|
||||
|
||||
#include "hash.h"
|
||||
#include "tcoding.h"
|
||||
#include "tglobal.h"
|
||||
#include "tkvstore.h"
|
||||
#include "tlist.h"
|
||||
#include "tlog.h"
|
||||
#include "tref.h"
|
||||
#include "tsdb.h"
|
||||
#include "tskiplist.h"
|
||||
#include "tutil.h"
|
||||
#include "tlog.h"
|
||||
#include "tcoding.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -34,174 +37,101 @@ extern int tsdbDebugFlag;
|
|||
#define tsdbTrace(...) { if (tsdbDebugFlag & DEBUG_TRACE) { taosPrintLog("TDB ", tsdbDebugFlag, __VA_ARGS__); }}
|
||||
#define tsdbPrint(...) { taosPrintLog("TDB ", 255, __VA_ARGS__); }
|
||||
|
||||
// ------------------------------ TSDB META FILE INTERFACES ------------------------------
|
||||
#define TSDB_META_FILE_NAME "meta"
|
||||
#define TSDB_META_HASH_FRACTION 1.1
|
||||
|
||||
typedef int (*iterFunc)(void *, void *cont, int contLen);
|
||||
typedef void (*afterFunc)(void *);
|
||||
|
||||
typedef struct {
|
||||
int fd; // File descriptor
|
||||
int nDel; // number of deletions
|
||||
int tombSize; // deleted size
|
||||
int64_t size; // Total file size
|
||||
void * map; // Map from uid ==> position
|
||||
iterFunc iFunc;
|
||||
afterFunc aFunc;
|
||||
void * appH;
|
||||
} SMetaFile;
|
||||
|
||||
SMetaFile *tsdbInitMetaFile(char *rootDir, int32_t maxTables, iterFunc iFunc, afterFunc aFunc, void *appH);
|
||||
int32_t tsdbInsertMetaRecord(SMetaFile *mfh, uint64_t uid, void *cont, int32_t contLen);
|
||||
int32_t tsdbDeleteMetaRecord(SMetaFile *mfh, uint64_t uid);
|
||||
int32_t tsdbUpdateMetaRecord(SMetaFile *mfh, uint64_t uid, void *cont, int32_t contLen);
|
||||
void tsdbCloseMetaFile(SMetaFile *mfh);
|
||||
|
||||
// ------------------------------ TSDB META INTERFACES ------------------------------
|
||||
#define IS_CREATE_STABLE(pCfg) ((pCfg)->tagValues != NULL)
|
||||
|
||||
typedef struct {
|
||||
TSKEY keyFirst;
|
||||
TSKEY keyLast;
|
||||
int32_t numOfRows;
|
||||
void * pData;
|
||||
} SMemTable;
|
||||
|
||||
// ---------- TSDB TABLE DEFINITION
|
||||
#define TSDB_MAX_TABLE_SCHEMAS 16
|
||||
typedef struct STable {
|
||||
int8_t type;
|
||||
STableId tableId;
|
||||
uint64_t superUid; // Super table UID
|
||||
int16_t numOfSchemas;
|
||||
STSchema ** schema;
|
||||
STSchema * tagSchema;
|
||||
SKVRow tagVal;
|
||||
SMemTable * mem;
|
||||
SMemTable * imem;
|
||||
void * pIndex; // For TSDB_SUPER_TABLE, it is the skiplist index
|
||||
void * eventHandler; // TODO
|
||||
void * streamHandler; // TODO
|
||||
TSKEY lastKey; // lastkey inserted in this table, initialized as 0, TODO: make a structure
|
||||
struct STable *next; // TODO: remove the next
|
||||
struct STable *prev;
|
||||
tstr * name; // NOTE: there a flexible string here
|
||||
char * sql;
|
||||
void * cqhandle;
|
||||
} STable;
|
||||
|
||||
#define TSDB_GET_TABLE_LAST_KEY(tb) ((tb)->lastKey)
|
||||
|
||||
void tsdbEncodeTable(STable *pTable, char *buf, int *contLen);
|
||||
STable *tsdbDecodeTable(void *cont, int contLen);
|
||||
void tsdbFreeEncode(void *cont);
|
||||
|
||||
// ---------- TSDB META HANDLE DEFINITION
|
||||
typedef struct {
|
||||
int32_t maxTables; // Max number of tables
|
||||
|
||||
int32_t nTables; // Tables created
|
||||
|
||||
STable **tables; // table array
|
||||
|
||||
STable *superList; // super table list TODO: change it to list container
|
||||
|
||||
void *map; // table map of (uid ===> table)
|
||||
|
||||
SMetaFile *mfh; // meta file handle
|
||||
int maxRowBytes;
|
||||
int maxCols;
|
||||
void * pRepo;
|
||||
} STsdbMeta;
|
||||
|
||||
// element put in skiplist for each table
|
||||
typedef struct STableIndexElem {
|
||||
STsdbMeta* pMeta;
|
||||
STable* pTable;
|
||||
} STableIndexElem;
|
||||
|
||||
STsdbMeta *tsdbInitMeta(char *rootDir, int32_t maxTables, void *pRepo);
|
||||
int32_t tsdbFreeMeta(STsdbMeta *pMeta);
|
||||
STSchema * tsdbGetTableTagSchema(STsdbMeta *pMeta, STable *pTable);
|
||||
|
||||
// ---- Operation on STable
|
||||
#define TSDB_TABLE_ID(pTable) ((pTable)->tableId)
|
||||
#define TSDB_TABLE_UID(pTable) ((pTable)->uid)
|
||||
#define TSDB_TABLE_NAME(pTable) ((pTable)->tableName)
|
||||
#define TSDB_TABLE_TYPE(pTable) ((pTable)->type)
|
||||
#define TSDB_TABLE_SUPER_TABLE_UID(pTable) ((pTable)->stableUid)
|
||||
#define TSDB_TABLE_IS_SUPER_TABLE(pTable) (TSDB_TABLE_TYPE(pTable) == TSDB_SUPER_TABLE)
|
||||
#define TSDB_TABLE_TAG_VALUE(pTable) ((pTable)->pTagVal)
|
||||
#define TSDB_TABLE_CACHE_DATA(pTable) ((pTable)->content.pData)
|
||||
#define TSDB_SUPER_TABLE_INDEX(pTable) ((pTable)->content.pIndex)
|
||||
|
||||
// ---- Operation on SMetaHandle
|
||||
#define TSDB_NUM_OF_TABLES(pHandle) ((pHandle)->numOfTables)
|
||||
#define TSDB_NUM_OF_SUPER_TABLES(pHandle) ((pHandle)->numOfSuperTables)
|
||||
#define TSDB_TABLE_OF_ID(pHandle, id) ((pHandle)->pTables)[id]
|
||||
#define TSDB_GET_TABLE_OF_NAME(pHandle, name) /* TODO */
|
||||
|
||||
STsdbMeta *tsdbGetMeta(TsdbRepoT *pRepo);
|
||||
|
||||
STable *tsdbIsValidTableToInsert(STsdbMeta *pMeta, STableId tableId);
|
||||
// int32_t tsdbInsertRowToTableImpl(SSkipListNode *pNode, STable *pTable);
|
||||
STable *tsdbGetTableByUid(STsdbMeta *pMeta, uint64_t uid);
|
||||
char *getTSTupleKey(const void * data);
|
||||
|
||||
typedef struct {
|
||||
int blockId;
|
||||
int offset;
|
||||
int remain;
|
||||
int padding;
|
||||
char data[];
|
||||
} STsdbCacheBlock;
|
||||
|
||||
typedef struct {
|
||||
int64_t index;
|
||||
int numOfCacheBlocks;
|
||||
SList * memPool;
|
||||
} STsdbBufferPool;
|
||||
|
||||
typedef struct {
|
||||
TSKEY keyFirst;
|
||||
TSKEY keyLast;
|
||||
int64_t numOfRows;
|
||||
SList * list;
|
||||
} SCacheMem;
|
||||
|
||||
typedef struct {
|
||||
int cacheBlockSize;
|
||||
int totalCacheBlocks;
|
||||
STsdbBufferPool pool;
|
||||
STsdbCacheBlock *curBlock;
|
||||
SCacheMem * mem;
|
||||
SCacheMem * imem;
|
||||
TsdbRepoT * pRepo;
|
||||
} STsdbCache;
|
||||
|
||||
STsdbCache *tsdbInitCache(int cacheBlockSize, int totalBlocks, TsdbRepoT *pRepo);
|
||||
void tsdbFreeCache(STsdbCache *pCache);
|
||||
void * tsdbAllocFromCache(STsdbCache *pCache, int bytes, TSKEY key);
|
||||
|
||||
// ------------------------------ TSDB FILE INTERFACES ------------------------------
|
||||
#define TSDB_FILE_HEAD_SIZE 512
|
||||
#define TSDB_FILE_DELIMITER 0xF00AFA0F
|
||||
|
||||
#define tsdbGetKeyFileId(key, daysPerFile, precision) ((key) / tsMsPerDay[(precision)] / (daysPerFile))
|
||||
#define tsdbGetMaxNumOfFiles(keep, daysPerFile) ((keep) / (daysPerFile) + 3)
|
||||
// Definitions
|
||||
// ------------------ tsdbMeta.c
|
||||
typedef struct STable {
|
||||
ETableType type;
|
||||
tstr* name; // NOTE: there a flexible string here
|
||||
STableId tableId;
|
||||
uint64_t suid;
|
||||
struct STable* pSuper; // super table pointer
|
||||
uint8_t numOfSchemas;
|
||||
STSchema* schema[TSDB_MAX_TABLE_SCHEMAS];
|
||||
STSchema* tagSchema;
|
||||
SKVRow tagVal;
|
||||
SSkipList* pIndex; // For TSDB_SUPER_TABLE, it is the skiplist index
|
||||
void* eventHandler; // TODO
|
||||
void* streamHandler; // TODO
|
||||
TSKEY lastKey; // lastkey inserted in this table, initialized as 0, TODO: make a structure
|
||||
char* sql;
|
||||
void* cqhandle;
|
||||
T_REF_DECLARE();
|
||||
} STable;
|
||||
|
||||
typedef struct {
|
||||
pthread_rwlock_t rwLock;
|
||||
|
||||
int32_t nTables;
|
||||
STable** tables;
|
||||
SList* superList;
|
||||
SHashObj* uidMap;
|
||||
SKVStore* pStore;
|
||||
int maxRowBytes;
|
||||
int maxCols;
|
||||
} STsdbMeta;
|
||||
|
||||
// ------------------ tsdbBuffer.c
|
||||
typedef struct {
|
||||
int64_t blockId;
|
||||
int offset;
|
||||
int remain;
|
||||
char data[];
|
||||
} STsdbBufBlock;
|
||||
|
||||
typedef struct {
|
||||
pthread_cond_t poolNotEmpty;
|
||||
int bufBlockSize;
|
||||
int tBufBlocks;
|
||||
int nBufBlocks;
|
||||
int64_t index;
|
||||
SList* bufBlockList;
|
||||
} STsdbBufPool;
|
||||
|
||||
// ------------------ tsdbMemTable.c
|
||||
typedef struct {
|
||||
uint64_t uid;
|
||||
TSKEY keyFirst;
|
||||
TSKEY keyLast;
|
||||
int64_t numOfRows;
|
||||
SSkipList* pData;
|
||||
} STableData;
|
||||
|
||||
typedef struct {
|
||||
T_REF_DECLARE();
|
||||
TSKEY keyFirst;
|
||||
TSKEY keyLast;
|
||||
int64_t numOfRows;
|
||||
STableData** tData;
|
||||
SList* actList;
|
||||
SList* bufBlockList;
|
||||
} SMemTable;
|
||||
|
||||
enum { TSDB_UPDATE_META, TSDB_DROP_META };
|
||||
typedef struct __attribute__((packed)){
|
||||
char act;
|
||||
uint64_t uid;
|
||||
} SActObj;
|
||||
|
||||
typedef struct {
|
||||
int len;
|
||||
char cont[];
|
||||
} SActCont;
|
||||
|
||||
// ------------------ tsdbFile.c
|
||||
extern const char* tsdbFileSuffix[];
|
||||
typedef enum {
|
||||
TSDB_FILE_TYPE_HEAD = 0, // .head file type
|
||||
TSDB_FILE_TYPE_DATA, // .data file type
|
||||
TSDB_FILE_TYPE_LAST, // .last file type
|
||||
TSDB_FILE_TYPE_MAX
|
||||
TSDB_FILE_TYPE_HEAD = 0,
|
||||
TSDB_FILE_TYPE_DATA,
|
||||
TSDB_FILE_TYPE_LAST,
|
||||
TSDB_FILE_TYPE_MAX,
|
||||
TSDB_FILE_TYPE_NHEAD,
|
||||
TSDB_FILE_TYPE_NLAST
|
||||
} TSDB_FILE_TYPE;
|
||||
|
||||
#define IS_VALID_TSDB_FILE_TYPE(type) ((type) >= TSDB_FILE_TYPE_HEAD && (type) < TSDB_FILE_TYPE_MAX)
|
||||
|
||||
extern const char *tsdbFileSuffix[];
|
||||
|
||||
typedef struct {
|
||||
uint32_t offset;
|
||||
uint32_t len;
|
||||
|
@ -211,46 +141,26 @@ typedef struct {
|
|||
uint32_t totalSubBlocks;
|
||||
} STsdbFileInfo;
|
||||
|
||||
void *tsdbEncodeSFileInfo(void *buf, const STsdbFileInfo *pInfo);
|
||||
void *tsdbDecodeSFileInfo(void *buf, STsdbFileInfo *pInfo);
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
char fname[128];
|
||||
char fname[TSDB_FILENAME_LEN];
|
||||
int fd;
|
||||
|
||||
STsdbFileInfo info;
|
||||
} SFile;
|
||||
|
||||
#define TSDB_IS_FILE_OPENED(f) ((f)->fd != -1)
|
||||
|
||||
typedef struct {
|
||||
int32_t fileId;
|
||||
SFile files[TSDB_FILE_TYPE_MAX];
|
||||
int fileId;
|
||||
SFile files[TSDB_FILE_TYPE_MAX];
|
||||
} SFileGroup;
|
||||
|
||||
// TSDB file handle
|
||||
typedef struct {
|
||||
int maxFGroups;
|
||||
int numOfFGroups;
|
||||
pthread_rwlock_t fhlock;
|
||||
|
||||
SFileGroup *fGroup;
|
||||
int maxFGroups;
|
||||
int nFGroups;
|
||||
SFileGroup* pFGroup;
|
||||
} STsdbFileH;
|
||||
|
||||
#define TSDB_MIN_FILE_ID(fh) (fh)->fGroup[0].fileId
|
||||
#define TSDB_MAX_FILE_ID(fh) (fh)->fGroup[(fh)->numOfFGroups - 1].fileId
|
||||
|
||||
STsdbFileH *tsdbInitFileH(char *dataDir, STsdbCfg *pCfg);
|
||||
void tsdbCloseFileH(STsdbFileH *pFileH);
|
||||
int tsdbCreateFile(char *dataDir, int fileId, const char *suffix, SFile *pFile);
|
||||
SFileGroup *tsdbCreateFGroup(STsdbFileH *pFileH, char *dataDir, int fid, int maxTables);
|
||||
int tsdbOpenFile(SFile *pFile, int oflag);
|
||||
int tsdbCloseFile(SFile *pFile);
|
||||
SFileGroup *tsdbOpenFilesForCommit(STsdbFileH *pFileH, int fid);
|
||||
int tsdbRemoveFileGroup(STsdbFileH *pFile, int fid);
|
||||
int tsdbGetFileName(char *dataDir, int fileId, const char *suffix, char *fname);
|
||||
|
||||
#define TSDB_FGROUP_ITER_FORWARD TSDB_ORDER_ASC
|
||||
#define TSDB_FGROUP_ITER_BACKWARD TSDB_ORDER_DESC
|
||||
|
||||
typedef struct {
|
||||
int numOfFGroups;
|
||||
SFileGroup *base;
|
||||
|
@ -258,49 +168,49 @@ typedef struct {
|
|||
int direction;
|
||||
} SFileGroupIter;
|
||||
|
||||
void tsdbInitFileGroupIter(STsdbFileH *pFileH, SFileGroupIter *pIter, int direction);
|
||||
void tsdbSeekFileGroupIter(SFileGroupIter *pIter, int fid);
|
||||
SFileGroup *tsdbGetFileGroupNext(SFileGroupIter *pIter);
|
||||
// ------------------ tsdbMain.c
|
||||
typedef struct {
|
||||
int8_t state;
|
||||
|
||||
char* rootDir;
|
||||
STsdbCfg config;
|
||||
STsdbAppH appH;
|
||||
STsdbStat stat;
|
||||
STsdbMeta* tsdbMeta;
|
||||
STsdbBufPool* pPool;
|
||||
SMemTable* mem;
|
||||
SMemTable* imem;
|
||||
STsdbFileH* tsdbFileH;
|
||||
int commit;
|
||||
pthread_t commitThread;
|
||||
pthread_mutex_t mutex;
|
||||
bool repoLocked;
|
||||
} STsdbRepo;
|
||||
|
||||
// ------------------ tsdbRWHelper.c
|
||||
typedef struct {
|
||||
uint32_t len;
|
||||
uint32_t offset;
|
||||
uint32_t padding; // For padding purpose
|
||||
// uint32_t padding;
|
||||
uint32_t hasLast : 2;
|
||||
uint32_t numOfBlocks : 30;
|
||||
uint64_t uid;
|
||||
TSKEY maxKey;
|
||||
} SCompIdx; /* sizeof(SCompIdx) = 28 */
|
||||
} SCompIdx;
|
||||
|
||||
void *tsdbEncodeSCompIdx(void *buf, SCompIdx *pIdx);
|
||||
void *tsdbDecodeSCompIdx(void *buf, SCompIdx *pIdx);
|
||||
|
||||
/**
|
||||
* if numOfSubBlocks == 0, then the SCompBlock is a sub-block
|
||||
* if numOfSubBlocks >= 1, then the SCompBlock is a super-block
|
||||
* - if numOfSubBlocks == 1, then the SCompBlock refers to the data block, and offset/len refer to
|
||||
* the data block offset and length
|
||||
* - if numOfSubBlocks > 1, then the offset/len refer to the offset of the first sub-block in the
|
||||
* binary
|
||||
*/
|
||||
typedef struct {
|
||||
int64_t last : 1; // If the block in data file or last file
|
||||
int64_t offset : 63; // Offset of data block or sub-block index depending on numOfSubBlocks
|
||||
int32_t algorithm : 8; // Compression algorithm
|
||||
int32_t numOfRows : 24; // Number of total points
|
||||
int32_t sversion; // Schema version
|
||||
int32_t len; // Data block length or nothing
|
||||
int16_t numOfSubBlocks; // Number of sub-blocks;
|
||||
int64_t last : 1;
|
||||
int64_t offset : 63;
|
||||
int32_t algorithm : 8;
|
||||
int32_t numOfRows : 24;
|
||||
int32_t sversion;
|
||||
int32_t len;
|
||||
int16_t numOfSubBlocks;
|
||||
int16_t numOfCols;
|
||||
TSKEY keyFirst;
|
||||
TSKEY keyLast;
|
||||
} SCompBlock;
|
||||
|
||||
// Maximum number of sub-blocks a super-block can have
|
||||
#define TSDB_MAX_SUBBLOCKS 8
|
||||
#define IS_SUPER_BLOCK(pBlock) ((pBlock)->numOfSubBlocks >= 1)
|
||||
#define IS_SUB_BLOCK(pBlock) ((pBlock)->numOfSubBlocks == 0)
|
||||
|
||||
typedef struct {
|
||||
int32_t delimiter; // For recovery usage
|
||||
int32_t checksum; // TODO: decide if checksum logic in this file or make it one API
|
||||
|
@ -308,21 +218,9 @@ typedef struct {
|
|||
SCompBlock blocks[];
|
||||
} SCompInfo;
|
||||
|
||||
#define TSDB_COMPBLOCK_AT(pCompInfo, idx) ((pCompInfo)->blocks + (idx))
|
||||
#define TSDB_COMPBLOCK_GET_START_AND_SIZE(pCompInfo, pCompBlock, size) \
|
||||
do { \
|
||||
if (pCompBlock->numOfSubBlocks > 1) { \
|
||||
pCompBlock = pCompInfo->blocks + pCompBlock->offset; \
|
||||
size = pCompBlock->numOfSubBlocks; \
|
||||
} else { \
|
||||
size = 1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// TODO: take pre-calculation into account
|
||||
typedef struct {
|
||||
int16_t colId; // Column ID
|
||||
int16_t len; // Column length // TODO: int16_t is not enough
|
||||
int16_t colId;
|
||||
int16_t len;
|
||||
int32_t type : 8;
|
||||
int32_t offset : 24;
|
||||
int64_t sum;
|
||||
|
@ -334,7 +232,6 @@ typedef struct {
|
|||
char padding[2];
|
||||
} SCompCol;
|
||||
|
||||
// TODO: Take recover into account
|
||||
typedef struct {
|
||||
int32_t delimiter; // For recovery usage
|
||||
int32_t numOfCols; // For recovery usage
|
||||
|
@ -342,88 +239,10 @@ typedef struct {
|
|||
SCompCol cols[];
|
||||
} SCompData;
|
||||
|
||||
STsdbFileH *tsdbGetFile(TsdbRepoT *pRepo);
|
||||
|
||||
int tsdbCopyBlockDataInFile(SFile *pOutFile, SFile *pInFile, SCompInfo *pCompInfo, int idx, int isLast,
|
||||
SDataCols *pCols);
|
||||
SFileGroup *tsdbSearchFGroup(STsdbFileH *pFileH, int fid);
|
||||
void tsdbGetKeyRangeOfFileId(int32_t daysPerFile, int8_t precision, int32_t fileId, TSKEY *minKey, TSKEY *maxKey);
|
||||
|
||||
// TSDB repository definition
|
||||
typedef struct STsdbRepo {
|
||||
char *rootDir;
|
||||
// TSDB configuration
|
||||
STsdbCfg config;
|
||||
|
||||
STsdbAppH appH;
|
||||
|
||||
STsdbStat stat;
|
||||
|
||||
// The meter meta handle of this TSDB repository
|
||||
STsdbMeta *tsdbMeta;
|
||||
|
||||
// The cache Handle
|
||||
STsdbCache *tsdbCache;
|
||||
|
||||
// The TSDB file handle
|
||||
STsdbFileH *tsdbFileH;
|
||||
|
||||
// Disk tier handle for multi-tier storage
|
||||
void *diskTier;
|
||||
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
int commit;
|
||||
pthread_t commitThread;
|
||||
|
||||
// A limiter to monitor the resources used by tsdb
|
||||
void *limiter;
|
||||
|
||||
int8_t state;
|
||||
|
||||
} STsdbRepo;
|
||||
|
||||
typedef struct {
|
||||
int32_t totalLen;
|
||||
int32_t len;
|
||||
SDataRow row;
|
||||
} SSubmitBlkIter;
|
||||
|
||||
int tsdbInitSubmitBlkIter(SSubmitBlk *pBlock, SSubmitBlkIter *pIter);
|
||||
SDataRow tsdbGetSubmitBlkNext(SSubmitBlkIter *pIter);
|
||||
|
||||
#define TSDB_SUBMIT_MSG_HEAD_SIZE sizeof(SSubmitMsg)
|
||||
|
||||
// SSubmitMsg Iterator
|
||||
typedef struct {
|
||||
int32_t totalLen;
|
||||
int32_t len;
|
||||
SSubmitBlk *pBlock;
|
||||
} SSubmitMsgIter;
|
||||
|
||||
int tsdbInitSubmitMsgIter(SSubmitMsg *pMsg, SSubmitMsgIter *pIter);
|
||||
SSubmitBlk *tsdbGetSubmitMsgNext(SSubmitMsgIter *pIter);
|
||||
|
||||
int32_t tsdbTriggerCommit(TsdbRepoT *repo);
|
||||
int32_t tsdbLockRepo(TsdbRepoT *repo);
|
||||
int32_t tsdbUnLockRepo(TsdbRepoT *repo);
|
||||
|
||||
typedef enum { TSDB_WRITE_HELPER, TSDB_READ_HELPER } tsdb_rw_helper_t;
|
||||
|
||||
typedef struct {
|
||||
tsdb_rw_helper_t type; // helper type
|
||||
|
||||
int maxTables;
|
||||
int maxRowSize;
|
||||
int maxRows;
|
||||
int maxCols;
|
||||
int minRowsPerFileBlock;
|
||||
int maxRowsPerFileBlock;
|
||||
int8_t compress;
|
||||
} SHelperCfg;
|
||||
|
||||
typedef struct {
|
||||
int fid;
|
||||
int fid;
|
||||
TSKEY minKey;
|
||||
TSKEY maxKey;
|
||||
// For read/write purpose
|
||||
|
@ -442,82 +261,139 @@ typedef struct {
|
|||
} SHelperTable;
|
||||
|
||||
typedef struct {
|
||||
// Global configuration
|
||||
SHelperCfg config;
|
||||
|
||||
int8_t state;
|
||||
tsdb_rw_helper_t type;
|
||||
|
||||
STsdbRepo* pRepo;
|
||||
int8_t state;
|
||||
// For file set usage
|
||||
SHelperFile files;
|
||||
SCompIdx * pCompIdx;
|
||||
|
||||
SCompIdx* pCompIdx;
|
||||
// For table set usage
|
||||
SHelperTable tableInfo;
|
||||
SCompInfo * pCompInfo;
|
||||
SCompInfo* pCompInfo;
|
||||
bool hasOldLastBlock;
|
||||
|
||||
// For block set usage
|
||||
SCompData *pCompData;
|
||||
SDataCols *pDataCols[2];
|
||||
|
||||
void *pBuffer; // Buffer to hold the whole data block
|
||||
void *compBuffer; // Buffer for temperary compress/decompress purpose
|
||||
SCompData* pCompData;
|
||||
SDataCols* pDataCols[2];
|
||||
void* pBuffer; // Buffer to hold the whole data block
|
||||
void* compBuffer; // Buffer for temperary compress/decompress purpose
|
||||
} SRWHelper;
|
||||
|
||||
// --------- Helper state
|
||||
|
||||
// Operations
|
||||
// ------------------ tsdbMeta.c
|
||||
#define TABLE_TYPE(t) (t)->type
|
||||
#define TABLE_NAME(t) (t)->name
|
||||
#define TABLE_CHAR_NAME(t) TABLE_NAME(t)->data
|
||||
#define TABLE_UID(t) (t)->tableId.uid
|
||||
#define TABLE_TID(t) (t)->tableId.tid
|
||||
#define TABLE_SUID(t) (t)->suid
|
||||
#define TABLE_LASTKEY(t) (t)->lastKey
|
||||
|
||||
STsdbMeta* tsdbNewMeta(STsdbCfg* pCfg);
|
||||
void tsdbFreeMeta(STsdbMeta* pMeta);
|
||||
int tsdbOpenMeta(STsdbRepo* pRepo);
|
||||
int tsdbCloseMeta(STsdbRepo* pRepo);
|
||||
STSchema* tsdbGetTableSchema(STable* pTable);
|
||||
STable* tsdbGetTableByUid(STsdbMeta* pMeta, uint64_t uid);
|
||||
STSchema* tsdbGetTableSchemaByVersion(STable* pTable, int16_t version);
|
||||
STSchema* tsdbGetTableTagSchema(STable* pTable);
|
||||
int tsdbUpdateTable(STsdbRepo* pRepo, STable* pTable, STableCfg* pCfg);
|
||||
int tsdbWLockRepoMeta(STsdbRepo* pRepo);
|
||||
int tsdbRLockRepoMeta(STsdbRepo* pRepo);
|
||||
int tsdbUnlockRepoMeta(STsdbRepo* pRepo);
|
||||
void tsdbRefTable(STable* pTable);
|
||||
void tsdbUnRefTable(STable* pTable);
|
||||
|
||||
// ------------------ tsdbBuffer.c
|
||||
STsdbBufPool* tsdbNewBufPool();
|
||||
void tsdbFreeBufPool(STsdbBufPool* pBufPool);
|
||||
int tsdbOpenBufPool(STsdbRepo* pRepo);
|
||||
void tsdbCloseBufPool(STsdbRepo* pRepo);
|
||||
SListNode* tsdbAllocBufBlockFromPool(STsdbRepo* pRepo);
|
||||
|
||||
// ------------------ tsdbMemTable.c
|
||||
int tsdbInsertRowToMem(STsdbRepo* pRepo, SDataRow row, STable* pTable);
|
||||
int tsdbRefMemTable(STsdbRepo* pRepo, SMemTable* pMemTable);
|
||||
int tsdbUnRefMemTable(STsdbRepo* pRepo, SMemTable* pMemTable);
|
||||
int tsdbTakeMemSnapshot(STsdbRepo* pRepo, SMemTable** pMem, SMemTable** pIMem);
|
||||
void* tsdbAllocBytes(STsdbRepo* pRepo, int bytes);
|
||||
int tsdbAsyncCommit(STsdbRepo* pRepo);
|
||||
|
||||
// ------------------ tsdbFile.c
|
||||
#define TSDB_KEY_FILEID(key, daysPerFile, precision) ((key) / tsMsPerDay[(precision)] / (daysPerFile))
|
||||
#define TSDB_MAX_FILE(keep, daysPerFile) ((keep) / (daysPerFile) + 3)
|
||||
#define TSDB_MIN_FILE_ID(fh) (fh)->pFGroup[0].fileId
|
||||
#define TSDB_MAX_FILE_ID(fh) (fh)->pFGroup[(fh)->nFGroups - 1].fileId
|
||||
#define TSDB_IS_FILE_OPENED(f) ((f)->fd > 0)
|
||||
#define TSDB_FGROUP_ITER_FORWARD TSDB_ORDER_ASC
|
||||
#define TSDB_FGROUP_ITER_BACKWARD TSDB_ORDER_DESC
|
||||
|
||||
STsdbFileH* tsdbNewFileH(STsdbCfg* pCfg);
|
||||
void tsdbFreeFileH(STsdbFileH* pFileH);
|
||||
int tsdbOpenFileH(STsdbRepo* pRepo);
|
||||
void tsdbCloseFileH(STsdbRepo* pRepo);
|
||||
SFileGroup* tsdbCreateFGroupIfNeed(STsdbRepo* pRepo, char* dataDir, int fid, int maxTables);
|
||||
void tsdbInitFileGroupIter(STsdbFileH* pFileH, SFileGroupIter* pIter, int direction);
|
||||
void tsdbSeekFileGroupIter(SFileGroupIter* pIter, int fid);
|
||||
SFileGroup* tsdbGetFileGroupNext(SFileGroupIter* pIter);
|
||||
int tsdbOpenFile(SFile* pFile, int oflag);
|
||||
void tsdbCloseFile(SFile* pFile);
|
||||
int tsdbCreateFile(SFile* pFile, STsdbRepo* pRepo, int fid, int type);
|
||||
SFileGroup* tsdbSearchFGroup(STsdbFileH* pFileH, int fid, int flags);
|
||||
void tsdbFitRetention(STsdbRepo* pRepo);
|
||||
int tsdbUpdateFileHeader(SFile* pFile, uint32_t version);
|
||||
int tsdbEncodeSFileInfo(void** buf, const STsdbFileInfo* pInfo);
|
||||
void* tsdbDecodeSFileInfo(void* buf, STsdbFileInfo* pInfo);
|
||||
void tsdbRemoveFileGroup(STsdbRepo* pRepo, SFileGroup* pFGroup);
|
||||
|
||||
// ------------------ tsdbRWHelper.c
|
||||
#define TSDB_HELPER_CLEAR_STATE 0x0 // Clear state
|
||||
#define TSDB_HELPER_FILE_SET_AND_OPEN 0x1 // File is set
|
||||
#define TSDB_HELPER_IDX_LOAD 0x2 // SCompIdx part is loaded
|
||||
#define TSDB_HELPER_TABLE_SET 0x4 // Table is set
|
||||
#define TSDB_HELPER_INFO_LOAD 0x8 // SCompInfo part is loaded
|
||||
#define TSDB_HELPER_FILE_DATA_LOAD 0x10 // SCompData part is loaded
|
||||
|
||||
#define TSDB_HELPER_TYPE(h) ((h)->config.type)
|
||||
|
||||
#define helperSetState(h, s) (((h)->state) |= (s))
|
||||
#define helperClearState(h, s) ((h)->state &= (~(s)))
|
||||
#define helperHasState(h, s) ((((h)->state) & (s)) == (s))
|
||||
#define blockAtIdx(h, idx) ((h)->pCompInfo->blocks + idx)
|
||||
#define TSDB_MAX_SUBBLOCKS 8
|
||||
#define IS_SUB_BLOCK(pBlock) ((pBlock)->numOfSubBlocks == 0)
|
||||
#define helperType(h) (h)->type
|
||||
#define helperRepo(h) (h)->pRepo
|
||||
#define helperState(h) (h)->state
|
||||
|
||||
int tsdbInitReadHelper(SRWHelper *pHelper, STsdbRepo *pRepo);
|
||||
int tsdbInitWriteHelper(SRWHelper *pHelper, STsdbRepo *pRepo);
|
||||
void tsdbDestroyHelper(SRWHelper *pHelper);
|
||||
void tsdbResetHelper(SRWHelper *pHelper);
|
||||
int tsdbInitReadHelper(SRWHelper* pHelper, STsdbRepo* pRepo);
|
||||
int tsdbInitWriteHelper(SRWHelper* pHelper, STsdbRepo* pRepo);
|
||||
void tsdbDestroyHelper(SRWHelper* pHelper);
|
||||
void tsdbResetHelper(SRWHelper* pHelper);
|
||||
int tsdbSetAndOpenHelperFile(SRWHelper* pHelper, SFileGroup* pGroup);
|
||||
int tsdbCloseHelperFile(SRWHelper* pHelper, bool hasError);
|
||||
void tsdbSetHelperTable(SRWHelper* pHelper, STable* pTable, STsdbRepo* pRepo);
|
||||
int tsdbWriteDataBlock(SRWHelper* pHelper, SDataCols* pDataCols);
|
||||
int tsdbMoveLastBlockIfNeccessary(SRWHelper* pHelper);
|
||||
int tsdbWriteCompInfo(SRWHelper* pHelper);
|
||||
int tsdbWriteCompIdx(SRWHelper* pHelper);
|
||||
int tsdbLoadCompIdx(SRWHelper* pHelper, void* target);
|
||||
int tsdbLoadCompInfo(SRWHelper* pHelper, void* target);
|
||||
int tsdbLoadCompData(SRWHelper* phelper, SCompBlock* pcompblock, void* target);
|
||||
void tsdbGetDataStatis(SRWHelper* pHelper, SDataStatis* pStatis, int numOfCols);
|
||||
int tsdbLoadBlockDataCols(SRWHelper* pHelper, SDataCols* pDataCols, int blkIdx, int16_t* colIds, int numOfColIds);
|
||||
int tsdbLoadBlockData(SRWHelper* pHelper, SCompBlock* pCompBlock, SDataCols* target);
|
||||
|
||||
// --------- For set operations
|
||||
int tsdbSetAndOpenHelperFile(SRWHelper *pHelper, SFileGroup *pGroup);
|
||||
void tsdbSetHelperTable(SRWHelper *pHelper, STable *pTable, STsdbRepo *pRepo);
|
||||
int tsdbCloseHelperFile(SRWHelper *pHelper, bool hasError);
|
||||
// ------------------ tsdbMain.c
|
||||
#define REPO_ID(r) (r)->config.tsdbId
|
||||
#define IS_REPO_LOCKED(r) (r)->repoLocked
|
||||
#define TSDB_SUBMIT_MSG_HEAD_SIZE sizeof(SSubmitMsg)
|
||||
|
||||
// --------- For read operations
|
||||
int tsdbLoadCompIdx(SRWHelper *pHelper, void *target);
|
||||
int tsdbLoadCompInfo(SRWHelper *pHelper, void *target);
|
||||
int tsdbLoadCompData(SRWHelper *pHelper, SCompBlock *pCompBlock, void *target);
|
||||
int tsdbLoadBlockDataCols(SRWHelper *pHelper, SDataCols *pDataCols, int blkIdx, int16_t *colIds, int numOfColIds);
|
||||
int tsdbLoadBlockData(SRWHelper *pHelper, SCompBlock *pCompBlock, SDataCols *target);
|
||||
void tsdbGetDataStatis(SRWHelper *pHelper, SDataStatis *pStatis, int numOfCols);
|
||||
|
||||
// --------- For write operations
|
||||
int tsdbWriteDataBlock(SRWHelper *pHelper, SDataCols *pDataCols);
|
||||
int tsdbMoveLastBlockIfNeccessary(SRWHelper *pHelper);
|
||||
int tsdbWriteCompInfo(SRWHelper *pHelper);
|
||||
int tsdbWriteCompIdx(SRWHelper *pHelper);
|
||||
|
||||
// --------- Other functions need to further organize
|
||||
void tsdbFitRetention(STsdbRepo *pRepo);
|
||||
int tsdbAlterCacheTotalBlocks(STsdbRepo *pRepo, int totalBlocks);
|
||||
void tsdbAdjustCacheBlocks(STsdbCache *pCache);
|
||||
int32_t tsdbGetMetaFileName(char *rootDir, char *fname);
|
||||
int tsdbUpdateFileHeader(SFile *pFile, uint32_t version);
|
||||
int tsdbUpdateTable(STsdbMeta *pMeta, STable *pTable, STableCfg *pCfg);
|
||||
int tsdbRemoveTableFromIndex(STsdbMeta *pMeta, STable *pTable);
|
||||
int tsdbAddTableIntoIndex(STsdbMeta *pMeta, STable *pTable);
|
||||
STSchema *tsdbGetTableSchemaByVersion(STsdbMeta *pMeta, STable *pTable, int16_t version);
|
||||
STSchema *tsdbGetTableSchema(STsdbMeta *pMeta, STable *pTable);
|
||||
|
||||
#define DEFAULT_TAG_INDEX_COLUMN 0 // skip list built based on the first column of tags
|
||||
|
||||
int compFGroupKey(const void *key, const void *fgroup);
|
||||
char* tsdbGetMetaFileName(char* rootDir);
|
||||
void tsdbGetDataFileName(STsdbRepo* pRepo, int fid, int type, char* fname);
|
||||
int tsdbLockRepo(STsdbRepo* pRepo);
|
||||
int tsdbUnlockRepo(STsdbRepo* pRepo);
|
||||
char* tsdbGetDataDirName(char* rootDir);
|
||||
STsdbMeta* tsdbGetMeta(TSDB_REPO_T* pRepo);
|
||||
STsdbFileH* tsdbGetFile(TSDB_REPO_T* pRepo);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* 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 "tsdb.h"
|
||||
#include "tsdbMain.h"
|
||||
|
||||
#define POOL_IS_EMPTY(b) (listNEles((b)->bufBlockList) == 0)
|
||||
|
||||
static STsdbBufBlock *tsdbNewBufBlock(int bufBlockSize);
|
||||
static void tsdbFreeBufBlock(STsdbBufBlock *pBufBlock);
|
||||
|
||||
// ---------------- INTERNAL FUNCTIONS ----------------
|
||||
STsdbBufPool *tsdbNewBufPool() {
|
||||
STsdbBufPool *pBufPool = (STsdbBufPool *)calloc(1, sizeof(*pBufPool));
|
||||
if (pBufPool == NULL) {
|
||||
terrno = TSDB_CODE_TDB_OUT_OF_MEMORY;
|
||||
goto _err;
|
||||
}
|
||||
|
||||
int code = pthread_cond_init(&(pBufPool->poolNotEmpty), NULL);
|
||||
if (code != 0) {
|
||||
terrno = TAOS_SYSTEM_ERROR(code);
|
||||
goto _err;
|
||||
}
|
||||
|
||||
pBufPool->bufBlockList = tdListNew(sizeof(STsdbBufBlock *));
|
||||
if (pBufPool->bufBlockList == NULL) {
|
||||
terrno = TSDB_CODE_TDB_OUT_OF_MEMORY;
|
||||
goto _err;
|
||||
}
|
||||
|
||||
return pBufPool;
|
||||
|
||||
_err:
|
||||
tsdbFreeBufPool(pBufPool);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void tsdbFreeBufPool(STsdbBufPool *pBufPool) {
|
||||
if (pBufPool) {
|
||||
if (pBufPool->bufBlockList) {
|
||||
ASSERT(listNEles(pBufPool->bufBlockList) == 0);
|
||||
tdListFree(pBufPool->bufBlockList);
|
||||
}
|
||||
|
||||
pthread_cond_destroy(&pBufPool->poolNotEmpty);
|
||||
|
||||
free(pBufPool);
|
||||
}
|
||||
}
|
||||
|
||||
int tsdbOpenBufPool(STsdbRepo *pRepo) {
|
||||
STsdbCfg * pCfg = &(pRepo->config);
|
||||
STsdbBufPool *pPool = pRepo->pPool;
|
||||
|
||||
ASSERT(pPool != NULL);
|
||||
|
||||
pPool->bufBlockSize = pCfg->cacheBlockSize * 1024 * 1024; // MB
|
||||
pPool->tBufBlocks = pCfg->totalBlocks;
|
||||
pPool->nBufBlocks = 0;
|
||||
pPool->index = 0;
|
||||
|
||||
for (int i = 0; i < pCfg->totalBlocks; i++) {
|
||||
STsdbBufBlock *pBufBlock = tsdbNewBufBlock(pPool->bufBlockSize);
|
||||
if (pBufBlock == NULL) goto _err;
|
||||
|
||||
if (tdListAppend(pPool->bufBlockList, (void *)(&pBufBlock)) < 0) {
|
||||
tsdbFreeBufBlock(pBufBlock);
|
||||
terrno = TSDB_CODE_TDB_OUT_OF_MEMORY;
|
||||
goto _err;
|
||||
}
|
||||
|
||||
pPool->nBufBlocks++;
|
||||
}
|
||||
|
||||
tsdbTrace("vgId:%d buffer pool is opened! bufBlockSize:%d tBufBlocks:%d nBufBlocks:%d", REPO_ID(pRepo),
|
||||
pPool->bufBlockSize, pPool->tBufBlocks, pPool->nBufBlocks);
|
||||
|
||||
return 0;
|
||||
|
||||
_err:
|
||||
tsdbCloseBufPool(pRepo);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void tsdbCloseBufPool(STsdbRepo *pRepo) {
|
||||
if (pRepo == NULL) return;
|
||||
|
||||
STsdbBufPool * pBufPool = pRepo->pPool;
|
||||
STsdbBufBlock *pBufBlock = NULL;
|
||||
|
||||
if (pBufPool) {
|
||||
SListNode *pNode = NULL;
|
||||
while ((pNode = tdListPopHead(pBufPool->bufBlockList)) != NULL) {
|
||||
tdListNodeGetData(pBufPool->bufBlockList, pNode, (void *)(&pBufBlock));
|
||||
tsdbFreeBufBlock(pBufBlock);
|
||||
free(pNode);
|
||||
}
|
||||
}
|
||||
|
||||
tsdbTrace("vgId:%d buffer pool is closed", REPO_ID(pRepo));
|
||||
}
|
||||
|
||||
SListNode *tsdbAllocBufBlockFromPool(STsdbRepo *pRepo) {
|
||||
ASSERT(pRepo != NULL && pRepo->pPool != NULL);
|
||||
ASSERT(IS_REPO_LOCKED(pRepo));
|
||||
|
||||
STsdbBufPool *pBufPool = pRepo->pPool;
|
||||
|
||||
while (POOL_IS_EMPTY(pBufPool)) {
|
||||
pthread_cond_wait(&(pBufPool->poolNotEmpty), &(pRepo->mutex));
|
||||
}
|
||||
|
||||
SListNode * pNode = tdListPopHead(pBufPool->bufBlockList);
|
||||
STsdbBufBlock *pBufBlock = NULL;
|
||||
tdListNodeGetData(pBufPool->bufBlockList, pNode, (void *)(&pBufBlock));
|
||||
|
||||
pBufBlock->blockId = pBufPool->index++;
|
||||
pBufBlock->offset = 0;
|
||||
pBufBlock->remain = pBufPool->bufBlockSize;
|
||||
|
||||
tsdbTrace("vgId:%d buffer block is allocated, blockId:%" PRId64, REPO_ID(pRepo), pBufBlock->blockId);
|
||||
return pNode;
|
||||
}
|
||||
|
||||
// ---------------- LOCAL FUNCTIONS ----------------
|
||||
static STsdbBufBlock *tsdbNewBufBlock(int bufBlockSize) {
|
||||
STsdbBufBlock *pBufBlock = (STsdbBufBlock *)malloc(sizeof(*pBufBlock) + bufBlockSize);
|
||||
if (pBufBlock == NULL) {
|
||||
terrno = TSDB_CODE_TDB_OUT_OF_MEMORY;
|
||||
goto _err;
|
||||
}
|
||||
|
||||
pBufBlock->blockId = 0;
|
||||
pBufBlock->offset = 0;
|
||||
pBufBlock->remain = bufBlockSize;
|
||||
|
||||
return pBufBlock;
|
||||
|
||||
_err:
|
||||
tsdbFreeBufBlock(pBufBlock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void tsdbFreeBufBlock(STsdbBufBlock *pBufBlock) { tfree(pBufBlock); }
|
|
@ -1,207 +0,0 @@
|
|||
/*
|
||||
* 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 <stdlib.h>
|
||||
|
||||
#include "tsdb.h"
|
||||
#include "tsdbMain.h"
|
||||
|
||||
static int tsdbAllocBlockFromPool(STsdbCache *pCache);
|
||||
static void tsdbFreeBlockList(SList *list);
|
||||
static void tsdbFreeCacheMem(SCacheMem *mem);
|
||||
static int tsdbAddCacheBlockToPool(STsdbCache *pCache);
|
||||
|
||||
STsdbCache *tsdbInitCache(int cacheBlockSize, int totalBlocks, TsdbRepoT *pRepo) {
|
||||
STsdbCache *pCache = (STsdbCache *)calloc(1, sizeof(STsdbCache));
|
||||
if (pCache == NULL) return NULL;
|
||||
|
||||
if (cacheBlockSize < 0) cacheBlockSize = TSDB_DEFAULT_CACHE_BLOCK_SIZE;
|
||||
cacheBlockSize *= (1024 * 1024);
|
||||
|
||||
if (totalBlocks <= 1) totalBlocks = TSDB_DEFAULT_TOTAL_BLOCKS;
|
||||
|
||||
pCache->cacheBlockSize = cacheBlockSize;
|
||||
pCache->totalCacheBlocks = totalBlocks;
|
||||
pCache->pRepo = pRepo;
|
||||
|
||||
STsdbBufferPool *pPool = &(pCache->pool);
|
||||
pPool->index = 0;
|
||||
pPool->memPool = tdListNew(sizeof(STsdbCacheBlock *));
|
||||
if (pPool->memPool == NULL) goto _err;
|
||||
|
||||
for (int i = 0; i < totalBlocks; i++) {
|
||||
if (tsdbAddCacheBlockToPool(pCache) < 0) goto _err;
|
||||
}
|
||||
|
||||
pCache->mem = NULL;
|
||||
pCache->imem = NULL;
|
||||
|
||||
return pCache;
|
||||
|
||||
_err:
|
||||
tsdbFreeCache(pCache);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void tsdbFreeCache(STsdbCache *pCache) {
|
||||
tsdbFreeCacheMem(pCache->imem);
|
||||
tsdbFreeCacheMem(pCache->mem);
|
||||
tsdbFreeBlockList(pCache->pool.memPool);
|
||||
free(pCache);
|
||||
}
|
||||
|
||||
void *tsdbAllocFromCache(STsdbCache *pCache, int bytes, TSKEY key) {
|
||||
if (pCache == NULL) return NULL;
|
||||
if (bytes > pCache->cacheBlockSize) return NULL;
|
||||
|
||||
if (pCache->curBlock == NULL || pCache->curBlock->remain < bytes) {
|
||||
if (pCache->curBlock !=NULL && listNEles(pCache->mem->list) >= pCache->totalCacheBlocks/2) {
|
||||
tsdbTriggerCommit(pCache->pRepo);
|
||||
}
|
||||
|
||||
while (tsdbAllocBlockFromPool(pCache) < 0) {
|
||||
// TODO: deal with the error
|
||||
// printf("Failed to allocate from cache pool\n");
|
||||
}
|
||||
}
|
||||
|
||||
void *ptr = (void *)(pCache->curBlock->data + pCache->curBlock->offset);
|
||||
pCache->curBlock->offset += bytes;
|
||||
pCache->curBlock->remain -= bytes;
|
||||
memset(ptr, 0, bytes);
|
||||
if (key < pCache->mem->keyFirst) pCache->mem->keyFirst = key;
|
||||
if (key > pCache->mem->keyLast) pCache->mem->keyLast = key;
|
||||
pCache->mem->numOfRows++;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void tsdbFreeBlockList(SList *list) {
|
||||
SListNode * node = NULL;
|
||||
STsdbCacheBlock *pBlock = NULL;
|
||||
while ((node = tdListPopHead(list)) != NULL) {
|
||||
tdListNodeGetData(list, node, (void *)(&pBlock));
|
||||
free(pBlock);
|
||||
listNodeFree(node);
|
||||
}
|
||||
tdListFree(list);
|
||||
}
|
||||
|
||||
static void tsdbFreeCacheMem(SCacheMem *mem) {
|
||||
if (mem == NULL) return;
|
||||
SList *list = mem->list;
|
||||
tsdbFreeBlockList(list);
|
||||
free(mem);
|
||||
}
|
||||
|
||||
static int tsdbAllocBlockFromPool(STsdbCache *pCache) {
|
||||
STsdbBufferPool *pPool = &(pCache->pool);
|
||||
|
||||
tsdbLockRepo(pCache->pRepo);
|
||||
if (listNEles(pPool->memPool) == 0) {
|
||||
tsdbUnLockRepo(pCache->pRepo);
|
||||
return -1;
|
||||
}
|
||||
|
||||
SListNode *node = tdListPopHead(pPool->memPool);
|
||||
|
||||
STsdbCacheBlock *pBlock = NULL;
|
||||
tdListNodeGetData(pPool->memPool, node, (void *)(&pBlock));
|
||||
pBlock->blockId = pPool->index++;
|
||||
pBlock->offset = 0;
|
||||
pBlock->remain = pCache->cacheBlockSize;
|
||||
|
||||
if (pCache->mem == NULL) { // Create a new one
|
||||
pCache->mem = (SCacheMem *)malloc(sizeof(SCacheMem));
|
||||
if (pCache->mem == NULL) return -1;
|
||||
pCache->mem->keyFirst = INT64_MAX;
|
||||
pCache->mem->keyLast = 0;
|
||||
pCache->mem->numOfRows = 0;
|
||||
pCache->mem->list = tdListNew(sizeof(STsdbCacheBlock *));
|
||||
}
|
||||
|
||||
tdListAppendNode(pCache->mem->list, node);
|
||||
pCache->curBlock = pBlock;
|
||||
|
||||
tsdbUnLockRepo(pCache->pRepo);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsdbAlterCacheTotalBlocks(STsdbRepo *pRepo, int totalBlocks) {
|
||||
STsdbCache *pCache = pRepo->tsdbCache;
|
||||
int oldNumOfBlocks = pCache->totalCacheBlocks;
|
||||
|
||||
tsdbLockRepo((TsdbRepoT *)pRepo);
|
||||
|
||||
ASSERT(pCache->totalCacheBlocks != totalBlocks);
|
||||
|
||||
if (pCache->totalCacheBlocks < totalBlocks) {
|
||||
ASSERT(pCache->totalCacheBlocks == pCache->pool.numOfCacheBlocks);
|
||||
int blocksToAdd = pCache->totalCacheBlocks - totalBlocks;
|
||||
pCache->totalCacheBlocks = totalBlocks;
|
||||
for (int i = 0; i < blocksToAdd; i++) {
|
||||
if (tsdbAddCacheBlockToPool(pCache) < 0) {
|
||||
tsdbUnLockRepo((TsdbRepoT *)pRepo);
|
||||
tsdbError("tsdbId:%d, failed to add cache block to cache pool", pRepo->config.tsdbId);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pCache->totalCacheBlocks = totalBlocks;
|
||||
tsdbAdjustCacheBlocks(pCache);
|
||||
}
|
||||
pRepo->config.totalBlocks = totalBlocks;
|
||||
|
||||
tsdbUnLockRepo((TsdbRepoT *)pRepo);
|
||||
tsdbTrace("vgId:%d, tsdb total cache blocks changed from %d to %d", pRepo->config.tsdbId, oldNumOfBlocks, totalBlocks);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tsdbAddCacheBlockToPool(STsdbCache *pCache) {
|
||||
STsdbBufferPool *pPool = &pCache->pool;
|
||||
|
||||
STsdbCacheBlock *pBlock = malloc(sizeof(STsdbCacheBlock) + pCache->cacheBlockSize);
|
||||
if (pBlock == NULL) return -1;
|
||||
|
||||
pBlock->offset = 0;
|
||||
pBlock->remain = pCache->cacheBlockSize;
|
||||
tdListAppend(pPool->memPool, (void *)(&pBlock));
|
||||
pPool->numOfCacheBlocks++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tsdbRemoveCacheBlockFromPool(STsdbCache *pCache) {
|
||||
STsdbBufferPool *pPool = &pCache->pool;
|
||||
STsdbCacheBlock *pBlock = NULL;
|
||||
|
||||
ASSERT(pCache->totalCacheBlocks >= 0);
|
||||
|
||||
SListNode *node = tdListPopHead(pPool->memPool);
|
||||
if (node == NULL) return -1;
|
||||
|
||||
tdListNodeGetData(pPool->memPool, node, &pBlock);
|
||||
free(pBlock);
|
||||
listNodeFree(node);
|
||||
pPool->numOfCacheBlocks--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tsdbAdjustCacheBlocks(STsdbCache *pCache) {
|
||||
while (pCache->totalCacheBlocks < pCache->pool.numOfCacheBlocks) {
|
||||
if (tsdbRemoveCacheBlockFromPool(pCache) < 0) break;
|
||||
}
|
||||
}
|
|
@ -29,178 +29,172 @@
|
|||
#include "tutil.h"
|
||||
#include "ttime.h"
|
||||
|
||||
const char *tsdbFileSuffix[] = {
|
||||
".head", // TSDB_FILE_TYPE_HEAD
|
||||
".data", // TSDB_FILE_TYPE_DATA
|
||||
".last" // TSDB_FILE_TYPE_LAST
|
||||
};
|
||||
const char *tsdbFileSuffix[] = {".head", ".data", ".last", "", ".h", ".h"};
|
||||
|
||||
static int compFGroup(const void *arg1, const void *arg2);
|
||||
static int tsdbOpenFGroup(STsdbFileH *pFileH, char *dataDir, int fid);
|
||||
static int tsdbInitFile(SFile *pFile, STsdbRepo *pRepo, int fid, int type);
|
||||
static void tsdbDestroyFile(SFile *pFile);
|
||||
static int compFGroup(const void *arg1, const void *arg2);
|
||||
static int keyFGroupCompFunc(const void *key, const void *fgroup);
|
||||
|
||||
STsdbFileH *tsdbInitFileH(char *dataDir, STsdbCfg *pCfg) {
|
||||
STsdbFileH *pFileH = (STsdbFileH *)calloc(1, sizeof(STsdbFileH));
|
||||
if (pFileH == NULL) { // TODO: deal with ERROR here
|
||||
return NULL;
|
||||
// ---------------- INTERNAL FUNCTIONS ----------------
|
||||
STsdbFileH *tsdbNewFileH(STsdbCfg *pCfg) {
|
||||
STsdbFileH *pFileH = (STsdbFileH *)calloc(1, sizeof(*pFileH));
|
||||
if (pFileH == NULL) {
|
||||
terrno = TSDB_CODE_TDB_OUT_OF_MEMORY;
|
||||
goto _err;
|
||||
}
|
||||
|
||||
pFileH->maxFGroups = pCfg->keep / pCfg->daysPerFile + 3;
|
||||
int code = pthread_rwlock_init(&(pFileH->fhlock), NULL);
|
||||
if (code != 0) {
|
||||
tsdbError("vgId:%d failed to init file handle lock since %s", pCfg->tsdbId, strerror(code));
|
||||
terrno = TAOS_SYSTEM_ERROR(code);
|
||||
goto _err;
|
||||
}
|
||||
|
||||
pFileH->fGroup = (SFileGroup *)calloc(pFileH->maxFGroups, sizeof(SFileGroup));
|
||||
if (pFileH->fGroup == NULL) {
|
||||
pFileH->maxFGroups = TSDB_MAX_FILE(pCfg->keep, pCfg->daysPerFile);
|
||||
|
||||
pFileH->pFGroup = (SFileGroup *)calloc(pFileH->maxFGroups, sizeof(SFileGroup));
|
||||
if (pFileH->pFGroup == NULL) {
|
||||
terrno = TSDB_CODE_TDB_OUT_OF_MEMORY;
|
||||
goto _err;
|
||||
}
|
||||
|
||||
return pFileH;
|
||||
|
||||
_err:
|
||||
tsdbFreeFileH(pFileH);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void tsdbFreeFileH(STsdbFileH *pFileH) {
|
||||
if (pFileH) {
|
||||
pthread_rwlock_destroy(&pFileH->fhlock);
|
||||
tfree(pFileH->pFGroup);
|
||||
free(pFileH);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int tsdbOpenFileH(STsdbRepo *pRepo) {
|
||||
ASSERT(pRepo != NULL && pRepo->tsdbFileH != NULL);
|
||||
|
||||
char *tDataDir = NULL;
|
||||
DIR * dir = NULL;
|
||||
int fid = 0;
|
||||
int vid = 0;
|
||||
|
||||
SFileGroup fileGroup = {0};
|
||||
STsdbFileH *pFileH = pRepo->tsdbFileH;
|
||||
|
||||
tDataDir = tsdbGetDataDirName(pRepo->rootDir);
|
||||
if (tDataDir == NULL) {
|
||||
terrno = TSDB_CODE_TDB_OUT_OF_MEMORY;
|
||||
goto _err;
|
||||
}
|
||||
|
||||
DIR *dir = opendir(dataDir);
|
||||
dir = opendir(tDataDir);
|
||||
if (dir == NULL) {
|
||||
free(pFileH);
|
||||
return NULL;
|
||||
tsdbError("vgId:%d failed to open directory %s since %s", REPO_ID(pRepo), tDataDir, strerror(errno));
|
||||
terrno = TAOS_SYSTEM_ERROR(errno);
|
||||
goto _err;
|
||||
}
|
||||
|
||||
struct dirent *dp = NULL;
|
||||
while ((dp = readdir(dir)) != NULL) {
|
||||
if (strncmp(dp->d_name, ".", 1) == 0 || strncmp(dp->d_name, "..", 1) == 0) continue;
|
||||
int fid = 0;
|
||||
sscanf(dp->d_name, "f%d", &fid);
|
||||
if (tsdbOpenFGroup(pFileH, dataDir, fid) < 0) {
|
||||
break;
|
||||
// TODO
|
||||
if (strncmp(dp->d_name, ".", 1) == 0 || strncmp(dp->d_name, "..", 2) == 0) continue;
|
||||
sscanf(dp->d_name, "v%df%d", &vid, &fid);
|
||||
|
||||
if (tsdbSearchFGroup(pRepo->tsdbFileH, fid, TD_EQ) != NULL) continue;
|
||||
|
||||
memset((void *)(&fileGroup), 0, sizeof(SFileGroup));
|
||||
fileGroup.fileId = fid;
|
||||
for (int type = TSDB_FILE_TYPE_HEAD; type < TSDB_FILE_TYPE_MAX; type++) {
|
||||
if (tsdbInitFile(&fileGroup.files[type], pRepo, fid, type) < 0) {
|
||||
tsdbError("vgId:%d failed to init file fid %d type %d", REPO_ID(pRepo), fid, type);
|
||||
goto _err;
|
||||
}
|
||||
}
|
||||
|
||||
tsdbTrace("vgId:%d file group %d init", REPO_ID(pRepo), fid);
|
||||
|
||||
pFileH->pFGroup[pFileH->nFGroups++] = fileGroup;
|
||||
qsort((void *)(pFileH->pFGroup), pFileH->nFGroups, sizeof(SFileGroup), compFGroup);
|
||||
}
|
||||
|
||||
tfree(tDataDir);
|
||||
closedir(dir);
|
||||
return 0;
|
||||
|
||||
_err:
|
||||
for (int type = TSDB_FILE_TYPE_HEAD; type < TSDB_FILE_TYPE_MAX; type++) tsdbDestroyFile(&fileGroup.files[type]);
|
||||
|
||||
tfree(tDataDir);
|
||||
if (dir != NULL) closedir(dir);
|
||||
tsdbCloseFileH(pRepo);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void tsdbCloseFileH(STsdbRepo *pRepo) {
|
||||
STsdbFileH *pFileH = pRepo->tsdbFileH;
|
||||
|
||||
for (int i = 0; i < pFileH->nFGroups; i++) {
|
||||
SFileGroup *pFGroup = pFileH->pFGroup + i;
|
||||
for (int type = TSDB_FILE_TYPE_HEAD; type < TSDB_FILE_TYPE_MAX; type++) {
|
||||
tsdbDestroyFile(&pFGroup->files[type]);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
return pFileH;
|
||||
}
|
||||
|
||||
void tsdbCloseFileH(STsdbFileH *pFileH) {
|
||||
if (pFileH) {
|
||||
tfree(pFileH->fGroup);
|
||||
free(pFileH);
|
||||
}
|
||||
}
|
||||
SFileGroup *tsdbCreateFGroupIfNeed(STsdbRepo *pRepo, char *dataDir, int fid, int maxTables) {
|
||||
STsdbFileH *pFileH = pRepo->tsdbFileH;
|
||||
|
||||
static int tsdbInitFile(char *dataDir, int fid, const char *suffix, SFile *pFile) {
|
||||
uint32_t version;
|
||||
char buf[512] = "\0";
|
||||
|
||||
tsdbGetFileName(dataDir, fid, suffix, pFile->fname);
|
||||
if (access(pFile->fname, F_OK|R_OK|W_OK) < 0) return -1;
|
||||
pFile->fd = -1;
|
||||
if (tsdbOpenFile(pFile, O_RDONLY) < 0) return -1;
|
||||
|
||||
if (tread(pFile->fd, buf, TSDB_FILE_HEAD_SIZE) < TSDB_FILE_HEAD_SIZE) return -1;
|
||||
if (!taosCheckChecksumWhole((uint8_t *)buf, TSDB_FILE_HEAD_SIZE)) return -1;
|
||||
|
||||
void *pBuf = buf;
|
||||
pBuf = taosDecodeFixedU32(pBuf, &version);
|
||||
pBuf = tsdbDecodeSFileInfo(pBuf, &(pFile->info));
|
||||
|
||||
tsdbCloseFile(pFile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tsdbOpenFGroup(STsdbFileH *pFileH, char *dataDir, int fid) {
|
||||
if (tsdbSearchFGroup(pFileH, fid) != NULL) return 0;
|
||||
|
||||
SFileGroup fGroup = {0};
|
||||
fGroup.fileId = fid;
|
||||
|
||||
for (int type = TSDB_FILE_TYPE_HEAD; type < TSDB_FILE_TYPE_MAX; type++) {
|
||||
if (tsdbInitFile(dataDir, fid, tsdbFileSuffix[type], &fGroup.files[type]) < 0) return -1;
|
||||
}
|
||||
pFileH->fGroup[pFileH->numOfFGroups++] = fGroup;
|
||||
qsort((void *)(pFileH->fGroup), pFileH->numOfFGroups, sizeof(SFileGroup), compFGroup);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the file group if the file group not exists.
|
||||
*
|
||||
* @return A pointer to
|
||||
*/
|
||||
SFileGroup *tsdbCreateFGroup(STsdbFileH *pFileH, char *dataDir, int fid, int maxTables) {
|
||||
if (pFileH->numOfFGroups >= pFileH->maxFGroups) return NULL;
|
||||
if (pFileH->nFGroups >= pFileH->maxFGroups) return NULL;
|
||||
|
||||
SFileGroup fGroup;
|
||||
SFileGroup *pFGroup = &fGroup;
|
||||
|
||||
SFileGroup *pGroup = tsdbSearchFGroup(pFileH, fid);
|
||||
SFileGroup *pGroup = tsdbSearchFGroup(pFileH, fid, TD_EQ);
|
||||
if (pGroup == NULL) { // if not exists, create one
|
||||
pFGroup->fileId = fid;
|
||||
for (int type = TSDB_FILE_TYPE_HEAD; type < TSDB_FILE_TYPE_MAX; type++) {
|
||||
if (tsdbCreateFile(dataDir, fid, tsdbFileSuffix[type], &(pFGroup->files[type])) < 0)
|
||||
if (tsdbCreateFile(&pFGroup->files[type], pRepo, fid, type) < 0)
|
||||
goto _err;
|
||||
}
|
||||
|
||||
pFileH->fGroup[pFileH->numOfFGroups++] = fGroup;
|
||||
qsort((void *)(pFileH->fGroup), pFileH->numOfFGroups, sizeof(SFileGroup), compFGroup);
|
||||
return tsdbSearchFGroup(pFileH, fid);
|
||||
pFileH->pFGroup[pFileH->nFGroups++] = fGroup;
|
||||
qsort((void *)(pFileH->pFGroup), pFileH->nFGroups, sizeof(SFileGroup), compFGroup);
|
||||
return tsdbSearchFGroup(pFileH, fid, TD_EQ);
|
||||
}
|
||||
|
||||
return pGroup;
|
||||
|
||||
_err:
|
||||
// TODO: deal with the err here
|
||||
for (int type = TSDB_FILE_TYPE_HEAD; type < TSDB_FILE_TYPE_MAX; type++) tsdbDestroyFile(&pGroup->files[type]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int tsdbRemoveFileGroup(STsdbFileH *pFileH, int fid) {
|
||||
SFileGroup *pGroup =
|
||||
bsearch((void *)&fid, (void *)(pFileH->fGroup), pFileH->numOfFGroups, sizeof(SFileGroup), compFGroupKey);
|
||||
if (pGroup == NULL) return -1;
|
||||
|
||||
// Remove from disk
|
||||
for (int type = TSDB_FILE_TYPE_HEAD; type < TSDB_FILE_TYPE_MAX; type++) {
|
||||
remove(pGroup->files[type].fname);
|
||||
}
|
||||
|
||||
// Adjust the memory
|
||||
int filesBehind = pFileH->numOfFGroups - (((char *)pGroup - (char *)(pFileH->fGroup)) / sizeof(SFileGroup) + 1);
|
||||
if (filesBehind > 0) {
|
||||
memmove((void *)pGroup, (void *)((char *)pGroup + sizeof(SFileGroup)), sizeof(SFileGroup) * filesBehind);
|
||||
}
|
||||
pFileH->numOfFGroups--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tsdbInitFileGroupIter(STsdbFileH *pFileH, SFileGroupIter *pIter, int direction) {
|
||||
void tsdbInitFileGroupIter(STsdbFileH *pFileH, SFileGroupIter *pIter, int direction) { // TODO
|
||||
pIter->direction = direction;
|
||||
pIter->base = pFileH->fGroup;
|
||||
pIter->numOfFGroups = pFileH->numOfFGroups;
|
||||
if (pFileH->numOfFGroups == 0){
|
||||
pIter->base = pFileH->pFGroup;
|
||||
pIter->numOfFGroups = pFileH->nFGroups;
|
||||
if (pFileH->nFGroups == 0) {
|
||||
pIter->pFileGroup = NULL;
|
||||
} else {
|
||||
if (direction == TSDB_FGROUP_ITER_FORWARD) {
|
||||
pIter->pFileGroup = pFileH->fGroup;
|
||||
pIter->pFileGroup = pFileH->pFGroup;
|
||||
} else {
|
||||
pIter->pFileGroup = pFileH->fGroup + pFileH->numOfFGroups - 1;
|
||||
pIter->pFileGroup = pFileH->pFGroup + pFileH->nFGroups - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tsdbFitRetention(STsdbRepo *pRepo) {
|
||||
STsdbFileH *pFileH = pRepo->tsdbFileH;
|
||||
SFileGroup *pGroup = pFileH->fGroup;
|
||||
|
||||
int mfid =
|
||||
tsdbGetKeyFileId(taosGetTimestamp(pRepo->config.precision), pRepo->config.daysPerFile, pRepo->config.precision) - pFileH->maxFGroups + 3;
|
||||
|
||||
while (pFileH->numOfFGroups > 0 && pGroup[0].fileId < mfid) {
|
||||
tsdbRemoveFileGroup(pFileH, pGroup[0].fileId);
|
||||
}
|
||||
}
|
||||
|
||||
void tsdbSeekFileGroupIter(SFileGroupIter *pIter, int fid) {
|
||||
void tsdbSeekFileGroupIter(SFileGroupIter *pIter, int fid) { // TODO
|
||||
if (pIter->numOfFGroups == 0) {
|
||||
assert(pIter->pFileGroup == NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
int flags = (pIter->direction == TSDB_FGROUP_ITER_FORWARD) ? TD_GE : TD_LE;
|
||||
void *ptr = taosbsearch(&fid, pIter->base, pIter->numOfFGroups, sizeof(SFileGroup), compFGroupKey, flags);
|
||||
|
||||
int flags = (pIter->direction == TSDB_FGROUP_ITER_FORWARD) ? TD_GE : TD_LE;
|
||||
void *ptr = taosbsearch(&fid, pIter->base, pIter->numOfFGroups, sizeof(SFileGroup), keyFGroupCompFunc, flags);
|
||||
if (ptr == NULL) {
|
||||
pIter->pFileGroup = NULL;
|
||||
} else {
|
||||
|
@ -208,7 +202,7 @@ void tsdbSeekFileGroupIter(SFileGroupIter *pIter, int fid) {
|
|||
}
|
||||
}
|
||||
|
||||
SFileGroup *tsdbGetFileGroupNext(SFileGroupIter *pIter) {
|
||||
SFileGroup *tsdbGetFileGroupNext(SFileGroupIter *pIter) {//TODO
|
||||
SFileGroup *ret = pIter->pFileGroup;
|
||||
if (ret == NULL) return NULL;
|
||||
|
||||
|
@ -228,123 +222,40 @@ SFileGroup *tsdbGetFileGroupNext(SFileGroupIter *pIter) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
// int tsdbLoadDataBlock(SFile *pFile, SCompBlock *pStartBlock, int numOfBlocks, SDataCols *pCols, SCompData *pCompData) {
|
||||
// SCompBlock *pBlock = pStartBlock;
|
||||
// for (int i = 0; i < numOfBlocks; i++) {
|
||||
// if (tsdbLoadCompCols(pFile, pBlock, (void *)pCompData) < 0) return -1;
|
||||
// pCols->numOfRows += (pCompData->cols[0].len / 8);
|
||||
// for (int iCol = 0; iCol < pBlock->numOfCols; iCol++) {
|
||||
// SCompCol *pCompCol = &(pCompData->cols[iCol]);
|
||||
// // pCols->numOfRows += pBlock->numOfRows;
|
||||
// int k = 0;
|
||||
// for (; k < pCols->numOfCols; k++) {
|
||||
// if (pCompCol->colId == pCols->cols[k].colId) break;
|
||||
// }
|
||||
|
||||
// if (tsdbLoadColData(pFile, pCompCol, pBlock->offset,
|
||||
// (void *)((char *)(pCols->cols[k].pData) + pCols->cols[k].len)) < 0)
|
||||
// return -1;
|
||||
// }
|
||||
// pStartBlock++;
|
||||
// }
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
int tsdbCopyBlockDataInFile(SFile *pOutFile, SFile *pInFile, SCompInfo *pCompInfo, int idx, int isLast, SDataCols *pCols) {
|
||||
SCompBlock *pSuperBlock = TSDB_COMPBLOCK_AT(pCompInfo, idx);
|
||||
SCompBlock *pStartBlock = NULL;
|
||||
SCompBlock *pBlock = NULL;
|
||||
int numOfBlocks = pSuperBlock->numOfSubBlocks;
|
||||
|
||||
if (numOfBlocks == 1)
|
||||
pStartBlock = pSuperBlock;
|
||||
else
|
||||
pStartBlock = TSDB_COMPBLOCK_AT(pCompInfo, pSuperBlock->offset);
|
||||
|
||||
int maxNumOfCols = 0;
|
||||
pBlock = pStartBlock;
|
||||
for (int i = 0; i < numOfBlocks; i++) {
|
||||
if (pBlock->numOfCols > maxNumOfCols) maxNumOfCols = pBlock->numOfCols;
|
||||
pBlock++;
|
||||
}
|
||||
|
||||
SCompData *pCompData = (SCompData *)malloc(sizeof(SCompData) + sizeof(SCompCol) * maxNumOfCols);
|
||||
if (pCompData == NULL) return -1;
|
||||
|
||||
// Load data from the block
|
||||
// if (tsdbLoadDataBlock(pOutFile, pStartBlock, numOfBlocks, pCols, pCompData));
|
||||
|
||||
// Write data block to the file
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
||||
if (pCompData) free(pCompData);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int compFGroupKey(const void *key, const void *fgroup) {
|
||||
int fid = *(int *)key;
|
||||
SFileGroup *pFGroup = (SFileGroup *)fgroup;
|
||||
if (fid == pFGroup->fileId) {
|
||||
return 0;
|
||||
} else {
|
||||
return fid > pFGroup->fileId? 1:-1;
|
||||
}
|
||||
}
|
||||
|
||||
static int compFGroup(const void *arg1, const void *arg2) {
|
||||
return ((SFileGroup *)arg1)->fileId - ((SFileGroup *)arg2)->fileId;
|
||||
}
|
||||
|
||||
int tsdbGetFileName(char *dataDir, int fileId, const char *suffix, char *fname) {
|
||||
if (dataDir == NULL || fname == NULL) return -1;
|
||||
|
||||
sprintf(fname, "%s/f%d%s", dataDir, fileId, suffix);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsdbOpenFile(SFile *pFile, int oflag) { // TODO: change the function
|
||||
if (TSDB_IS_FILE_OPENED(pFile)) return -1;
|
||||
int tsdbOpenFile(SFile *pFile, int oflag) {
|
||||
ASSERT(!TSDB_IS_FILE_OPENED(pFile));
|
||||
|
||||
pFile->fd = open(pFile->fname, oflag, 0755);
|
||||
if (pFile->fd < 0) return -1;
|
||||
if (pFile->fd < 0) {
|
||||
tsdbError("failed to open file %s since %s", pFile->fname, strerror(errno));
|
||||
terrno = TAOS_SYSTEM_ERROR(errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsdbCloseFile(SFile *pFile) {
|
||||
int ret = close(pFile->fd);
|
||||
pFile->fd = -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
SFileGroup * tsdbOpenFilesForCommit(STsdbFileH *pFileH, int fid) {
|
||||
SFileGroup *pGroup = tsdbSearchFGroup(pFileH, fid);
|
||||
if (pGroup == NULL) return NULL;
|
||||
|
||||
for (int type = TSDB_FILE_TYPE_HEAD; type < TSDB_FILE_TYPE_MAX; type++) {
|
||||
tsdbOpenFile(&(pGroup->files[type]), O_RDWR);
|
||||
void tsdbCloseFile(SFile *pFile) {
|
||||
if (TSDB_IS_FILE_OPENED(pFile)) {
|
||||
close(pFile->fd);
|
||||
pFile->fd = -1;
|
||||
}
|
||||
return pGroup;
|
||||
}
|
||||
|
||||
int tsdbCreateFile(char *dataDir, int fileId, const char *suffix, SFile *pFile) {
|
||||
int tsdbCreateFile(SFile *pFile, STsdbRepo *pRepo, int fid, int type) {
|
||||
memset((void *)pFile, 0, sizeof(SFile));
|
||||
pFile->fd = -1;
|
||||
|
||||
tsdbGetFileName(dataDir, fileId, suffix, pFile->fname);
|
||||
|
||||
tsdbGetDataFileName(pRepo, fid, type, pFile->fname);
|
||||
|
||||
if (access(pFile->fname, F_OK) == 0) {
|
||||
// File already exists
|
||||
return -1;
|
||||
tsdbError("vgId:%d file %s already exists", REPO_ID(pRepo), pFile->fname);
|
||||
terrno = TSDB_CODE_TDB_FILE_ALREADY_EXISTS;
|
||||
goto _err;
|
||||
}
|
||||
|
||||
if (tsdbOpenFile(pFile, O_RDWR | O_CREAT) < 0) {
|
||||
// TODO: deal with the ERROR here
|
||||
return -1;
|
||||
goto _err;
|
||||
}
|
||||
|
||||
pFile->info.size = TSDB_FILE_HEAD_SIZE;
|
||||
|
@ -357,18 +268,156 @@ int tsdbCreateFile(char *dataDir, int fileId, const char *suffix, SFile *pFile)
|
|||
tsdbCloseFile(pFile);
|
||||
|
||||
return 0;
|
||||
|
||||
_err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void tsdbGetKeyRangeOfFileId(int32_t daysPerFile, int8_t precision, int32_t fileId, TSKEY *minKey,
|
||||
TSKEY *maxKey) {
|
||||
*minKey = fileId * daysPerFile * tsMsPerDay[precision];
|
||||
*maxKey = *minKey + daysPerFile * tsMsPerDay[precision] - 1;
|
||||
}
|
||||
|
||||
SFileGroup *tsdbSearchFGroup(STsdbFileH *pFileH, int fid) {
|
||||
if (pFileH->numOfFGroups == 0 || fid < pFileH->fGroup[0].fileId || fid > pFileH->fGroup[pFileH->numOfFGroups - 1].fileId)
|
||||
return NULL;
|
||||
void *ptr = bsearch((void *)&fid, (void *)(pFileH->fGroup), pFileH->numOfFGroups, sizeof(SFileGroup), compFGroupKey);
|
||||
SFileGroup *tsdbSearchFGroup(STsdbFileH *pFileH, int fid, int flags) {
|
||||
void *ptr =
|
||||
taosbsearch((void *)(&fid), (void *)(pFileH->pFGroup), pFileH->nFGroups, sizeof(SFileGroup), keyFGroupCompFunc, flags);
|
||||
if (ptr == NULL) return NULL;
|
||||
return (SFileGroup *)ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void tsdbFitRetention(STsdbRepo *pRepo) {
|
||||
STsdbCfg *pCfg = &(pRepo->config);
|
||||
STsdbFileH *pFileH = pRepo->tsdbFileH;
|
||||
SFileGroup *pGroup = pFileH->pFGroup;
|
||||
|
||||
int mfid = TSDB_KEY_FILEID(taosGetTimestamp(pCfg->precision), pCfg->daysPerFile, pCfg->precision) -
|
||||
TSDB_MAX_FILE(pCfg->keep, pCfg->daysPerFile);
|
||||
|
||||
pthread_rwlock_wrlock(&(pFileH->fhlock));
|
||||
|
||||
while (pFileH->nFGroups > 0 && pGroup[0].fileId < mfid) {
|
||||
tsdbRemoveFileGroup(pRepo, pGroup);
|
||||
}
|
||||
|
||||
pthread_rwlock_unlock(&(pFileH->fhlock));
|
||||
}
|
||||
|
||||
int tsdbUpdateFileHeader(SFile *pFile, uint32_t version) {
|
||||
char buf[TSDB_FILE_HEAD_SIZE] = "\0";
|
||||
|
||||
void *pBuf = (void *)buf;
|
||||
taosEncodeFixedU32((void *)(&pBuf), version);
|
||||
tsdbEncodeSFileInfo((void *)(&pBuf), &(pFile->info));
|
||||
|
||||
taosCalcChecksumAppend(0, (uint8_t *)buf, TSDB_FILE_HEAD_SIZE);
|
||||
|
||||
if (lseek(pFile->fd, 0, SEEK_SET) < 0) {
|
||||
tsdbError("failed to lseek file %s since %s", pFile->fname, strerror(errno));
|
||||
terrno = TAOS_SYSTEM_ERROR(errno);
|
||||
return -1;
|
||||
}
|
||||
if (twrite(pFile->fd, (void *)buf, TSDB_FILE_HEAD_SIZE) < TSDB_FILE_HEAD_SIZE) {
|
||||
tsdbError("failed to write %d bytes to file %s since %s", TSDB_FILE_HEAD_SIZE, pFile->fname, strerror(errno));
|
||||
terrno = TAOS_SYSTEM_ERROR(errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsdbEncodeSFileInfo(void **buf, const STsdbFileInfo *pInfo) {
|
||||
int tlen = 0;
|
||||
tlen += taosEncodeFixedU32(buf, pInfo->offset);
|
||||
tlen += taosEncodeFixedU32(buf, pInfo->len);
|
||||
tlen += taosEncodeFixedU64(buf, pInfo->size);
|
||||
tlen += taosEncodeFixedU64(buf, pInfo->tombSize);
|
||||
tlen += taosEncodeFixedU32(buf, pInfo->totalBlocks);
|
||||
tlen += taosEncodeFixedU32(buf, pInfo->totalSubBlocks);
|
||||
|
||||
return tlen;
|
||||
}
|
||||
|
||||
void *tsdbDecodeSFileInfo(void *buf, STsdbFileInfo *pInfo) {
|
||||
buf = taosDecodeFixedU32(buf, &(pInfo->offset));
|
||||
buf = taosDecodeFixedU32(buf, &(pInfo->len));
|
||||
buf = taosDecodeFixedU64(buf, &(pInfo->size));
|
||||
buf = taosDecodeFixedU64(buf, &(pInfo->tombSize));
|
||||
buf = taosDecodeFixedU32(buf, &(pInfo->totalBlocks));
|
||||
buf = taosDecodeFixedU32(buf, &(pInfo->totalSubBlocks));
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void tsdbRemoveFileGroup(STsdbRepo *pRepo, SFileGroup *pFGroup) {
|
||||
ASSERT(pFGroup != NULL);
|
||||
STsdbFileH *pFileH = pRepo->tsdbFileH;
|
||||
|
||||
SFileGroup fileGroup = *pFGroup;
|
||||
|
||||
int nFilesLeft = pFileH->nFGroups - (POINTER_DISTANCE(pFGroup, pFileH->pFGroup) / sizeof(SFileGroup) + 1);
|
||||
if (nFilesLeft > 0) {
|
||||
memmove((void *)pFGroup, POINTER_SHIFT(pFGroup, sizeof(SFileGroup)), sizeof(SFileGroup) * nFilesLeft);
|
||||
}
|
||||
|
||||
pFileH->nFGroups--;
|
||||
ASSERT(pFileH->nFGroups >= 0);
|
||||
|
||||
for (int type = TSDB_FILE_TYPE_HEAD; type < TSDB_FILE_TYPE_MAX; type++) {
|
||||
remove(fileGroup.files[type].fname);
|
||||
tsdbDestroyFile(&fileGroup.files[type]);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------- LOCAL FUNCTIONS ----------------
|
||||
static int tsdbInitFile(SFile *pFile, STsdbRepo *pRepo, int fid, int type) {
|
||||
uint32_t version;
|
||||
char buf[512] = "\0";
|
||||
|
||||
tsdbGetDataFileName(pRepo, fid, type, pFile->fname);
|
||||
|
||||
pFile->fd = -1;
|
||||
if (tsdbOpenFile(pFile, O_RDONLY) < 0) goto _err;
|
||||
|
||||
if (tread(pFile->fd, buf, TSDB_FILE_HEAD_SIZE) < TSDB_FILE_HEAD_SIZE) {
|
||||
tsdbError("vgId:%d failed to read %d bytes from file %s since %s", REPO_ID(pRepo), TSDB_FILE_HEAD_SIZE,
|
||||
pFile->fname, strerror(errno));
|
||||
terrno = TAOS_SYSTEM_ERROR(errno);
|
||||
goto _err;
|
||||
}
|
||||
if (!taosCheckChecksumWhole((uint8_t *)buf, TSDB_FILE_HEAD_SIZE)) {
|
||||
tsdbError("vgId:%d file %s head part is corrupted", REPO_ID(pRepo), pFile->fname);
|
||||
terrno = TSDB_CODE_TDB_FILE_CORRUPTED;
|
||||
goto _err;
|
||||
}
|
||||
|
||||
void *pBuf = buf;
|
||||
pBuf = taosDecodeFixedU32(pBuf, &version);
|
||||
pBuf = tsdbDecodeSFileInfo(pBuf, &(pFile->info));
|
||||
|
||||
tsdbCloseFile(pFile);
|
||||
|
||||
return 0;
|
||||
_err:
|
||||
tsdbDestroyFile(pFile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void tsdbDestroyFile(SFile *pFile) { tsdbCloseFile(pFile); }
|
||||
|
||||
static int compFGroup(const void *arg1, const void *arg2) {
|
||||
int val1 = ((SFileGroup *)arg1)->fileId;
|
||||
int val2 = ((SFileGroup *)arg2)->fileId;
|
||||
|
||||
if (val1 < val2) {
|
||||
return -1;
|
||||
} else if (val1 > val2) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int keyFGroupCompFunc(const void *key, const void *fgroup) {
|
||||
int fid = *(int *)key;
|
||||
SFileGroup *pFGroup = (SFileGroup *)fgroup;
|
||||
if (fid == pFGroup->fileId) {
|
||||
return 0;
|
||||
} else {
|
||||
return fid > pFGroup->fileId ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,695 @@
|
|||
/*
|
||||
* 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 "tsdb.h"
|
||||
#include "tsdbMain.h"
|
||||
|
||||
#define TSDB_DATA_SKIPLIST_LEVEL 5
|
||||
|
||||
typedef struct {
|
||||
STable * pTable;
|
||||
SSkipListIterator *pIter;
|
||||
} SCommitIter;
|
||||
|
||||
static FORCE_INLINE STsdbBufBlock *tsdbGetCurrBufBlock(STsdbRepo *pRepo);
|
||||
|
||||
static void tsdbFreeBytes(STsdbRepo *pRepo, void *ptr, int bytes);
|
||||
static SMemTable * tsdbNewMemTable(STsdbCfg *pCfg);
|
||||
static void tsdbFreeMemTable(SMemTable *pMemTable);
|
||||
static STableData *tsdbNewTableData(STsdbCfg *pCfg, STable *pTable);
|
||||
static void tsdbFreeTableData(STableData *pTableData);
|
||||
static char * tsdbGetTsTupleKey(const void *data);
|
||||
static void * tsdbCommitData(void *arg);
|
||||
static int tsdbCommitMeta(STsdbRepo *pRepo);
|
||||
static void tsdbEndCommit(STsdbRepo *pRepo);
|
||||
static TSKEY tsdbNextIterKey(SCommitIter *pIter);
|
||||
static int tsdbHasDataToCommit(SCommitIter *iters, int nIters, TSKEY minKey, TSKEY maxKey);
|
||||
static int tsdbCommitToFile(STsdbRepo *pRepo, int fid, SCommitIter *iters, SRWHelper *pHelper, SDataCols *pDataCols);
|
||||
static void tsdbGetFidKeyRange(int daysPerFile, int8_t precision, int fileId, TSKEY *minKey, TSKEY *maxKey);
|
||||
static SCommitIter *tsdbCreateTableIters(STsdbRepo *pRepo);
|
||||
static void tsdbDestroyTableIters(SCommitIter *iters, int maxTables);
|
||||
static int tsdbReadRowsFromCache(STsdbMeta *pMeta, STable *pTable, SSkipListIterator *pIter, TSKEY maxKey,
|
||||
int maxRowsToRead, SDataCols *pCols);
|
||||
|
||||
// ---------------- INTERNAL FUNCTIONS ----------------
|
||||
int tsdbInsertRowToMem(STsdbRepo *pRepo, SDataRow row, STable *pTable) {
|
||||
STsdbCfg * pCfg = &pRepo->config;
|
||||
int32_t level = 0;
|
||||
int32_t headSize = 0;
|
||||
TSKEY key = dataRowKey(row);
|
||||
SMemTable * pMemTable = pRepo->mem;
|
||||
STableData *pTableData = NULL;
|
||||
SSkipList * pSList = NULL;
|
||||
int bytes = 0;
|
||||
|
||||
if (pMemTable != NULL && pMemTable->tData[TABLE_TID(pTable)] != NULL &&
|
||||
pMemTable->tData[TABLE_TID(pTable)]->uid == TABLE_UID(pTable)) {
|
||||
pTableData = pMemTable->tData[TABLE_TID(pTable)];
|
||||
pSList = pTableData->pData;
|
||||
}
|
||||
|
||||
tSkipListNewNodeInfo(pSList, &level, &headSize);
|
||||
|
||||
bytes = headSize + dataRowLen(row);
|
||||
SSkipListNode *pNode = tsdbAllocBytes(pRepo, bytes);
|
||||
if (pNode == NULL) {
|
||||
tsdbError("vgId:%d failed to insert row with key %" PRId64 " to table %s while allocate %d bytes since %s",
|
||||
REPO_ID(pRepo), key, TABLE_CHAR_NAME(pTable), bytes, tstrerror(terrno));
|
||||
return -1;
|
||||
}
|
||||
pNode->level = level;
|
||||
dataRowCpy(SL_GET_NODE_DATA(pNode), row);
|
||||
|
||||
// Operations above may change pRepo->mem, retake those values
|
||||
ASSERT(pRepo->mem != NULL);
|
||||
pMemTable = pRepo->mem;
|
||||
pTableData = pMemTable->tData[TABLE_TID(pTable)];
|
||||
|
||||
if (pTableData == NULL || pTableData->uid != TABLE_UID(pTable)) {
|
||||
if (pTableData != NULL) { // destroy the table skiplist (may have race condition problem)
|
||||
pMemTable->tData[TABLE_TID(pTable)] = NULL;
|
||||
tsdbFreeTableData(pTableData);
|
||||
}
|
||||
pTableData = tsdbNewTableData(pCfg, pTable);
|
||||
if (pTableData == NULL) {
|
||||
tsdbError("vgId:%d failed to insert row with key %" PRId64
|
||||
" to table %s while create new table data object since %s",
|
||||
REPO_ID(pRepo), key, TABLE_CHAR_NAME(pTable), tstrerror(terrno));
|
||||
tsdbFreeBytes(pRepo, (void *)pNode, bytes);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pRepo->mem->tData[TABLE_TID(pTable)] = pTableData;
|
||||
}
|
||||
|
||||
ASSERT((pTableData != NULL) && pTableData->uid == TABLE_UID(pTable));
|
||||
|
||||
if (tSkipListPut(pTableData->pData, pNode) == NULL) {
|
||||
tsdbFreeBytes(pRepo, (void *)pNode, bytes);
|
||||
} else {
|
||||
if (pMemTable->keyFirst > key) pMemTable->keyFirst = key;
|
||||
if (pMemTable->keyLast < key) pMemTable->keyLast = key;
|
||||
pMemTable->numOfRows++;
|
||||
|
||||
if (pTableData->keyFirst > key) pTableData->keyFirst = key;
|
||||
if (pTableData->keyLast < key) pTableData->keyLast = key;
|
||||
pTableData->numOfRows++;
|
||||
|
||||
ASSERT(pTableData->numOfRows == tSkipListGetSize(pTableData->pData));
|
||||
}
|
||||
|
||||
tsdbTrace("vgId:%d a row is inserted to table %s tid %d uid %" PRIu64 " key %" PRIu64, REPO_ID(pRepo),
|
||||
TABLE_CHAR_NAME(pTable), TABLE_TID(pTable), TABLE_UID(pTable), key);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsdbRefMemTable(STsdbRepo *pRepo, SMemTable *pMemTable) {
|
||||
if (pMemTable == NULL) return 0;
|
||||
T_REF_INC(pMemTable);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Need to lock the repository
|
||||
int tsdbUnRefMemTable(STsdbRepo *pRepo, SMemTable *pMemTable) {
|
||||
if (pMemTable == NULL) return 0;
|
||||
|
||||
if (T_REF_DEC(pMemTable) == 0) {
|
||||
STsdbCfg * pCfg = &pRepo->config;
|
||||
STsdbBufPool *pBufPool = pRepo->pPool;
|
||||
|
||||
SListNode *pNode = NULL;
|
||||
if (tsdbLockRepo(pRepo) < 0) return -1;
|
||||
while ((pNode = tdListPopHead(pMemTable->bufBlockList)) != NULL) {
|
||||
tdListAppendNode(pBufPool->bufBlockList, pNode);
|
||||
}
|
||||
int code = pthread_cond_signal(&pBufPool->poolNotEmpty);
|
||||
if (code != 0) {
|
||||
tsdbUnlockRepo(pRepo);
|
||||
tsdbError("vgId:%d failed to signal pool not empty since %s", REPO_ID(pRepo), strerror(code));
|
||||
terrno = TAOS_SYSTEM_ERROR(code);
|
||||
return -1;
|
||||
}
|
||||
if (tsdbUnlockRepo(pRepo) < 0) return -1;
|
||||
|
||||
for (int i = 0; i < pCfg->maxTables; i++) {
|
||||
if (pMemTable->tData[i] != NULL) {
|
||||
tsdbFreeTableData(pMemTable->tData[i]);
|
||||
}
|
||||
}
|
||||
|
||||
tdListDiscard(pMemTable->actList);
|
||||
tdListDiscard(pMemTable->bufBlockList);
|
||||
tsdbFreeMemTable(pMemTable);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsdbTakeMemSnapshot(STsdbRepo *pRepo, SMemTable **pMem, SMemTable **pIMem) {
|
||||
if (tsdbLockRepo(pRepo) < 0) return -1;
|
||||
|
||||
*pMem = pRepo->mem;
|
||||
*pIMem = pRepo->imem;
|
||||
tsdbRefMemTable(pRepo, *pMem);
|
||||
tsdbRefMemTable(pRepo, *pIMem);
|
||||
|
||||
if (tsdbUnlockRepo(pRepo) < 0) return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *tsdbAllocBytes(STsdbRepo *pRepo, int bytes) {
|
||||
STsdbCfg * pCfg = &pRepo->config;
|
||||
STsdbBufBlock *pBufBlock = tsdbGetCurrBufBlock(pRepo);
|
||||
|
||||
if (pBufBlock != NULL && pBufBlock->remain < bytes) {
|
||||
if (listNEles(pRepo->mem->bufBlockList) >= pCfg->totalBlocks / 2) { // need to commit mem
|
||||
if (tsdbAsyncCommit(pRepo) < 0) return NULL;
|
||||
} else {
|
||||
if (tsdbLockRepo(pRepo) < 0) return NULL;
|
||||
SListNode *pNode = tsdbAllocBufBlockFromPool(pRepo);
|
||||
tdListAppendNode(pRepo->mem->bufBlockList, pNode);
|
||||
if (tsdbUnlockRepo(pRepo) < 0) return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (pRepo->mem == NULL) {
|
||||
SMemTable *pMemTable = tsdbNewMemTable(&pRepo->config);
|
||||
if (pMemTable == NULL) return NULL;
|
||||
|
||||
if (tsdbLockRepo(pRepo) < 0) {
|
||||
tsdbFreeMemTable(pMemTable);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SListNode *pNode = tsdbAllocBufBlockFromPool(pRepo);
|
||||
tdListAppendNode(pMemTable->bufBlockList, pNode);
|
||||
pRepo->mem = pMemTable;
|
||||
|
||||
if (tsdbUnlockRepo(pRepo) < 0) return NULL;
|
||||
}
|
||||
|
||||
pBufBlock = tsdbGetCurrBufBlock(pRepo);
|
||||
ASSERT(pBufBlock->remain >= bytes);
|
||||
void *ptr = POINTER_SHIFT(pBufBlock->data, pBufBlock->offset);
|
||||
pBufBlock->offset += bytes;
|
||||
pBufBlock->remain -= bytes;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
int tsdbAsyncCommit(STsdbRepo *pRepo) {
|
||||
SMemTable *pIMem = pRepo->imem;
|
||||
int code = 0;
|
||||
|
||||
if (pIMem != NULL) {
|
||||
ASSERT(pRepo->commit);
|
||||
code = pthread_join(pRepo->commitThread, NULL);
|
||||
if (code != 0) {
|
||||
tsdbError("vgId:%d failed to thread join since %s", REPO_ID(pRepo), strerror(errno));
|
||||
terrno = TAOS_SYSTEM_ERROR(errno);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(pRepo->commit == 0);
|
||||
if (pRepo->appH.notifyStatus) pRepo->appH.notifyStatus(pRepo->appH.appH, TSDB_STATUS_COMMIT_START);
|
||||
if (pRepo->mem != NULL) {
|
||||
if (tsdbLockRepo(pRepo) < 0) return -1;
|
||||
pRepo->imem = pRepo->mem;
|
||||
pRepo->mem = NULL;
|
||||
pRepo->commit = 1;
|
||||
code = pthread_create(&pRepo->commitThread, NULL, tsdbCommitData, (void *)pRepo);
|
||||
if (code != 0) {
|
||||
tsdbError("vgId:%d failed to create commit thread since %s", REPO_ID(pRepo), strerror(errno));
|
||||
terrno = TAOS_SYSTEM_ERROR(code);
|
||||
tsdbUnlockRepo(pRepo);
|
||||
return -1;
|
||||
}
|
||||
if (tsdbUnlockRepo(pRepo) < 0) return -1;
|
||||
}
|
||||
|
||||
if (pIMem && tsdbUnRefMemTable(pRepo, pIMem) < 0) return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ---------------- LOCAL FUNCTIONS ----------------
|
||||
static FORCE_INLINE STsdbBufBlock *tsdbGetCurrBufBlock(STsdbRepo *pRepo) {
|
||||
ASSERT(pRepo != NULL);
|
||||
if (pRepo->mem == NULL) return NULL;
|
||||
|
||||
SListNode *pNode = listTail(pRepo->mem->bufBlockList);
|
||||
if (pNode == NULL) return NULL;
|
||||
|
||||
STsdbBufBlock *pBufBlock = NULL;
|
||||
tdListNodeGetData(pRepo->mem->bufBlockList, pNode, (void *)(&pBufBlock));
|
||||
|
||||
return pBufBlock;
|
||||
}
|
||||
|
||||
static void tsdbFreeBytes(STsdbRepo *pRepo, void *ptr, int bytes) {
|
||||
STsdbBufBlock *pBufBlock = tsdbGetCurrBufBlock(pRepo);
|
||||
ASSERT(pBufBlock != NULL);
|
||||
pBufBlock->offset -= bytes;
|
||||
pBufBlock->remain += bytes;
|
||||
ASSERT(ptr == POINTER_SHIFT(pBufBlock->data, pBufBlock->offset));
|
||||
}
|
||||
|
||||
static SMemTable* tsdbNewMemTable(STsdbCfg* pCfg) {
|
||||
SMemTable *pMemTable = (SMemTable *)calloc(1, sizeof(*pMemTable));
|
||||
if (pMemTable == NULL) {
|
||||
terrno = TSDB_CODE_TDB_OUT_OF_MEMORY;
|
||||
goto _err;
|
||||
}
|
||||
|
||||
pMemTable->keyFirst = INT64_MAX;
|
||||
pMemTable->keyLast = 0;
|
||||
pMemTable->numOfRows = 0;
|
||||
|
||||
pMemTable->tData = (STableData**)calloc(pCfg->maxTables, sizeof(STableData*));
|
||||
if (pMemTable->tData == NULL) {
|
||||
terrno = TSDB_CODE_TDB_OUT_OF_MEMORY;
|
||||
goto _err;
|
||||
}
|
||||
|
||||
pMemTable->actList = tdListNew(0);
|
||||
if (pMemTable->actList == NULL) {
|
||||
terrno = TSDB_CODE_TDB_OUT_OF_MEMORY;
|
||||
goto _err;
|
||||
}
|
||||
|
||||
pMemTable->bufBlockList = tdListNew(sizeof(STsdbBufBlock*));
|
||||
if (pMemTable->bufBlockList == NULL) {
|
||||
terrno = TSDB_CODE_TDB_OUT_OF_MEMORY;
|
||||
goto _err;
|
||||
}
|
||||
|
||||
T_REF_INC(pMemTable);
|
||||
|
||||
return pMemTable;
|
||||
|
||||
_err:
|
||||
tsdbFreeMemTable(pMemTable);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void tsdbFreeMemTable(SMemTable* pMemTable) {
|
||||
if (pMemTable) {
|
||||
ASSERT((pMemTable->bufBlockList == NULL) ? true : (listNEles(pMemTable->bufBlockList) == 0));
|
||||
ASSERT((pMemTable->actList == NULL) ? true : (listNEles(pMemTable->actList) == 0));
|
||||
|
||||
tdListFree(pMemTable->bufBlockList);
|
||||
tdListFree(pMemTable->actList);
|
||||
tfree(pMemTable->tData);
|
||||
free(pMemTable);
|
||||
}
|
||||
}
|
||||
|
||||
static STableData *tsdbNewTableData(STsdbCfg *pCfg, STable *pTable) {
|
||||
STableData *pTableData = (STableData *)calloc(1, sizeof(*pTableData));
|
||||
if (pTableData == NULL) {
|
||||
terrno = TSDB_CODE_TDB_OUT_OF_MEMORY;
|
||||
goto _err;
|
||||
}
|
||||
|
||||
pTableData->uid = TABLE_UID(pTable);
|
||||
pTableData->keyFirst = INT64_MAX;
|
||||
pTableData->keyLast = 0;
|
||||
pTableData->numOfRows = 0;
|
||||
|
||||
pTableData->pData = tSkipListCreate(TSDB_DATA_SKIPLIST_LEVEL, TSDB_DATA_TYPE_TIMESTAMP,
|
||||
TYPE_BYTES[TSDB_DATA_TYPE_TIMESTAMP], 0, 0, 0, tsdbGetTsTupleKey);
|
||||
if (pTableData->pData == NULL) {
|
||||
terrno = TSDB_CODE_TDB_OUT_OF_MEMORY;
|
||||
goto _err;
|
||||
}
|
||||
|
||||
// TODO: operation here should not be here, remove it
|
||||
pTableData->pData->level = 1;
|
||||
|
||||
return pTableData;
|
||||
|
||||
_err:
|
||||
tsdbFreeTableData(pTableData);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void tsdbFreeTableData(STableData *pTableData) {
|
||||
if (pTableData) {
|
||||
tSkipListDestroy(pTableData->pData);
|
||||
free(pTableData);
|
||||
}
|
||||
}
|
||||
|
||||
static char *tsdbGetTsTupleKey(const void *data) { return dataRowTuple(data); }
|
||||
|
||||
static void *tsdbCommitData(void *arg) {
|
||||
STsdbRepo * pRepo = (STsdbRepo *)arg;
|
||||
SMemTable * pMem = pRepo->imem;
|
||||
STsdbCfg * pCfg = &pRepo->config;
|
||||
SDataCols * pDataCols = NULL;
|
||||
STsdbMeta * pMeta = pRepo->tsdbMeta;
|
||||
SCommitIter *iters = NULL;
|
||||
SRWHelper whelper = {0};
|
||||
ASSERT(pRepo->commit == 1);
|
||||
ASSERT(pMem != NULL);
|
||||
|
||||
tsdbPrint("vgId:%d start to commit! keyFirst %" PRId64 " keyLast %" PRId64 " numOfRows %" PRId64, REPO_ID(pRepo),
|
||||
pMem->keyFirst, pMem->keyLast, pMem->numOfRows);
|
||||
|
||||
// Create the iterator to read from cache
|
||||
if (pMem->numOfRows > 0) {
|
||||
iters = tsdbCreateTableIters(pRepo);
|
||||
if (iters == NULL) {
|
||||
tsdbError("vgId:%d failed to create commit iterator since %s", REPO_ID(pRepo), tstrerror(terrno));
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
if (tsdbInitWriteHelper(&whelper, pRepo) < 0) {
|
||||
tsdbError("vgId:%d failed to init write helper since %s", REPO_ID(pRepo), tstrerror(terrno));
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
if ((pDataCols = tdNewDataCols(pMeta->maxRowBytes, pMeta->maxCols, pCfg->maxRowsPerFileBlock)) == NULL) {
|
||||
terrno = TSDB_CODE_TDB_OUT_OF_MEMORY;
|
||||
tsdbError("vgId:%d failed to init data cols with maxRowBytes %d maxCols %d maxRowsPerFileBlock %d since %s",
|
||||
REPO_ID(pRepo), pMeta->maxCols, pMeta->maxRowBytes, pCfg->maxRowsPerFileBlock, tstrerror(terrno));
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
int sfid = TSDB_KEY_FILEID(pMem->keyFirst, pCfg->daysPerFile, pCfg->precision);
|
||||
int efid = TSDB_KEY_FILEID(pMem->keyLast, pCfg->daysPerFile, pCfg->precision);
|
||||
|
||||
// Loop to commit to each file
|
||||
for (int fid = sfid; fid <= efid; fid++) {
|
||||
if (tsdbCommitToFile(pRepo, fid, iters, &whelper, pDataCols) < 0) {
|
||||
tsdbError("vgId:%d failed to commit to file %d since %s", REPO_ID(pRepo), fid, tstrerror(terrno));
|
||||
goto _exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Commit to update meta file
|
||||
if (tsdbCommitMeta(pRepo) < 0) {
|
||||
tsdbError("vgId:%d failed to commit data while committing meta data since %s", REPO_ID(pRepo), tstrerror(terrno));
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
tsdbFitRetention(pRepo);
|
||||
|
||||
_exit:
|
||||
tdFreeDataCols(pDataCols);
|
||||
tsdbDestroyTableIters(iters, pCfg->maxTables);
|
||||
tsdbDestroyHelper(&whelper);
|
||||
tsdbEndCommit(pRepo);
|
||||
tsdbPrint("vgId:%d commit over", pRepo->config.tsdbId);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int tsdbCommitMeta(STsdbRepo *pRepo) {
|
||||
SMemTable *pMem = pRepo->imem;
|
||||
STsdbMeta *pMeta = pRepo->tsdbMeta;
|
||||
SActObj * pAct = NULL;
|
||||
SActCont * pCont = NULL;
|
||||
|
||||
if (listNEles(pMem->actList) > 0) {
|
||||
if (tdKVStoreStartCommit(pMeta->pStore) < 0) {
|
||||
tsdbError("vgId:%d failed to commit data while start commit meta since %s", REPO_ID(pRepo), tstrerror(terrno));
|
||||
goto _err;
|
||||
}
|
||||
|
||||
SListNode *pNode = NULL;
|
||||
|
||||
while ((pNode = tdListPopHead(pMem->actList)) != NULL) {
|
||||
pAct = (SActObj *)pNode->data;
|
||||
if (pAct->act == TSDB_UPDATE_META) {
|
||||
pCont = (SActCont *)POINTER_SHIFT(pAct, sizeof(SActObj));
|
||||
if (tdUpdateKVStoreRecord(pMeta->pStore, pAct->uid, (void *)(pCont->cont), pCont->len) < 0) {
|
||||
tsdbError("vgId:%d failed to update meta with uid %" PRIu64 " since %s", REPO_ID(pRepo), pAct->uid,
|
||||
tstrerror(terrno));
|
||||
goto _err;
|
||||
}
|
||||
} else if (pAct->act == TSDB_DROP_META) {
|
||||
if (tdDropKVStoreRecord(pMeta->pStore, pAct->uid) < 0) {
|
||||
tsdbError("vgId:%d failed to drop meta with uid %" PRIu64 " since %s", REPO_ID(pRepo), pAct->uid,
|
||||
tstrerror(terrno));
|
||||
goto _err;
|
||||
}
|
||||
} else {
|
||||
ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (tdKVStoreEndCommit(pMeta->pStore) < 0) {
|
||||
tsdbError("vgId:%d failed to commit data while end commit meta since %s", REPO_ID(pRepo), tstrerror(terrno));
|
||||
goto _err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
_err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void tsdbEndCommit(STsdbRepo *pRepo) {
|
||||
ASSERT(pRepo->commit == 1);
|
||||
tsdbLockRepo(pRepo);
|
||||
pRepo->commit = 0;
|
||||
tsdbUnlockRepo(pRepo);
|
||||
if (pRepo->appH.notifyStatus) pRepo->appH.notifyStatus(pRepo->appH.appH, TSDB_STATUS_COMMIT_OVER);
|
||||
}
|
||||
|
||||
static TSKEY tsdbNextIterKey(SCommitIter *pIter) {
|
||||
if (pIter == NULL) return -1;
|
||||
|
||||
SSkipListNode *node = tSkipListIterGet(pIter->pIter);
|
||||
if (node == NULL) return -1;
|
||||
|
||||
SDataRow row = SL_GET_NODE_DATA(node);
|
||||
return dataRowKey(row);
|
||||
}
|
||||
|
||||
static int tsdbHasDataToCommit(SCommitIter *iters, int nIters, TSKEY minKey, TSKEY maxKey) {
|
||||
for (int i = 0; i < nIters; i++) {
|
||||
TSKEY nextKey = tsdbNextIterKey(iters + i);
|
||||
if (nextKey > 0 && (nextKey >= minKey && nextKey <= maxKey)) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tsdbGetFidKeyRange(int daysPerFile, int8_t precision, int fileId, TSKEY *minKey, TSKEY *maxKey) {
|
||||
*minKey = fileId * daysPerFile * tsMsPerDay[precision];
|
||||
*maxKey = *minKey + daysPerFile * tsMsPerDay[precision] - 1;
|
||||
}
|
||||
|
||||
static int tsdbCommitToFile(STsdbRepo *pRepo, int fid, SCommitIter *iters, SRWHelper *pHelper, SDataCols *pDataCols) {
|
||||
char * dataDir = NULL;
|
||||
STsdbMeta * pMeta = pRepo->tsdbMeta;
|
||||
STsdbCfg * pCfg = &pRepo->config;
|
||||
STsdbFileH *pFileH = pRepo->tsdbFileH;
|
||||
SFileGroup *pGroup = NULL;
|
||||
|
||||
TSKEY minKey = 0, maxKey = 0;
|
||||
tsdbGetFidKeyRange(pCfg->daysPerFile, pCfg->precision, fid, &minKey, &maxKey);
|
||||
|
||||
// Check if there are data to commit to this file
|
||||
int hasDataToCommit = tsdbHasDataToCommit(iters, pCfg->maxTables, minKey, maxKey);
|
||||
if (!hasDataToCommit) {
|
||||
tsdbTrace("vgId:%d no data to commit to file %d", REPO_ID(pRepo), fid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Create and open files for commit
|
||||
dataDir = tsdbGetDataDirName(pRepo->rootDir);
|
||||
if (dataDir == NULL) {
|
||||
terrno = TSDB_CODE_TDB_OUT_OF_MEMORY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((pGroup = tsdbCreateFGroupIfNeed(pRepo, dataDir, fid, pCfg->maxTables)) == NULL) {
|
||||
tsdbError("vgId:%d failed to create file group %d since %s", REPO_ID(pRepo), fid, tstrerror(terrno));
|
||||
goto _err;
|
||||
}
|
||||
|
||||
free(dataDir);
|
||||
|
||||
// Open files for write/read
|
||||
if (tsdbSetAndOpenHelperFile(pHelper, pGroup) < 0) {
|
||||
tsdbError("vgId:%d failed to set helper file since %s", REPO_ID(pRepo), tstrerror(terrno));
|
||||
goto _err;
|
||||
}
|
||||
|
||||
// Loop to commit data in each table
|
||||
for (int tid = 1; tid < pCfg->maxTables; tid++) {
|
||||
SCommitIter *pIter = iters + tid;
|
||||
if (pIter->pTable == NULL) continue;
|
||||
|
||||
tsdbSetHelperTable(pHelper, pIter->pTable, pRepo);
|
||||
|
||||
if (pIter->pIter != NULL) {
|
||||
tdInitDataCols(pDataCols, tsdbGetTableSchema(pIter->pTable));
|
||||
|
||||
int maxRowsToRead = pCfg->maxRowsPerFileBlock * 4 / 5;
|
||||
int nLoop = 0;
|
||||
while (true) {
|
||||
int rowsRead = tsdbReadRowsFromCache(pMeta, pIter->pTable, pIter->pIter, maxKey, maxRowsToRead, pDataCols);
|
||||
ASSERT(rowsRead >= 0);
|
||||
if (pDataCols->numOfRows == 0) break;
|
||||
nLoop++;
|
||||
|
||||
ASSERT(dataColsKeyFirst(pDataCols) >= minKey && dataColsKeyFirst(pDataCols) <= maxKey);
|
||||
ASSERT(dataColsKeyLast(pDataCols) >= minKey && dataColsKeyLast(pDataCols) <= maxKey);
|
||||
|
||||
int rowsWritten = tsdbWriteDataBlock(pHelper, pDataCols);
|
||||
ASSERT(rowsWritten != 0);
|
||||
if (rowsWritten < 0) {
|
||||
tsdbError("vgId:%d failed to write data block to table %s tid %d uid %" PRIu64 " since %s", REPO_ID(pRepo),
|
||||
TABLE_CHAR_NAME(pIter->pTable), TABLE_TID(pIter->pTable), TABLE_UID(pIter->pTable),
|
||||
tstrerror(terrno));
|
||||
goto _err;
|
||||
}
|
||||
ASSERT(rowsWritten <= pDataCols->numOfRows);
|
||||
|
||||
tdPopDataColsPoints(pDataCols, rowsWritten);
|
||||
maxRowsToRead = pCfg->maxRowsPerFileBlock * 4 / 5 - pDataCols->numOfRows;
|
||||
}
|
||||
|
||||
ASSERT(pDataCols->numOfRows == 0);
|
||||
}
|
||||
|
||||
// Move the last block to the new .l file if neccessary
|
||||
if (tsdbMoveLastBlockIfNeccessary(pHelper) < 0) {
|
||||
tsdbError("vgId:%d, failed to move last block, since %s", REPO_ID(pRepo), tstrerror(terrno));
|
||||
goto _err;
|
||||
}
|
||||
|
||||
// Write the SCompBlock part
|
||||
if (tsdbWriteCompInfo(pHelper) < 0) {
|
||||
tsdbError("vgId:%d, failed to write compInfo part since %s", REPO_ID(pRepo), tstrerror(terrno));
|
||||
goto _err;
|
||||
}
|
||||
}
|
||||
|
||||
if (tsdbWriteCompIdx(pHelper) < 0) {
|
||||
tsdbError("vgId:%d failed to write compIdx part to file %d since %s", REPO_ID(pRepo), fid, tstrerror(terrno));
|
||||
goto _err;
|
||||
}
|
||||
|
||||
tsdbCloseHelperFile(pHelper, 0);
|
||||
|
||||
pthread_rwlock_wrlock(&(pFileH->fhlock));
|
||||
pGroup->files[TSDB_FILE_TYPE_HEAD] = pHelper->files.headF;
|
||||
pGroup->files[TSDB_FILE_TYPE_DATA] = pHelper->files.dataF;
|
||||
pGroup->files[TSDB_FILE_TYPE_LAST] = pHelper->files.lastF;
|
||||
pthread_rwlock_unlock(&(pFileH->fhlock));
|
||||
|
||||
return 0;
|
||||
|
||||
_err:
|
||||
// ASSERT(false);
|
||||
tsdbCloseHelperFile(pHelper, 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static SCommitIter *tsdbCreateTableIters(STsdbRepo *pRepo) {
|
||||
STsdbCfg * pCfg = &(pRepo->config);
|
||||
SMemTable *pMem = pRepo->imem;
|
||||
STsdbMeta *pMeta = pRepo->tsdbMeta;
|
||||
|
||||
SCommitIter *iters = (SCommitIter *)calloc(pCfg->maxTables, sizeof(SCommitIter));
|
||||
if (iters == NULL) {
|
||||
terrno = TSDB_CODE_TDB_OUT_OF_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (tsdbRLockRepoMeta(pRepo) < 0) goto _err;
|
||||
|
||||
// reference all tables
|
||||
for (int i = 0; i < pCfg->maxTables; i++) {
|
||||
if (pMeta->tables[i] != NULL) {
|
||||
tsdbRefTable(pMeta->tables[i]);
|
||||
iters[i].pTable = pMeta->tables[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (tsdbUnlockRepoMeta(pRepo) < 0) goto _err;
|
||||
|
||||
for (int i = 0; i < pCfg->maxTables; i++) {
|
||||
if ((iters[i].pTable != NULL) && (pMem->tData[i] != NULL) && (TABLE_UID(iters[i].pTable) == pMem->tData[i]->uid)) {
|
||||
if ((iters[i].pIter = tSkipListCreateIter(pMem->tData[i]->pData)) == NULL) {
|
||||
terrno = TSDB_CODE_TDB_OUT_OF_MEMORY;
|
||||
goto _err;
|
||||
}
|
||||
|
||||
if (!tSkipListIterNext(iters[i].pIter)) {
|
||||
terrno = TSDB_CODE_TDB_NO_TABLE_DATA_IN_MEM;
|
||||
goto _err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return iters;
|
||||
|
||||
_err:
|
||||
tsdbDestroyTableIters(iters, pCfg->maxTables);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void tsdbDestroyTableIters(SCommitIter *iters, int maxTables) {
|
||||
if (iters == NULL) return;
|
||||
|
||||
for (int i = 1; i < maxTables; i++) {
|
||||
if (iters[i].pTable != NULL) {
|
||||
tsdbUnRefTable(iters[i].pTable);
|
||||
tSkipListDestroyIter(iters[i].pIter);
|
||||
}
|
||||
}
|
||||
|
||||
free(iters);
|
||||
}
|
||||
|
||||
static int tsdbReadRowsFromCache(STsdbMeta *pMeta, STable *pTable, SSkipListIterator *pIter, TSKEY maxKey, int maxRowsToRead, SDataCols *pCols) {
|
||||
ASSERT(maxRowsToRead > 0);
|
||||
if (pIter == NULL) return 0;
|
||||
STSchema *pSchema = NULL;
|
||||
|
||||
int numOfRows = 0;
|
||||
|
||||
do {
|
||||
if (numOfRows >= maxRowsToRead) break;
|
||||
|
||||
SSkipListNode *node = tSkipListIterGet(pIter);
|
||||
if (node == NULL) break;
|
||||
|
||||
SDataRow row = SL_GET_NODE_DATA(node);
|
||||
if (dataRowKey(row) > maxKey) break;
|
||||
|
||||
if (pSchema == NULL || schemaVersion(pSchema) != dataRowVersion(row)) {
|
||||
pSchema = tsdbGetTableSchemaByVersion(pTable, dataRowVersion(row));
|
||||
if (pSchema == NULL) {
|
||||
// TODO: deal with the error here
|
||||
ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
tdAppendDataRowToDataCol(row, pSchema, pCols);
|
||||
numOfRows++;
|
||||
} while (tSkipListIterNext(pIter));
|
||||
|
||||
return numOfRows;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,281 +0,0 @@
|
|||
/*
|
||||
* 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 "os.h"
|
||||
|
||||
#include "taosdef.h"
|
||||
#include "hash.h"
|
||||
#include "tsdbMain.h"
|
||||
|
||||
#define TSDB_META_FILE_VERSION_MAJOR 1
|
||||
#define TSDB_META_FILE_VERSION_MINOR 0
|
||||
#define TSDB_META_FILE_HEADER_SIZE 512
|
||||
|
||||
typedef struct {
|
||||
int32_t offset;
|
||||
int32_t size;
|
||||
uint64_t uid;
|
||||
} SRecordInfo;
|
||||
|
||||
// static int32_t tsdbGetMetaFileName(char *rootDir, char *fname);
|
||||
// static int32_t tsdbCheckMetaHeader(int fd);
|
||||
static int32_t tsdbWriteMetaHeader(int fd);
|
||||
static int tsdbCreateMetaFile(char *fname);
|
||||
static int tsdbRestoreFromMetaFile(char *fname, SMetaFile *mfh);
|
||||
|
||||
SMetaFile *tsdbInitMetaFile(char *rootDir, int32_t maxTables, iterFunc iFunc, afterFunc aFunc, void *appH) {
|
||||
char fname[128] = "\0";
|
||||
if (tsdbGetMetaFileName(rootDir, fname) < 0) return NULL;
|
||||
|
||||
SMetaFile *mfh = (SMetaFile *)calloc(1, sizeof(SMetaFile));
|
||||
if (mfh == NULL) return NULL;
|
||||
|
||||
mfh->iFunc = iFunc;
|
||||
mfh->aFunc = aFunc;
|
||||
mfh->appH = appH;
|
||||
mfh->nDel = 0;
|
||||
mfh->tombSize = 0;
|
||||
mfh->size = 0;
|
||||
|
||||
// OPEN MAP
|
||||
mfh->map =
|
||||
taosHashInit(maxTables * TSDB_META_HASH_FRACTION, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BIGINT), false);
|
||||
if (mfh->map == NULL) {
|
||||
free(mfh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// OPEN FILE
|
||||
if (access(fname, F_OK) < 0) { // file not exists
|
||||
mfh->fd = tsdbCreateMetaFile(fname);
|
||||
if (mfh->fd < 0) {
|
||||
taosHashCleanup(mfh->map);
|
||||
free(mfh);
|
||||
return NULL;
|
||||
}
|
||||
mfh->size += TSDB_META_FILE_HEADER_SIZE;
|
||||
} else { // file exists, recover from file
|
||||
if (tsdbRestoreFromMetaFile(fname, mfh) < 0) {
|
||||
taosHashCleanup(mfh->map);
|
||||
free(mfh);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return mfh;
|
||||
}
|
||||
|
||||
int32_t tsdbInsertMetaRecord(SMetaFile *mfh, uint64_t uid, void *cont, int32_t contLen) {
|
||||
if (taosHashGet(mfh->map, (char *)(&uid), sizeof(uid)) != NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SRecordInfo info;
|
||||
info.offset = mfh->size;
|
||||
info.size = contLen;
|
||||
info.uid = uid;
|
||||
|
||||
mfh->size += (contLen + sizeof(SRecordInfo));
|
||||
|
||||
if (taosHashPut(mfh->map, (char *)(&uid), sizeof(uid), (void *)(&info), sizeof(SRecordInfo)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO: make below a function to implement
|
||||
if (lseek(mfh->fd, info.offset, SEEK_SET) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (write(mfh->fd, (void *)(&info), sizeof(SRecordInfo)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (write(mfh->fd, cont, contLen) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// fsync(mfh->fd);
|
||||
|
||||
mfh->tombSize++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t tsdbDeleteMetaRecord(SMetaFile *mfh, uint64_t uid) {
|
||||
char *ptr = taosHashGet(mfh->map, (char *)(&uid), sizeof(uid));
|
||||
if (ptr == NULL) return -1;
|
||||
|
||||
SRecordInfo info = *(SRecordInfo *)ptr;
|
||||
|
||||
// Remove record from hash table
|
||||
taosHashRemove(mfh->map, (char *)(&uid), sizeof(uid));
|
||||
|
||||
// Remove record from file
|
||||
|
||||
info.offset = -info.offset;
|
||||
if (lseek(mfh->fd, -info.offset, SEEK_CUR) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (write(mfh->fd, (void *)(&info), sizeof(SRecordInfo)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// fsync(mfh->fd);
|
||||
|
||||
mfh->nDel++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t tsdbUpdateMetaRecord(SMetaFile *mfh, uint64_t uid, void *cont, int32_t contLen) {
|
||||
char *ptr = taosHashGet(mfh->map, (char *)(&uid), sizeof(uid));
|
||||
if (ptr == NULL) return -1;
|
||||
|
||||
SRecordInfo info = *(SRecordInfo *)ptr;
|
||||
// Update the hash table
|
||||
if (taosHashPut(mfh->map, (char *)(&uid), sizeof(uid), (void *)(&info), sizeof(SRecordInfo)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Update record in file
|
||||
if (info.size >= contLen) { // Just update it in place
|
||||
info.size = contLen;
|
||||
|
||||
} else { // Just append to the end of file
|
||||
info.offset = mfh->size;
|
||||
info.size = contLen;
|
||||
|
||||
mfh->size += contLen;
|
||||
}
|
||||
if (lseek(mfh->fd, -info.offset, SEEK_CUR) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (write(mfh->fd, (void *)(&info), sizeof(SRecordInfo)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// fsync(mfh->fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tsdbCloseMetaFile(SMetaFile *mfh) {
|
||||
if (mfh == NULL) return;
|
||||
close(mfh->fd);
|
||||
|
||||
taosHashCleanup(mfh->map);
|
||||
tfree(mfh);
|
||||
}
|
||||
|
||||
int32_t tsdbGetMetaFileName(char *rootDir, char *fname) {
|
||||
if (rootDir == NULL) return -1;
|
||||
sprintf(fname, "%s/%s", rootDir, TSDB_META_FILE_NAME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// static int32_t tsdbCheckMetaHeader(int fd) {
|
||||
// // TODO: write the meta file header check function
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
static int32_t tsdbWriteMetaHeader(int fd) {
|
||||
// TODO: write the meta file header to file
|
||||
char head[TSDB_META_FILE_HEADER_SIZE] = "\0";
|
||||
sprintf(head, "version: %d.%d", TSDB_META_FILE_VERSION_MAJOR, TSDB_META_FILE_VERSION_MINOR);
|
||||
|
||||
write(fd, (void *)head, TSDB_META_FILE_HEADER_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// static int32_t tsdbReadMetaHeader(int fd) {
|
||||
// lseek(fd, TSDB_META_FILE_HEADER_SIZE, SEEK_SET);
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
static int tsdbCreateMetaFile(char *fname) {
|
||||
int fd = open(fname, O_RDWR | O_CREAT, 0755);
|
||||
if (fd < 0) return -1;
|
||||
|
||||
if (tsdbWriteMetaHeader(fd) < 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int tsdbCheckMetaFileIntegrety(int fd) {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tsdbRestoreFromMetaFile(char *fname, SMetaFile *mfh) {
|
||||
int fd = open(fname, O_RDWR);
|
||||
if (fd < 0) return -1;
|
||||
|
||||
if (tsdbCheckMetaFileIntegrety(fd) < 0) {
|
||||
// TODO: decide if to auto-recover the file
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lseek(fd, TSDB_META_FILE_HEADER_SIZE, SEEK_SET) < 0) {
|
||||
// TODO: deal with the error
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
mfh->size += TSDB_META_FILE_HEADER_SIZE;
|
||||
|
||||
mfh->fd = fd;
|
||||
|
||||
void *buf = NULL;
|
||||
// int buf_size = 0;
|
||||
|
||||
SRecordInfo info;
|
||||
while (1) {
|
||||
if (read(mfh->fd, (void *)(&info), sizeof(SRecordInfo)) == 0) break;
|
||||
if (info.offset < 0) {
|
||||
mfh->size += (info.size + sizeof(SRecordInfo));
|
||||
mfh->tombSize += (info.size + sizeof(SRecordInfo));
|
||||
lseek(mfh->fd, info.size, SEEK_CUR);
|
||||
mfh->size = mfh->size + sizeof(SRecordInfo) + info.size;
|
||||
mfh->tombSize = mfh->tombSize + sizeof(SRecordInfo) + info.size;
|
||||
} else {
|
||||
if (taosHashPut(mfh->map, (char *)(&info.uid), sizeof(info.uid), (void *)(&info), sizeof(SRecordInfo)) < 0) {
|
||||
if (buf) free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf = realloc(buf, info.size);
|
||||
if (buf == NULL) return -1;
|
||||
|
||||
if (read(mfh->fd, buf, info.size) < 0) {
|
||||
if (buf) free(buf);
|
||||
return -1;
|
||||
}
|
||||
(*mfh->iFunc)(mfh->appH, buf, info.size);
|
||||
|
||||
mfh->size = mfh->size + sizeof(SRecordInfo) + info.size;
|
||||
}
|
||||
|
||||
}
|
||||
(*mfh->aFunc)(mfh->appH);
|
||||
|
||||
if (buf) free(buf);
|
||||
|
||||
return 0;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -72,9 +72,11 @@ typedef struct STableCheckInfo {
|
|||
int32_t compSize;
|
||||
int32_t numOfBlocks; // number of qualified data blocks not the original blocks
|
||||
SDataCols* pDataCols;
|
||||
|
||||
int32_t chosen; // indicate which iterator should move forward
|
||||
bool initBuf; // whether to initialize the in-memory skip list iterator or not
|
||||
SMemTable* mem; // in-mem buffer, hold the ref count
|
||||
SMemTable* imem; // imem buffer, hold the ref count to avoid release
|
||||
|
||||
SSkipListIterator* iter; // mem buffer skip list iterator
|
||||
SSkipListIterator* iiter; // imem buffer skip list iterator
|
||||
} STableCheckInfo;
|
||||
|
@ -135,7 +137,7 @@ static void tsdbInitCompBlockLoadInfo(SLoadCompBlockInfo* pCompBlockLoadInfo) {
|
|||
pCompBlockLoadInfo->fileId = -1;
|
||||
}
|
||||
|
||||
TsdbQueryHandleT* tsdbQueryTables(TsdbRepoT* tsdb, STsdbQueryCond* pCond, STableGroupInfo* groupList, void* qinfo) {
|
||||
TsdbQueryHandleT* tsdbQueryTables(TSDB_REPO_T* tsdb, STsdbQueryCond* pCond, STableGroupInfo* groupList, void* qinfo) {
|
||||
// todo 1. filter not exist table
|
||||
// todo 2. add the reference count for each table that is involved in query
|
||||
|
||||
|
@ -203,7 +205,7 @@ TsdbQueryHandleT* tsdbQueryTables(TsdbRepoT* tsdb, STsdbQueryCond* pCond, STable
|
|||
return (TsdbQueryHandleT) pQueryHandle;
|
||||
}
|
||||
|
||||
TsdbQueryHandleT tsdbQueryLastRow(TsdbRepoT *tsdb, STsdbQueryCond *pCond, STableGroupInfo *groupList, void* qinfo) {
|
||||
TsdbQueryHandleT tsdbQueryLastRow(TSDB_REPO_T *tsdb, STsdbQueryCond *pCond, STableGroupInfo *groupList, void* qinfo) {
|
||||
STsdbQueryHandle *pQueryHandle = (STsdbQueryHandle*) tsdbQueryTables(tsdb, pCond, groupList, qinfo);
|
||||
|
||||
pQueryHandle->type = TSDB_QUERY_TYPE_LAST;
|
||||
|
@ -229,7 +231,7 @@ SArray* tsdbGetQueriedTableIdList(TsdbQueryHandleT *pHandle) {
|
|||
return res;
|
||||
}
|
||||
|
||||
TsdbQueryHandleT tsdbQueryRowsInExternalWindow(TsdbRepoT *tsdb, STsdbQueryCond* pCond, STableGroupInfo *groupList, void* qinfo) {
|
||||
TsdbQueryHandleT tsdbQueryRowsInExternalWindow(TSDB_REPO_T *tsdb, STsdbQueryCond* pCond, STableGroupInfo *groupList, void* qinfo) {
|
||||
STsdbQueryHandle *pQueryHandle = (STsdbQueryHandle*) tsdbQueryTables(tsdb, pCond, groupList, qinfo);
|
||||
|
||||
pQueryHandle->type = TSDB_QUERY_TYPE_EXTERNAL;
|
||||
|
@ -247,22 +249,24 @@ static bool initTableMemIterator(STsdbQueryHandle* pHandle, STableCheckInfo* pCh
|
|||
|
||||
pCheckInfo->initBuf = true;
|
||||
int32_t order = pHandle->order;
|
||||
|
||||
|
||||
tsdbTakeMemSnapshot(pHandle->pTsdb, &pCheckInfo->mem, &pCheckInfo->imem);
|
||||
|
||||
// no data in buffer, abort
|
||||
if (pTable->mem == NULL && pTable->imem == NULL) {
|
||||
if (pCheckInfo->mem == NULL && pCheckInfo->imem == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(pCheckInfo->iter == NULL && pCheckInfo->iiter == NULL);
|
||||
|
||||
if (pTable->mem) {
|
||||
pCheckInfo->iter = tSkipListCreateIterFromVal(pTable->mem->pData, (const char*) &pCheckInfo->lastKey,
|
||||
TSDB_DATA_TYPE_TIMESTAMP, order);
|
||||
if (pCheckInfo->mem && pCheckInfo->mem->tData[pCheckInfo->tableId.tid] != NULL) {
|
||||
pCheckInfo->iter = tSkipListCreateIterFromVal(pCheckInfo->mem->tData[pCheckInfo->tableId.tid]->pData,
|
||||
(const char*) &pCheckInfo->lastKey, TSDB_DATA_TYPE_TIMESTAMP, order);
|
||||
}
|
||||
|
||||
if (pTable->imem) {
|
||||
pCheckInfo->iiter = tSkipListCreateIterFromVal(pTable->imem->pData, (const char*) &pCheckInfo->lastKey,
|
||||
TSDB_DATA_TYPE_TIMESTAMP, order);
|
||||
if (pCheckInfo->imem && pCheckInfo->imem->tData[pCheckInfo->tableId.tid] != NULL) {
|
||||
pCheckInfo->iiter = tSkipListCreateIterFromVal(pCheckInfo->imem->tData[pCheckInfo->tableId.tid]->pData,
|
||||
(const char*) &pCheckInfo->lastKey, TSDB_DATA_TYPE_TIMESTAMP, order);
|
||||
}
|
||||
|
||||
// both iterators are NULL, no data in buffer right now
|
||||
|
@ -586,10 +590,12 @@ static bool doLoadFileDataBlock(STsdbQueryHandle* pQueryHandle, SCompBlock* pBlo
|
|||
|
||||
if (pCheckInfo->pDataCols == NULL) {
|
||||
STsdbMeta* pMeta = tsdbGetMeta(pRepo);
|
||||
pCheckInfo->pDataCols = tdNewDataCols(pMeta->maxRowBytes, pMeta->maxCols, pRepo->config.maxRowsPerFileBlock);
|
||||
// TODO
|
||||
pCheckInfo->pDataCols =
|
||||
tdNewDataCols(pMeta->maxRowBytes, pMeta->maxCols, pRepo->config.maxRowsPerFileBlock);
|
||||
}
|
||||
|
||||
tdInitDataCols(pCheckInfo->pDataCols, tsdbGetTableSchema(tsdbGetMeta(pQueryHandle->pTsdb), pCheckInfo->pTableObj));
|
||||
tdInitDataCols(pCheckInfo->pDataCols, tsdbGetTableSchema(pCheckInfo->pTableObj));
|
||||
|
||||
if (tsdbLoadBlockData(&(pQueryHandle->rhelper), pBlock, NULL) == 0) {
|
||||
SDataBlockLoadInfo* pBlockLoadInfo = &pQueryHandle->dataBlockLoadInfo;
|
||||
|
@ -875,7 +881,7 @@ static void copyOneRowFromMem(STsdbQueryHandle* pQueryHandle, int32_t capacity,
|
|||
char* pData = NULL;
|
||||
|
||||
// the schema version info is embeded in SDataRow
|
||||
STSchema* pSchema = tsdbGetTableSchemaByVersion(pMeta, pTable, dataRowVersion(row));
|
||||
STSchema* pSchema = tsdbGetTableSchemaByVersion(pTable, dataRowVersion(row));
|
||||
int32_t numOfRowCols = schemaNCols(pSchema);
|
||||
|
||||
int32_t i = 0, j = 0;
|
||||
|
@ -1861,8 +1867,8 @@ static int32_t getAllTableIdList(STable* pSuperTable, SArray* list) {
|
|||
while (tSkipListIterNext(iter)) {
|
||||
SSkipListNode* pNode = tSkipListIterGet(iter);
|
||||
|
||||
STableIndexElem* elem = (STableIndexElem*)(SL_GET_NODE_DATA((SSkipListNode*) pNode));
|
||||
taosArrayPush(list, &elem->pTable->tableId);
|
||||
STable** pTable = (STable**) SL_GET_NODE_DATA((SSkipListNode*) pNode);
|
||||
taosArrayPush(list, &(*pTable)->tableId);
|
||||
}
|
||||
|
||||
tSkipListDestroyIter(iter);
|
||||
|
@ -1881,8 +1887,8 @@ static void convertQueryResult(SArray* pRes, SArray* pTableList) {
|
|||
|
||||
size_t size = taosArrayGetSize(pTableList);
|
||||
for (int32_t i = 0; i < size; ++i) { // todo speedup by using reserve space.
|
||||
STableIndexElem* elem = taosArrayGet(pTableList, i);
|
||||
taosArrayPush(pRes, &elem->pTable->tableId);
|
||||
STable* pTable = taosArrayGetP(pTableList, i);
|
||||
taosArrayPush(pRes, &pTable->tableId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2041,7 +2047,7 @@ void createTableGroupImpl(SArray* pGroups, SArray* pTableIdList, size_t numOfTab
|
|||
}
|
||||
|
||||
SArray* createTableGroup(SArray* pTableList, STSchema* pTagSchema, SColIndex* pCols, int32_t numOfOrderCols,
|
||||
TsdbRepoT* tsdb) {
|
||||
TSDB_REPO_T* tsdb) {
|
||||
assert(pTableList != NULL);
|
||||
SArray* pTableGroup = taosArrayInit(1, POINTER_BYTES);
|
||||
|
||||
|
@ -2078,16 +2084,16 @@ SArray* createTableGroup(SArray* pTableList, STSchema* pTagSchema, SColIndex* pC
|
|||
bool indexedNodeFilterFp(const void* pNode, void* param) {
|
||||
tQueryInfo* pInfo = (tQueryInfo*) param;
|
||||
|
||||
STableIndexElem* elem = (STableIndexElem*)(SL_GET_NODE_DATA((SSkipListNode*)pNode));
|
||||
STable* pTable = *(STable**)(SL_GET_NODE_DATA((SSkipListNode*)pNode));
|
||||
|
||||
char* val = NULL;
|
||||
int8_t type = pInfo->sch.type;
|
||||
|
||||
if (pInfo->colIndex == TSDB_TBNAME_COLUMN_INDEX) {
|
||||
val = (char*) elem->pTable->name;
|
||||
val = (char*) pTable->name;
|
||||
type = TSDB_DATA_TYPE_BINARY;
|
||||
} else {
|
||||
val = tdGetKVRowValOfCol(elem->pTable->tagVal, pInfo->sch.colId);
|
||||
val = tdGetKVRowValOfCol(pTable->tagVal, pInfo->sch.colId);
|
||||
}
|
||||
|
||||
//todo :the val is possible to be null, so check it out carefully
|
||||
|
@ -2143,7 +2149,7 @@ static int32_t doQueryTableList(STable* pSTable, SArray* pRes, tExprNode* pExpr)
|
|||
.pExtInfo = pSTable->tagSchema,
|
||||
};
|
||||
|
||||
SArray* pTableList = taosArrayInit(8, sizeof(STableIndexElem));
|
||||
SArray* pTableList = taosArrayInit(8, POINTER_BYTES);
|
||||
|
||||
tExprTreeTraverse(pExpr, pSTable->pIndex, pTableList, &supp);
|
||||
tExprTreeDestroy(&pExpr, destroyHelper);
|
||||
|
@ -2153,7 +2159,7 @@ static int32_t doQueryTableList(STable* pSTable, SArray* pRes, tExprNode* pExpr)
|
|||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t tsdbQuerySTableByTagCond(TsdbRepoT* tsdb, uint64_t uid, const char* pTagCond, size_t len,
|
||||
int32_t tsdbQuerySTableByTagCond(TSDB_REPO_T* tsdb, uint64_t uid, const char* pTagCond, size_t len,
|
||||
int16_t tagNameRelType, const char* tbnameCond, STableGroupInfo* pGroupInfo,
|
||||
SColIndex* pColIndex, int32_t numOfCols) {
|
||||
STable* pTable = tsdbGetTableByUid(tsdbGetMeta(tsdb), uid);
|
||||
|
@ -2170,7 +2176,7 @@ int32_t tsdbQuerySTableByTagCond(TsdbRepoT* tsdb, uint64_t uid, const char* pTag
|
|||
}
|
||||
|
||||
SArray* res = taosArrayInit(8, sizeof(STableId));
|
||||
STSchema* pTagSchema = tsdbGetTableTagSchema(tsdbGetMeta(tsdb), pTable);
|
||||
STSchema* pTagSchema = tsdbGetTableTagSchema(pTable);
|
||||
|
||||
// no tags and tbname condition, all child tables of this stable are involved
|
||||
if (tbnameCond == NULL && (pTagCond == NULL || len == 0)) {
|
||||
|
@ -2230,7 +2236,7 @@ int32_t tsdbQuerySTableByTagCond(TsdbRepoT* tsdb, uint64_t uid, const char* pTag
|
|||
return ret;
|
||||
}
|
||||
|
||||
int32_t tsdbGetOneTableGroup(TsdbRepoT* tsdb, uint64_t uid, STableGroupInfo* pGroupInfo) {
|
||||
int32_t tsdbGetOneTableGroup(TSDB_REPO_T* tsdb, uint64_t uid, STableGroupInfo* pGroupInfo) {
|
||||
STable* pTable = tsdbGetTableByUid(tsdbGetMeta(tsdb), uid);
|
||||
if (pTable == NULL) {
|
||||
return TSDB_CODE_TDB_INVALID_TABLE_ID;
|
||||
|
@ -2257,6 +2263,10 @@ void tsdbCleanupQueryHandle(TsdbQueryHandleT queryHandle) {
|
|||
size_t size = taosArrayGetSize(pQueryHandle->pTableCheckInfo);
|
||||
for (int32_t i = 0; i < size; ++i) {
|
||||
STableCheckInfo* pTableCheckInfo = taosArrayGet(pQueryHandle->pTableCheckInfo, i);
|
||||
|
||||
tsdbUnRefMemTable(pQueryHandle->pTsdb, pTableCheckInfo->mem);
|
||||
tsdbUnRefMemTable(pQueryHandle->pTsdb, pTableCheckInfo->imem);
|
||||
|
||||
tSkipListDestroyIter(pTableCheckInfo->iter);
|
||||
|
||||
if (pTableCheckInfo->pDataCols != NULL) {
|
||||
|
|
|
@ -13,7 +13,7 @@ static double getCurTime() {
|
|||
}
|
||||
|
||||
typedef struct {
|
||||
TsdbRepoT *pRepo;
|
||||
TSDB_REPO_T *pRepo;
|
||||
bool isAscend;
|
||||
int tid;
|
||||
uint64_t uid;
|
||||
|
@ -136,7 +136,7 @@ TEST(TsdbTest, createRepo) {
|
|||
tsdbSetDefaultCfg(&config);
|
||||
ASSERT_EQ(tsdbCreateRepo("/home/ubuntu/work/ttest/vnode0", &config, NULL), 0);
|
||||
|
||||
TsdbRepoT *pRepo = tsdbOpenRepo("/home/ubuntu/work/ttest/vnode0", NULL);
|
||||
TSDB_REPO_T *pRepo = tsdbOpenRepo("/home/ubuntu/work/ttest/vnode0", NULL);
|
||||
ASSERT_NE(pRepo, nullptr);
|
||||
|
||||
// 2. Create a normal table
|
||||
|
|
|
@ -33,9 +33,13 @@ static const int32_t TNUMBER = 1;
|
|||
#define ZIGZAGD(T, v) ((v) >> 1) ^ -((T)((v)&1)) // zigzag decode
|
||||
|
||||
// ---- Fixed U8
|
||||
static FORCE_INLINE void *taosEncodeFixedU8(void *buf, uint8_t value) {
|
||||
((uint8_t *)buf)[0] = value;
|
||||
return POINTER_SHIFT(buf, sizeof(value));
|
||||
static FORCE_INLINE int taosEncodeFixedU8(void **buf, uint8_t value) {
|
||||
if (buf != NULL) {
|
||||
((uint8_t *)(*buf))[0] = value;
|
||||
*buf = POINTER_SHIFT(*buf, sizeof(value));
|
||||
}
|
||||
|
||||
return (int)sizeof(value);
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosDecodeFixedU8(void *buf, uint8_t *value) {
|
||||
|
@ -44,9 +48,12 @@ static FORCE_INLINE void *taosDecodeFixedU8(void *buf, uint8_t *value) {
|
|||
}
|
||||
|
||||
// ---- Fixed I8
|
||||
static FORCE_INLINE void *taosEncodeFixedI8(void *buf, int8_t value) {
|
||||
((int8_t *)buf)[0] = value;
|
||||
return POINTER_SHIFT(buf, sizeof(value));
|
||||
static FORCE_INLINE int taosEncodeFixedI8(void **buf, int8_t value) {
|
||||
if (buf != NULL) {
|
||||
((int8_t *)(*buf))[0] = value;
|
||||
*buf = POINTER_SHIFT(*buf, sizeof(value));
|
||||
}
|
||||
return (int)sizeof(value);
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosDecodeFixedI8(void *buf, int8_t *value) {
|
||||
|
@ -55,15 +62,18 @@ static FORCE_INLINE void *taosDecodeFixedI8(void *buf, int8_t *value) {
|
|||
}
|
||||
|
||||
// ---- Fixed U16
|
||||
static FORCE_INLINE void *taosEncodeFixedU16(void *buf, uint16_t value) {
|
||||
if (IS_LITTLE_ENDIAN()) {
|
||||
memcpy(buf, &value, sizeof(value));
|
||||
} else {
|
||||
((uint8_t *)buf)[0] = value & 0xff;
|
||||
((uint8_t *)buf)[1] = (value >> 8) & 0xff;
|
||||
static FORCE_INLINE int taosEncodeFixedU16(void **buf, uint16_t value) {
|
||||
if (buf != NULL) {
|
||||
if (IS_LITTLE_ENDIAN()) {
|
||||
memcpy(*buf, &value, sizeof(value));
|
||||
} else {
|
||||
((uint8_t *)(*buf))[0] = value & 0xff;
|
||||
((uint8_t *)(*buf))[1] = (value >> 8) & 0xff;
|
||||
}
|
||||
*buf = POINTER_SHIFT(*buf, sizeof(value));
|
||||
}
|
||||
|
||||
return POINTER_SHIFT(buf, sizeof(value));
|
||||
return (int)sizeof(value);
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosDecodeFixedU16(void *buf, uint16_t *value) {
|
||||
|
@ -78,7 +88,7 @@ static FORCE_INLINE void *taosDecodeFixedU16(void *buf, uint16_t *value) {
|
|||
}
|
||||
|
||||
// ---- Fixed I16
|
||||
static FORCE_INLINE void *taosEncodeFixedI16(void *buf, int16_t value) {
|
||||
static FORCE_INLINE int taosEncodeFixedI16(void **buf, int16_t value) {
|
||||
return taosEncodeFixedU16(buf, ZIGZAGE(int16_t, value));
|
||||
}
|
||||
|
||||
|
@ -90,17 +100,20 @@ static FORCE_INLINE void *taosDecodeFixedI16(void *buf, int16_t *value) {
|
|||
}
|
||||
|
||||
// ---- Fixed U32
|
||||
static FORCE_INLINE void *taosEncodeFixedU32(void *buf, uint32_t value) {
|
||||
if (IS_LITTLE_ENDIAN()) {
|
||||
memcpy(buf, &value, sizeof(value));
|
||||
} else {
|
||||
((uint8_t *)buf)[0] = value & 0xff;
|
||||
((uint8_t *)buf)[1] = (value >> 8) & 0xff;
|
||||
((uint8_t *)buf)[2] = (value >> 16) & 0xff;
|
||||
((uint8_t *)buf)[3] = (value >> 24) & 0xff;
|
||||
static FORCE_INLINE int taosEncodeFixedU32(void **buf, uint32_t value) {
|
||||
if (buf != NULL) {
|
||||
if (IS_LITTLE_ENDIAN()) {
|
||||
memcpy(*buf, &value, sizeof(value));
|
||||
} else {
|
||||
((uint8_t *)(*buf))[0] = value & 0xff;
|
||||
((uint8_t *)(*buf))[1] = (value >> 8) & 0xff;
|
||||
((uint8_t *)(*buf))[2] = (value >> 16) & 0xff;
|
||||
((uint8_t *)(*buf))[3] = (value >> 24) & 0xff;
|
||||
}
|
||||
*buf = POINTER_SHIFT(*buf, sizeof(value));
|
||||
}
|
||||
|
||||
return POINTER_SHIFT(buf, sizeof(value));
|
||||
return (int)sizeof(value);
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosDecodeFixedU32(void *buf, uint32_t *value) {
|
||||
|
@ -117,7 +130,7 @@ static FORCE_INLINE void *taosDecodeFixedU32(void *buf, uint32_t *value) {
|
|||
}
|
||||
|
||||
// ---- Fixed I32
|
||||
static FORCE_INLINE void *taosEncodeFixedI32(void *buf, int32_t value) {
|
||||
static FORCE_INLINE int taosEncodeFixedI32(void **buf, int32_t value) {
|
||||
return taosEncodeFixedU32(buf, ZIGZAGE(int32_t, value));
|
||||
}
|
||||
|
||||
|
@ -129,21 +142,25 @@ static FORCE_INLINE void *taosDecodeFixedI32(void *buf, int32_t *value) {
|
|||
}
|
||||
|
||||
// ---- Fixed U64
|
||||
static FORCE_INLINE void *taosEncodeFixedU64(void *buf, uint64_t value) {
|
||||
if (IS_LITTLE_ENDIAN()) {
|
||||
memcpy(buf, &value, sizeof(value));
|
||||
} else {
|
||||
((uint8_t *)buf)[0] = value & 0xff;
|
||||
((uint8_t *)buf)[1] = (value >> 8) & 0xff;
|
||||
((uint8_t *)buf)[2] = (value >> 16) & 0xff;
|
||||
((uint8_t *)buf)[3] = (value >> 24) & 0xff;
|
||||
((uint8_t *)buf)[4] = (value >> 32) & 0xff;
|
||||
((uint8_t *)buf)[5] = (value >> 40) & 0xff;
|
||||
((uint8_t *)buf)[6] = (value >> 48) & 0xff;
|
||||
((uint8_t *)buf)[7] = (value >> 56) & 0xff;
|
||||
static FORCE_INLINE int taosEncodeFixedU64(void **buf, uint64_t value) {
|
||||
if (buf != NULL) {
|
||||
if (IS_LITTLE_ENDIAN()) {
|
||||
memcpy(*buf, &value, sizeof(value));
|
||||
} else {
|
||||
((uint8_t *)(*buf))[0] = value & 0xff;
|
||||
((uint8_t *)(*buf))[1] = (value >> 8) & 0xff;
|
||||
((uint8_t *)(*buf))[2] = (value >> 16) & 0xff;
|
||||
((uint8_t *)(*buf))[3] = (value >> 24) & 0xff;
|
||||
((uint8_t *)(*buf))[4] = (value >> 32) & 0xff;
|
||||
((uint8_t *)(*buf))[5] = (value >> 40) & 0xff;
|
||||
((uint8_t *)(*buf))[6] = (value >> 48) & 0xff;
|
||||
((uint8_t *)(*buf))[7] = (value >> 56) & 0xff;
|
||||
}
|
||||
|
||||
*buf = POINTER_SHIFT(*buf, sizeof(value));
|
||||
}
|
||||
|
||||
return POINTER_SHIFT(buf, sizeof(value));
|
||||
return (int)sizeof(value);
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosDecodeFixedU64(void *buf, uint64_t *value) {
|
||||
|
@ -164,7 +181,7 @@ static FORCE_INLINE void *taosDecodeFixedU64(void *buf, uint64_t *value) {
|
|||
}
|
||||
|
||||
// ---- Fixed I64
|
||||
static FORCE_INLINE void *taosEncodeFixedI64(void *buf, int64_t value) {
|
||||
static FORCE_INLINE int taosEncodeFixedI64(void **buf, int64_t value) {
|
||||
return taosEncodeFixedU64(buf, ZIGZAGE(int64_t, value));
|
||||
}
|
||||
|
||||
|
@ -176,18 +193,21 @@ static FORCE_INLINE void *taosDecodeFixedI64(void *buf, int64_t *value) {
|
|||
}
|
||||
|
||||
// ---- Variant U16
|
||||
static FORCE_INLINE void *taosEncodeVariantU16(void *buf, uint16_t value) {
|
||||
static FORCE_INLINE int taosEncodeVariantU16(void **buf, uint16_t value) {
|
||||
int i = 0;
|
||||
while (value >= ENCODE_LIMIT) {
|
||||
((uint8_t *)buf)[i] = (value | ENCODE_LIMIT);
|
||||
if (buf != NULL) ((uint8_t *)(*buf))[i] = (value | ENCODE_LIMIT);
|
||||
value >>= 7;
|
||||
i++;
|
||||
ASSERT(i < 3);
|
||||
}
|
||||
|
||||
((uint8_t *)buf)[i] = value;
|
||||
if (buf != NULL) {
|
||||
((uint8_t *)(*buf))[i] = value;
|
||||
*buf = POINTER_SHIFT(*buf, i + 1);
|
||||
}
|
||||
|
||||
return POINTER_SHIFT(buf, i + 1);
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosDecodeVariantU16(void *buf, uint16_t *value) {
|
||||
|
@ -209,7 +229,7 @@ static FORCE_INLINE void *taosDecodeVariantU16(void *buf, uint16_t *value) {
|
|||
}
|
||||
|
||||
// ---- Variant I16
|
||||
static FORCE_INLINE void *taosEncodeVariantI16(void *buf, int16_t value) {
|
||||
static FORCE_INLINE int taosEncodeVariantI16(void **buf, int16_t value) {
|
||||
return taosEncodeVariantU16(buf, ZIGZAGE(int16_t, value));
|
||||
}
|
||||
|
||||
|
@ -221,18 +241,21 @@ static FORCE_INLINE void *taosDecodeVariantI16(void *buf, int16_t *value) {
|
|||
}
|
||||
|
||||
// ---- Variant U32
|
||||
static FORCE_INLINE void *taosEncodeVariantU32(void *buf, uint32_t value) {
|
||||
static FORCE_INLINE int taosEncodeVariantU32(void **buf, uint32_t value) {
|
||||
int i = 0;
|
||||
while (value >= ENCODE_LIMIT) {
|
||||
((uint8_t *)buf)[i] = (value | ENCODE_LIMIT);
|
||||
if (buf != NULL) ((uint8_t *)(*buf))[i] = (value | ENCODE_LIMIT);
|
||||
value >>= 7;
|
||||
i++;
|
||||
ASSERT(i < 5);
|
||||
}
|
||||
|
||||
((uint8_t *)buf)[i] = value;
|
||||
if (buf != NULL) {
|
||||
((uint8_t *)(*buf))[i] = value;
|
||||
*buf = POINTER_SHIFT(*buf, i + 1);
|
||||
}
|
||||
|
||||
return POINTER_SHIFT(buf, i + 1);
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosDecodeVariantU32(void *buf, uint32_t *value) {
|
||||
|
@ -254,7 +277,7 @@ static FORCE_INLINE void *taosDecodeVariantU32(void *buf, uint32_t *value) {
|
|||
}
|
||||
|
||||
// ---- Variant I32
|
||||
static FORCE_INLINE void *taosEncodeVariantI32(void *buf, int32_t value) {
|
||||
static FORCE_INLINE int taosEncodeVariantI32(void **buf, int32_t value) {
|
||||
return taosEncodeVariantU32(buf, ZIGZAGE(int32_t, value));
|
||||
}
|
||||
|
||||
|
@ -266,18 +289,21 @@ static FORCE_INLINE void *taosDecodeVariantI32(void *buf, int32_t *value) {
|
|||
}
|
||||
|
||||
// ---- Variant U64
|
||||
static FORCE_INLINE void *taosEncodeVariantU64(void *buf, uint64_t value) {
|
||||
static FORCE_INLINE int taosEncodeVariantU64(void **buf, uint64_t value) {
|
||||
int i = 0;
|
||||
while (value >= ENCODE_LIMIT) {
|
||||
((uint8_t *)buf)[i] = (value | ENCODE_LIMIT);
|
||||
if (buf != NULL) ((uint8_t *)(*buf))[i] = (value | ENCODE_LIMIT);
|
||||
value >>= 7;
|
||||
i++;
|
||||
ASSERT(i < 10);
|
||||
}
|
||||
|
||||
((uint8_t *)buf)[i] = value;
|
||||
if (buf != NULL) {
|
||||
((uint8_t *)(*buf))[i] = value;
|
||||
*buf = POINTER_SHIFT(*buf, i + 1);
|
||||
}
|
||||
|
||||
return POINTER_SHIFT(buf, i + 1);
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosDecodeVariantU64(void *buf, uint64_t *value) {
|
||||
|
@ -299,7 +325,7 @@ static FORCE_INLINE void *taosDecodeVariantU64(void *buf, uint64_t *value) {
|
|||
}
|
||||
|
||||
// ---- Variant I64
|
||||
static FORCE_INLINE void *taosEncodeVariantI64(void *buf, int64_t value) {
|
||||
static FORCE_INLINE int taosEncodeVariantI64(void **buf, int64_t value) {
|
||||
return taosEncodeVariantU64(buf, ZIGZAGE(int64_t, value));
|
||||
}
|
||||
|
||||
|
@ -311,13 +337,18 @@ static FORCE_INLINE void *taosDecodeVariantI64(void *buf, int64_t *value) {
|
|||
}
|
||||
|
||||
// ---- string
|
||||
static FORCE_INLINE void *taosEncodeString(void *buf, char *value) {
|
||||
static FORCE_INLINE int taosEncodeString(void **buf, char *value) {
|
||||
int tlen = 0;
|
||||
size_t size = strlen(value);
|
||||
|
||||
buf = taosEncodeVariantU64(buf, size);
|
||||
memcpy(buf, value, size);
|
||||
tlen += taosEncodeVariantU64(buf, size);
|
||||
if (buf != NULL) {
|
||||
memcpy(*buf, value, size);
|
||||
*buf = POINTER_SHIFT(*buf, size);
|
||||
}
|
||||
tlen += size;
|
||||
|
||||
return POINTER_SHIFT(buf, size);
|
||||
return tlen;
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosDecodeString(void *buf, char **value) {
|
||||
|
|
|
@ -25,7 +25,7 @@ typedef int (*iterFunc)(void *, void *cont, int contLen);
|
|||
typedef void (*afterFunc)(void *);
|
||||
|
||||
typedef struct {
|
||||
int64_t size;
|
||||
int64_t size; // including 512 bytes of header size
|
||||
int64_t tombSize;
|
||||
int64_t nRecords;
|
||||
int64_t nDels;
|
||||
|
|
|
@ -57,6 +57,7 @@ SListNode *tdListPopHead(SList *list);
|
|||
SListNode *tdListPopTail(SList *list);
|
||||
SListNode *tdListPopNode(SList *list, SListNode *node);
|
||||
void tdListMove(SList *src, SList *dst);
|
||||
void tdListDiscard(SList *list);
|
||||
|
||||
void tdListNodeGetData(SList *list, SListNode *node, void *target);
|
||||
void tdListInitIter(SList *list, SListIter *pIter, TD_LIST_DIRECTION_T direction);
|
||||
|
|
|
@ -31,7 +31,7 @@ typedef void (*_ref_fn_t)(const void* pObj);
|
|||
_ref_fn_t end; \
|
||||
} _ref_func = {.begin = (s), .end = (e)};
|
||||
|
||||
#define T_REF_INC(x) (atomic_add_fetch_16(&((x)->_ref.val), 1));
|
||||
#define T_REF_INC(x) (atomic_add_fetch_16(&((x)->_ref.val), 1))
|
||||
|
||||
#define T_REF_INC_WITH_CB(x, p) \
|
||||
do { \
|
||||
|
@ -41,7 +41,7 @@ typedef void (*_ref_fn_t)(const void* pObj);
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
#define T_REF_DEC(x) (atomic_sub_fetch_16(&((x)->_ref.val), 1));
|
||||
#define T_REF_DEC(x) (atomic_sub_fetch_16(&((x)->_ref.val), 1))
|
||||
|
||||
#define T_REF_DEC_WITH_CB(x, p) \
|
||||
do { \
|
||||
|
|
|
@ -309,9 +309,7 @@ void taosHashRemove(SHashObj *pHashObj, const void *key, size_t keyLen) {
|
|||
}
|
||||
|
||||
void taosHashCleanup(SHashObj *pHashObj) {
|
||||
if (pHashObj == NULL || pHashObj->capacity <= 0) {
|
||||
return;
|
||||
}
|
||||
if (pHashObj == NULL) return;
|
||||
|
||||
SHashNode *pNode, *pNext;
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ typedef struct {
|
|||
} SKVRecord;
|
||||
|
||||
static int tdInitKVStoreHeader(int fd, char *fname);
|
||||
static void * tdEncodeStoreInfo(void *buf, SStoreInfo *pInfo);
|
||||
static int tdEncodeStoreInfo(void **buf, SStoreInfo *pInfo);
|
||||
static void * tdDecodeStoreInfo(void *buf, SStoreInfo *pInfo);
|
||||
static SKVStore *tdNewKVStore(char *fname, iterFunc iFunc, afterFunc aFunc, void *appH);
|
||||
static char * tdGetKVStoreSnapshotFname(char *fdata);
|
||||
|
@ -49,7 +49,7 @@ static char * tdGetKVStoreNewFname(char *fdata);
|
|||
static void tdFreeKVStore(SKVStore *pStore);
|
||||
static int tdUpdateKVStoreHeader(int fd, char *fname, SStoreInfo *pInfo);
|
||||
static int tdLoadKVStoreHeader(int fd, char *fname, SStoreInfo *pInfo);
|
||||
static void * tdEncodeKVRecord(void *buf, SKVRecord *pRecord);
|
||||
static int tdEncodeKVRecord(void **buf, SKVRecord *pRecord);
|
||||
static void * tdDecodeKVRecord(void *buf, SKVRecord *pRecord);
|
||||
static int tdRestoreKVStore(SKVStore *pStore);
|
||||
|
||||
|
@ -61,25 +61,26 @@ int tdCreateKVStore(char *fname) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (tdInitKVStoreHeader(fd, fname) < 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
if (tdInitKVStoreHeader(fd, fname) < 0) goto _err;
|
||||
|
||||
if (fsync(fd) < 0) {
|
||||
uError("failed to fsync file %s since %s", fname, strerror(errno));
|
||||
terrno = TAOS_SYSTEM_ERROR(errno);
|
||||
close(fd);
|
||||
return -1;
|
||||
goto _err;
|
||||
}
|
||||
|
||||
if (close(fd) < 0) {
|
||||
uError("failed to close file %s since %s", fname, strerror(errno));
|
||||
terrno = TAOS_SYSTEM_ERROR(errno);
|
||||
return -1;
|
||||
goto _err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
_err:
|
||||
if (fd > 0) close(fd);
|
||||
remove(fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int tdDestroyKVStore(char *fname) {
|
||||
|
@ -105,7 +106,7 @@ SKVStore *tdOpenKVStore(char *fname, iterFunc iFunc, afterFunc aFunc, void *appH
|
|||
goto _err;
|
||||
}
|
||||
|
||||
if (access(pStore->fsnap, F_OK) == 0) {
|
||||
if (access(pStore->fsnap, F_OK) == 0) { // .snap file exists
|
||||
uTrace("file %s exists, try to recover the KV store", pStore->fsnap);
|
||||
pStore->sfd = open(pStore->fsnap, O_RDONLY);
|
||||
if (pStore->sfd < 0) {
|
||||
|
@ -114,16 +115,22 @@ SKVStore *tdOpenKVStore(char *fname, iterFunc iFunc, afterFunc aFunc, void *appH
|
|||
goto _err;
|
||||
}
|
||||
|
||||
if (tdLoadKVStoreHeader(pStore->sfd, pStore->fsnap, &info) < 0) goto _err;
|
||||
if (tdLoadKVStoreHeader(pStore->sfd, pStore->fsnap, &info) < 0) {
|
||||
if (terrno != TSDB_CODE_COM_FILE_CORRUPTED) goto _err;
|
||||
} else {
|
||||
if (ftruncate(pStore->fd, info.size) < 0) {
|
||||
uError("failed to truncate %s to %" PRId64 " size since %s", pStore->fname, info.size, strerror(errno));
|
||||
terrno = TAOS_SYSTEM_ERROR(errno);
|
||||
goto _err;
|
||||
}
|
||||
|
||||
if (ftruncate(pStore->fd, info.size) < 0) {
|
||||
uError("failed to truncate %s to %" PRId64 " size since %s", pStore->fname, info.size, strerror(errno));
|
||||
terrno = TAOS_SYSTEM_ERROR(errno);
|
||||
goto _err;
|
||||
if (tdUpdateKVStoreHeader(pStore->fd, pStore->fname, &info) < 0) goto _err;
|
||||
if (fsync(pStore->fd) < 0) {
|
||||
uError("failed to fsync file %s since %s", pStore->fname, strerror(errno));
|
||||
goto _err;
|
||||
}
|
||||
}
|
||||
|
||||
if (tdUpdateKVStoreHeader(pStore->fd, pStore->fname, &info) < 0) goto _err;
|
||||
|
||||
close(pStore->sfd);
|
||||
pStore->sfd = -1;
|
||||
remove(pStore->fsnap);
|
||||
|
@ -131,22 +138,7 @@ SKVStore *tdOpenKVStore(char *fname, iterFunc iFunc, afterFunc aFunc, void *appH
|
|||
|
||||
if (tdLoadKVStoreHeader(pStore->fd, pStore->fname, &info) < 0) goto _err;
|
||||
|
||||
struct stat tfstat;
|
||||
if (fstat(pStore->fd, &tfstat) < 0) {
|
||||
uError("failed to fstat file %s since %s", pStore->fname, strerror(errno));
|
||||
terrno = TAOS_SYSTEM_ERROR(errno);
|
||||
goto _err;
|
||||
}
|
||||
|
||||
ASSERT(info.size == tfstat.st_size);
|
||||
|
||||
if (lseek(pStore->fd, TD_KVSTORE_HEADER_SIZE, SEEK_SET) < 0) {
|
||||
uError("failed to lseek file %s since %s", pStore->fname, strerror(errno));
|
||||
terrno = TAOS_SYSTEM_ERROR(errno);
|
||||
goto _err;
|
||||
}
|
||||
|
||||
pStore->info.size += TD_KVSTORE_HEADER_SIZE;
|
||||
pStore->info.size = TD_KVSTORE_HEADER_SIZE;
|
||||
|
||||
if (tdRestoreKVStore(pStore) < 0) goto _err;
|
||||
|
||||
|
@ -230,12 +222,44 @@ _err:
|
|||
}
|
||||
|
||||
int tdUpdateKVStoreRecord(SKVStore *pStore, uint64_t uid, void *cont, int contLen) {
|
||||
SKVRecord *pRecord = taosHashGet(pStore->map, (void *)&uid, sizeof(uid));
|
||||
if (pRecord != NULL) {
|
||||
pStore->info.tombSize += (pRecord->size + sizeof(SKVRecord));
|
||||
SKVRecord rInfo = {0};
|
||||
char buf[64] = "\0";
|
||||
char * pBuf = buf;
|
||||
|
||||
rInfo.offset = lseek(pStore->fd, 0, SEEK_CUR);
|
||||
if (rInfo.offset < 0) {
|
||||
uError("failed to lseek file %s since %s", pStore->fname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO
|
||||
rInfo.uid = uid;
|
||||
rInfo.size = contLen;
|
||||
|
||||
int tlen = tdEncodeKVRecord((void *)(&pBuf), &rInfo);
|
||||
ASSERT(tlen == POINTER_DISTANCE(pBuf, buf));
|
||||
ASSERT(tlen == sizeof(SKVRecord));
|
||||
|
||||
if (twrite(pStore->fd, buf, tlen) < tlen) {
|
||||
uError("failed to write %d bytes to file %s since %s", tlen, pStore->fname, strerror(errno));
|
||||
terrno = TAOS_SYSTEM_ERROR(errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (twrite(pStore->fd, cont, contLen) < contLen) {
|
||||
uError("failed to write %d bytes to file %s since %s", contLen, pStore->fname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
pStore->info.size += (sizeof(SKVRecord) + contLen);
|
||||
SKVRecord *pRecord = taosHashGet(pStore->map, (void *)&uid, sizeof(uid));
|
||||
if (pRecord != NULL) { // just to insert
|
||||
pStore->info.tombSize += pRecord->size;
|
||||
} else {
|
||||
pStore->info.nRecords++;
|
||||
}
|
||||
|
||||
taosHashPut(pStore->map, (void *)(&uid), sizeof(uid), (void *)(&rInfo), sizeof(rInfo));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -243,7 +267,7 @@ int tdDropKVStoreRecord(SKVStore *pStore, uint64_t uid) {
|
|||
SKVRecord rInfo = {0};
|
||||
char buf[128] = "\0";
|
||||
|
||||
SKVRecord *pRecord = taosHashGet(pStore->map, &uid, sizeof(uid));
|
||||
SKVRecord *pRecord = taosHashGet(pStore->map, (void *)(&uid), sizeof(uid));
|
||||
if (pRecord == NULL) {
|
||||
uError("failed to drop KV store record with key %" PRIu64 " since not find", uid);
|
||||
return -1;
|
||||
|
@ -253,7 +277,8 @@ int tdDropKVStoreRecord(SKVStore *pStore, uint64_t uid) {
|
|||
rInfo.uid = pRecord->uid;
|
||||
rInfo.size = pRecord->size;
|
||||
|
||||
void *pBuf = tdEncodeKVRecord(buf, &rInfo);
|
||||
void *pBuf = buf;
|
||||
tdEncodeKVRecord(&pBuf, &rInfo);
|
||||
|
||||
if (twrite(pStore->fd, buf, POINTER_DISTANCE(pBuf, buf)) < POINTER_DISTANCE(pBuf, buf)) {
|
||||
uError("failed to write %" PRId64 " bytes to file %s since %s", POINTER_DISTANCE(pBuf, buf), pStore->fname, strerror(errno));
|
||||
|
@ -266,6 +291,8 @@ int tdDropKVStoreRecord(SKVStore *pStore, uint64_t uid) {
|
|||
pStore->info.nRecords--;
|
||||
pStore->info.tombSize += (rInfo.size + sizeof(SKVRecord) * 2);
|
||||
|
||||
taosHashRemove(pStore->map, (void *)(&uid), sizeof(uid));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -326,7 +353,10 @@ static int tdUpdateKVStoreHeader(int fd, char *fname, SStoreInfo *pInfo) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
tdEncodeStoreInfo(buf, pInfo);
|
||||
void *pBuf = buf;
|
||||
tdEncodeStoreInfo(&pBuf, pInfo);
|
||||
ASSERT(POINTER_DISTANCE(pBuf, buf) + sizeof(TSCKSUM) <= TD_KVSTORE_HEADER_SIZE);
|
||||
|
||||
taosCalcChecksumAppend(0, (uint8_t *)buf, TD_KVSTORE_HEADER_SIZE);
|
||||
if (twrite(fd, buf, TD_KVSTORE_HEADER_SIZE) < TD_KVSTORE_HEADER_SIZE) {
|
||||
uError("failed to write %d bytes to file %s since %s", TD_KVSTORE_HEADER_SIZE, fname, strerror(errno));
|
||||
|
@ -343,13 +373,14 @@ static int tdInitKVStoreHeader(int fd, char *fname) {
|
|||
return tdUpdateKVStoreHeader(fd, fname, &info);
|
||||
}
|
||||
|
||||
static void *tdEncodeStoreInfo(void *buf, SStoreInfo *pInfo) {
|
||||
buf = taosEncodeVariantI64(buf, pInfo->size);
|
||||
buf = taosEncodeVariantI64(buf, pInfo->tombSize);
|
||||
buf = taosEncodeVariantI64(buf, pInfo->nRecords);
|
||||
buf = taosEncodeVariantI64(buf, pInfo->nDels);
|
||||
static int tdEncodeStoreInfo(void **buf, SStoreInfo *pInfo) {
|
||||
int tlen = 0;
|
||||
tlen += taosEncodeVariantI64(buf, pInfo->size);
|
||||
tlen += taosEncodeVariantI64(buf, pInfo->tombSize);
|
||||
tlen += taosEncodeVariantI64(buf, pInfo->nRecords);
|
||||
tlen += taosEncodeVariantI64(buf, pInfo->nDels);
|
||||
|
||||
return buf;
|
||||
return tlen;
|
||||
}
|
||||
|
||||
static void *tdDecodeStoreInfo(void *buf, SStoreInfo *pInfo) {
|
||||
|
@ -362,17 +393,19 @@ static void *tdDecodeStoreInfo(void *buf, SStoreInfo *pInfo) {
|
|||
}
|
||||
|
||||
static SKVStore *tdNewKVStore(char *fname, iterFunc iFunc, afterFunc aFunc, void *appH) {
|
||||
SKVStore *pStore = (SKVStore *)malloc(sizeof(SKVStore));
|
||||
SKVStore *pStore = (SKVStore *)calloc(1, sizeof(SKVStore));
|
||||
if (pStore == NULL) goto _err;
|
||||
|
||||
pStore->fname = strdup(fname);
|
||||
if (pStore->map == NULL) {
|
||||
if (pStore->fname == NULL) {
|
||||
terrno = TSDB_CODE_COM_OUT_OF_MEMORY;
|
||||
goto _err;
|
||||
}
|
||||
|
||||
pStore->fsnap = tdGetKVStoreSnapshotFname(fname);
|
||||
if (pStore->fsnap == NULL) goto _err;
|
||||
if (pStore->fsnap == NULL) {
|
||||
goto _err;
|
||||
}
|
||||
|
||||
pStore->fnew = tdGetKVStoreNewFname(fname);
|
||||
if (pStore->fnew == NULL) goto _err;
|
||||
|
@ -428,12 +461,13 @@ static char *tdGetKVStoreNewFname(char *fdata) {
|
|||
return fname;
|
||||
}
|
||||
|
||||
static void *tdEncodeKVRecord(void *buf, SKVRecord *pRecord) {
|
||||
buf = taosEncodeFixedU64(buf, pRecord->uid);
|
||||
buf = taosEncodeFixedI64(buf, pRecord->offset);
|
||||
buf = taosEncodeFixedI64(buf, pRecord->size);
|
||||
static int tdEncodeKVRecord(void **buf, SKVRecord *pRecord) {
|
||||
int tlen = 0;
|
||||
tlen += taosEncodeFixedU64(buf, pRecord->uid);
|
||||
tlen += taosEncodeFixedI64(buf, pRecord->offset);
|
||||
tlen += taosEncodeFixedI64(buf, pRecord->size);
|
||||
|
||||
return buf;
|
||||
return tlen;
|
||||
}
|
||||
|
||||
static void *tdDecodeKVRecord(void *buf, SKVRecord *pRecord) {
|
||||
|
@ -452,28 +486,29 @@ static int tdRestoreKVStore(SKVStore *pStore) {
|
|||
SHashMutableIterator *pIter = NULL;
|
||||
|
||||
ASSERT(TD_KVSTORE_HEADER_SIZE == lseek(pStore->fd, 0, SEEK_CUR));
|
||||
ASSERT(pStore->info.size == TD_KVSTORE_HEADER_SIZE);
|
||||
|
||||
while (true) {
|
||||
ssize_t tsize = tread(pStore->fd, tbuf, sizeof(SKVRecord));
|
||||
if (tsize == 0) break;
|
||||
if (tsize < sizeof(SKVRecord)) {
|
||||
uError("failed to read %zu bytes from file %s since %s", sizeof(SKVRecord), pStore->fname, strerror(errno));
|
||||
uError("failed to read %zu bytes from file %s at offset %" PRId64 "since %s", sizeof(SKVRecord), pStore->fname,
|
||||
pStore->info.size, strerror(errno));
|
||||
terrno = TAOS_SYSTEM_ERROR(errno);
|
||||
goto _err;
|
||||
}
|
||||
|
||||
char *pBuf = tdDecodeKVRecord(tbuf, &rInfo);
|
||||
ASSERT(POINTER_DISTANCE(pBuf, tbuf) == sizeof(SKVRecord));
|
||||
ASSERT(rInfo.offset > 0 ? pStore->info.size == rInfo.offset : true);
|
||||
ASSERT(pStore->info.size == rInfo.offset);
|
||||
|
||||
if (rInfo.offset < 0) {
|
||||
taosHashRemove(pStore->map, (void *)(&rInfo.uid), sizeof(rInfo.uid));
|
||||
pStore->info.size += sizeof(SKVRecord);
|
||||
pStore->info.nRecords--;
|
||||
pStore->info.nDels++;
|
||||
pStore->info.tombSize += (rInfo.size + sizeof(SKVRecord) + sizeof(SKVRecord));
|
||||
pStore->info.tombSize += (rInfo.size + sizeof(SKVRecord) * 2);
|
||||
} else {
|
||||
// TODO: add statistics
|
||||
ASSERT(rInfo.offset > 0 && rInfo.size > 0);
|
||||
if (taosHashPut(pStore->map, (void *)(&rInfo.uid), sizeof(rInfo.uid), &rInfo, sizeof(rInfo)) < 0) {
|
||||
uError("failed to put record in KV store %s", pStore->fname);
|
||||
|
@ -488,6 +523,9 @@ static int tdRestoreKVStore(SKVStore *pStore) {
|
|||
terrno = TAOS_SYSTEM_ERROR(errno);
|
||||
goto _err;
|
||||
}
|
||||
|
||||
pStore->info.size += (sizeof(SKVRecord) + rInfo.size);
|
||||
pStore->info.nRecords++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -508,36 +546,37 @@ static int tdRestoreKVStore(SKVStore *pStore) {
|
|||
while (taosHashIterNext(pIter)) {
|
||||
SKVRecord *pRecord = taosHashIterGet(pIter);
|
||||
|
||||
if (lseek(pStore->fd, pRecord->offset, SEEK_SET) < 0) {
|
||||
uError("failed to lseek file %s since %s", pStore->fname, strerror(errno));
|
||||
if (lseek(pStore->fd, pRecord->offset + sizeof(SKVRecord), SEEK_SET) < 0) {
|
||||
uError("failed to lseek file %s since %s, offset %" PRId64, pStore->fname, strerror(errno), pRecord->offset);
|
||||
terrno = TAOS_SYSTEM_ERROR(errno);
|
||||
goto _err;
|
||||
}
|
||||
|
||||
if (tread(pStore->fd, buf, pRecord->size) < pRecord->size) {
|
||||
uError("failed to read %" PRId64 " bytes from file %s since %s", pRecord->size, pStore->fname, strerror(errno));
|
||||
uError("failed to read %" PRId64 " bytes from file %s since %s, offset %" PRId64, pRecord->size, pStore->fname,
|
||||
strerror(errno), pRecord->offset);
|
||||
terrno = TAOS_SYSTEM_ERROR(errno);
|
||||
goto _err;
|
||||
}
|
||||
|
||||
if (!taosCheckChecksumWhole((uint8_t *)buf, pRecord->size)) {
|
||||
uError("file %s has checksum error, offset %" PRId64 " size %" PRId64, pStore->fname, pRecord->offset, pRecord->size);
|
||||
terrno = TSDB_CODE_COM_FILE_CORRUPTED;
|
||||
goto _err;
|
||||
if (pStore->iFunc) {
|
||||
if ((*pStore->iFunc)(pStore->appH, buf, pRecord->size) < 0) {
|
||||
uError("failed to restore record uid %" PRIu64 " in kv store %s at offset %" PRId64 " size %" PRId64
|
||||
" since %s",
|
||||
pRecord->uid, pStore->fname, pRecord->offset, pRecord->size, tstrerror(terrno));
|
||||
goto _err;
|
||||
}
|
||||
}
|
||||
|
||||
if (pStore->iFunc) (*pStore->iFunc)(pStore->appH, buf, pRecord->size);
|
||||
}
|
||||
|
||||
taosHashDestroyIter(pIter);
|
||||
|
||||
if (pStore->aFunc) (*pStore->aFunc)(pStore->appH);
|
||||
|
||||
taosHashDestroyIter(pIter);
|
||||
tfree(buf);
|
||||
return 0;
|
||||
|
||||
_err:
|
||||
tfree(buf);
|
||||
taosHashDestroyIter(pIter);
|
||||
tfree(buf);
|
||||
return -1;
|
||||
}
|
|
@ -39,8 +39,10 @@ void tdListEmpty(SList *list) {
|
|||
}
|
||||
|
||||
void tdListFree(SList *list) {
|
||||
tdListEmpty(list);
|
||||
free(list);
|
||||
if (list) {
|
||||
tdListEmpty(list);
|
||||
free(list);
|
||||
}
|
||||
}
|
||||
|
||||
void tdListPrependNode(SList *list, SListNode *node) {
|
||||
|
@ -81,7 +83,7 @@ int tdListPrepend(SList *list, void *data) {
|
|||
}
|
||||
|
||||
int tdListAppend(SList *list, void *data) {
|
||||
SListNode *node = (SListNode *)malloc(sizeof(SListNode) + list->eleSize);
|
||||
SListNode *node = (SListNode *)calloc(1, sizeof(SListNode) + list->eleSize);
|
||||
if (node == NULL) return -1;
|
||||
|
||||
memcpy((void *)(node->data), data, list->eleSize);
|
||||
|
@ -148,6 +150,13 @@ void tdListMove(SList *src, SList *dst) {
|
|||
}
|
||||
}
|
||||
|
||||
void tdListDiscard(SList *list) {
|
||||
if (list) {
|
||||
list->head = list->tail = NULL;
|
||||
list->numOfEles = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void tdListNodeGetData(SList *list, SListNode *node, void *target) { memcpy(target, node->data, list->eleSize); }
|
||||
|
||||
void tdListInitIter(SList *list, SListIter *pIter, TD_LIST_DIRECTION_T direction) {
|
||||
|
|
|
@ -219,6 +219,8 @@ void *tSkipListDestroy(SSkipList *pSkipList) {
|
|||
|
||||
void tSkipListNewNodeInfo(SSkipList *pSkipList, int32_t *level, int32_t *headSize) {
|
||||
if (pSkipList == NULL) {
|
||||
*level = 1;
|
||||
*headSize = SL_NODE_HEADER_SIZE(*level);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -277,7 +279,7 @@ SSkipListNode *tSkipListPut(SSkipList *pSkipList, SSkipListNode *pNode) {
|
|||
pthread_rwlock_unlock(pSkipList->lock);
|
||||
}
|
||||
|
||||
return forward[0];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tSkipListDoInsert(pSkipList, forward, pNode);
|
||||
|
|
|
@ -58,6 +58,7 @@ uint32_t taosRand(void)
|
|||
#endif
|
||||
|
||||
size_t twcslen(const wchar_t *wcs) {
|
||||
#ifdef WINDOWS
|
||||
int *wstr = (int *)wcs;
|
||||
if (NULL == wstr) {
|
||||
return 0;
|
||||
|
@ -72,6 +73,9 @@ size_t twcslen(const wchar_t *wcs) {
|
|||
}
|
||||
|
||||
return n;
|
||||
#else
|
||||
return wcslen(wcs);
|
||||
#endif
|
||||
}
|
||||
|
||||
int32_t strdequote(char *z) {
|
||||
|
|
|
@ -9,120 +9,144 @@ static bool test_fixed_uint16(uint16_t value) {
|
|||
char buf[20] = "\0";
|
||||
uint16_t value_check = 0;
|
||||
|
||||
void *ptr1 = taosEncodeFixedU16(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeFixedU16(static_cast<void *>(buf), &value_check);
|
||||
void *pBuf = (void *)buf;
|
||||
|
||||
return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2));
|
||||
int tlen = taosEncodeFixedU16(static_cast<void **>(&pBuf), value);
|
||||
void *ptr = taosDecodeFixedU16(static_cast<void *>(buf), &value_check);
|
||||
|
||||
return ((ptr != NULL) && (value == value_check) && (pBuf == ptr) && POINTER_DISTANCE(pBuf, buf) == tlen);
|
||||
}
|
||||
|
||||
static bool test_fixed_int16(int16_t value) {
|
||||
char buf[20] = "\0";
|
||||
int16_t value_check = 0;
|
||||
|
||||
void *ptr1 = taosEncodeFixedI16(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeFixedI16(static_cast<void *>(buf), &value_check);
|
||||
void *pBuf = (void *)buf;
|
||||
|
||||
return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2));
|
||||
int tlen = taosEncodeFixedI16(static_cast<void **>(&pBuf), value);
|
||||
void *ptr = taosDecodeFixedI16(static_cast<void *>(buf), &value_check);
|
||||
|
||||
return ((ptr != NULL) && (value == value_check) && (pBuf == ptr) && POINTER_DISTANCE(pBuf, buf) == tlen);
|
||||
}
|
||||
|
||||
static bool test_fixed_uint32(uint32_t value) {
|
||||
char buf[20] = "\0";
|
||||
uint32_t value_check = 0;
|
||||
|
||||
void *ptr1 = taosEncodeFixedU32(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeFixedU32(static_cast<void *>(buf), &value_check);
|
||||
void *pBuf = (void *)buf;
|
||||
|
||||
return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2));
|
||||
int tlen = taosEncodeFixedU32(static_cast<void **>(&pBuf), value);
|
||||
void *ptr = taosDecodeFixedU32(static_cast<void *>(buf), &value_check);
|
||||
|
||||
return ((ptr != NULL) && (value == value_check) && (pBuf == ptr) && POINTER_DISTANCE(pBuf, buf) == tlen);
|
||||
}
|
||||
|
||||
static bool test_fixed_int32(int32_t value) {
|
||||
char buf[20] = "\0";
|
||||
int32_t value_check = 0;
|
||||
|
||||
void *ptr1 = taosEncodeFixedI32(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeFixedI32(static_cast<void *>(buf), &value_check);
|
||||
void *pBuf = (void *)buf;
|
||||
|
||||
return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2));
|
||||
int tlen = taosEncodeFixedI32(static_cast<void **>(&pBuf), value);
|
||||
void *ptr = taosDecodeFixedI32(static_cast<void *>(buf), &value_check);
|
||||
|
||||
return ((ptr != NULL) && (value == value_check) && (pBuf == ptr) && POINTER_DISTANCE(pBuf, buf) == tlen);
|
||||
}
|
||||
|
||||
static bool test_fixed_uint64(uint64_t value) {
|
||||
char buf[20] = "\0";
|
||||
uint64_t value_check = 0;
|
||||
|
||||
void *ptr1 = taosEncodeFixedU64(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeFixedU64(static_cast<void *>(buf), &value_check);
|
||||
void *pBuf = (void *)buf;
|
||||
|
||||
return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2));
|
||||
int tlen = taosEncodeFixedU64(static_cast<void **>(&pBuf), value);
|
||||
void *ptr = taosDecodeFixedU64(static_cast<void *>(buf), &value_check);
|
||||
|
||||
return ((ptr != NULL) && (value == value_check) && (pBuf == ptr) && POINTER_DISTANCE(pBuf, buf) == tlen);
|
||||
}
|
||||
|
||||
static bool test_fixed_int64(int64_t value) {
|
||||
char buf[20] = "\0";
|
||||
int64_t value_check = 0;
|
||||
|
||||
void *ptr1 = taosEncodeFixedI64(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeFixedI64(static_cast<void *>(buf), &value_check);
|
||||
void *pBuf = (void *)buf;
|
||||
|
||||
return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2));
|
||||
int tlen = taosEncodeFixedI64(static_cast<void **>(&pBuf), value);
|
||||
void *ptr = taosDecodeFixedI64(static_cast<void *>(buf), &value_check);
|
||||
|
||||
return ((ptr != NULL) && (value == value_check) && (pBuf == ptr) && POINTER_DISTANCE(pBuf, buf) == tlen);
|
||||
}
|
||||
|
||||
static bool test_variant_uint16(uint16_t value) {
|
||||
char buf[20] = "\0";
|
||||
uint16_t value_check = 0;
|
||||
|
||||
void *ptr1 = taosEncodeVariantU16(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeVariantU16(static_cast<void *>(buf), &value_check);
|
||||
void *pBuf = (void *)buf;
|
||||
|
||||
return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2));
|
||||
int tlen = taosEncodeVariantU16(static_cast<void **>(&pBuf), value);
|
||||
void *ptr = taosDecodeVariantU16(static_cast<void *>(buf), &value_check);
|
||||
|
||||
return ((ptr != NULL) && (value == value_check) && (pBuf == ptr) && POINTER_DISTANCE(pBuf, buf) == tlen);
|
||||
}
|
||||
|
||||
static bool test_variant_int16(int16_t value) {
|
||||
char buf[20] = "\0";
|
||||
int16_t value_check = 0;
|
||||
|
||||
void *ptr1 = taosEncodeVariantI16(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeVariantI16(static_cast<void *>(buf), &value_check);
|
||||
void *pBuf = (void *)buf;
|
||||
|
||||
return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2));
|
||||
int tlen = taosEncodeVariantI16(static_cast<void **>(&pBuf), value);
|
||||
void *ptr = taosDecodeVariantI16(static_cast<void *>(buf), &value_check);
|
||||
|
||||
return ((ptr != NULL) && (value == value_check) && (pBuf == ptr) && POINTER_DISTANCE(pBuf, buf) == tlen);
|
||||
}
|
||||
|
||||
static bool test_variant_uint32(uint32_t value) {
|
||||
char buf[20] = "\0";
|
||||
uint32_t value_check = 0;
|
||||
|
||||
void *ptr1 = taosEncodeVariantU32(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeVariantU32(static_cast<void *>(buf), &value_check);
|
||||
void *pBuf = (void *)buf;
|
||||
|
||||
return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2));
|
||||
int tlen = taosEncodeVariantU32(static_cast<void **>(&pBuf), value);
|
||||
void *ptr = taosDecodeVariantU32(static_cast<void *>(buf), &value_check);
|
||||
|
||||
return ((ptr != NULL) && (value == value_check) && (pBuf == ptr) && POINTER_DISTANCE(pBuf, buf) == tlen);
|
||||
}
|
||||
|
||||
static bool test_variant_int32(int32_t value) {
|
||||
char buf[20] = "\0";
|
||||
int32_t value_check = 0;
|
||||
|
||||
void *ptr1 = taosEncodeVariantI32(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeVariantI32(static_cast<void *>(buf), &value_check);
|
||||
void *pBuf = (void *)buf;
|
||||
|
||||
return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2));
|
||||
int tlen = taosEncodeVariantI32(static_cast<void **>(&pBuf), value);
|
||||
void *ptr = taosDecodeVariantI32(static_cast<void *>(buf), &value_check);
|
||||
|
||||
return ((ptr != NULL) && (value == value_check) && (pBuf == ptr) && POINTER_DISTANCE(pBuf, buf) == tlen);
|
||||
}
|
||||
|
||||
static bool test_variant_uint64(uint64_t value) {
|
||||
char buf[20] = "\0";
|
||||
uint64_t value_check = 0;
|
||||
|
||||
void *ptr1 = taosEncodeVariantU64(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeVariantU64(static_cast<void *>(buf), &value_check);
|
||||
void *pBuf = (void *)buf;
|
||||
|
||||
return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2));
|
||||
int tlen = taosEncodeVariantU64(static_cast<void **>(&pBuf), value);
|
||||
void *ptr = taosDecodeVariantU64(static_cast<void *>(buf), &value_check);
|
||||
|
||||
return ((ptr != NULL) && (value == value_check) && (pBuf == ptr) && POINTER_DISTANCE(pBuf, buf) == tlen);
|
||||
}
|
||||
|
||||
static bool test_variant_int64(int64_t value) {
|
||||
char buf[20] = "\0";
|
||||
int64_t value_check = 0;
|
||||
|
||||
void *ptr1 = taosEncodeVariantI64(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeVariantI64(static_cast<void *>(buf), &value_check);
|
||||
void *pBuf = (void *)buf;
|
||||
|
||||
return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2));
|
||||
int tlen = taosEncodeVariantI64(static_cast<void **>(&pBuf), value);
|
||||
void *ptr = taosDecodeVariantI64(static_cast<void *>(buf), &value_check);
|
||||
|
||||
return ((ptr != NULL) && (value == value_check) && (pBuf == ptr) && POINTER_DISTANCE(pBuf, buf) == tlen);
|
||||
}
|
||||
|
||||
TEST(codingTest, fixed_encode_decode) {
|
||||
|
|
|
@ -123,7 +123,7 @@ int32_t vnodeCreate(SMDCreateVnodeMsg *pVnodeCfg) {
|
|||
|
||||
char tsdbDir[TSDB_FILENAME_LEN] = {0};
|
||||
sprintf(tsdbDir, "%s/vnode%d/tsdb", tsVnodeDir, pVnodeCfg->cfg.vgId);
|
||||
code = tsdbCreateRepo(tsdbDir, &tsdbCfg, NULL);
|
||||
code = tsdbCreateRepo(tsdbDir, &tsdbCfg);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
vError("vgId:%d, failed to create tsdb in vnode, reason:%s", pVnodeCfg->cfg.vgId, tstrerror(code));
|
||||
return TSDB_CODE_VND_INIT_FAILED;
|
||||
|
|
|
@ -91,7 +91,7 @@ int32_t vnodeProcessWrite(void *param1, int qtype, void *param2, void *item) {
|
|||
}
|
||||
|
||||
static int32_t vnodeProcessSubmitMsg(SVnodeObj *pVnode, void *pCont, SRspRet *pRet) {
|
||||
int32_t code = 0;
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
|
||||
// save insert result into item
|
||||
|
||||
|
@ -100,7 +100,7 @@ static int32_t vnodeProcessSubmitMsg(SVnodeObj *pVnode, void *pCont, SRspRet *pR
|
|||
pRet->len = sizeof(SShellSubmitRspMsg);
|
||||
pRet->rsp = rpcMallocCont(pRet->len);
|
||||
SShellSubmitRspMsg *pRsp = pRet->rsp;
|
||||
code = tsdbInsertData(pVnode->tsdb, pCont, pRsp);
|
||||
if (tsdbInsertData(pVnode->tsdb, pCont, pRsp) < 0) code = terrno;
|
||||
pRsp->numOfFailedBlocks = 0; //TODO
|
||||
//pRet->len += pRsp->numOfFailedBlocks * sizeof(SShellSubmitRspBlock); //TODO
|
||||
pRsp->code = 0;
|
||||
|
@ -110,10 +110,11 @@ static int32_t vnodeProcessSubmitMsg(SVnodeObj *pVnode, void *pCont, SRspRet *pR
|
|||
}
|
||||
|
||||
static int32_t vnodeProcessCreateTableMsg(SVnodeObj *pVnode, void *pCont, SRspRet *pRet) {
|
||||
int code = TSDB_CODE_SUCCESS;
|
||||
|
||||
STableCfg *pCfg = tsdbCreateTableCfgFromMsg((SMDCreateTableMsg *)pCont);
|
||||
if (pCfg == NULL) return terrno;
|
||||
int32_t code = tsdbCreateTable(pVnode->tsdb, pCfg);
|
||||
if (tsdbCreateTable(pVnode->tsdb, pCfg) < 0) code = terrno;
|
||||
|
||||
tsdbClearTableCfg(pCfg);
|
||||
return code;
|
||||
|
@ -121,47 +122,40 @@ static int32_t vnodeProcessCreateTableMsg(SVnodeObj *pVnode, void *pCont, SRspRe
|
|||
|
||||
static int32_t vnodeProcessDropTableMsg(SVnodeObj *pVnode, void *pCont, SRspRet *pRet) {
|
||||
SMDDropTableMsg *pTable = pCont;
|
||||
int32_t code = 0;
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
|
||||
vTrace("vgId:%d, table:%s, start to drop", pVnode->vgId, pTable->tableId);
|
||||
STableId tableId = {
|
||||
.uid = htobe64(pTable->uid),
|
||||
.tid = htonl(pTable->sid)
|
||||
};
|
||||
STableId tableId = {.uid = htobe64(pTable->uid), .tid = htonl(pTable->sid)};
|
||||
|
||||
code = tsdbDropTable(pVnode->tsdb, tableId);
|
||||
if (tsdbDropTable(pVnode->tsdb, tableId) < 0) code = terrno;
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t vnodeProcessAlterTableMsg(SVnodeObj *pVnode, void *pCont, SRspRet *pRet) {
|
||||
STableCfg *pCfg = tsdbCreateTableCfgFromMsg((SMDCreateTableMsg *)pCont);
|
||||
if (pCfg == NULL) return terrno;
|
||||
int32_t code = tsdbAlterTable(pVnode->tsdb, pCfg);
|
||||
tsdbClearTableCfg(pCfg);
|
||||
return code;
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static int32_t vnodeProcessDropStableMsg(SVnodeObj *pVnode, void *pCont, SRspRet *pRet) {
|
||||
SMDDropSTableMsg *pTable = pCont;
|
||||
int32_t code = 0;
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
|
||||
vTrace("vgId:%d, stable:%s, start to drop", pVnode->vgId, pTable->tableId);
|
||||
|
||||
STableId stableId = {
|
||||
.uid = htobe64(pTable->uid),
|
||||
.tid = -1
|
||||
};
|
||||
|
||||
code = tsdbDropTable(pVnode->tsdb, stableId);
|
||||
|
||||
STableId stableId = {.uid = htobe64(pTable->uid), .tid = -1};
|
||||
|
||||
if (tsdbDropTable(pVnode->tsdb, stableId) < 0) code = terrno;
|
||||
|
||||
vTrace("vgId:%d, stable:%s, drop stable result:%s", pVnode->vgId, pTable->tableId, tstrerror(code));
|
||||
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t vnodeProcessUpdateTagValMsg(SVnodeObj *pVnode, void *pCont, SRspRet *pRet) {
|
||||
return tsdbUpdateTagValue(pVnode->tsdb, (SUpdateTableTagValMsg *)pCont);
|
||||
if (tsdbUpdateTagValue(pVnode->tsdb, (SUpdateTableTagValMsg *)pCont) < 0) {
|
||||
return terrno;
|
||||
}
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
int vnodeWriteToQueue(void *param, void *data, int type) {
|
||||
|
|
|
@ -0,0 +1,259 @@
|
|||
###################################################################
|
||||
# Copyright (c) 2016 by TAOS Technologies, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This file is proprietary and confidential to TAOS Technologies.
|
||||
# No part of this file may be reproduced, stored, transmitted,
|
||||
# disclosed or used in any form or by any means other than as
|
||||
# expressly provided by the written permission from Jianhui Tao
|
||||
#
|
||||
###################################################################
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
import random
|
||||
import threading
|
||||
import queue
|
||||
|
||||
from util.log import *
|
||||
from util.cases import *
|
||||
from util.sql import *
|
||||
from util.dnodes import *
|
||||
|
||||
current_tb = ""
|
||||
last_tb = ""
|
||||
written = 0
|
||||
|
||||
|
||||
class Test (threading.Thread):
|
||||
def __init__(self, threadId, name, sleepTime, q):
|
||||
threading.Thread.__init__(self)
|
||||
self.threadId = threadId
|
||||
self.name = name
|
||||
self.sleepTime = sleepTime
|
||||
self.q = q
|
||||
|
||||
self.threadLock = threading.Lock()
|
||||
|
||||
def create_table(self):
|
||||
global current_tb
|
||||
global last_tb
|
||||
global written
|
||||
|
||||
tdLog.info("create a table")
|
||||
current_tb = "tb%d" % int(round(time.time() * 1000))
|
||||
tdLog.info("current table %s" % current_tb)
|
||||
|
||||
if (current_tb == last_tb):
|
||||
return
|
||||
else:
|
||||
tdSql.execute(
|
||||
'create table %s (ts timestamp, speed int)' %
|
||||
current_tb)
|
||||
last_tb = current_tb
|
||||
written = 0
|
||||
|
||||
def insert_data(self):
|
||||
global current_tb
|
||||
global last_tb
|
||||
global written
|
||||
|
||||
tdLog.info("will insert data to table")
|
||||
if (current_tb == ""):
|
||||
tdLog.info("no table, create first")
|
||||
self.create_table()
|
||||
|
||||
tdLog.info("insert data to table")
|
||||
for i in range(0, 10):
|
||||
self.threadLock.acquire()
|
||||
insertRows = 1000
|
||||
tdLog.info("insert %d rows to %s" % (insertRows, current_tb))
|
||||
|
||||
for j in range(0, insertRows):
|
||||
ret = tdSql.execute(
|
||||
'insert into %s values (now + %dm, %d)' %
|
||||
(current_tb, j, j))
|
||||
written = written + 1
|
||||
self.threadLock.release()
|
||||
|
||||
def query_data(self):
|
||||
global current_tb
|
||||
global last_tb
|
||||
global written
|
||||
|
||||
if (written > 0):
|
||||
tdLog.info("query data from table")
|
||||
tdSql.query("select * from %s" % last_tb)
|
||||
tdSql.checkRows(written)
|
||||
|
||||
def query_stable(self):
|
||||
tdLog.sleep(10)
|
||||
self.threadLock.acquire()
|
||||
tdLog.info("query super table")
|
||||
|
||||
try:
|
||||
tdSql.query("select * from st")
|
||||
except Exception as e:
|
||||
tdLog.info(repr(e))
|
||||
self.q.put(-1)
|
||||
tdLog.exit("failed")
|
||||
tdSql.checkRows(1)
|
||||
self.threadLock.release()
|
||||
|
||||
def create_stable(self):
|
||||
global current_tb
|
||||
global last_tb
|
||||
global written
|
||||
|
||||
self.threadLock.acquire()
|
||||
|
||||
tdLog.info("create a super table and sub-table and insert data")
|
||||
|
||||
try:
|
||||
tdSql.execute(
|
||||
"create table if not exists st (ts timestamp, tagtype int) tags(dev nchar(50))")
|
||||
tdSql.execute(
|
||||
'CREATE TABLE if not exists dev_001 using st tags("dev_01")')
|
||||
tdSql.execute(
|
||||
"INSERT INTO dev_001(ts, tagtype) VALUES('2020-05-13 10:00:00.000', 1)")
|
||||
except Exception as e:
|
||||
tdLog.info(repr(e))
|
||||
self.q.put(-1)
|
||||
tdLog.exit("failed")
|
||||
self.stop_database()
|
||||
self.delete_datafiles()
|
||||
self.restart_database()
|
||||
self.threadLock.release()
|
||||
|
||||
def stop_database(self):
|
||||
tdLog.info("stop databae")
|
||||
tdDnodes.stop(1)
|
||||
|
||||
def restart_database(self):
|
||||
global current_tb
|
||||
global last_tb
|
||||
global written
|
||||
|
||||
tdLog.info("restart databae")
|
||||
tdDnodes.stop(1)
|
||||
tdDnodes.start(1)
|
||||
tdLog.sleep(5)
|
||||
|
||||
def force_restart(self):
|
||||
global current_tb
|
||||
global last_tb
|
||||
global written
|
||||
|
||||
tdLog.info("force restart database")
|
||||
tdDnodes.forcestop(1)
|
||||
tdDnodes.start(1)
|
||||
tdLog.sleep(5)
|
||||
|
||||
def drop_table(self):
|
||||
global current_tb
|
||||
global last_tb
|
||||
global written
|
||||
|
||||
for i in range(0, 10):
|
||||
self.threadLock.acquire()
|
||||
|
||||
tdLog.info("current_tb %s" % current_tb)
|
||||
|
||||
if (current_tb != ""):
|
||||
tdLog.info("drop current tb %s" % current_tb)
|
||||
tdSql.execute("drop table %s" % current_tb)
|
||||
current_tb = ""
|
||||
last_tb = ""
|
||||
written = 0
|
||||
tdLog.sleep(self.sleepTime)
|
||||
self.threadLock.release()
|
||||
|
||||
def reset_query_cache(self):
|
||||
global current_tb
|
||||
global last_tb
|
||||
global written
|
||||
|
||||
tdLog.info("reset query cache")
|
||||
tdSql.execute("reset query cache")
|
||||
tdLog.sleep(1)
|
||||
|
||||
def reset_database(self):
|
||||
global current_tb
|
||||
global last_tb
|
||||
global written
|
||||
|
||||
tdLog.info("reset database")
|
||||
tdDnodes.forcestop(1)
|
||||
tdDnodes.deploy(1)
|
||||
current_tb = ""
|
||||
last_tb = ""
|
||||
written = 0
|
||||
tdDnodes.start(1)
|
||||
tdSql.prepare()
|
||||
|
||||
def delete_datafiles(self):
|
||||
global current_tb
|
||||
global last_tb
|
||||
global written
|
||||
|
||||
tdLog.info("delete data files")
|
||||
dnodesDir = tdDnodes.getDnodesRootDir()
|
||||
dataDir = dnodesDir + '/dnode1/*'
|
||||
deleteCmd = 'rm -rf %s' % dataDir
|
||||
os.system(deleteCmd)
|
||||
|
||||
current_tb = ""
|
||||
last_tb = ""
|
||||
written = 0
|
||||
tdDnodes.start(1)
|
||||
tdSql.prepare()
|
||||
|
||||
def run(self):
|
||||
switch = {
|
||||
1: self.create_table,
|
||||
2: self.insert_data,
|
||||
3: self.query_data,
|
||||
4: self.create_stable,
|
||||
5: self.restart_database,
|
||||
6: self.force_restart,
|
||||
7: self.drop_table,
|
||||
8: self.reset_query_cache,
|
||||
9: self.reset_database,
|
||||
10: self.delete_datafiles,
|
||||
11: self.query_stable,
|
||||
}
|
||||
|
||||
switch.get(self.threadId, lambda: "ERROR")()
|
||||
|
||||
|
||||
class TDTestCase:
|
||||
def init(self, conn, logSql):
|
||||
tdLog.debug("start to execute %s" % __file__)
|
||||
tdSql.init(conn.cursor(), logSql)
|
||||
|
||||
def run(self):
|
||||
tdSql.prepare()
|
||||
|
||||
q = queue.Queue()
|
||||
test1 = Test(4, "create_stable", 1, q)
|
||||
test2 = Test(11, "query_stable", 2, q)
|
||||
|
||||
test1.start()
|
||||
test2.start()
|
||||
test1.join()
|
||||
test2.join()
|
||||
|
||||
while not q.empty():
|
||||
if (q.get() == -1):
|
||||
tdLog.exit("failed to end of test")
|
||||
|
||||
tdLog.info("end of test")
|
||||
|
||||
def stop(self):
|
||||
tdSql.close()
|
||||
tdLog.success("%s successfully executed" % __file__)
|
||||
|
||||
|
||||
tdCases.addWindows(__file__, TDTestCase())
|
||||
tdCases.addLinux(__file__, TDTestCase())
|
Loading…
Reference in New Issue