diff --git a/src/client/inc/tsclient.h b/src/client/inc/tsclient.h index 27caa33ff1d5965b48c4c4a81c860701568aac89..a0eb1bd63c7767b774e58301625611e58817ec55 100644 --- a/src/client/inc/tsclient.h +++ b/src/client/inc/tsclient.h @@ -404,6 +404,7 @@ void tscKillSTableQuery(SSqlObj *pSql); void tscInitResObjForLocalQuery(SSqlObj *pObj, int32_t numOfRes, int32_t rowLen); bool tscIsUpdateQuery(SSqlObj* pSql); bool tscHasReachLimitation(SQueryInfo *pQueryInfo, SSqlRes *pRes); +bool tscResultsetFetchCompleted(TAOS_RES *result); char *tscGetErrorMsgPayload(SSqlCmd *pCmd); diff --git a/src/client/src/tscSub.c b/src/client/src/tscSub.c index bbde276c3b9d9d5fd8873335816d512b8d15aa5b..30a0de76fc690bd12b34f3d6b76acc5903503867 100644 --- a/src/client/src/tscSub.c +++ b/src/client/src/tscSub.c @@ -182,21 +182,25 @@ static SArray* getTableList( SSqlObj* pSql ) { char* sql = alloca(strlen(p) + 32); sprintf(sql, "select tbid(tbname)%s", p); - SSqlObj* pSql1 = taos_query(pSql->pTscObj, sql); - if (terrno != TSDB_CODE_SUCCESS) { - tscError("failed to retrieve table id: %s", tstrerror(terrno)); + SSqlObj* pNew = taos_query(pSql->pTscObj, sql); + if (pNew == NULL) { + tscError("failed to retrieve table id: cannot create new sql object."); + return NULL; + + } else if (taos_errno(pNew) != TSDB_CODE_SUCCESS) { + tscError("failed to retrieve table id: %s", tstrerror(taos_errno(pNew))); return NULL; } TAOS_ROW row; SArray* result = taosArrayInit( 128, sizeof(STidTags) ); - while ((row = taos_fetch_row(pSql1))) { + while ((row = taos_fetch_row(pNew))) { STidTags tags; memcpy(&tags, row[0], sizeof(tags)); taosArrayPush(result, &tags); } - taos_free_result(pSql1); + taos_free_result(pNew); return result; } @@ -222,6 +226,9 @@ static int tscUpdateSubscription(STscObj* pObj, SSub* pSub) { } SArray* tables = getTableList(pSql); + if (tables == NULL) { + return 0; + } size_t numOfTables = taosArrayGetSize(tables); SArray* progress = taosArrayInit(numOfTables, sizeof(SSubscriptionProgress)); @@ -242,6 +249,7 @@ static int tscUpdateSubscription(STscObj* pObj, SSub* pSub) { } taosArrayDestroy(tables); + TSDB_QUERY_SET_TYPE(tscGetQueryInfoDetail(pCmd, 0)->type, TSDB_QUERY_TYPE_MULTITABLE_QUERY); return 1; } @@ -413,7 +421,7 @@ TAOS_RES *taos_consume(TAOS_SUB *tsub) { } if (pRes->code != TSDB_CODE_SUCCESS) { - tscError("failed to query data, error code=%d", pRes->code); + tscError("failed to query data: %s", tstrerror(pRes->code)); tscRemoveFromSqlList(pSql); return NULL; } diff --git a/src/client/src/tscUtil.c b/src/client/src/tscUtil.c index c6b3de69b666a5fa592067b5afba48f77ece79a8..b56470e8da56d19becac72674b6ed852fa08dde5 100644 --- a/src/client/src/tscUtil.c +++ b/src/client/src/tscUtil.c @@ -1984,6 +1984,11 @@ bool tscHasReachLimitation(SQueryInfo* pQueryInfo, SSqlRes* pRes) { return (pQueryInfo->clauseLimit > 0 && pRes->numOfClauseTotal >= pQueryInfo->clauseLimit); } +bool tscResultsetFetchCompleted(TAOS_RES *result) { + SSqlRes* pRes = result; + return pRes->completed; +} + char* tscGetErrorMsgPayload(SSqlCmd* pCmd) { return pCmd->payload; } /** diff --git a/src/common/inc/tdataformat.h b/src/common/inc/tdataformat.h index 3ad2df8d3a63f9d7c01c6bf73b843844faf850be..1cd72eafdedd512bb2d675613b178252efe5d5b2 100644 --- a/src/common/inc/tdataformat.h +++ b/src/common/inc/tdataformat.h @@ -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) { diff --git a/src/common/src/tdataformat.c b/src/common/src/tdataformat.c index 8dcbbf2c0b5e592e7aff876abe1813ca6490aca1..cd1f4b1ca447f326d4dfd8432252829fee43d7d7 100644 --- a/src/common/src/tdataformat.c +++ b/src/common/src/tdataformat.c @@ -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)); } diff --git a/src/inc/taoserror.h b/src/inc/taoserror.h index 562b9be854d3e648f094fa79f7eaca270e735fa3..33e0aa24b6eab113242337b04133766f2ea9b94f 100644 --- a/src/inc/taoserror.h +++ b/src/inc/taoserror.h @@ -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") diff --git a/src/inc/tsdb.h b/src/inc/tsdb.h index add85d9438440b9992649bdbd349b378de691405..ee18396b61e1e56985a829827f961c95931e7e42 100644 --- a/src/inc/tsdb.h +++ b/src/inc/tsdb.h @@ -19,11 +19,11 @@ #include #include -#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 diff --git a/src/mnode/inc/mnodeDef.h b/src/mnode/inc/mnodeDef.h index 67159ecea74784b32b74429b5756b1e497677a15..ae1ba98a0f4a15d37824de71e5db81c73effa89c 100644 --- a/src/mnode/inc/mnodeDef.h +++ b/src/mnode/inc/mnodeDef.h @@ -82,7 +82,8 @@ typedef struct STableObj { typedef struct SSuperTableObj { STableObj info; - int8_t reserved0[3]; // for fill struct STableObj to 4byte align + int8_t reserved0[1]; // for fill struct STableObj to 4byte align + int16_t nextColId; int32_t sversion; uint64_t uid; int64_t createdTime; @@ -95,13 +96,13 @@ typedef struct SSuperTableObj { int32_t numOfTables; SSchema * schema; void * vgHash; - int16_t nextColId; int8_t reserved2[6]; } SSuperTableObj; typedef struct { STableObj info; - int8_t reserved0[3]; // for fill struct STableObj to 4byte align + int8_t reserved0[1]; // for fill struct STableObj to 4byte align + int16_t nextColId; //used by normal table int32_t sversion; //used by normal table uint64_t uid; uint64_t suid; @@ -112,7 +113,6 @@ typedef struct { int32_t sqlLen; int8_t updateEnd[1]; int8_t reserved1[1]; - int16_t nextColId; //used by normal table int32_t refCount; char* sql; //used by normal table SSchema* schema; //used by normal table diff --git a/src/mnode/src/mnodeSdb.c b/src/mnode/src/mnodeSdb.c index d8fc9aee5a680913ce52753214cac27b225033ab..193ec1924bb80aa5ed9af2ceee92987714ed8aa0 100644 --- a/src/mnode/src/mnodeSdb.c +++ b/src/mnode/src/mnodeSdb.c @@ -678,29 +678,16 @@ int32_t sdbDeleteRow(SSdbOper *pOper) { return TSDB_CODE_SUCCESS; } - void * key = sdbGetObjKey(pTable, pOper->pObj); - int32_t keySize = 0; - switch (pTable->keyType) { - case SDB_KEY_STRING: - case SDB_KEY_VAR_STRING: - keySize = strlen((char *)key) + 1; - break; - case SDB_KEY_INT: - case SDB_KEY_AUTO: - keySize = sizeof(uint32_t); - break; - default: - return TSDB_CODE_MND_SDB_INVAID_KEY_TYPE; - } - - int32_t size = sizeof(SSdbOper) + sizeof(SWalHead) + keySize + SDB_SYNC_HACK; + int32_t size = sizeof(SSdbOper) + sizeof(SWalHead) + pTable->maxRowSize + SDB_SYNC_HACK; SSdbOper *pNewOper = taosAllocateQitem(size); SWalHead *pHead = (void *)pNewOper + sizeof(SSdbOper) + SDB_SYNC_HACK; pHead->version = 0; - pHead->len = keySize; pHead->msgType = pTable->tableId * 10 + SDB_ACTION_DELETE; - memcpy(pHead->cont, key, keySize); + + pOper->rowData = pHead->cont; + (*pTable->encodeFp)(pOper); + pHead->len = pOper->rowSize; memcpy(pNewOper, pOper, sizeof(SSdbOper)); diff --git a/src/mnode/src/mnodeShow.c b/src/mnode/src/mnodeShow.c index fb283eb61d062b18458e9107fefde872e1274644..996e9ced0bbdbd02a18ffc6bb7a1c86188aca39a 100644 --- a/src/mnode/src/mnodeShow.c +++ b/src/mnode/src/mnodeShow.c @@ -65,7 +65,7 @@ int32_t mnodeInitShow() { mnodeAddReadMsgHandle(TSDB_MSG_TYPE_CM_CONNECT, mnodeProcessConnectMsg); mnodeAddReadMsgHandle(TSDB_MSG_TYPE_CM_USE_DB, mnodeProcessUseMsg); - tsMnodeShowCache = taosCacheInitWithCb(10, mnodeFreeShowObj); + tsMnodeShowCache = taosCacheInitWithCb(5, mnodeFreeShowObj); return 0; } @@ -139,7 +139,7 @@ static int32_t mnodeProcessShowMsg(SMnodeMsg *pMsg) { pShowRsp->qhandle = htobe64((uint64_t) pShow); int32_t code = (*tsMnodeShowMetaFp[pShowMsg->type])(&pShowRsp->tableMeta, pShow, pMsg->rpcMsg.handle); - mTrace("%p, show type:%s index:%d, get meta finished, rows:%d cols:%d result:%s", pShow, + mTrace("%p, show type:%s index:%d, get meta finished, numOfRows:%d cols:%d result:%s", pShow, mnodeGetShowType(pShowMsg->type), pShow->index, pShow->numOfRows, pShow->numOfColumns, tstrerror(code)); if (code == TSDB_CODE_SUCCESS) { @@ -179,7 +179,7 @@ static int32_t mnodeProcessRetrieveMsg(SMnodeMsg *pMsg) { mTrace("%p, show is already read finished, numOfReads:%d numOfRows:%d", pShow, pShow->numOfReads, pShow->numOfRows); pShow->numOfReads = pShow->numOfRows; } - + if ((pRetrieve->free & TSDB_QUERY_TYPE_FREE_RESOURCE) != TSDB_QUERY_TYPE_FREE_RESOURCE) { rowsToRead = pShow->numOfRows - pShow->numOfReads; } @@ -219,8 +219,10 @@ static int32_t mnodeProcessRetrieveMsg(SMnodeMsg *pMsg) { if (rowsToRead == 0 || (rowsRead == rowsToRead && pShow->numOfRows == pShow->numOfReads)) { pRsp->completed = 1; + mTrace("%p, retrieve completed", pShow); mnodeReleaseShowObj(pShow, true); } else { + mTrace("%p, retrieve not completed yet", pShow); mnodeReleaseShowObj(pShow, false); } @@ -379,10 +381,10 @@ static void *mnodePutShowObj(SShowObj *pShow, int32_t size) { pShow->index = atomic_add_fetch_32(&tsShowObjIndex, 1); sprintf(key, "%d", pShow->index); - SShowObj *newQhandle = taosCachePut(tsMnodeShowCache, key, pShow, size, 60); + SShowObj *newQhandle = taosCachePut(tsMnodeShowCache, key, pShow, size, 6); free(pShow); - mTrace("%p, show is put into cache", newQhandle); + mTrace("%p, show is put into cache, index:%s", newQhandle, key); return newQhandle; } diff --git a/src/mnode/src/mnodeTable.c b/src/mnode/src/mnodeTable.c index 7019cc942c8d9505ed4e9733eba07a6e9ef04d93..565ce9910ebcf74b6b97677e71a339050d022e65 100644 --- a/src/mnode/src/mnodeTable.c +++ b/src/mnode/src/mnodeTable.c @@ -1753,11 +1753,43 @@ static int32_t mnodeFindNormalTableColumnIndex(SChildTableObj *pTable, char *col return -1; } -static int32_t mnodeAddNormalTableColumnCb(SMnodeMsg *pMsg, int32_t code) { +static int32_t mnodeAlterNormalTableColumnCb(SMnodeMsg *pMsg, int32_t code) { SChildTableObj *pTable = (SChildTableObj *)pMsg->pTable; - mLPrint("app:%p:%p, ctable %s, add column result:%s", pMsg->rpcMsg.ahandle, pMsg, pTable->info.tableId, - tstrerror(code)); - return code; + if (code != TSDB_CODE_SUCCESS) { + mError("app:%p:%p, ctable %s, failed to alter column, reason:%s", pMsg->rpcMsg.ahandle, pMsg, pTable->info.tableId, + tstrerror(code)); + return code; + } + + SMDCreateTableMsg *pMDCreate = mnodeBuildCreateChildTableMsg(NULL, pTable); + if (pMDCreate == NULL) { + return terrno; + } + + if (pMsg->pVgroup == NULL) { + pMsg->pVgroup = mnodeGetVgroup(pTable->vgId); + if (pMsg->pVgroup == NULL) { + rpcFreeCont(pMDCreate); + mError("app:%p:%p, ctable %s, vgId:%d not exist in mnode", pMsg->rpcMsg.ahandle, pMsg, pTable->info.tableId, + pTable->vgId); + return TSDB_CODE_MND_VGROUP_NOT_EXIST; + } + } + + SRpcIpSet ipSet = mnodeGetIpSetFromVgroup(pMsg->pVgroup); + SRpcMsg rpcMsg = { + .handle = pMsg, + .pCont = pMDCreate, + .contLen = htonl(pMDCreate->contLen), + .code = 0, + .msgType = TSDB_MSG_TYPE_MD_ALTER_TABLE + }; + + mTrace("app:%p:%p, ctable %s, send alter column msg to vgId:%d", pMsg->rpcMsg.ahandle, pMsg, pTable->info.tableId, + pMsg->pVgroup->vgId); + + dnodeSendMsgToDnode(&ipSet, &rpcMsg); + return TSDB_CODE_MND_ACTION_IN_PROGRESS; } static int32_t mnodeAddNormalTableColumn(SMnodeMsg *pMsg, SSchema schema[], int32_t ncols) { @@ -1802,7 +1834,7 @@ static int32_t mnodeAddNormalTableColumn(SMnodeMsg *pMsg, SSchema schema[], int3 .table = tsChildTableSdb, .pObj = pTable, .pMsg = pMsg, - .cb = mnodeAddNormalTableColumnCb + .cb = mnodeAlterNormalTableColumnCb }; int32_t code = sdbUpdateRow(&oper); @@ -1813,13 +1845,6 @@ static int32_t mnodeAddNormalTableColumn(SMnodeMsg *pMsg, SSchema schema[], int3 return code; } -static int32_t mnodeDropNormalTableColumnCb(SMnodeMsg *pMsg, int32_t code) { - SChildTableObj *pTable = (SChildTableObj *)pMsg->pTable; - mLPrint("app:%p:%p, ctable %s, drop column result:%s", pMsg->rpcMsg.ahandle, pMsg, pTable->info.tableId, - tstrerror(code)); - return code; -} - static int32_t mnodeDropNormalTableColumn(SMnodeMsg *pMsg, char *colName) { SDbObj *pDb = pMsg->pDb; SChildTableObj *pTable = (SChildTableObj *)pMsg->pTable; @@ -1847,7 +1872,7 @@ static int32_t mnodeDropNormalTableColumn(SMnodeMsg *pMsg, char *colName) { .table = tsChildTableSdb, .pObj = pTable, .pMsg = pMsg, - .cb = mnodeDropNormalTableColumnCb + .cb = mnodeAlterNormalTableColumnCb }; int32_t code = sdbUpdateRow(&oper); @@ -2185,9 +2210,33 @@ static void mnodeProcessCreateChildTableRsp(SRpcMsg *rpcMsg) { } } -// not implemented yet static void mnodeProcessAlterTableRsp(SRpcMsg *rpcMsg) { - mTrace("alter table rsp received, handle:%p code:%s", rpcMsg->handle, tstrerror(rpcMsg->code)); + if (rpcMsg->handle == NULL) return; + + SMnodeMsg *mnodeMsg = rpcMsg->handle; + mnodeMsg->received++; + + SChildTableObj *pTable = (SChildTableObj *)mnodeMsg->pTable; + assert(pTable); + + if (rpcMsg->code == TSDB_CODE_SUCCESS || rpcMsg->code == TSDB_CODE_TDB_TABLE_ALREADY_EXIST) { + mTrace("app:%p:%p, ctable:%s, altered in dnode, thandle:%p result:%s", mnodeMsg->rpcMsg.ahandle, mnodeMsg, + pTable->info.tableId, mnodeMsg->rpcMsg.handle, tstrerror(rpcMsg->code)); + + dnodeSendRpcMnodeWriteRsp(mnodeMsg, TSDB_CODE_SUCCESS); + } else { + if (mnodeMsg->retry++ < 3) { + mTrace("app:%p:%p, table:%s, alter table rsp received, need retry, times:%d result:%s thandle:%p", + mnodeMsg->rpcMsg.ahandle, mnodeMsg, pTable->info.tableId, mnodeMsg->retry, tstrerror(rpcMsg->code), + mnodeMsg->rpcMsg.handle); + + dnodeDelayReprocessMnodeWriteMsg(mnodeMsg); + } else { + mError("app:%p:%p, table:%s, failed to alter in dnode, result:%s thandle:%p", mnodeMsg->rpcMsg.ahandle, mnodeMsg, + pTable->info.tableId, tstrerror(rpcMsg->code), mnodeMsg->rpcMsg.handle); + dnodeSendRpcMnodeWriteRsp(mnodeMsg, rpcMsg->code); + } + } } static int32_t mnodeProcessMultiTableMetaMsg(SMnodeMsg *pMsg) { diff --git a/src/mnode/src/mnodeVgroup.c b/src/mnode/src/mnodeVgroup.c index 8df28aeec68bc77e46efcaf5fda6a0169c83c7d9..9553ade3aa4ff2f245f0b194e2301ca8c6a91900 100644 --- a/src/mnode/src/mnodeVgroup.c +++ b/src/mnode/src/mnodeVgroup.c @@ -258,7 +258,37 @@ void mnodeUpdateVgroup(SVgObj *pVgroup) { mnodeSendCreateVgroupMsg(pVgroup, NULL); } -void mnodeCheckUnCreatedVgroup(SDnodeObj *pDnode, SVnodeLoad *pVloads, int32_t openVnodes) {} +/* + Traverse all vgroups on mnode, if there no such vgId on a dnode, so send msg to this dnode for re-creating this vgId/vnode +*/ +void mnodeCheckUnCreatedVgroup(SDnodeObj *pDnode, SVnodeLoad *pVloads, int32_t openVnodes) { + SVnodeLoad *pNextV = NULL; + + void *pIter = NULL; + while (1) { + SVgObj *pVgroup; + pIter = mnodeGetNextVgroup(pIter, &pVgroup); + if (pVgroup == NULL) break; + + pNextV = pVloads; + int32_t i; + for (i = 0; i < openVnodes; ++i) { + if ((pVgroup->vnodeGid[i].pDnode == pDnode) && (pVgroup->vgId == pNextV->vgId)) { + break; + } + pNextV++; + } + + if (i == openVnodes) { + mnodeSendCreateVgroupMsg(pVgroup, NULL); + } + + mnodeDecVgroupRef(pVgroup); + } + + sdbFreeIter(pIter); + return; +} void mnodeUpdateVgroupStatus(SVgObj *pVgroup, SDnodeObj *pDnode, SVnodeLoad *pVload) { bool dnodeExist = false; @@ -861,4 +891,4 @@ void mnodeSendDropAllDbVgroupsMsg(SDbObj *pDropDb) { sdbFreeIter(pIter); mPrint("db:%s, all vgroups:%d drop msg is sent to dnode", pDropDb->name, numOfVgroups); -} \ No newline at end of file +} diff --git a/src/plugins/http/src/httpSql.c b/src/plugins/http/src/httpSql.c index ce2f7a83bdd4a5a132a31b3a5de1f2ba372b6329..9d584544609b9a31274868b8f981a6329f93b65a 100644 --- a/src/plugins/http/src/httpSql.c +++ b/src/plugins/http/src/httpSql.c @@ -205,6 +205,10 @@ void httpProcessSingleSqlRetrieveCallBack(void *param, TAOS_RES *result, int num } } + if (tscResultsetFetchCompleted(result)) { + isContinue = false; + } + if (isContinue) { // retrieve next batch of rows httpTrace("context:%p, fd:%d, ip:%s, user:%s, continue retrieve, numOfRows:%d", pContext, pContext->fd, diff --git a/src/plugins/http/src/tgHandle.c b/src/plugins/http/src/tgHandle.c index 354fa6b07e543e056ebc1b3f6f71345f4fa9a2b9..17192db3caa2284bd026f9129fa3e8c8440f860f 100644 --- a/src/plugins/http/src/tgHandle.c +++ b/src/plugins/http/src/tgHandle.c @@ -269,14 +269,20 @@ int tgReadSchema(char *fileName) { httpPrint("open telegraf schema file:%s success", fileName); fseek(fp, 0, SEEK_END); int32_t contentSize = (int32_t)ftell(fp); + if (contentSize <= 0) { + fclose(fp); + return 0; + } + rewind(fp); char * content = (char *)calloc(contentSize + 1, 1); int32_t result = fread(content, 1, contentSize, fp); + if (result != contentSize) { httpError("failed to read telegraf schema file:%s", fileName); fclose(fp); free(content); - return -1; + return 0; } content[contentSize] = 0; diff --git a/src/query/src/qast.c b/src/query/src/qast.c index 36a91ee5456035df0a70998f3cc0770c9bf17f02..dc3b1499bbe02fd389cb1502361fd5cdc46bc54e 100644 --- a/src/query/src/qast.c +++ b/src/query/src/qast.c @@ -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) { diff --git a/src/rpc/src/rpcTcp.c b/src/rpc/src/rpcTcp.c index 674d560952a246d517832f184a8b63625af9964c..5d156492c7dbd5641ba24bbf0835ccafa26a15a5 100644 --- a/src/rpc/src/rpcTcp.c +++ b/src/rpc/src/rpcTcp.c @@ -437,7 +437,7 @@ static void *taosProcessTcpData(void *param) { while (1) { int fdNum = epoll_wait(pThreadObj->pollFd, events, maxEvents, -1); if (pThreadObj->stop) { - tTrace("%s, tcp thread get stop event, exiting...", pThreadObj->label); + tTrace("%s TCP thread get stop event, exiting...", pThreadObj->label); break; } if (fdNum < 0) continue; diff --git a/src/rpc/src/rpcUdp.c b/src/rpc/src/rpcUdp.c index 279cf7ed49be70d31b3afc86d53b07453578806f..41446f87fbd13a5c610f381f6fe9b1eee679b13e 100644 --- a/src/rpc/src/rpcUdp.c +++ b/src/rpc/src/rpcUdp.c @@ -142,16 +142,15 @@ void taosCleanUpUdpConnection(void *handle) { pConn = pSet->udpConn + i; pConn->signature = NULL; - // shutdown to signal the thread to exit - if ( pConn->fd >=0) shutdown(pConn->fd, SHUT_RD); + if (pConn->fd >=0) shutdown(pConn->fd, SHUT_RDWR); + if (pConn->fd >=0) taosCloseSocket(pConn->fd); } for (int i = 0; i < pSet->threads; ++i) { pConn = pSet->udpConn + i; if (pConn->thread) pthread_join(pConn->thread, NULL); - if (pConn->fd >=0) taosCloseSocket(pConn->fd); tfree(pConn->buffer); - tTrace("UDP chandle:%p is closed", pConn); + tTrace("%s UDP thread is closed, inedx:%d", pConn->label, i); } tfree(pSet); @@ -185,15 +184,15 @@ static void *taosRecvUdpData(void *param) { while (1) { dataLen = recvfrom(pConn->fd, pConn->buffer, RPC_MAX_UDP_SIZE, 0, (struct sockaddr *)&sourceAdd, &addLen); - if(dataLen == 0) { - tTrace("data length is 0, socket was closed, exiting"); + if(dataLen <= 0) { + tTrace("%s UDP socket was closed, exiting", pConn->label); break; } port = ntohs(sourceAdd.sin_port); if (dataLen < sizeof(SRpcHead)) { - tError("%s recvfrom failed, reason:%s\n", pConn->label, strerror(errno)); + tError("%s recvfrom failed(%s)", pConn->label, strerror(errno)); continue; } diff --git a/src/tsdb/inc/tsdbMain.h b/src/tsdb/inc/tsdbMain.h index f52022d79dbd553e333ef26e8d59b86ea871db94..cd64e48347f8fb99cd70000042fa010b325831a5 100644 --- a/src/tsdb/inc/tsdbMain.h +++ b/src/tsdb/inc/tsdbMain.h @@ -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 +#define TSDB_FILE_HEAD_SIZE 512 +#define TSDB_FILE_DELIMITER 0xF00AFA0F + +// Definitions +// ------------------ tsdbMeta.c typedef struct STable { - int8_t type; + ETableType type; + tstr* name; // NOTE: there a flexible string here STableId tableId; - uint64_t superUid; // Super table UID - int16_t numOfSchemas; - STSchema ** schema; - STSchema * tagSchema; + uint64_t suid; + struct STable* pSuper; // super table pointer + uint8_t numOfSchemas; + STSchema* schema[TSDB_MAX_TABLE_SCHEMAS]; + 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 + 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 - struct STable *next; // TODO: remove the next - struct STable *prev; - tstr * name; // NOTE: there a flexible string here - char * sql; - void * cqhandle; + char* sql; + void* cqhandle; + T_REF_DECLARE(); } 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; + pthread_rwlock_t rwLock; + + int32_t nTables; + STable** tables; + SList* superList; + SHashObj* uidMap; + SKVStore* pStore; + int maxRowBytes; + int maxCols; } 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); - +// ------------------ tsdbBuffer.c typedef struct { - int blockId; - int offset; - int remain; - int padding; - char data[]; -} STsdbCacheBlock; + int64_t blockId; + int offset; + int remain; + char data[]; +} STsdbBufBlock; typedef struct { - int64_t index; - int numOfCacheBlocks; - SList * memPool; -} STsdbBufferPool; - + pthread_cond_t poolNotEmpty; + int bufBlockSize; + int tBufBlocks; + int nBufBlocks; + int64_t index; + SList* bufBlockList; +} STsdbBufPool; + +// ------------------ tsdbMemTable.c typedef struct { - TSKEY keyFirst; - TSKEY keyLast; - int64_t numOfRows; - SList * list; -} SCacheMem; + uint64_t uid; + TSKEY keyFirst; + TSKEY keyLast; + int64_t numOfRows; + SSkipList* pData; +} STableData; 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 + T_REF_DECLARE(); + TSKEY keyFirst; + TSKEY keyLast; + int64_t numOfRows; + STableData** tData; + SList* actList; + SList* bufBlockList; +} SMemTable; -#define tsdbGetKeyFileId(key, daysPerFile, precision) ((key) / tsMsPerDay[(precision)] / (daysPerFile)) -#define tsdbGetMaxNumOfFiles(keep, daysPerFile) ((keep) / (daysPerFile) + 3) +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 */ - -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 - */ +} SCompIdx; + 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 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); + +// ------------------ tsdbMain.c +#define REPO_ID(r) (r)->config.tsdbId +#define IS_REPO_LOCKED(r) (r)->repoLocked +#define TSDB_SUBMIT_MSG_HEAD_SIZE sizeof(SSubmitMsg) -int tsdbInitReadHelper(SRWHelper *pHelper, STsdbRepo *pRepo); -int tsdbInitWriteHelper(SRWHelper *pHelper, STsdbRepo *pRepo); -void tsdbDestroyHelper(SRWHelper *pHelper); -void tsdbResetHelper(SRWHelper *pHelper); - -// --------- For set operations -int tsdbSetAndOpenHelperFile(SRWHelper *pHelper, SFileGroup *pGroup); -void tsdbSetHelperTable(SRWHelper *pHelper, STable *pTable, STsdbRepo *pRepo); -int tsdbCloseHelperFile(SRWHelper *pHelper, bool hasError); - -// --------- 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 } diff --git a/src/tsdb/src/tsdbBuffer.c b/src/tsdb/src/tsdbBuffer.c new file mode 100644 index 0000000000000000000000000000000000000000..686fc4bbec512864e2249d741504af2e5f7596b0 --- /dev/null +++ b/src/tsdb/src/tsdbBuffer.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * 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 . + */ + +#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); } \ No newline at end of file diff --git a/src/tsdb/src/tsdbCache.c b/src/tsdb/src/tsdbCache.c deleted file mode 100644 index 24476d89975bd420f53d7a40ac1cb6dd0c961bf0..0000000000000000000000000000000000000000 --- a/src/tsdb/src/tsdbCache.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (c) 2019 TAOS Data, Inc. - * - * 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 . - */ -#include - -#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; - } -} \ No newline at end of file diff --git a/src/tsdb/src/tsdbCompactor.c b/src/tsdb/src/tsdbCompactor.c deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/src/tsdb/src/tsdbFile.c b/src/tsdb/src/tsdbFile.c index f8c00033b2d6a1597b4b322d05e0af77fcfeaac1..ffac8da944009c14c887917a45bc1cb5f3f5bc7f 100644 --- a/src/tsdb/src/tsdbFile.c +++ b/src/tsdb/src/tsdbFile.c @@ -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 -}; - -static int compFGroup(const void *arg1, const void *arg2); -static int tsdbOpenFGroup(STsdbFileH *pFileH, char *dataDir, int fid); - -STsdbFileH *tsdbInitFileH(char *dataDir, STsdbCfg *pCfg) { - STsdbFileH *pFileH = (STsdbFileH *)calloc(1, sizeof(STsdbFileH)); - if (pFileH == NULL) { // TODO: deal with ERROR here - return NULL; +const char *tsdbFileSuffix[] = {".head", ".data", ".last", "", ".h", ".h"}; + +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); + +// ---------------- 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; - - pFileH->fGroup = (SFileGroup *)calloc(pFileH->maxFGroups, sizeof(SFileGroup)); - if (pFileH->fGroup == NULL) { - free(pFileH); - return NULL; + 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; } - DIR *dir = opendir(dataDir); - if (dir == NULL) { - free(pFileH); - return NULL; - } + pFileH->maxFGroups = TSDB_MAX_FILE(pCfg->keep, pCfg->daysPerFile); - 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 - } + pFileH->pFGroup = (SFileGroup *)calloc(pFileH->maxFGroups, sizeof(SFileGroup)); + if (pFileH->pFGroup == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + goto _err; } - closedir(dir); return pFileH; + +_err: + tsdbFreeFileH(pFileH); + return NULL; } -void tsdbCloseFileH(STsdbFileH *pFileH) { +void tsdbFreeFileH(STsdbFileH *pFileH) { if (pFileH) { - tfree(pFileH->fGroup); + pthread_rwlock_destroy(&pFileH->fhlock); + tfree(pFileH->pFGroup); free(pFileH); } } -static int tsdbInitFile(char *dataDir, int fid, const char *suffix, SFile *pFile) { - uint32_t version; - char buf[512] = "\0"; +int tsdbOpenFileH(STsdbRepo *pRepo) { + ASSERT(pRepo != NULL && pRepo->tsdbFileH != NULL); - 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; + char *tDataDir = NULL; + DIR * dir = NULL; + int fid = 0; + int vid = 0; - 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; + SFileGroup fileGroup = {0}; + STsdbFileH *pFileH = pRepo->tsdbFileH; - void *pBuf = buf; - pBuf = taosDecodeFixedU32(pBuf, &version); - pBuf = tsdbDecodeSFileInfo(pBuf, &(pFile->info)); + tDataDir = tsdbGetDataDirName(pRepo->rootDir); + if (tDataDir == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + goto _err; + } - tsdbCloseFile(pFile); + dir = opendir(tDataDir); + if (dir == NULL) { + tsdbError("vgId:%d failed to open directory %s since %s", REPO_ID(pRepo), tDataDir, strerror(errno)); + terrno = TAOS_SYSTEM_ERROR(errno); + goto _err; + } - return 0; -} + struct dirent *dp = NULL; + while ((dp = readdir(dir)) != NULL) { + if (strncmp(dp->d_name, ".", 1) == 0 || strncmp(dp->d_name, "..", 2) == 0) continue; + sscanf(dp->d_name, "v%df%d", &vid, &fid); -static int tsdbOpenFGroup(STsdbFileH *pFileH, char *dataDir, int fid) { - if (tsdbSearchFGroup(pFileH, fid) != NULL) return 0; + if (tsdbSearchFGroup(pRepo->tsdbFileH, fid, TD_EQ) != NULL) continue; - SFileGroup fGroup = {0}; - fGroup.fileId = fid; + 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; + } + } - 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; + 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); } - pFileH->fGroup[pFileH->numOfFGroups++] = fGroup; - qsort((void *)(pFileH->fGroup), pFileH->numOfFGroups, 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; } -/** - * 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; +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]); + } + } +} + +SFileGroup *tsdbCreateFGroupIfNeed(STsdbRepo *pRepo, char *dataDir, int fid, int maxTables) { + STsdbFileH *pFileH = pRepo->tsdbFileH; + + 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,147 +222,202 @@ 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++; +int tsdbOpenFile(SFile *pFile, int oflag) { + ASSERT(!TSDB_IS_FILE_OPENED(pFile)); + + pFile->fd = open(pFile->fname, oflag, 0755); + if (pFile->fd < 0) { + tsdbError("failed to open file %s since %s", pFile->fname, strerror(errno)); + terrno = TAOS_SYSTEM_ERROR(errno); + return -1; } - SCompData *pCompData = (SCompData *)malloc(sizeof(SCompData) + sizeof(SCompCol) * maxNumOfCols); - if (pCompData == NULL) return -1; + return 0; +} - // Load data from the block - // if (tsdbLoadDataBlock(pOutFile, pStartBlock, numOfBlocks, pCols, pCompData)); +void tsdbCloseFile(SFile *pFile) { + if (TSDB_IS_FILE_OPENED(pFile)) { + close(pFile->fd); + pFile->fd = -1; + } +} + +int tsdbCreateFile(SFile *pFile, STsdbRepo *pRepo, int fid, int type) { + memset((void *)pFile, 0, sizeof(SFile)); + pFile->fd = -1; + + tsdbGetDataFileName(pRepo, fid, type, pFile->fname); - // Write data block to the file - { - // TODO + if (access(pFile->fname, F_OK) == 0) { + 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) { + goto _err; + } - if (pCompData) free(pCompData); - return 0; -} + pFile->info.size = TSDB_FILE_HEAD_SIZE; -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; + if (tsdbUpdateFileHeader(pFile, 0) < 0) { + tsdbCloseFile(pFile); + return -1; } + + tsdbCloseFile(pFile); + + return 0; + +_err: + return -1; } -static int compFGroup(const void *arg1, const void *arg2) { - return ((SFileGroup *)arg1)->fileId - ((SFileGroup *)arg2)->fileId; +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; } -int tsdbGetFileName(char *dataDir, int fileId, const char *suffix, char *fname) { - if (dataDir == NULL || fname == NULL) return -1; +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); - sprintf(fname, "%s/f%d%s", dataDir, fileId, suffix); + pthread_rwlock_wrlock(&(pFileH->fhlock)); - return 0; + while (pFileH->nFGroups > 0 && pGroup[0].fileId < mfid) { + tsdbRemoveFileGroup(pRepo, pGroup); + } + + pthread_rwlock_unlock(&(pFileH->fhlock)); } -int tsdbOpenFile(SFile *pFile, int oflag) { // TODO: change the function - if (TSDB_IS_FILE_OPENED(pFile)) return -1; +int tsdbUpdateFileHeader(SFile *pFile, uint32_t version) { + char buf[TSDB_FILE_HEAD_SIZE] = "\0"; - pFile->fd = open(pFile->fname, oflag, 0755); - if (pFile->fd < 0) return -1; + 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 tsdbCloseFile(SFile *pFile) { - int ret = close(pFile->fd); - pFile->fd = -1; - return ret; +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; } -SFileGroup * tsdbOpenFilesForCommit(STsdbFileH *pFileH, int fid) { - SFileGroup *pGroup = tsdbSearchFGroup(pFileH, fid); - if (pGroup == NULL) return NULL; +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)); - for (int type = TSDB_FILE_TYPE_HEAD; type < TSDB_FILE_TYPE_MAX; type++) { - tsdbOpenFile(&(pGroup->files[type]), O_RDWR); - } - return pGroup; + return buf; } -int tsdbCreateFile(char *dataDir, int fileId, const char *suffix, SFile *pFile) { - memset((void *)pFile, 0, sizeof(SFile)); - pFile->fd = -1; +void tsdbRemoveFileGroup(STsdbRepo *pRepo, SFileGroup *pFGroup) { + ASSERT(pFGroup != NULL); + STsdbFileH *pFileH = pRepo->tsdbFileH; - tsdbGetFileName(dataDir, fileId, suffix, pFile->fname); - - if (access(pFile->fname, F_OK) == 0) { - // File already exists - return -1; + 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); } - if (tsdbOpenFile(pFile, O_RDWR | O_CREAT) < 0) { - // TODO: deal with the ERROR here - return -1; + 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]); } +} - pFile->info.size = TSDB_FILE_HEAD_SIZE; +// ---------------- LOCAL FUNCTIONS ---------------- +static int tsdbInitFile(SFile *pFile, STsdbRepo *pRepo, int fid, int type) { + uint32_t version; + char buf[512] = "\0"; - if (tsdbUpdateFileHeader(pFile, 0) < 0) { - tsdbCloseFile(pFile); - return -1; + 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; } -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; +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; + } } -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); - if (ptr == NULL) return NULL; - return (SFileGroup *)ptr; -} \ No newline at end of file +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; + } +} diff --git a/src/tsdb/src/tsdbMain.c b/src/tsdb/src/tsdbMain.c index 181cda118f4de5856677a22d8054ec777bf2e9a7..80e5e8ea0d6419c631acb742d51a7217f7b83b3b 100644 --- a/src/tsdb/src/tsdbMain.c +++ b/src/tsdb/src/tsdbMain.c @@ -1,320 +1,283 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * 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 . + */ +#include "tsdbMain.h" #include "os.h" -#include "taosdef.h" -#include "tulog.h" #include "talgo.h" -#include "tsdb.h" -#include "tsdbMain.h" -#include "tscompression.h" +#include "taosdef.h" #include "tchecksum.h" +#include "tscompression.h" +#include "tsdb.h" #include "ttime.h" -#include +#include "tulog.h" -#define IS_VALID_PRECISION(precision) (((precision) >= TSDB_TIME_PRECISION_MILLI) && ((precision) <= TSDB_TIME_PRECISION_NANO)) -#define TSDB_DEFAULT_COMPRESSION TWO_STAGE_COMP -#define IS_VALID_COMPRESSION(compression) (((compression) >= NO_COMPRESSION) && ((compression) <= TWO_STAGE_COMP)) -#define TSDB_MIN_ID 0 -#define TSDB_MAX_ID INT_MAX +#include +#include #define TSDB_CFG_FILE_NAME "config" #define TSDB_DATA_DIR_NAME "data" -#define TSDB_DEFAULT_FILE_BLOCK_ROW_OPTION 0.7 -#define TSDB_MAX_LAST_FILE_SIZE (1024 * 1024 * 10) // 10M - -enum { TSDB_REPO_STATE_ACTIVE, TSDB_REPO_STATE_CLOSED, TSDB_REPO_STATE_CONFIGURING }; - -static int32_t tsdbCheckAndSetDefaultCfg(STsdbCfg *pCfg); -static int32_t tsdbSetRepoEnv(STsdbRepo *pRepo); -static int32_t tsdbDestroyRepoEnv(STsdbRepo *pRepo); -// static int tsdbOpenMetaFile(char *tsdbDir); -static int32_t tsdbInsertDataToTable(TsdbRepoT *repo, SSubmitBlk *pBlock, TSKEY now, int * affectedrows); -static int32_t tsdbRestoreCfg(STsdbRepo *pRepo, STsdbCfg *pCfg); -static int32_t tsdbGetDataDirName(STsdbRepo *pRepo, char *fname); -static void * tsdbCommitData(void *arg); -static int tsdbCommitToFile(STsdbRepo *pRepo, int fid, SSkipListIterator **iters, SRWHelper *pHelper, - SDataCols *pDataCols); -static TSKEY tsdbNextIterKey(SSkipListIterator *pIter); -static int tsdbHasDataToCommit(SSkipListIterator **iters, int nIters, TSKEY minKey, TSKEY maxKey); -static void tsdbAlterCompression(STsdbRepo *pRepo, int8_t compression); -static void tsdbAlterKeep(STsdbRepo *pRepo, int32_t keep); -static void tsdbAlterMaxTables(STsdbRepo *pRepo, int32_t maxTables); -static int32_t tsdbSaveConfig(STsdbRepo *pRepo); - -#define TSDB_GET_TABLE_BY_ID(pRepo, sid) (((STSDBRepo *)pRepo)->pTableList)[sid] -#define TSDB_GET_TABLE_BY_NAME(pRepo, name) -#define TSDB_IS_REPO_ACTIVE(pRepo) ((pRepo)->state == TSDB_REPO_STATE_ACTIVE) -#define TSDB_IS_REPO_CLOSED(pRepo) ((pRepo)->state == TSDB_REPO_STATE_CLOSED) - -/** - * Set the default TSDB configuration - */ -void tsdbSetDefaultCfg(STsdbCfg *pCfg) { - if (pCfg == NULL) return; - - pCfg->precision = -1; - pCfg->tsdbId = 0; - pCfg->maxTables = -1; - pCfg->daysPerFile = -1; - pCfg->minRowsPerFileBlock = -1; - pCfg->maxRowsPerFileBlock = -1; - pCfg->keep = -1; - pCfg->compression = TWO_STAGE_COMP; -} - -/** - * Create a configuration for TSDB default - * @return a pointer to a configuration. the configuration object - * must call tsdbFreeCfg to free memory after usage - */ -STsdbCfg *tsdbCreateDefaultCfg() { - STsdbCfg *pCfg = (STsdbCfg *)malloc(sizeof(STsdbCfg)); - if (pCfg == NULL) return NULL; +#define TSDB_META_FILE_NAME "meta" +#define TSDB_META_FILE_INDEX 10000000 +#define IS_VALID_PRECISION(precision) \ + (((precision) >= TSDB_TIME_PRECISION_MILLI) && ((precision) <= TSDB_TIME_PRECISION_NANO)) +#define TSDB_DEFAULT_COMPRESSION TWO_STAGE_COMP +#define IS_VALID_COMPRESSION(compression) (((compression) >= NO_COMPRESSION) && ((compression) <= TWO_STAGE_COMP)) - tsdbSetDefaultCfg(pCfg); +typedef struct { + int32_t totalLen; + int32_t len; + SDataRow row; +} SSubmitBlkIter; + +typedef struct { + int32_t totalLen; + int32_t len; + SSubmitBlk *pBlock; +} SSubmitMsgIter; + +static int32_t tsdbCheckAndSetDefaultCfg(STsdbCfg *pCfg); +static int32_t tsdbSetRepoEnv(char *rootDir, STsdbCfg *pCfg); +static int32_t tsdbUnsetRepoEnv(char *rootDir); +static int32_t tsdbSaveConfig(char *rootDir, STsdbCfg *pCfg); +static int tsdbLoadConfig(char *rootDir, STsdbCfg *pCfg); +static char * tsdbGetCfgFname(char *rootDir); +static STsdbRepo * tsdbNewRepo(char *rootDir, STsdbAppH *pAppH, STsdbCfg *pCfg); +static void tsdbFreeRepo(STsdbRepo *pRepo); +static int tsdbInitSubmitMsgIter(SSubmitMsg *pMsg, SSubmitMsgIter *pIter); +static int32_t tsdbInsertDataToTable(STsdbRepo *pRepo, SSubmitBlk *pBlock, TSKEY now, int32_t *affectedrows); +static SSubmitBlk *tsdbGetSubmitMsgNext(SSubmitMsgIter *pIter); +static SDataRow tsdbGetSubmitBlkNext(SSubmitBlkIter *pIter); +static int tsdbRestoreInfo(STsdbRepo *pRepo); +static int tsdbInitSubmitBlkIter(SSubmitBlk *pBlock, SSubmitBlkIter *pIter); +static void tsdbAlterCompression(STsdbRepo *pRepo, int8_t compression); +static int tsdbAlterKeep(STsdbRepo *pRepo, int32_t keep); +static int tsdbAlterMaxTables(STsdbRepo *pRepo, int32_t maxTables); +static int tsdbAlterCacheTotalBlocks(STsdbRepo *pRepo, int totalBlocks); +static int keyFGroupCompFunc(const void *key, const void *fgroup); +static int tsdbEncodeCfg(void **buf, STsdbCfg *pCfg); +static void * tsdbDecodeCfg(void *buf, STsdbCfg *pCfg); +static int tsdbCheckTableSchema(STsdbRepo *pRepo, SSubmitBlk *pBlock, STable *pTable); + +// Function declaration +int32_t tsdbCreateRepo(char *rootDir, STsdbCfg *pCfg) { + if (mkdir(rootDir, 0755) < 0) { + tsdbError("vgId:%d failed to create rootDir %s since %s", pCfg->tsdbId, rootDir, strerror(errno)); + terrno = TAOS_SYSTEM_ERROR(errno); + return -1; + } - return pCfg; -} + if (tsdbCheckAndSetDefaultCfg(pCfg) < 0) return -1; -void tsdbFreeCfg(STsdbCfg *pCfg) { - if (pCfg != NULL) free(pCfg); -} + if (tsdbSetRepoEnv(rootDir, pCfg) < 0) return -1; -STsdbCfg *tsdbGetCfg(const TsdbRepoT *repo) { - assert(repo != NULL); - return &((STsdbRepo*)repo)->config; + tsdbTrace( + "vgId:%d tsdb env create succeed! cacheBlockSize %d totalBlocks %d maxTables %d daysPerFile %d keep " + "%d minRowsPerFileBlock %d maxRowsPerFileBlock %d precision %d compression %d", + pCfg->tsdbId, pCfg->cacheBlockSize, pCfg->totalBlocks, pCfg->maxTables, pCfg->daysPerFile, pCfg->keep, + pCfg->minRowsPerFileBlock, pCfg->maxRowsPerFileBlock, pCfg->precision, pCfg->compression); + return 0; } -/** - * Create a new TSDB repository - * @param rootDir the TSDB repository root directory - * @param pCfg the TSDB repository configuration, upper layer need to free the pointer - * @param limiter the limitation tracker will implement in the future, make it void now - * - * @return a TSDB repository handle on success, NULL for failure - */ -int32_t tsdbCreateRepo(char *rootDir, STsdbCfg *pCfg, void *limiter /* TODO */) { - if (mkdir(rootDir, 0755) != 0) { - tsdbError("vgId:%d, failed to create rootDir! rootDir:%s, reason:%s", pCfg->tsdbId, rootDir, strerror(errno)); - if (errno == EACCES) { - return TSDB_CODE_TDB_NO_DISK_PERMISSIONS; - } else if (errno == ENOSPC) { - return TSDB_CODE_TDB_NO_DISKSPACE; - } else if (errno == EEXIST) { - } else { - return TSDB_CODE_TDB_INIT_FAILED; - } - } +int32_t tsdbDropRepo(char *rootDir) { return tsdbUnsetRepoEnv(rootDir); } - if (access(rootDir, F_OK | R_OK | W_OK) == -1) return -1; +TSDB_REPO_T *tsdbOpenRepo(char *rootDir, STsdbAppH *pAppH) { + STsdbCfg config = {0}; + STsdbRepo *pRepo = NULL; - if (tsdbCheckAndSetDefaultCfg(pCfg) < 0) { - return -1; + if (tsdbLoadConfig(rootDir, &config) < 0) { + tsdbError("failed to open repo in rootDir %s since %s", rootDir, tstrerror(terrno)); + return NULL; } - STsdbRepo *pRepo = (STsdbRepo *)malloc(sizeof(STsdbRepo)); + pRepo = tsdbNewRepo(rootDir, pAppH, &config); if (pRepo == NULL) { - return -1; + tsdbError("failed to open repo in rootDir %s since %s", rootDir, tstrerror(terrno)); + return NULL; } - pRepo->rootDir = strdup(rootDir); - pRepo->config = *pCfg; - pRepo->limiter = limiter; + if (tsdbOpenMeta(pRepo) < 0) { + tsdbError("vgId:%d failed to open meta since %s", REPO_ID(pRepo), tstrerror(terrno)); + goto _err; + } - // Create the environment files and directories - int32_t code = tsdbSetRepoEnv(pRepo); - - free(pRepo->rootDir); - free(pRepo); - return code; -} + if (tsdbOpenBufPool(pRepo) < 0) { + tsdbError("vgId:%d failed to open buffer pool since %s", REPO_ID(pRepo), tstrerror(terrno)); + goto _err; + } -/** - * Close and free all resources taken by the repository - * @param repo the TSDB repository handle. The interface will free the handle too, so upper - * layer do NOT need to free the repo handle again. - * - * @return 0 for success, -1 for failure and the error number is set - */ -int32_t tsdbDropRepo(TsdbRepoT *repo) { - STsdbRepo *pRepo = (STsdbRepo *)repo; - int id = pRepo->config.tsdbId; + if (tsdbOpenFileH(pRepo) < 0) { + tsdbError("vgId:%d failed to open file handle since %s", REPO_ID(pRepo), tstrerror(terrno)); + goto _err; + } - pRepo->state = TSDB_REPO_STATE_CLOSED; + if (tsdbRestoreInfo(pRepo) < 0) { + tsdbError("vgId:%d failed to restore info from file since %s", REPO_ID(pRepo), tstrerror(terrno)); + goto _err; + } - // Free the metaHandle - tsdbFreeMeta(pRepo->tsdbMeta); + // pRepo->state = TSDB_REPO_STATE_ACTIVE; - // Free the cache - tsdbFreeCache(pRepo->tsdbCache); + tsdbTrace("vgId:%d open tsdb repository succeed!", REPO_ID(pRepo)); - // Destroy the repository info - tsdbDestroyRepoEnv(pRepo); + return (TSDB_REPO_T *)pRepo; - free(pRepo->rootDir); - free(pRepo); +_err: + tsdbCloseRepo(pRepo, false); + return NULL; +} - tsdbTrace("vgId:%d, tsdb repository is dropped!", id); +// Note: all working thread and query thread must stopped when calling this function +void tsdbCloseRepo(TSDB_REPO_T *repo, int toCommit) { + if (repo == NULL) return; - return 0; + STsdbRepo *pRepo = (STsdbRepo *)repo; + int vgId = REPO_ID(pRepo); + + if (toCommit) { + tsdbAsyncCommit(pRepo); + if (pRepo->commit) pthread_join(pRepo->commitThread, NULL); + } + tsdbUnRefMemTable(pRepo, pRepo->mem); + tsdbUnRefMemTable(pRepo, pRepo->imem); + pRepo->mem = NULL; + pRepo->imem = NULL; + + tsdbCloseFileH(pRepo); + tsdbCloseBufPool(pRepo); + tsdbCloseMeta(pRepo); + tsdbFreeRepo(pRepo); + tsdbTrace("vgId:%d repository is closed", vgId); } -static int tsdbRestoreInfo(STsdbRepo *pRepo) { - STsdbMeta * pMeta = pRepo->tsdbMeta; - STsdbFileH *pFileH = pRepo->tsdbFileH; - SFileGroup *pFGroup = NULL; +int32_t tsdbInsertData(TSDB_REPO_T *repo, SSubmitMsg *pMsg, SShellSubmitRspMsg *pRsp) { + STsdbRepo * pRepo = (STsdbRepo *)repo; + SSubmitMsgIter msgIter = {0}; - SFileGroupIter iter; - SRWHelper rhelper = {{0}}; + if (tsdbInitSubmitMsgIter(pMsg, &msgIter) < 0) { + tsdbError("vgId:%d failed to insert data since %s", REPO_ID(pRepo), tstrerror(terrno)); + return -1; + } - if (tsdbInitReadHelper(&rhelper, pRepo) < 0) goto _err; - tsdbInitFileGroupIter(pFileH, &iter, TSDB_ORDER_ASC); - while ((pFGroup = tsdbGetFileGroupNext(&iter)) != NULL) { - if (tsdbSetAndOpenHelperFile(&rhelper, pFGroup) < 0) goto _err; - for (int i = 1; i < pRepo->config.maxTables; i++) { - STable * pTable = pMeta->tables[i]; - if (pTable == NULL) continue; - SCompIdx *pIdx = &rhelper.pCompIdx[i]; + SSubmitBlk *pBlock = NULL; + int32_t affectedrows = 0; - if (pIdx->offset > 0 && pTable->lastKey < pIdx->maxKey) pTable->lastKey = pIdx->maxKey; + TSKEY now = taosGetTimestamp(pRepo->config.precision); + + while ((pBlock = tsdbGetSubmitMsgNext(&msgIter)) != NULL) { + if (tsdbInsertDataToTable(pRepo, pBlock, now, &affectedrows) < 0) { + return -1; } } - - tsdbDestroyHelper(&rhelper); + pRsp->affectedRows = htonl(affectedrows); return 0; - -_err: - tsdbDestroyHelper(&rhelper); - return -1; } -/** - * Open an existing TSDB storage repository - * @param tsdbDir the existing TSDB root directory - * - * @return a TSDB repository handle on success, NULL for failure and the error number is set - */ -TsdbRepoT *tsdbOpenRepo(char *rootDir, STsdbAppH *pAppH) { - char dataDir[128] = "\0"; - if (access(rootDir, F_OK | W_OK | R_OK) < 0) { - return NULL; - } +uint32_t tsdbGetFileInfo(TSDB_REPO_T *repo, char *name, uint32_t *index, uint32_t eindex, int32_t *size) { + STsdbRepo *pRepo = (STsdbRepo *)repo; + // STsdbMeta *pMeta = pRepo->tsdbMeta; + STsdbFileH *pFileH = pRepo->tsdbFileH; + uint32_t magic = 0; + char * fname = NULL; - STsdbRepo *pRepo = (STsdbRepo *)calloc(1, sizeof(STsdbRepo)); - if (pRepo == NULL) { - return NULL; - } + struct stat fState; - pRepo->rootDir = strdup(rootDir); + tsdbTrace("vgId:%d name:%s index:%d eindex:%d", pRepo->config.tsdbId, name, *index, eindex); + ASSERT(*index <= eindex); - tsdbRestoreCfg(pRepo, &(pRepo->config)); - if (pAppH) pRepo->appH = *pAppH; + char *sdup = strdup(pRepo->rootDir); + char *prefix = dirname(sdup); - pRepo->tsdbMeta = tsdbInitMeta(rootDir, pRepo->config.maxTables, pRepo); - if (pRepo->tsdbMeta == NULL) { - free(pRepo->rootDir); - free(pRepo); - return NULL; - } + if (name[0] == 0) { // get the file from index or after, but not larger than eindex + int fid = (*index) / 3; - pRepo->tsdbCache = tsdbInitCache(pRepo->config.cacheBlockSize, pRepo->config.totalBlocks, (TsdbRepoT *)pRepo); - if (pRepo->tsdbCache == NULL) { - tsdbFreeMeta(pRepo->tsdbMeta); - free(pRepo->rootDir); - free(pRepo); - return NULL; - } + if (pFileH->nFGroups == 0 || fid > pFileH->pFGroup[pFileH->nFGroups - 1].fileId) { + if (*index <= TSDB_META_FILE_INDEX && TSDB_META_FILE_INDEX <= eindex) { + fname = tsdbGetMetaFileName(pRepo->rootDir); + *index = TSDB_META_FILE_INDEX; + } else { + tfree(sdup); + return 0; + } + } else { + SFileGroup *pFGroup = + taosbsearch(&fid, pFileH->pFGroup, pFileH->nFGroups, sizeof(SFileGroup), keyFGroupCompFunc, TD_GE); + if (pFGroup->fileId == fid) { + strcpy(fname, pFGroup->files[(*index) % 3].fname); + } else { + if (pFGroup->fileId * 3 + 2 < eindex) { + strcpy(fname, pFGroup->files[0].fname); + *index = pFGroup->fileId * 3; + } else { + tfree(sdup); + return 0; + } + } + } + strcpy(name, fname + strlen(prefix)); + } else { // get the named file at the specified index. If not there, return 0 + if (*index == TSDB_META_FILE_INDEX) { // get meta file + fname = tsdbGetMetaFileName(pRepo->rootDir); + } else { + int fid = (*index) / 3; + SFileGroup *pFGroup = tsdbSearchFGroup(pFileH, fid, TD_EQ); + if (pFGroup == NULL) { // not found + tfree(sdup); + return 0; + } - tsdbGetDataDirName(pRepo, dataDir); - pRepo->tsdbFileH = tsdbInitFileH(dataDir, &(pRepo->config)); - if (pRepo->tsdbFileH == NULL) { - tsdbFreeCache(pRepo->tsdbCache); - tsdbFreeMeta(pRepo->tsdbMeta); - free(pRepo->rootDir); - free(pRepo); - return NULL; + SFile *pFile = &pFGroup->files[(*index) % 3]; + strcpy(fname, pFile->fname); + } } - // Restore key from file - if (tsdbRestoreInfo(pRepo) < 0) { - tsdbFreeCache(pRepo->tsdbCache); - tsdbFreeMeta(pRepo->tsdbMeta); - tsdbCloseFileH(pRepo->tsdbFileH); - free(pRepo->rootDir); - free(pRepo); - return NULL; + if (stat(fname, &fState) < 0) { + tfree(sdup); + return 0; } - pRepo->state = TSDB_REPO_STATE_ACTIVE; + tfree(sdup); + *size = fState.st_size; + magic = *size; - tsdbTrace("vgId:%d, open tsdb repository successfully!", pRepo->config.tsdbId); - return (TsdbRepoT *)pRepo; + tfree(fname); + return magic; } -// static int32_t tsdbFlushCache(STsdbRepo *pRepo) { -// // TODO -// return 0; -// } - -/** - * Close a TSDB repository. Only free memory resources, and keep the files. - * @param repo the opened TSDB repository handle. The interface will free the handle too, so upper - * layer do NOT need to free the repo handle again. - * - * @return 0 for success, -1 for failure and the error number is set - */ -int32_t tsdbCloseRepo(TsdbRepoT *repo, int toCommit) { +void tsdbStartStream(TSDB_REPO_T *repo) { STsdbRepo *pRepo = (STsdbRepo *)repo; - if (pRepo == NULL) return 0; - int id = pRepo->config.tsdbId; + STsdbMeta *pMeta = pRepo->tsdbMeta; - pRepo->state = TSDB_REPO_STATE_CLOSED; - tsdbLockRepo(repo); - if (pRepo->commit) { - tsdbUnLockRepo(repo); - return -1; - } - pRepo->commit = 1; - // Loop to move pData to iData - for (int i = 1; i < pRepo->config.maxTables; i++) { - STable *pTable = pRepo->tsdbMeta->tables[i]; - if (pTable != NULL && pTable->mem != NULL) { - pTable->imem = pTable->mem; - pTable->mem = NULL; + for (int i = 0; i < pRepo->config.maxTables; i++) { + STable *pTable = pMeta->tables[i]; + if (pTable && pTable->type == TSDB_STREAM_TABLE) { + pTable->cqhandle = (*pRepo->appH.cqCreateFunc)(pRepo->appH.cqH, TABLE_UID(pTable), TABLE_TID(pTable), pTable->sql, + tsdbGetTableSchema(pTable)); } } - // TODO: Loop to move mem to imem - pRepo->tsdbCache->imem = pRepo->tsdbCache->mem; - pRepo->tsdbCache->mem = NULL; - pRepo->tsdbCache->curBlock = NULL; - tsdbUnLockRepo(repo); - - if (pRepo->appH.notifyStatus) pRepo->appH.notifyStatus(pRepo->appH.appH, TSDB_STATUS_COMMIT_START); - if (toCommit) tsdbCommitData((void *)repo); - - tsdbCloseFileH(pRepo->tsdbFileH); - - tsdbFreeMeta(pRepo->tsdbMeta); - - tsdbFreeCache(pRepo->tsdbCache); - - tfree(pRepo->rootDir); - tfree(pRepo); - - tsdbTrace("vgId:%d, repository is closed!", id); +} - return 0; +STsdbCfg *tsdbGetCfg(const TSDB_REPO_T *repo) { + ASSERT(repo != NULL); + return &((STsdbRepo *)repo)->config; } -/** - * Change the configuration of a repository - * @param pCfg the repository configuration, the upper layer should free the pointer - * - * @return 0 for success, -1 for failure and the error number is set - */ -int32_t tsdbConfigRepo(TsdbRepoT *repo, STsdbCfg *pCfg) { +int32_t tsdbConfigRepo(TSDB_REPO_T *repo, STsdbCfg *pCfg) { + // TODO: think about multithread cases STsdbRepo *pRepo = (STsdbRepo *)repo; STsdbCfg * pRCfg = &pRepo->config; - if (tsdbCheckAndSetDefaultCfg(pCfg) < 0) return TSDB_CODE_TDB_INVALID_CONFIG; + if (tsdbCheckAndSetDefaultCfg(pCfg) < 0) return -1; ASSERT(pRCfg->tsdbId == pCfg->tsdbId); ASSERT(pRCfg->cacheBlockSize == pCfg->cacheBlockSize); @@ -325,422 +288,138 @@ int32_t tsdbConfigRepo(TsdbRepoT *repo, STsdbCfg *pCfg) { bool configChanged = false; if (pRCfg->compression != pCfg->compression) { - configChanged = true; tsdbAlterCompression(pRepo, pCfg->compression); + configChanged = true; } if (pRCfg->keep != pCfg->keep) { + if (tsdbAlterKeep(pRepo, pCfg->keep) < 0) { + tsdbError("vgId:%d failed to configure repo when alter keep since %s", REPO_ID(pRepo), tstrerror(terrno)); + return -1; + } configChanged = true; - tsdbAlterKeep(pRepo, pCfg->keep); } if (pRCfg->totalBlocks != pCfg->totalBlocks) { - configChanged = true; tsdbAlterCacheTotalBlocks(pRepo, pCfg->totalBlocks); + configChanged = true; } if (pRCfg->maxTables != pCfg->maxTables) { + if (tsdbAlterMaxTables(pRepo, pCfg->maxTables) < 0) { + tsdbError("vgId:%d failed to configure repo when alter maxTables since %s", REPO_ID(pRepo), tstrerror(terrno)); + return -1; + } configChanged = true; - tsdbAlterMaxTables(pRepo, pCfg->maxTables); } - if (configChanged) tsdbSaveConfig(pRepo); - - return TSDB_CODE_SUCCESS; -} - -int32_t tsdbTriggerCommit(TsdbRepoT *repo) { - STsdbRepo *pRepo = (STsdbRepo *)repo; - - if (pRepo->appH.notifyStatus) pRepo->appH.notifyStatus(pRepo->appH.appH, TSDB_STATUS_COMMIT_START); - - tsdbLockRepo(repo); - if (pRepo->commit) { - tsdbUnLockRepo(repo); - return -1; - } - pRepo->commit = 1; - // Loop to move pData to iData - for (int i = 1; i < pRepo->config.maxTables; i++) { - STable *pTable = pRepo->tsdbMeta->tables[i]; - if (pTable != NULL && pTable->mem != NULL) { - pTable->imem = pTable->mem; - pTable->mem = NULL; + if (configChanged) { + if (tsdbSaveConfig(pRepo->rootDir, &pRepo->config) < 0) { + tsdbError("vgId:%d failed to configure repository while save config since %s", REPO_ID(pRepo), tstrerror(terrno)); + return -1; } } - // TODO: Loop to move mem to imem - pRepo->tsdbCache->imem = pRepo->tsdbCache->mem; - pRepo->tsdbCache->mem = NULL; - pRepo->tsdbCache->curBlock = NULL; - tsdbUnLockRepo(repo); - - // TODO: here should set as detached or use join for memory leak - pthread_attr_t thattr; - pthread_attr_init(&thattr); - pthread_attr_setdetachstate(&thattr, PTHREAD_CREATE_DETACHED); - pthread_create(&(pRepo->commitThread), &thattr, tsdbCommitData, (void *)repo); - tsdbTrace("vgId:%d, start to commit!", pRepo->config.tsdbId); return 0; } -int32_t tsdbLockRepo(TsdbRepoT *repo) { - STsdbRepo *pRepo = (STsdbRepo *)repo; - return pthread_mutex_lock(&(pRepo->mutex)); +void tsdbReportStat(void *repo, int64_t *totalPoints, int64_t *totalStorage, int64_t *compStorage) { + ASSERT(repo != NULL); + STsdbRepo *pRepo = repo; + *totalPoints = pRepo->stat.pointsWritten; + *totalStorage = pRepo->stat.totalStorage; + *compStorage = pRepo->stat.compStorage; } -int32_t tsdbUnLockRepo(TsdbRepoT *repo) { - STsdbRepo *pRepo = (STsdbRepo *)repo; - return pthread_mutex_unlock(&(pRepo->mutex)); +// ----------------- INTERNAL FUNCTIONS ----------------- +char *tsdbGetMetaFileName(char *rootDir) { + int tlen = strlen(rootDir) + strlen(TSDB_META_FILE_NAME) + 2; + char *fname = calloc(1, tlen); + if (fname == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + return NULL; + } + + snprintf(fname, tlen, "%s/%s", rootDir, TSDB_META_FILE_NAME); + return fname; } -/** - * Get the TSDB repository information, including some statistics - * @param pRepo the TSDB repository handle - * @param error the error number to set when failure occurs - * - * @return a info struct handle on success, NULL for failure and the error number is set. The upper - * layers should free the info handle themselves or memory leak will occur - */ -STsdbRepoInfo *tsdbGetStatus(TsdbRepoT *pRepo) { - // TODO - return NULL; +void tsdbGetDataFileName(STsdbRepo *pRepo, int fid, int type, char *fname) { + snprintf(fname, TSDB_FILENAME_LEN, "%s/%s/v%df%d%s", pRepo->rootDir, TSDB_DATA_DIR_NAME, REPO_ID(pRepo), fid, tsdbFileSuffix[type]); } -int tsdbAlterTable(TsdbRepoT *pRepo, STableCfg *pCfg) { - // TODO +int tsdbLockRepo(STsdbRepo *pRepo) { + int code = pthread_mutex_lock(&pRepo->mutex); + if (code != 0) { + tsdbError("vgId:%d failed to lock tsdb since %s", REPO_ID(pRepo), strerror(errno)); + terrno = TAOS_SYSTEM_ERROR(code); + return -1; + } + pRepo->repoLocked = true; return 0; } -int tsdbUpdateTagValue(TsdbRepoT *repo, SUpdateTableTagValMsg *pMsg) { - STsdbRepo *pRepo = (STsdbRepo *)repo; - STsdbMeta *pMeta = pRepo->tsdbMeta; - int16_t tversion = htons(pMsg->tversion); - - STable *pTable = tsdbGetTableByUid(pMeta, htobe64(pMsg->uid)); - if (pTable == NULL) return TSDB_CODE_TDB_INVALID_TABLE_ID; - if (pTable->tableId.tid != htonl(pMsg->tid)) return TSDB_CODE_TDB_INVALID_TABLE_ID; - - if (pTable->type != TSDB_CHILD_TABLE) { - tsdbError("vgId:%d failed to update tag value of table %s since its type is %d", pRepo->config.tsdbId, - pTable->name->data, pTable->type); - return TSDB_CODE_TDB_INVALID_TABLE_TYPE; +int tsdbUnlockRepo(STsdbRepo *pRepo) { + ASSERT(IS_REPO_LOCKED(pRepo)); + pRepo->repoLocked = false; + int code = pthread_mutex_unlock(&pRepo->mutex); + if (code != 0) { + tsdbError("vgId:%d failed to unlock tsdb since %s", REPO_ID(pRepo), strerror(errno)); + terrno = TAOS_SYSTEM_ERROR(code); + return -1; } + return 0; +} - if (schemaVersion(tsdbGetTableTagSchema(pMeta, pTable)) < tversion) { - tsdbTrace("vgId:%d server tag version %d is older than client tag version %d, try to config", pRepo->config.tsdbId, - schemaVersion(tsdbGetTableTagSchema(pMeta, pTable)), tversion); - void *msg = (*pRepo->appH.configFunc)(pRepo->config.tsdbId, htonl(pMsg->tid)); - if (msg == NULL) { - return terrno; - } - // Deal with error her - STableCfg *pTableCfg = tsdbCreateTableCfgFromMsg(msg); - STable *super = tsdbGetTableByUid(pMeta, pTableCfg->superUid); - ASSERT(super != NULL); - - int32_t code = tsdbUpdateTable(pMeta, super, pTableCfg); - if (code != TSDB_CODE_SUCCESS) { - return code; - } - tsdbClearTableCfg(pTableCfg); - rpcFreeCont(msg); +char *tsdbGetDataDirName(char *rootDir) { + int tlen = strlen(rootDir) + strlen(TSDB_DATA_DIR_NAME) + 2; + char *fname = calloc(1, tlen); + if (fname == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + return NULL; } - STSchema *pTagSchema = tsdbGetTableTagSchema(pMeta, pTable); - - if (schemaVersion(pTagSchema) > tversion) { - tsdbError( - "vgId:%d failed to update tag value of table %s since version out of date, client tag version:%d server tag " - "version:%d", - pRepo->config.tsdbId, pTable->name->data, tversion, schemaVersion(pTable->tagSchema)); - return TSDB_CODE_TDB_TAG_VER_OUT_OF_DATE; - } - if (schemaColAt(pTagSchema, DEFAULT_TAG_INDEX_COLUMN)->colId == htons(pMsg->colId)) { - tsdbRemoveTableFromIndex(pMeta, pTable); - } - // TODO: remove table from index if it is the first column of tag - tdSetKVRowDataOfCol(&pTable->tagVal, htons(pMsg->colId), htons(pMsg->type), pMsg->data); - if (schemaColAt(pTagSchema, DEFAULT_TAG_INDEX_COLUMN)->colId == htons(pMsg->colId)) { - tsdbAddTableIntoIndex(pMeta, pTable); - } - return TSDB_CODE_SUCCESS; + snprintf(fname, tlen, "%s/%s", rootDir, TSDB_DATA_DIR_NAME); + return fname; } -TSKEY tsdbGetTableLastKey(TsdbRepoT *repo, uint64_t uid) { - STsdbRepo *pRepo = (STsdbRepo *)repo; - - STable *pTable = tsdbGetTableByUid(pRepo->tsdbMeta, uid); - if (pTable == NULL) return -1; - - return TSDB_GET_TABLE_LAST_KEY(pTable); -} +STsdbMeta * tsdbGetMeta(TSDB_REPO_T *pRepo) { return ((STsdbRepo *)pRepo)->tsdbMeta; } +STsdbFileH * tsdbGetFile(TSDB_REPO_T *pRepo) { return ((STsdbRepo *)pRepo)->tsdbFileH; } +STsdbRepoInfo *tsdbGetStatus(TSDB_REPO_T *pRepo) { return NULL; } -void tsdbStartStream(TsdbRepoT *repo) { - STsdbRepo *pRepo = (STsdbRepo *)repo; - STsdbMeta *pMeta = pRepo->tsdbMeta; +// ----------------- LOCAL FUNCTIONS ----------------- +static int32_t tsdbCheckAndSetDefaultCfg(STsdbCfg *pCfg) { + // Check precision + if (pCfg->precision == -1) { + pCfg->precision = TSDB_DEFAULT_PRECISION; + } else { + if (!IS_VALID_PRECISION(pCfg->precision)) { + tsdbError("vgId:%d invalid precision configuration %d", pCfg->tsdbId, pCfg->precision); + goto _err; + } + } - for (int i = 0; i < pRepo->config.maxTables; i++) { - STable *pTable = pMeta->tables[i]; - if (pTable && pTable->type == TSDB_STREAM_TABLE) { - pTable->cqhandle = (*pRepo->appH.cqCreateFunc)(pRepo->appH.cqH, pTable->tableId.uid, pTable->tableId.tid, pTable->sql, tsdbGetTableSchema(pMeta, pTable)); - } - } -} - -STableInfo *tsdbGetTableInfo(TsdbRepoT *pRepo, STableId tableId) { - // TODO - return NULL; -} - -// TODO: need to return the number of data inserted -int32_t tsdbInsertData(TsdbRepoT *repo, SSubmitMsg *pMsg, SShellSubmitRspMsg * pRsp) { - SSubmitMsgIter msgIter; - STsdbRepo *pRepo = (STsdbRepo *)repo; - - tsdbInitSubmitMsgIter(pMsg, &msgIter); - SSubmitBlk *pBlock = NULL; - int32_t code = TSDB_CODE_SUCCESS; - int32_t affectedrows = 0; - - TSKEY now = taosGetTimestamp(pRepo->config.precision); - - while ((pBlock = tsdbGetSubmitMsgNext(&msgIter)) != NULL) { - if ((code = tsdbInsertDataToTable(repo, pBlock, now, &affectedrows)) != TSDB_CODE_SUCCESS) { - return code; - } - } - pRsp->affectedRows = htonl(affectedrows); - return code; -} - -/** - * Initialize a table configuration - */ -int tsdbInitTableCfg(STableCfg *config, ETableType type, uint64_t uid, int32_t tid) { - if (config == NULL) return -1; - if (type != TSDB_CHILD_TABLE && type != TSDB_NORMAL_TABLE && type != TSDB_STREAM_TABLE) return -1; - - memset((void *)config, 0, sizeof(STableCfg)); - - config->type = type; - config->superUid = TSDB_INVALID_SUPER_TABLE_ID; - config->tableId.uid = uid; - config->tableId.tid = tid; - config->name = NULL; - config->sql = NULL; - return 0; -} - -/** - * Set the super table UID of the created table - */ -int tsdbTableSetSuperUid(STableCfg *config, uint64_t uid) { - if (config->type != TSDB_CHILD_TABLE) return -1; - if (uid == TSDB_INVALID_SUPER_TABLE_ID) return -1; - - config->superUid = uid; - return 0; -} - -/** - * Set the table schema in the configuration - * @param config the configuration to set - * @param pSchema the schema to set - * @param dup use the schema directly or duplicate one for use - * - * @return 0 for success and -1 for failure - */ -int tsdbTableSetSchema(STableCfg *config, STSchema *pSchema, bool dup) { - if (dup) { - config->schema = tdDupSchema(pSchema); - } else { - config->schema = pSchema; - } - return 0; -} - -/** - * Set the table schema in the configuration - * @param config the configuration to set - * @param pSchema the schema to set - * @param dup use the schema directly or duplicate one for use - * - * @return 0 for success and -1 for failure - */ -int tsdbTableSetTagSchema(STableCfg *config, STSchema *pSchema, bool dup) { - if (config->type != TSDB_CHILD_TABLE) return -1; - - if (dup) { - config->tagSchema = tdDupSchema(pSchema); - } else { - config->tagSchema = pSchema; - } - return 0; -} - -int tsdbTableSetTagValue(STableCfg *config, SKVRow row, bool dup) { - if (config->type != TSDB_CHILD_TABLE) return -1; - - if (dup) { - config->tagValues = tdKVRowDup(row); - } else { - config->tagValues = row; - } - - return 0; -} - -int tsdbTableSetName(STableCfg *config, char *name, bool dup) { - if (dup) { - config->name = strdup(name); - if (config->name == NULL) return -1; - } else { - config->name = name; - } - - return 0; -} - -int tsdbTableSetSName(STableCfg *config, char *sname, bool dup) { - if (config->type != TSDB_CHILD_TABLE) return -1; - - if (dup) { - config->sname = strdup(sname); - if (config->sname == NULL) return -1; - } else { - config->sname = sname; - } - return 0; -} - -int tsdbTableSetStreamSql(STableCfg *config, char *sql, bool dup) { - if (config->type != TSDB_STREAM_TABLE) return -1; - - if (dup) { - config->sql = strdup(sql); - if (config->sql == NULL) return -1; - } else { - config->sql = sql; - } - - return 0; -} - -void tsdbClearTableCfg(STableCfg *config) { - if (config) { - if (config->schema) tdFreeSchema(config->schema); - if (config->tagSchema) tdFreeSchema(config->tagSchema); - if (config->tagValues) kvRowFree(config->tagValues); - tfree(config->name); - tfree(config->sname); - tfree(config->sql); - free(config); - } -} - -int tsdbInitSubmitBlkIter(SSubmitBlk *pBlock, SSubmitBlkIter *pIter) { - if (pBlock->len <= 0) return -1; - pIter->totalLen = pBlock->len; - pIter->len = 0; - pIter->row = (SDataRow)(pBlock->data); - return 0; -} - -SDataRow tsdbGetSubmitBlkNext(SSubmitBlkIter *pIter) { - SDataRow row = pIter->row; - if (row == NULL) return NULL; - - pIter->len += dataRowLen(row); - if (pIter->len >= pIter->totalLen) { - pIter->row = NULL; - } else { - pIter->row = (char *)row + dataRowLen(row); - } - - return row; -} - -int tsdbInitSubmitMsgIter(SSubmitMsg *pMsg, SSubmitMsgIter *pIter) { - if (pMsg == NULL || pIter == NULL) return -1; - - pMsg->length = htonl(pMsg->length); - pMsg->numOfBlocks = htonl(pMsg->numOfBlocks); - pMsg->compressed = htonl(pMsg->compressed); - - pIter->totalLen = pMsg->length; - pIter->len = TSDB_SUBMIT_MSG_HEAD_SIZE; - if (pMsg->length <= TSDB_SUBMIT_MSG_HEAD_SIZE) { - pIter->pBlock = NULL; - } else { - pIter->pBlock = pMsg->blocks; - } - - return 0; -} - -SSubmitBlk *tsdbGetSubmitMsgNext(SSubmitMsgIter *pIter) { - SSubmitBlk *pBlock = pIter->pBlock; - if (pBlock == NULL) return NULL; - - pBlock->len = htonl(pBlock->len); - pBlock->numOfRows = htons(pBlock->numOfRows); - pBlock->uid = htobe64(pBlock->uid); - pBlock->tid = htonl(pBlock->tid); - - pBlock->sversion = htonl(pBlock->sversion); - pBlock->padding = htonl(pBlock->padding); - - pIter->len = pIter->len + sizeof(SSubmitBlk) + pBlock->len; - if (pIter->len >= pIter->totalLen) { - pIter->pBlock = NULL; - } else { - pIter->pBlock = (SSubmitBlk *)((char *)pBlock + pBlock->len + sizeof(SSubmitBlk)); - } - - return pBlock; -} - -STsdbMeta* tsdbGetMeta(TsdbRepoT* pRepo) { - STsdbRepo *tsdb = (STsdbRepo *)pRepo; - return tsdb->tsdbMeta; -} - -STsdbFileH* tsdbGetFile(TsdbRepoT* pRepo) { - STsdbRepo* tsdb = (STsdbRepo*) pRepo; - return tsdb->tsdbFileH; -} - -// Check the configuration and set default options -static int32_t tsdbCheckAndSetDefaultCfg(STsdbCfg *pCfg) { - // Check precision - if (pCfg->precision == -1) { - pCfg->precision = TSDB_DEFAULT_PRECISION; - } else { - if (!IS_VALID_PRECISION(pCfg->precision)) { - tsdbError("vgId:%d, invalid precision configuration! precision:%d", pCfg->tsdbId, pCfg->precision); - return -1; - } - } - - // Check compression - if (pCfg->compression == -1) { - pCfg->compression = TSDB_DEFAULT_COMPRESSION; - } else { - if (!IS_VALID_COMPRESSION(pCfg->compression)) { - tsdbError("vgId:%d: invalid compression configuration! compression:%d", pCfg->tsdbId, pCfg->precision); - return -1; + // Check compression + if (pCfg->compression == -1) { + pCfg->compression = TSDB_DEFAULT_COMPRESSION; + } else { + if (!IS_VALID_COMPRESSION(pCfg->compression)) { + tsdbError("vgId:%d invalid compression configuration %d", pCfg->tsdbId, pCfg->precision); + goto _err; } } // Check tsdbId - if (pCfg->tsdbId < 0) return -1; + if (pCfg->tsdbId < 0) { + tsdbError("vgId:%d invalid vgroup ID", pCfg->tsdbId); + goto _err; + } // Check maxTables if (pCfg->maxTables == -1) { pCfg->maxTables = TSDB_DEFAULT_TABLES; } else { if (pCfg->maxTables < TSDB_MIN_TABLES || pCfg->maxTables > TSDB_MAX_TABLES) { - tsdbError("vgId:%d: invalid maxTables configuration! maxTables:%d TSDB_MIN_TABLES:%d TSDB_MAX_TABLES:%d", + tsdbError("vgId:%d invalid maxTables configuration! maxTables %d TSDB_MIN_TABLES %d TSDB_MAX_TABLES %d", pCfg->tsdbId, pCfg->maxTables, TSDB_MIN_TABLES, TSDB_MAX_TABLES); - return -1; + goto _err; } } @@ -750,10 +429,10 @@ static int32_t tsdbCheckAndSetDefaultCfg(STsdbCfg *pCfg) { } else { if (pCfg->daysPerFile < TSDB_MIN_DAYS_PER_FILE || pCfg->daysPerFile > TSDB_MAX_DAYS_PER_FILE) { tsdbError( - "vgId:%d, invalid daysPerFile configuration! daysPerFile:%d TSDB_MIN_DAYS_PER_FILE:%d TSDB_MAX_DAYS_PER_FILE:" + "vgId:%d invalid daysPerFile configuration! daysPerFile %d TSDB_MIN_DAYS_PER_FILE %d TSDB_MAX_DAYS_PER_FILE " "%d", pCfg->tsdbId, pCfg->daysPerFile, TSDB_MIN_DAYS_PER_FILE, TSDB_MAX_DAYS_PER_FILE); - return -1; + goto _err; } } @@ -763,10 +442,10 @@ static int32_t tsdbCheckAndSetDefaultCfg(STsdbCfg *pCfg) { } else { if (pCfg->minRowsPerFileBlock < TSDB_MIN_MIN_ROW_FBLOCK || pCfg->minRowsPerFileBlock > TSDB_MAX_MIN_ROW_FBLOCK) { tsdbError( - "vgId:%d, invalid minRowsPerFileBlock configuration! minRowsPerFileBlock:%d TSDB_MIN_MIN_ROW_FBLOCK:%d " - "TSDB_MAX_MIN_ROW_FBLOCK:%d", + "vgId:%d invalid minRowsPerFileBlock configuration! minRowsPerFileBlock %d TSDB_MIN_MIN_ROW_FBLOCK %d " + "TSDB_MAX_MIN_ROW_FBLOCK %d", pCfg->tsdbId, pCfg->minRowsPerFileBlock, TSDB_MIN_MIN_ROW_FBLOCK, TSDB_MAX_MIN_ROW_FBLOCK); - return -1; + goto _err; } } @@ -775,14 +454,18 @@ static int32_t tsdbCheckAndSetDefaultCfg(STsdbCfg *pCfg) { } else { if (pCfg->maxRowsPerFileBlock < TSDB_MIN_MAX_ROW_FBLOCK || pCfg->maxRowsPerFileBlock > TSDB_MAX_MAX_ROW_FBLOCK) { tsdbError( - "vgId:%d, invalid maxRowsPerFileBlock configuration! maxRowsPerFileBlock:%d TSDB_MIN_MAX_ROW_FBLOCK:%d " - "TSDB_MAX_MAX_ROW_FBLOCK:%d", + "vgId:%d invalid maxRowsPerFileBlock configuration! maxRowsPerFileBlock %d TSDB_MIN_MAX_ROW_FBLOCK %d " + "TSDB_MAX_MAX_ROW_FBLOCK %d", pCfg->tsdbId, pCfg->maxRowsPerFileBlock, TSDB_MIN_MIN_ROW_FBLOCK, TSDB_MAX_MIN_ROW_FBLOCK); - return -1; + goto _err; } } - if (pCfg->minRowsPerFileBlock > pCfg->maxRowsPerFileBlock) return -1; + if (pCfg->minRowsPerFileBlock > pCfg->maxRowsPerFileBlock) { + tsdbError("vgId:%d invalid configuration! minRowsPerFileBlock %d maxRowsPerFileBlock %d", pCfg->tsdbId, + pCfg->minRowsPerFileBlock, pCfg->maxRowsPerFileBlock); + goto _err; + } // Check keep if (pCfg->keep == -1) { @@ -790,216 +473,269 @@ static int32_t tsdbCheckAndSetDefaultCfg(STsdbCfg *pCfg) { } else { if (pCfg->keep < TSDB_MIN_KEEP || pCfg->keep > TSDB_MAX_KEEP) { tsdbError( - "vgId:%d, invalid keep configuration! keep:%d TSDB_MIN_KEEP:%d " - "TSDB_MAX_KEEP:%d", + "vgId:%d invalid keep configuration! keep %d TSDB_MIN_KEEP %d " + "TSDB_MAX_KEEP %d", pCfg->tsdbId, pCfg->keep, TSDB_MIN_KEEP, TSDB_MAX_KEEP); - return -1; + goto _err; } } return 0; -} -static int32_t tsdbGetCfgFname(STsdbRepo *pRepo, char *fname) { - if (pRepo == NULL) return -1; - sprintf(fname, "%s/%s", pRepo->rootDir, TSDB_CFG_FILE_NAME); - return 0; +_err: + terrno = TSDB_CODE_TDB_INVALID_CONFIG; + return -1; } -static int32_t tsdbSaveConfig(STsdbRepo *pRepo) { - char fname[128] = "\0"; // TODO: get rid of the literal 128 +static int32_t tsdbSetRepoEnv(char *rootDir, STsdbCfg *pCfg) { + if (tsdbSaveConfig(rootDir, pCfg) < 0) { + tsdbError("vgId:%d failed to set TSDB environment since %s", pCfg->tsdbId, tstrerror(terrno)); + return -1; + } - if (tsdbGetCfgFname(pRepo, fname) < 0) return -1; + char *dirName = tsdbGetDataDirName(rootDir); + if (dirName == NULL) return -1; - int fd = open(fname, O_WRONLY | O_CREAT, 0755); - if (fd < 0) { + if (mkdir(dirName, 0755) < 0) { + tsdbError("vgId:%d failed to create directory %s since %s", pCfg->tsdbId, dirName, strerror(errno)); + terrno = TAOS_SYSTEM_ERROR(errno); + free(dirName); return -1; } - if (write(fd, (void *)(&(pRepo->config)), sizeof(STsdbCfg)) < 0) { + free(dirName); + + char *fname = tsdbGetMetaFileName(rootDir); + if (fname == NULL) return -1; + if (tdCreateKVStore(fname) < 0) { + tsdbError("vgId:%d failed to open KV store since %s", pCfg->tsdbId, tstrerror(terrno)); + free(fname); return -1; } - close(fd); + free(fname); return 0; } -static int32_t tsdbRestoreCfg(STsdbRepo *pRepo, STsdbCfg *pCfg) { - char fname[128] = "\0"; +static int32_t tsdbUnsetRepoEnv(char *rootDir) { + taosRemoveDir(rootDir); + tsdbTrace("repository %s is removed", rootDir); + return 0; +} - if (tsdbGetCfgFname(pRepo, fname) < 0) return -1; +static int32_t tsdbSaveConfig(char *rootDir, STsdbCfg *pCfg) { + int fd = -1; + char *fname = NULL; + char buf[TSDB_FILE_HEAD_SIZE] = "\0"; + char *pBuf = buf; - int fd = open(fname, O_RDONLY); + fname = tsdbGetCfgFname(rootDir); + if (fname == NULL) { + tsdbError("vgId:%d failed to save configuration since %s", pCfg->tsdbId, tstrerror(terrno)); + goto _err; + } + + fd = open(fname, O_WRONLY | O_CREAT, 0755); if (fd < 0) { - return -1; + tsdbError("vgId:%d failed to open file %s since %s", pCfg->tsdbId, fname, strerror(errno)); + terrno = TAOS_SYSTEM_ERROR(errno); + goto _err; } - if (read(fd, (void *)pCfg, sizeof(STsdbCfg)) < sizeof(STsdbCfg)) { - close(fd); - return -1; + int tlen = tsdbEncodeCfg((void *)(&pBuf), pCfg); + ASSERT((tlen + sizeof(TSCKSUM) <= TSDB_FILE_HEAD_SIZE) && (POINTER_DISTANCE(pBuf, buf) == tlen)); + + taosCalcChecksumAppend(0, (uint8_t *)buf, TSDB_FILE_HEAD_SIZE); + + if (twrite(fd, (void *)buf, TSDB_FILE_HEAD_SIZE) < TSDB_FILE_HEAD_SIZE) { + tsdbError("vgId:%d failed to write %d bytes to file %s since %s", pCfg->tsdbId, TSDB_FILE_HEAD_SIZE, fname, + strerror(errno)); + terrno = TAOS_SYSTEM_ERROR(errno); + goto _err; } - close(fd); + if (fsync(fd) < 0) { + tsdbError("vgId:%d failed to fsync file %s since %s", pCfg->tsdbId, fname, strerror(errno)); + terrno = TAOS_SYSTEM_ERROR(errno); + goto _err; + } + free(fname); + close(fd); return 0; -} -static int32_t tsdbGetDataDirName(STsdbRepo *pRepo, char *fname) { - if (pRepo == NULL || pRepo->rootDir == NULL) return -1; - sprintf(fname, "%s/%s", pRepo->rootDir, TSDB_DATA_DIR_NAME); - return 0; +_err: + tfree(fname); + if (fd > 0) close(fd); + return -1; } -static int32_t tsdbSetRepoEnv(STsdbRepo *pRepo) { - STsdbCfg *pCfg = &pRepo->config; - if (tsdbSaveConfig(pRepo) < 0) return -1; +static int tsdbLoadConfig(char *rootDir, STsdbCfg *pCfg) { + char *fname = NULL; + int fd = -1; + char buf[TSDB_FILE_HEAD_SIZE] = "\0"; - char dirName[128] = "\0"; - if (tsdbGetDataDirName(pRepo, dirName) < 0) return -1; + fname = tsdbGetCfgFname(rootDir); + if (fname == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + goto _err; + } - if (mkdir(dirName, 0755) < 0) { - tsdbError("vgId:%d, failed to create repository directory! reason:%s", pRepo->config.tsdbId, strerror(errno)); - return -1; + fd = open(fname, O_RDONLY); + if (fd < 0) { + tsdbError("failed to open file %s since %s", fname, strerror(errno)); + terrno = TAOS_SYSTEM_ERROR(errno); + goto _err; } - tsdbTrace( - "vgId:%d, set up tsdb environment succeed! cacheBlockSize:%d, totalBlocks:%d, maxTables:%d, daysPerFile:%d, keep:" - "%d, minRowsPerFileBlock:%d, maxRowsPerFileBlock:%d, precision:%d, compression:%d", - pRepo->config.tsdbId, pCfg->cacheBlockSize, pCfg->totalBlocks, pCfg->maxTables, pCfg->daysPerFile, pCfg->keep, - pCfg->minRowsPerFileBlock, pCfg->maxRowsPerFileBlock, pCfg->precision, pCfg->compression); + if (tread(fd, (void *)buf, TSDB_FILE_HEAD_SIZE) < TSDB_FILE_HEAD_SIZE) { + tsdbError("failed to read %d bytes from file %s since %s", TSDB_FILE_HEAD_SIZE, fname, strerror(errno)); + terrno = TAOS_SYSTEM_ERROR(errno); + goto _err; + } + + if (!taosCheckChecksumWhole((uint8_t *)buf, TSDB_FILE_HEAD_SIZE)) { + tsdbError("file %s is corrupted", fname); + terrno = TSDB_CODE_TDB_FILE_CORRUPTED; + goto _err; + } + + tsdbDecodeCfg(buf, pCfg); + + tfree(fname); + close(fd); + return 0; + +_err: + tfree(fname); + if (fd > 0) close(fd); + return -1; } -static int32_t tsdbDestroyRepoEnv(STsdbRepo *pRepo) { - char fname[260]; - if (pRepo == NULL) return 0; - char *dirName = calloc(1, strlen(pRepo->rootDir) + strlen("tsdb") + 2); - if (dirName == NULL) { - return -1; +static char *tsdbGetCfgFname(char *rootDir) { + int tlen = strlen(rootDir) + strlen(TSDB_CFG_FILE_NAME) + 2; + char *fname = calloc(1, tlen); + if (fname == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + return NULL; } - sprintf(dirName, "%s/%s", pRepo->rootDir, "tsdb"); + snprintf(fname, tlen, "%s/%s", rootDir, TSDB_CFG_FILE_NAME); + return fname; +} - DIR *dir = opendir(dirName); - if (dir == NULL) return -1; +static STsdbRepo *tsdbNewRepo(char *rootDir, STsdbAppH *pAppH, STsdbCfg *pCfg) { + STsdbRepo *pRepo = (STsdbRepo *)calloc(1, sizeof(STsdbRepo)); + if (pRepo == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + goto _err; + } - struct dirent *dp; - while ((dp = readdir(dir)) != NULL) { - if ((strcmp(dp->d_name, ".") == 0) || (strcmp(dp->d_name, "..") == 0)) continue; - sprintf(fname, "%s/%s", pRepo->rootDir, dp->d_name); - remove(fname); + int code = pthread_mutex_init(&pRepo->mutex, NULL); + if (code != 0) { + terrno = TAOS_SYSTEM_ERROR(code); + goto _err; } - closedir(dir); + pRepo->repoLocked = false; - rmdir(dirName); + pRepo->rootDir = strdup(rootDir); + if (pRepo->rootDir == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + goto _err; + } - return 0; -} + pRepo->config = *pCfg; + pRepo->appH = *pAppH; -// static int tsdbOpenMetaFile(char *tsdbDir) { -// // TODO -// return 0; -// } + pRepo->tsdbMeta = tsdbNewMeta(pCfg); + if (pRepo->tsdbMeta == NULL) { + tsdbError("vgId:%d failed to create meta since %s", REPO_ID(pRepo), tstrerror(terrno)); + goto _err; + } -static int32_t tdInsertRowToTable(STsdbRepo *pRepo, SDataRow row, STable *pTable) { - // TODO - int32_t level = 0; - int32_t headSize = 0; + pRepo->pPool = tsdbNewBufPool(pCfg); + if (pRepo->pPool == NULL) { + tsdbError("vgId:%d failed to create buffer pool since %s", REPO_ID(pRepo), tstrerror(terrno)); + goto _err; + } - if (pTable->mem == NULL) { - pTable->mem = (SMemTable *)calloc(1, sizeof(SMemTable)); - if (pTable->mem == NULL) return -1; - pTable->mem->pData = tSkipListCreate(5, TSDB_DATA_TYPE_TIMESTAMP, TYPE_BYTES[TSDB_DATA_TYPE_TIMESTAMP], 0, 0, 0, getTSTupleKey); - pTable->mem->keyFirst = INT64_MAX; - pTable->mem->keyLast = 0; + pRepo->tsdbFileH = tsdbNewFileH(pCfg); + if (pRepo->tsdbFileH == NULL) { + tsdbError("vgId:%d failed to create file handle since %s", REPO_ID(pRepo), tstrerror(terrno)); + goto _err; } - tSkipListNewNodeInfo(pTable->mem->pData, &level, &headSize); + return pRepo; - TSKEY key = dataRowKey(row); - // printf("insert:%lld, size:%d\n", key, pTable->mem->numOfRows); - - // Copy row into the memory - SSkipListNode *pNode = tsdbAllocFromCache(pRepo->tsdbCache, headSize + dataRowLen(row), key); - if (pNode == NULL) { - // TODO: deal with allocate failure - } - - pNode->level = level; - dataRowCpy(SL_GET_NODE_DATA(pNode), row); - - // Insert the skiplist node into the data - if (pTable->mem == NULL) { - pTable->mem = (SMemTable *)calloc(1, sizeof(SMemTable)); - if (pTable->mem == NULL) return -1; - pTable->mem->pData = tSkipListCreate(5, TSDB_DATA_TYPE_TIMESTAMP, TYPE_BYTES[TSDB_DATA_TYPE_TIMESTAMP], 0, 0, 0, getTSTupleKey); - pTable->mem->keyFirst = INT64_MAX; - pTable->mem->keyLast = 0; - } - tSkipListPut(pTable->mem->pData, pNode); - if (key > pTable->mem->keyLast) pTable->mem->keyLast = key; - if (key < pTable->mem->keyFirst) pTable->mem->keyFirst = key; - if (key > pTable->lastKey) pTable->lastKey = key; - - pTable->mem->numOfRows = tSkipListGetSize(pTable->mem->pData); +_err: + tsdbFreeRepo(pRepo); + return NULL; +} + +static void tsdbFreeRepo(STsdbRepo *pRepo) { + if (pRepo) { + tsdbFreeFileH(pRepo->tsdbFileH); + tsdbFreeBufPool(pRepo->pPool); + tsdbFreeMeta(pRepo->tsdbMeta); + // tsdbFreeMemTable(pRepo->mem); + // tsdbFreeMemTable(pRepo->imem); + tfree(pRepo->rootDir); + pthread_mutex_destroy(&pRepo->mutex); + free(pRepo); + } +} - tsdbTrace("vgId:%d, tid:%d, uid:%" PRId64 ", table:%s a row is inserted to table! key:%" PRId64, pRepo->config.tsdbId, - pTable->tableId.tid, pTable->tableId.uid, pTable->name->data, dataRowKey(row)); +static int tsdbInitSubmitMsgIter(SSubmitMsg *pMsg, SSubmitMsgIter *pIter) { + if (pMsg == NULL) { + terrno = TSDB_CODE_TDB_SUBMIT_MSG_MSSED_UP; + return -1; + } + + pMsg->length = htonl(pMsg->length); + pMsg->numOfBlocks = htonl(pMsg->numOfBlocks); + pMsg->compressed = htonl(pMsg->compressed); + + pIter->totalLen = pMsg->length; + pIter->len = TSDB_SUBMIT_MSG_HEAD_SIZE; + if (pMsg->length <= TSDB_SUBMIT_MSG_HEAD_SIZE) { + terrno = TSDB_CODE_TDB_SUBMIT_MSG_MSSED_UP; + return -1; + } else { + pIter->pBlock = pMsg->blocks; + } return 0; } -static int32_t tsdbInsertDataToTable(TsdbRepoT *repo, SSubmitBlk *pBlock, TSKEY now, int32_t *affectedrows) { - STsdbRepo *pRepo = (STsdbRepo *)repo; +static int32_t tsdbInsertDataToTable(STsdbRepo *pRepo, SSubmitBlk *pBlock, TSKEY now, int32_t *affectedrows) { STsdbMeta *pMeta = pRepo->tsdbMeta; int64_t points = 0; - STableId tableId = {.uid = pBlock->uid, .tid = pBlock->tid}; - STable *pTable = tsdbIsValidTableToInsert(pRepo->tsdbMeta, tableId); - if (pTable == NULL) { - tsdbError("vgId:%d, failed to get table for insert, uid:%" PRIu64 ", tid:%d", pRepo->config.tsdbId, pBlock->uid, + STable *pTable = tsdbGetTableByUid(pMeta, pBlock->uid); + if (pTable == NULL || TABLE_TID(pTable) != pBlock->tid) { + tsdbError("vgId:%d failed to get table to insert data, uid %" PRIu64 " tid %d", REPO_ID(pRepo), pBlock->uid, pBlock->tid); - return TSDB_CODE_TDB_INVALID_TABLE_ID; - } - - // Check schema version - int32_t tversion = pBlock->sversion; - STSchema * pSchema = tsdbGetTableSchema(pMeta, pTable); - ASSERT(pSchema != NULL); - int16_t nversion = schemaVersion(pSchema); - if (tversion > nversion) { - tsdbTrace("vgId:%d table:%s tid:%d server schema version %d is older than clien version %d, try to config.", - pRepo->config.tsdbId, pTable->name->data, pTable->tableId.tid, nversion, tversion); - void *msg = (*pRepo->appH.configFunc)(pRepo->config.tsdbId, pTable->tableId.tid); - if (msg == NULL) { - return terrno; - } - // Deal with error her - STableCfg *pTableCfg = tsdbCreateTableCfgFromMsg(msg); - STable *pTableUpdate = NULL; - if (pTable->type == TSDB_CHILD_TABLE) { - pTableUpdate = tsdbGetTableByUid(pMeta, pTableCfg->superUid); - } else { - pTableUpdate = pTable; - } + terrno = TSDB_CODE_TDB_INVALID_TABLE_ID; + return -1; + } - int32_t code = tsdbUpdateTable(pMeta, pTableUpdate, pTableCfg); - if (code != TSDB_CODE_SUCCESS) { - return code; - } - tsdbClearTableCfg(pTableCfg); - rpcFreeCont(msg); - } else { - if (tsdbGetTableSchemaByVersion(pMeta, pTable, tversion) == NULL) { - tsdbError("vgId:%d table:%s tid:%d invalid schema version %d from client", pRepo->config.tsdbId, - pTable->name->data, pTable->tableId.tid, tversion); - return TSDB_CODE_TDB_TABLE_SCHEMA_VERSION; - } + if (TABLE_TYPE(pTable) == TSDB_SUPER_TABLE) { + tsdbError("vgId:%d invalid action trying to insert a super table %s", REPO_ID(pRepo), TABLE_CHAR_NAME(pTable)); + terrno = TSDB_CODE_TDB_INVALID_ACTION; + return -1; + } + + // Check schema version and update schema if needed + if (tsdbCheckTableSchema(pRepo, pBlock, pTable) < 0) { + tsdbError("vgId:%d failed to insert data to table %s since %s", REPO_ID(pRepo), TABLE_CHAR_NAME(pTable), + tstrerror(terrno)); + return -1; } SSubmitBlkIter blkIter = {0}; - SDataRow row = NULL; + SDataRow row = NULL; TSKEY minKey = now - tsMsPerDay[pRepo->config.precision] * pRepo->config.keep; TSKEY maxKey = now + tsMsPerDay[pRepo->config.precision] * pRepo->config.daysPerFile; @@ -1007,391 +743,317 @@ static int32_t tsdbInsertDataToTable(TsdbRepoT *repo, SSubmitBlk *pBlock, TSKEY tsdbInitSubmitBlkIter(pBlock, &blkIter); while ((row = tsdbGetSubmitBlkNext(&blkIter)) != NULL) { if (dataRowKey(row) < minKey || dataRowKey(row) > maxKey) { - tsdbError("vgId:%d, table:%s, tid:%d, talbe uid:%ld timestamp is out of range. now:%" PRId64 ", maxKey:%" PRId64 - ", minKey:%" PRId64, - pRepo->config.tsdbId, pTable->name->data, pTable->tableId.tid, pTable->tableId.uid, now, minKey, maxKey); - return TSDB_CODE_TDB_TIMESTAMP_OUT_OF_RANGE; - } - - if (tdInsertRowToTable(pRepo, row, pTable) < 0) { + tsdbError("vgId:%d table %s tid %d uid %" PRIu64 " timestamp is out of range! now %" PRId64 " minKey %" PRId64 + " maxKey %" PRId64, + REPO_ID(pRepo), TABLE_CHAR_NAME(pTable), TABLE_TID(pTable), TABLE_UID(pTable), now, minKey, maxKey); + terrno = TSDB_CODE_TDB_TIMESTAMP_OUT_OF_RANGE; return -1; } - (*affectedrows)++; - points++; - } - atomic_fetch_add_64(&(pRepo->stat.pointsWritten), points * (pSchema->numOfCols)); - atomic_fetch_add_64(&(pRepo->stat.totalStorage), points * pSchema->vlen); - - return TSDB_CODE_SUCCESS; -} -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(pMeta, pTable, dataRowVersion(row)); - if (pSchema == NULL) { - // TODO: deal with the error here - ASSERT(false); - } - } + if (tsdbInsertRowToMem(pRepo, row, pTable) < 0) return -1; - tdAppendDataRowToDataCol(row, pSchema, pCols); - numOfRows++; - } while (tSkipListIterNext(pIter)); - - return numOfRows; -} - -static void tsdbDestroyTableIters(SSkipListIterator **iters, int maxTables) { - if (iters == NULL) return; - - for (int tid = 1; tid < maxTables; tid++) { - if (iters[tid] == NULL) continue; - tSkipListDestroyIter(iters[tid]); - } - - free(iters); -} - -static SSkipListIterator **tsdbCreateTableIters(STsdbMeta *pMeta, int maxTables) { - SSkipListIterator **iters = (SSkipListIterator **)calloc(maxTables, sizeof(SSkipListIterator *)); - if (iters == NULL) return NULL; - - for (int tid = 1; tid < maxTables; tid++) { - STable *pTable = pMeta->tables[tid]; - if (pTable == NULL || pTable->imem == NULL || pTable->imem->numOfRows == 0) continue; - - iters[tid] = tSkipListCreateIter(pTable->imem->pData); - if (iters[tid] == NULL) goto _err; - - if (!tSkipListIterNext(iters[tid])) goto _err; + (*affectedrows)++; + points++; } - return iters; - - _err: - tsdbDestroyTableIters(iters, maxTables); - return NULL; -} + STSchema *pSchema = tsdbGetTableSchemaByVersion(pTable, pBlock->sversion); + pRepo->stat.pointsWritten += points * schemaNCols(pSchema); + pRepo->stat.totalStorage += points * schemaVLen(pSchema); -static void tsdbFreeMemTable(SMemTable *pMemTable) { - if (pMemTable) { - tSkipListDestroy(pMemTable->pData); - free(pMemTable); - } + return 0; } -// Commit to file -static void *tsdbCommitData(void *arg) { - STsdbRepo * pRepo = (STsdbRepo *)arg; - STsdbMeta * pMeta = pRepo->tsdbMeta; - STsdbCache *pCache = pRepo->tsdbCache; - STsdbCfg * pCfg = &(pRepo->config); - SDataCols * pDataCols = NULL; - SRWHelper whelper = {{0}}; - if (pCache->imem == NULL) return NULL; - - tsdbPrint("vgId:%d, starting to commit....", pRepo->config.tsdbId); - - // Create the iterator to read from cache - SSkipListIterator **iters = tsdbCreateTableIters(pMeta, pCfg->maxTables); - if (iters == NULL) { - ASSERT(0); - return NULL; - } +static SSubmitBlk *tsdbGetSubmitMsgNext(SSubmitMsgIter *pIter) { + SSubmitBlk *pBlock = pIter->pBlock; + if (pBlock == NULL) return NULL; - if (tsdbInitWriteHelper(&whelper, pRepo) < 0) goto _exit; - if ((pDataCols = tdNewDataCols(pMeta->maxRowBytes, pMeta->maxCols, pCfg->maxRowsPerFileBlock)) == NULL) goto _exit; + pBlock->len = htonl(pBlock->len); + pBlock->numOfRows = htons(pBlock->numOfRows); + pBlock->uid = htobe64(pBlock->uid); + pBlock->tid = htonl(pBlock->tid); - int sfid = tsdbGetKeyFileId(pCache->imem->keyFirst, pCfg->daysPerFile, pCfg->precision); - int efid = tsdbGetKeyFileId(pCache->imem->keyLast, pCfg->daysPerFile, pCfg->precision); + pBlock->sversion = htonl(pBlock->sversion); + pBlock->padding = htonl(pBlock->padding); - // Loop to commit to each file - for (int fid = sfid; fid <= efid; fid++) { - if (tsdbCommitToFile(pRepo, fid, iters, &whelper, pDataCols) < 0) { - ASSERT(false); - goto _exit; - } + pIter->len = pIter->len + sizeof(SSubmitBlk) + pBlock->len; + if (pIter->len >= pIter->totalLen) { + pIter->pBlock = NULL; + } else { + pIter->pBlock = (SSubmitBlk *)((char *)pBlock + pBlock->len + sizeof(SSubmitBlk)); } - // Do retention actions - tsdbFitRetention(pRepo); - if (pRepo->appH.notifyStatus) pRepo->appH.notifyStatus(pRepo->appH.appH, TSDB_STATUS_COMMIT_OVER); + return pBlock; +} -_exit: - tdFreeDataCols(pDataCols); - tsdbDestroyTableIters(iters, pCfg->maxTables); - tsdbDestroyHelper(&whelper); +static SDataRow tsdbGetSubmitBlkNext(SSubmitBlkIter *pIter) { + SDataRow row = pIter->row; + if (row == NULL) return NULL; - tsdbLockRepo(arg); - tdListMove(pCache->imem->list, pCache->pool.memPool); - tsdbAdjustCacheBlocks(pCache); - tdListFree(pCache->imem->list); - free(pCache->imem); - pCache->imem = NULL; - pRepo->commit = 0; - for (int i = 1; i < pCfg->maxTables; i++) { - STable *pTable = pMeta->tables[i]; - if (pTable && pTable->imem) { - tsdbFreeMemTable(pTable->imem); - pTable->imem = NULL; - } + pIter->len += dataRowLen(row); + if (pIter->len >= pIter->totalLen) { + pIter->row = NULL; + } else { + pIter->row = (char *)row + dataRowLen(row); } - tsdbUnLockRepo(arg); - tsdbPrint("vgId:%d, commit over....", pRepo->config.tsdbId); - return NULL; + return row; } -static int tsdbCommitToFile(STsdbRepo *pRepo, int fid, SSkipListIterator **iters, SRWHelper *pHelper, SDataCols *pDataCols) { - char dataDir[128] = {0}; +static int tsdbRestoreInfo(STsdbRepo *pRepo) { + // TODO STsdbMeta * pMeta = pRepo->tsdbMeta; STsdbFileH *pFileH = pRepo->tsdbFileH; - STsdbCfg * pCfg = &pRepo->config; - SFileGroup *pGroup = NULL; - - TSKEY minKey = 0, maxKey = 0; - tsdbGetKeyRangeOfFileId(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) return 0; // No data to commit, just return - - // Create and open files for commit - tsdbGetDataDirName(pRepo, dataDir); - if ((pGroup = tsdbCreateFGroup(pFileH, dataDir, fid, pCfg->maxTables)) == NULL) { - tsdbError("vgId:%d, failed to create file group %d", pRepo->config.tsdbId, fid); - goto _err; - } - - // Open files for write/read - if (tsdbSetAndOpenHelperFile(pHelper, pGroup) < 0) { - tsdbError("vgId:%d, failed to set helper file", pRepo->config.tsdbId); - goto _err; - } - - // Loop to commit data in each table - for (int tid = 1; tid < pCfg->maxTables; tid++) { - STable * pTable = pMeta->tables[tid]; - if (pTable == NULL) continue; - - SSkipListIterator *pIter = iters[tid]; - - // Set the helper and the buffer dataCols object to help to write this table - tsdbSetHelperTable(pHelper, pTable, pRepo); - tdInitDataCols(pDataCols, tsdbGetTableSchema(pMeta, pTable)); - - // Loop to write the data in the cache to files. If no data to write, just break the loop - int maxRowsToRead = pCfg->maxRowsPerFileBlock * 4 / 5; - int nLoop = 0; - while (true) { - int rowsRead = tsdbReadRowsFromCache(pMeta, pTable, 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) goto _err; - ASSERT(rowsWritten <= pDataCols->numOfRows); + SFileGroup *pFGroup = NULL; - tdPopDataColsPoints(pDataCols, rowsWritten); - maxRowsToRead = pCfg->maxRowsPerFileBlock * 4 / 5 - pDataCols->numOfRows; - } + SFileGroupIter iter; + SRWHelper rhelper = {0}; - ASSERT(pDataCols->numOfRows == 0); + if (tsdbInitReadHelper(&rhelper, pRepo) < 0) goto _err; - // Move the last block to the new .l file if neccessary - if (tsdbMoveLastBlockIfNeccessary(pHelper) < 0) { - tsdbError("vgId:%d, failed to move last block", pRepo->config.tsdbId); - goto _err; - } + tsdbInitFileGroupIter(pFileH, &iter, TSDB_ORDER_DESC); + while ((pFGroup = tsdbGetFileGroupNext(&iter)) != NULL) { + if (tsdbSetAndOpenHelperFile(&rhelper, pFGroup) < 0) goto _err; + for (int i = 1; i < pRepo->config.maxTables; i++) { + STable *pTable = pMeta->tables[i]; + if (pTable == NULL) continue; + SCompIdx *pIdx = &rhelper.pCompIdx[i]; - // Write the SCompBlock part - if (tsdbWriteCompInfo(pHelper) < 0) { - tsdbError("vgId:%d, failed to write compInfo part", pRepo->config.tsdbId); - goto _err; + if (pIdx->offset > 0 && pTable->lastKey < pIdx->maxKey) pTable->lastKey = pIdx->maxKey; } } - if (tsdbWriteCompIdx(pHelper) < 0) { - tsdbError("vgId:%d, failed to write compIdx part", pRepo->config.tsdbId); - goto _err; - } - - tsdbCloseHelperFile(pHelper, 0); - // TODO: make it atomic with some methods - 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; - + tsdbDestroyHelper(&rhelper); return 0; - _err: - ASSERT(false); - tsdbCloseHelperFile(pHelper, 1); +_err: + tsdbDestroyHelper(&rhelper); return -1; } -/** - * Return the next iterator key. - * - * @return the next key if iter has - * -1 if iter not - */ -static TSKEY tsdbNextIterKey(SSkipListIterator *pIter) { - if (pIter == NULL) return -1; - - SSkipListNode *node = tSkipListIterGet(pIter); - if (node == NULL) return -1; - - SDataRow row = SL_GET_NODE_DATA(node); - return dataRowKey(row); -} - -static int tsdbHasDataToCommit(SSkipListIterator **iters, int nIters, TSKEY minKey, TSKEY maxKey) { - TSKEY nextKey; - for (int i = 0; i < nIters; i++) { - SSkipListIterator *pIter = iters[i]; - nextKey = tsdbNextIterKey(pIter); - if (nextKey > 0 && (nextKey >= minKey && nextKey <= maxKey)) return 1; - } +static int tsdbInitSubmitBlkIter(SSubmitBlk *pBlock, SSubmitBlkIter *pIter) { + if (pBlock->len <= 0) return -1; + pIter->totalLen = pBlock->len; + pIter->len = 0; + pIter->row = (SDataRow)(pBlock->data); return 0; } static void tsdbAlterCompression(STsdbRepo *pRepo, int8_t compression) { - int8_t oldCompRession = pRepo->config.compression; + int8_t ocompression = pRepo->config.compression; pRepo->config.compression = compression; - tsdbTrace("tsdb compression is changed from %d to %d", oldCompRession, compression); + tsdbTrace("vgId:%d tsdb compression is changed from %d to %d", REPO_ID(pRepo), ocompression, compression); } -static void tsdbAlterKeep(STsdbRepo *pRepo, int32_t keep) { - STsdbCfg *pCfg = &pRepo->config; - int oldKeep = pCfg->keep; +static int tsdbAlterKeep(STsdbRepo *pRepo, int32_t keep) { + STsdbCfg * pCfg = &pRepo->config; + STsdbFileH *pFileH = pRepo->tsdbFileH; + int okeep = pCfg->keep; + SFileGroup *pFGroup = NULL; - int maxFiles = keep / pCfg->maxTables + 3; - if (pRepo->config.keep > keep) { - pRepo->config.keep = keep; - pRepo->tsdbFileH->maxFGroups = maxFiles; - } else { - pRepo->config.keep = keep; - pRepo->tsdbFileH->fGroup = realloc(pRepo->tsdbFileH->fGroup, sizeof(SFileGroup)); - if (pRepo->tsdbFileH->fGroup == NULL) { - // TODO: deal with the error + ASSERT(pCfg->keep != keep); + int maxFiles = TSDB_MAX_FILE(keep, pCfg->daysPerFile); + + if (maxFiles != pFileH->maxFGroups) { + pthread_rwlock_wrlock(&(pFileH->fhlock)); + + pCfg->keep = keep; + pFGroup = (SFileGroup *)calloc(maxFiles, sizeof(SFileGroup)); + if (pFGroup == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + pthread_rwlock_unlock(&(pFileH->fhlock)); + return -1; + } + + int mfid = TSDB_KEY_FILEID(taosGetTimestamp(pCfg->precision), pCfg->daysPerFile, pCfg->precision) - + TSDB_MAX_FILE(keep, pCfg->daysPerFile); + + int i = 0; + for (; i < pFileH->nFGroups; i++) { + if (pFileH->pFGroup[i].fileId >= mfid) break; + tsdbRemoveFileGroup(pRepo, &(pFileH->pFGroup[i])); + } + + for (int j = 0; i < pFileH->nFGroups; i++, j++) { + pFGroup[j] = pFileH->pFGroup[i]; } - pRepo->tsdbFileH->maxFGroups = maxFiles; + + free(pFileH->pFGroup); + pFileH->pFGroup = pFGroup; + + pthread_rwlock_unlock(&(pFileH->fhlock)); } - tsdbTrace("vgId:%d, keep is changed from %d to %d", pRepo->config.tsdbId, oldKeep, keep); + + tsdbTrace("vgId:%d keep is changed from %d to %d", REPO_ID(pRepo), okeep, keep); + + return 0; } -static void tsdbAlterMaxTables(STsdbRepo *pRepo, int32_t maxTables) { +static int tsdbAlterMaxTables(STsdbRepo *pRepo, int32_t maxTables) { + // TODO int oldMaxTables = pRepo->config.maxTables; if (oldMaxTables < pRepo->config.maxTables) { - // TODO + terrno = TSDB_CODE_TDB_INVALID_ACTION; + return -1; } STsdbMeta *pMeta = pRepo->tsdbMeta; - pMeta->maxTables = maxTables; pMeta->tables = realloc(pMeta->tables, maxTables * sizeof(STable *)); - memset(&pMeta->tables[oldMaxTables], 0, sizeof(STable *) * (maxTables-oldMaxTables)); + memset(&pMeta->tables[oldMaxTables], 0, sizeof(STable *) * (maxTables - oldMaxTables)); pRepo->config.maxTables = maxTables; + if (pRepo->mem) { + pRepo->mem->tData = realloc(pRepo->mem->tData, maxTables * sizeof(STableData *)); + memset(POINTER_SHIFT(pRepo->mem->tData, sizeof(STableData *) * oldMaxTables), 0, + sizeof(STableData *) * (maxTables - oldMaxTables)); + } + + if (pRepo->imem) { + pRepo->imem->tData = realloc(pRepo->imem->tData, maxTables * sizeof(STableData *)); + memset(POINTER_SHIFT(pRepo->imem->tData, sizeof(STableData *) * oldMaxTables), 0, + sizeof(STableData *) * (maxTables - oldMaxTables)); + } + tsdbTrace("vgId:%d, tsdb maxTables is changed from %d to %d!", pRepo->config.tsdbId, oldMaxTables, maxTables); + return 0; } -#define TSDB_META_FILE_INDEX 10000000 -uint32_t tsdbGetFileInfo(TsdbRepoT *repo, char *name, uint32_t *index, uint32_t eindex, int32_t *size) { - STsdbRepo *pRepo = (STsdbRepo *)repo; - // STsdbMeta *pMeta = pRepo->tsdbMeta; - STsdbFileH *pFileH = pRepo->tsdbFileH; - uint32_t magic = 0; - char fname[256] = "\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; + } +} - struct stat fState; +static int tsdbEncodeCfg(void **buf, STsdbCfg *pCfg) { + int tlen = 0; + + tlen += taosEncodeVariantI32(buf, pCfg->tsdbId); + tlen += taosEncodeFixedI32(buf, pCfg->cacheBlockSize); + tlen += taosEncodeVariantI32(buf, pCfg->totalBlocks); + tlen += taosEncodeVariantI32(buf, pCfg->maxTables); + tlen += taosEncodeVariantI32(buf, pCfg->daysPerFile); + tlen += taosEncodeVariantI32(buf, pCfg->keep); + tlen += taosEncodeVariantI32(buf, pCfg->keep1); + tlen += taosEncodeVariantI32(buf, pCfg->keep2); + tlen += taosEncodeVariantI32(buf, pCfg->minRowsPerFileBlock); + tlen += taosEncodeVariantI32(buf, pCfg->maxRowsPerFileBlock); + tlen += taosEncodeFixedI8(buf, pCfg->precision); + tlen += taosEncodeFixedI8(buf, pCfg->compression); + + return tlen; +} - tsdbTrace("vgId:%d name:%s index:%d eindex:%d", pRepo->config.tsdbId, name, *index, eindex); - ASSERT(*index <= eindex); +static void *tsdbDecodeCfg(void *buf, STsdbCfg *pCfg) { + buf = taosDecodeVariantI32(buf, &(pCfg->tsdbId)); + buf = taosDecodeFixedI32(buf, &(pCfg->cacheBlockSize)); + buf = taosDecodeVariantI32(buf, &(pCfg->totalBlocks)); + buf = taosDecodeVariantI32(buf, &(pCfg->maxTables)); + buf = taosDecodeVariantI32(buf, &(pCfg->daysPerFile)); + buf = taosDecodeVariantI32(buf, &(pCfg->keep)); + buf = taosDecodeVariantI32(buf, &(pCfg->keep1)); + buf = taosDecodeVariantI32(buf, &(pCfg->keep2)); + buf = taosDecodeVariantI32(buf, &(pCfg->minRowsPerFileBlock)); + buf = taosDecodeVariantI32(buf, &(pCfg->maxRowsPerFileBlock)); + buf = taosDecodeFixedI8(buf, &(pCfg->precision)); + buf = taosDecodeFixedI8(buf, &(pCfg->compression)); + + return buf; +} - char *sdup = strdup(pRepo->rootDir); - char *prefix = dirname(sdup); +static int tsdbCheckTableSchema(STsdbRepo *pRepo, SSubmitBlk *pBlock, STable *pTable) { + ASSERT(pTable != NULL); + + STSchema *pSchema = tsdbGetTableSchema(pTable); + int sversion = schemaVersion(pSchema); + + if (pBlock->sversion == sversion) return 0; + if (pBlock->sversion > sversion) { // need to config + tsdbTrace("vgId:%d table %s tid %d has version %d smaller than client version %d, try to config", REPO_ID(pRepo), + TABLE_CHAR_NAME(pTable), TABLE_TID(pTable), sversion, pBlock->sversion); + if (pRepo->appH.configFunc) { + void *msg = (*pRepo->appH.configFunc)(REPO_ID(pRepo), TABLE_TID(pTable)); + if (msg == NULL) { + tsdbError("vgId:%d failed to config table %s tid %d since %s", REPO_ID(pRepo), TABLE_CHAR_NAME(pTable), + TABLE_TID(pTable), tstrerror(terrno)); + return -1; + } - if (name[0] == 0) { // get the file from index or after, but not larger than eindex - int fid = (*index) / 3; + STableCfg *pTableCfg = tsdbCreateTableCfgFromMsg(msg); + if (pTableCfg == NULL) { + rpcFreeCont(msg); + return -1; + } - if (pFileH->numOfFGroups == 0 || fid > pFileH->fGroup[pFileH->numOfFGroups - 1].fileId) { - if (*index <= TSDB_META_FILE_INDEX && TSDB_META_FILE_INDEX <= eindex) { - tsdbGetMetaFileName(pRepo->rootDir, fname); - *index = TSDB_META_FILE_INDEX; - } else { - tfree(sdup); - return 0; + if (tsdbUpdateTable(pRepo, (TABLE_TYPE(pTable) == TSDB_CHILD_TABLE) ? pTable->pSuper : pTable, pTableCfg) < 0) { + tsdbError("vgId:%d failed to update table %s since %s", REPO_ID(pRepo), TABLE_CHAR_NAME(pTable), + tstrerror(terrno)); + tsdbClearTableCfg(pTableCfg); + rpcFreeCont(msg); + return -1; } + tsdbClearTableCfg(pTableCfg); + rpcFreeCont(msg); } else { - SFileGroup *pFGroup = - taosbsearch(&fid, pFileH->fGroup, pFileH->numOfFGroups, sizeof(SFileGroup), compFGroupKey, TD_GE); - if (pFGroup->fileId == fid) { - strcpy(fname, pFGroup->files[(*index) % 3].fname); - } else { - if (pFGroup->fileId * 3 + 2 < eindex) { - strcpy(fname, pFGroup->files[0].fname); - *index = pFGroup->fileId * 3; - } else { - tfree(sdup); - return 0; - } - } + terrno = TSDB_CODE_TDB_IVD_TB_SCHEMA_VERSION; + return -1; } - strcpy(name, fname + strlen(prefix)); - } else { // get the named file at the specified index. If not there, return 0 - if (*index == TSDB_META_FILE_INDEX) { // get meta file - tsdbGetMetaFileName(pRepo->rootDir, fname); - } else { - int fid = (*index) / 3; - SFileGroup *pFGroup = tsdbSearchFGroup(pFileH, fid); - if (pFGroup == NULL) { // not found - tfree(sdup); - return 0; - } - - SFile *pFile = &pFGroup->files[(*index) % 3]; - strcpy(fname, pFile->fname); + } else { + if (tsdbGetTableSchemaByVersion(pTable, pBlock->sversion) == NULL) { + tsdbError("vgId:%d invalid submit schema version %d to table %s tid %d from client", REPO_ID(pRepo), + pBlock->sversion, TABLE_CHAR_NAME(pTable), TABLE_TID(pTable)); } + terrno = TSDB_CODE_TDB_IVD_TB_SCHEMA_VERSION; + return -1; } - if (stat(fname, &fState) < 0) { - tfree(sdup); - return 0; - } + return 0; + } - tfree(sdup); - *size = fState.st_size; - magic = *size; +static int tsdbAlterCacheTotalBlocks(STsdbRepo *pRepo, int totalBlocks) { + // TODO + // 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; +} - return magic; +#if 0 + +TSKEY tsdbGetTableLastKey(TSDB_REPO_T *repo, uint64_t uid) { + STsdbRepo *pRepo = (STsdbRepo *)repo; + + STable *pTable = tsdbGetTableByUid(pRepo->tsdbMeta, uid); + if (pTable == NULL) return -1; + + return TSDB_GET_TABLE_LAST_KEY(pTable); } -void tsdbReportStat(void *repo, int64_t *totalPoints, int64_t *totalStorage, int64_t *compStorage){ - ASSERT(repo != NULL); - STsdbRepo * pRepo = repo; - *totalPoints = pRepo->stat.pointsWritten; - *totalStorage = pRepo->stat.totalStorage; - *compStorage = pRepo->stat.compStorage; -} \ No newline at end of file +#endif \ No newline at end of file diff --git a/src/tsdb/src/tsdbMemTable.c b/src/tsdb/src/tsdbMemTable.c new file mode 100644 index 0000000000000000000000000000000000000000..e928cdc385de1eb77f128e931340d5e2c14043f8 --- /dev/null +++ b/src/tsdb/src/tsdbMemTable.c @@ -0,0 +1,695 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * 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 . + */ + +#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; +} \ No newline at end of file diff --git a/src/tsdb/src/tsdbMeta.c b/src/tsdb/src/tsdbMeta.c index 76125674117a2c8b84786c300cb05b6d1a838441..beb8f33052d66c46727208e876ca75293acdc565 100644 --- a/src/tsdb/src/tsdbMeta.c +++ b/src/tsdb/src/tsdbMeta.c @@ -1,265 +1,461 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * 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 . + */ #include -#include "tskiplist.h" -#include "tsdb.h" -#include "taosdef.h" #include "hash.h" +#include "taosdef.h" +#include "tchecksum.h" +#include "tsdb.h" #include "tsdbMain.h" +#include "tskiplist.h" + +#define TSDB_SUPER_TABLE_SL_LEVEL 5 +#define DEFAULT_TAG_INDEX_COLUMN 0 + +static int tsdbCompareSchemaVersion(const void *key1, const void *key2); +static int tsdbRestoreTable(void *pHandle, void *cont, int contLen); +static void tsdbOrgMeta(void *pHandle); +static char * getTagIndexKey(const void *pData); +static STable *tsdbNewTable(STableCfg *pCfg, bool isSuper); +static void tsdbFreeTable(STable *pTable); +static int tsdbUpdateTableTagSchema(STable *pTable, STSchema *newSchema); +static int tsdbAddTableToMeta(STsdbRepo *pRepo, STable *pTable, bool addIdx); +static void tsdbRemoveTableFromMeta(STsdbRepo *pRepo, STable *pTable, bool rmFromIdx, bool lock); +static int tsdbAddTableIntoIndex(STsdbMeta *pMeta, STable *pTable); +static int tsdbRemoveTableFromIndex(STsdbMeta *pMeta, STable *pTable); +static int tsdbInitTableCfg(STableCfg *config, ETableType type, uint64_t uid, int32_t tid); +static int tsdbTableSetSchema(STableCfg *config, STSchema *pSchema, bool dup); +static int tsdbTableSetName(STableCfg *config, char *name, bool dup); +static int tsdbTableSetTagSchema(STableCfg *config, STSchema *pSchema, bool dup); +static int tsdbTableSetSName(STableCfg *config, char *sname, bool dup); +static int tsdbTableSetSuperUid(STableCfg *config, uint64_t uid); +static int tsdbTableSetTagValue(STableCfg *config, SKVRow row, bool dup); +static int tsdbTableSetStreamSql(STableCfg *config, char *sql, bool dup); +static int tsdbEncodeTableName(void **buf, tstr *name); +static void * tsdbDecodeTableName(void *buf, tstr **name); +static int tsdbEncodeTable(void **buf, STable *pTable); +static void * tsdbDecodeTable(void *buf, STable **pRTable); +static int tsdbGetTableEncodeSize(int8_t act, STable *pTable); +static void * tsdbInsertTableAct(STsdbRepo *pRepo, int8_t act, void *buf, STable *pTable); + +// ------------------ OUTER FUNCTIONS ------------------ +int tsdbCreateTable(TSDB_REPO_T *repo, STableCfg *pCfg) { + STsdbRepo *pRepo = (STsdbRepo *)repo; + STsdbMeta *pMeta = pRepo->tsdbMeta; + STable * super = NULL; + STable * table = NULL; + int newSuper = 0; -#define TSDB_SUPER_TABLE_SL_LEVEL 5 // TODO: may change here -// #define TSDB_META_FILE_NAME "META" + STable *pTable = tsdbGetTableByUid(pMeta, pCfg->tableId.uid); + if (pTable != NULL) { + tsdbError("vgId:%d table %s already exists, tid %d uid %" PRId64, REPO_ID(pRepo), TABLE_CHAR_NAME(pTable), + TABLE_TID(pTable), TABLE_UID(pTable)); + return TSDB_CODE_TDB_TABLE_ALREADY_EXIST; + } + if (pCfg->type == TSDB_CHILD_TABLE) { + super = tsdbGetTableByUid(pMeta, pCfg->superUid); + if (super == NULL) { // super table not exists, try to create it + newSuper = 1; + super = tsdbNewTable(pCfg, true); + if (super == NULL) goto _err; + } else { + // TODO + if (super->type != TSDB_SUPER_TABLE) return -1; + if (super->tableId.uid != pCfg->superUid) return -1; + tsdbUpdateTable(pRepo, super, pCfg); + } + } -static int tsdbFreeTable(STable *pTable); -static int32_t tsdbCheckTableCfg(STableCfg *pCfg); -static int tsdbAddTableToMeta(STsdbMeta *pMeta, STable *pTable, bool addIdx); -static int tsdbRemoveTableFromMeta(STsdbMeta *pMeta, STable *pTable, bool rmFromIdx); + table = tsdbNewTable(pCfg, false); + if (table == NULL) goto _err; -/** - * Encode a TSDB table object as a binary content - * ASSUMPTIONS: VALID PARAMETERS - * - * @param pTable table object to encode - * @param contLen the encoded binary content length - * - * @return binary content for success - * NULL fro failure - */ -void tsdbEncodeTable(STable *pTable, char *buf, int *contLen) { - if (pTable == NULL) return; + // Register to meta + if (newSuper) { + if (tsdbAddTableToMeta(pRepo, super, true) < 0) goto _err; + } + if (tsdbAddTableToMeta(pRepo, table, true) < 0) goto _err; + + // Write to memtable action + int tlen1 = (newSuper) ? tsdbGetTableEncodeSize(TSDB_UPDATE_META, super) : 0; + int tlen2 = tsdbGetTableEncodeSize(TSDB_UPDATE_META, table); + int tlen = tlen1 + tlen2; + void *buf = tsdbAllocBytes(pRepo, tlen); + ASSERT(buf != NULL); + if (newSuper) { + void *pBuf = tsdbInsertTableAct(pRepo, TSDB_UPDATE_META, buf, super); + ASSERT(POINTER_DISTANCE(pBuf, buf) == tlen1); + buf = pBuf; + } + tsdbInsertTableAct(pRepo, TSDB_UPDATE_META, buf, table); - void *ptr = buf; - T_APPEND_MEMBER(ptr, pTable, STable, type); - // Encode name, todo refactor - *(int *)ptr = varDataLen(pTable->name); - ptr = (char *)ptr + sizeof(int); - memcpy(ptr, varDataVal(pTable->name), varDataLen(pTable->name)); - ptr = (char *)ptr + varDataLen(pTable->name); + return 0; - T_APPEND_MEMBER(ptr, &(pTable->tableId), STableId, uid); - T_APPEND_MEMBER(ptr, &(pTable->tableId), STableId, tid); - T_APPEND_MEMBER(ptr, pTable, STable, superUid); +_err: + tsdbFreeTable(super); + tsdbFreeTable(table); + return -1; +} - if (pTable->type == TSDB_SUPER_TABLE) { - T_APPEND_MEMBER(ptr, pTable, STable, numOfSchemas); - for (int i = 0; i < pTable->numOfSchemas; i++) { - ptr = tdEncodeSchema(ptr, pTable->schema[i]); - } - ptr = tdEncodeSchema(ptr, pTable->tagSchema); - } else if (pTable->type == TSDB_CHILD_TABLE) { - ptr = tdEncodeKVRow(ptr, pTable->tagVal); - } else { - T_APPEND_MEMBER(ptr, pTable, STable, numOfSchemas); - for (int i = 0; i < pTable->numOfSchemas; i++) { - ptr = tdEncodeSchema(ptr, pTable->schema[i]); +int tsdbDropTable(TSDB_REPO_T *repo, STableId tableId) { + STsdbRepo *pRepo = (STsdbRepo *)repo; + STsdbMeta *pMeta = pRepo->tsdbMeta; + uint64_t uid = tableId.uid; + int tid = 0; + char * tbname = NULL; + + STable *pTable = tsdbGetTableByUid(pMeta, uid); + if (pTable == NULL) { + tsdbError("vgId:%d failed to drop table since table not exists! tid:%d uid %" PRId64, REPO_ID(pRepo), tableId.tid, + uid); + terrno = TSDB_CODE_TDB_INVALID_TABLE_ID; + return -1; + } + + tsdbTrace("vgId:%d try to drop table %s type %d", REPO_ID(pRepo), TABLE_CHAR_NAME(pTable), TABLE_TYPE(pTable)); + + tid = TABLE_TID(pTable); + tbname = strdup(TABLE_CHAR_NAME(pTable)); + if (tbname == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + return -1; + } + + if (TABLE_TYPE(pTable) == TSDB_STREAM_TABLE) { + if (pTable->cqhandle) pRepo->appH.cqDropFunc(pTable->cqhandle); + } + + if (TABLE_TYPE(pTable) == TSDB_SUPER_TABLE) { + SSkipListIterator *pIter = tSkipListCreateIter(pTable->pIndex); + while (tSkipListIterNext(pIter)) { + STable *tTable = *(STable **)SL_GET_NODE_DATA(tSkipListIterGet(pIter)); + ASSERT(TABLE_TYPE(tTable) == TSDB_CHILD_TABLE); + int tlen = tsdbGetTableEncodeSize(TSDB_DROP_META, tTable); + void *buf = tsdbAllocBytes(pRepo, tlen); + ASSERT(buf != NULL); + tsdbInsertTableAct(pRepo, TSDB_DROP_META, buf, tTable); + tsdbRemoveTableFromMeta(pRepo, tTable, false, true); } } - if (pTable->type == TSDB_STREAM_TABLE) { - ptr = taosEncodeString(ptr, pTable->sql); + tsdbRemoveTableFromMeta(pRepo, pTable, true, true); + + tsdbTrace("vgId:%d, table %s is dropped! tid:%d, uid:%" PRId64, pRepo->config.tsdbId, tbname, tid, uid); + free(tbname); + + return 0; +} + +void *tsdbGetTableTagVal(TSDB_REPO_T *repo, const STableId *id, int32_t colId, int16_t type, int16_t bytes) { + // TODO: this function should be changed also + STsdbMeta *pMeta = tsdbGetMeta(repo); + STable * pTable = tsdbGetTableByUid(pMeta, id->uid); + + STSchema *pSchema = tsdbGetTableTagSchema(pTable); + STColumn *pCol = tdGetColOfID(pSchema, colId); + if (pCol == NULL) { + return NULL; // No matched tag volumn + } + + char *val = tdGetKVRowValOfCol(pTable->tagVal, colId); + assert(type == pCol->type && bytes == pCol->bytes); + + if (val != NULL && IS_VAR_DATA_TYPE(type)) { + assert(varDataLen(val) < pCol->bytes); } - *contLen = (char *)ptr - buf; + return val; } -/** - * Decode from an encoded binary - * ASSUMPTIONS: valid parameters - * - * @param cont binary object - * @param contLen binary length - * - * @return TSDB table object for success - * NULL for failure - */ -STable *tsdbDecodeTable(void *cont, int contLen) { - STable *pTable = (STable *)calloc(1, sizeof(STable)); - if (pTable == NULL) return NULL; +char *tsdbGetTableName(TSDB_REPO_T *repo, const STableId *id) { + // TODO: need to change as thread-safe + STsdbRepo *pRepo = (STsdbRepo *)repo; + STsdbMeta *pMeta = pRepo->tsdbMeta; - void *ptr = cont; - T_READ_MEMBER(ptr, int8_t, pTable->type); - if (pTable->type != TSDB_CHILD_TABLE) { - pTable->schema = (STSchema **)malloc(sizeof(STSchema *) * TSDB_MAX_TABLE_SCHEMAS); - if (pTable->schema == NULL) { - free(pTable); - return NULL; - } + STable *pTable = tsdbGetTableByUid(pMeta, id->uid); + + if (pTable == NULL) { + return NULL; + } else { + return (char *)pTable->name; } - int len = *(int *)ptr; - ptr = (char *)ptr + sizeof(int); - pTable->name = calloc(1, len + VARSTR_HEADER_SIZE + 1); - if (pTable->name == NULL) return NULL; +} - varDataSetLen(pTable->name, len); - memcpy(pTable->name->data, ptr, len); +STableCfg *tsdbCreateTableCfgFromMsg(SMDCreateTableMsg *pMsg) { + if (pMsg == NULL) return NULL; - ptr = (char *)ptr + len; - T_READ_MEMBER(ptr, uint64_t, pTable->tableId.uid); - T_READ_MEMBER(ptr, int32_t, pTable->tableId.tid); - T_READ_MEMBER(ptr, uint64_t, pTable->superUid); + SSchema *pSchema = (SSchema *)pMsg->data; + int16_t numOfCols = htons(pMsg->numOfColumns); + int16_t numOfTags = htons(pMsg->numOfTags); - if (pTable->type == TSDB_SUPER_TABLE) { - T_READ_MEMBER(ptr, int16_t, pTable->numOfSchemas); - for (int i = 0; i < pTable->numOfSchemas; i++) { - pTable->schema[i] = tdDecodeSchema(&ptr); + STSchemaBuilder schemaBuilder = {0}; + + STableCfg *pCfg = (STableCfg *)calloc(1, sizeof(STableCfg)); + if (pCfg == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + return NULL; + } + + if (tsdbInitTableCfg(pCfg, pMsg->tableType, htobe64(pMsg->uid), htonl(pMsg->sid)) < 0) goto _err; + if (tdInitTSchemaBuilder(&schemaBuilder, htonl(pMsg->sversion)) < 0) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + goto _err; + } + + for (int i = 0; i < numOfCols; i++) { + if (tdAddColToSchema(&schemaBuilder, pSchema[i].type, htons(pSchema[i].colId), htons(pSchema[i].bytes)) < 0) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + goto _err; } - pTable->tagSchema = tdDecodeSchema(&ptr); - } else if (pTable->type == TSDB_CHILD_TABLE) { - ptr = tdDecodeKVRow(ptr, &pTable->tagVal); - } else { - T_READ_MEMBER(ptr, int16_t, pTable->numOfSchemas); - for (int i = 0; i < pTable->numOfSchemas; i++) { - pTable->schema[i] = tdDecodeSchema(&ptr); + } + if (tsdbTableSetSchema(pCfg, tdGetSchemaFromBuilder(&schemaBuilder), false) < 0) goto _err; + if (tsdbTableSetName(pCfg, pMsg->tableId, true) < 0) goto _err; + + if (numOfTags > 0) { + // Decode tag schema + tdResetTSchemaBuilder(&schemaBuilder, htonl(pMsg->tversion)); + for (int i = numOfCols; i < numOfCols + numOfTags; i++) { + if (tdAddColToSchema(&schemaBuilder, pSchema[i].type, htons(pSchema[i].colId), htons(pSchema[i].bytes)) < 0) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + goto _err; + } + } + if (tsdbTableSetTagSchema(pCfg, tdGetSchemaFromBuilder(&schemaBuilder), false) < 0) goto _err; + if (tsdbTableSetSName(pCfg, pMsg->superTableId, true) < 0) goto _err; + if (tsdbTableSetSuperUid(pCfg, htobe64(pMsg->superTableUid)) < 0) goto _err; + + // Decode tag values + if (pMsg->tagDataLen) { + int accBytes = 0; + char *pTagData = pMsg->data + (numOfCols + numOfTags) * sizeof(SSchema); + + SKVRowBuilder kvRowBuilder = {0}; + if (tdInitKVRowBuilder(&kvRowBuilder) < 0) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + goto _err; + } + for (int i = numOfCols; i < numOfCols + numOfTags; i++) { + if (tdAddColToKVRow(&kvRowBuilder, htons(pSchema[i].colId), pSchema[i].type, pTagData + accBytes) < 0) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + goto _err; + } + accBytes += htons(pSchema[i].bytes); + } + + tsdbTableSetTagValue(pCfg, tdGetKVRowFromBuilder(&kvRowBuilder), false); + tdDestroyKVRowBuilder(&kvRowBuilder); } } - if (pTable->type == TSDB_STREAM_TABLE) { - ptr = taosDecodeString(ptr, &(pTable->sql)); + if (pMsg->tableType == TSDB_STREAM_TABLE) { + char *sql = pMsg->data + (numOfCols + numOfTags) * sizeof(SSchema); + tsdbTableSetStreamSql(pCfg, sql, true); } - pTable->lastKey = TSKEY_INITIAL_VAL; - return pTable; -} + tdDestroyTSchemaBuilder(&schemaBuilder); -void tsdbFreeEncode(void *cont) { - if (cont != NULL) free(cont); -} + return pCfg; -static char* getTagIndexKey(const void* pData) { - STableIndexElem* elem = (STableIndexElem*) pData; - - STSchema* pSchema = tsdbGetTableTagSchema(elem->pMeta, elem->pTable); - STColumn* pCol = &pSchema->columns[DEFAULT_TAG_INDEX_COLUMN]; - void * res = tdGetKVRowValOfCol(elem->pTable->tagVal, pCol->colId); - return res; +_err: + tdDestroyTSchemaBuilder(&schemaBuilder); + tsdbClearTableCfg(pCfg); + tfree(pCfg); + return NULL; } -int tsdbRestoreTable(void *pHandle, void *cont, int contLen) { - STsdbMeta *pMeta = (STsdbMeta *)pHandle; +int tsdbUpdateTagValue(TSDB_REPO_T *repo, SUpdateTableTagValMsg *pMsg) { + STsdbRepo *pRepo = (STsdbRepo *)repo; + STsdbMeta *pMeta = pRepo->tsdbMeta; + int16_t tversion = htons(pMsg->tversion); - STable *pTable = tsdbDecodeTable(cont, contLen); - if (pTable == NULL) return -1; - - if (pTable->type == TSDB_SUPER_TABLE) { - STColumn* pColSchema = schemaColAt(pTable->tagSchema, 0); - pTable->pIndex = tSkipListCreate(TSDB_SUPER_TABLE_SL_LEVEL, pColSchema->type, pColSchema->bytes, - 1, 0, 1, getTagIndexKey); + STable *pTable = tsdbGetTableByUid(pMeta, htobe64(pMsg->uid)); + if (pTable == NULL) { + terrno = TSDB_CODE_TDB_INVALID_TABLE_ID; + return -1; + } + if (TABLE_TID(pTable) != htonl(pMsg->tid)) { + terrno = TSDB_CODE_TDB_INVALID_TABLE_ID; + return -1; } - tsdbAddTableToMeta(pMeta, pTable, false); + if (TABLE_TYPE(pTable) != TSDB_CHILD_TABLE) { + tsdbError("vgId:%d failed to update tag value of table %s since its type is %d", REPO_ID(pRepo), + TABLE_CHAR_NAME(pTable), TABLE_TYPE(pTable)); + terrno = TSDB_CODE_TDB_INVALID_ACTION; + return -1; + } - return 0; -} + if (schemaVersion(tsdbGetTableTagSchema(pTable)) < tversion) { + tsdbTrace("vgId:%d server tag version %d is older than client tag version %d, try to config", REPO_ID(pRepo), + schemaVersion(tsdbGetTableTagSchema(pTable)), tversion); + void *msg = (*pRepo->appH.configFunc)(pRepo->config.tsdbId, htonl(pMsg->tid)); + if (msg == NULL) return -1; -void tsdbOrgMeta(void *pHandle) { - STsdbMeta *pMeta = (STsdbMeta *)pHandle; + // Deal with error her + STableCfg *pTableCfg = tsdbCreateTableCfgFromMsg(msg); + STable * super = tsdbGetTableByUid(pMeta, pTableCfg->superUid); + ASSERT(super != NULL); - for (int i = 1; i < pMeta->maxTables; i++) { - STable *pTable = pMeta->tables[i]; - if (pTable != NULL && pTable->type == TSDB_CHILD_TABLE) { - tsdbAddTableIntoIndex(pMeta, pTable); + int32_t code = tsdbUpdateTable(pRepo, super, pTableCfg); + if (code != TSDB_CODE_SUCCESS) { + return code; } + tsdbClearTableCfg(pTableCfg); + rpcFreeCont(msg); } + + STSchema *pTagSchema = tsdbGetTableTagSchema(pTable); + + if (schemaVersion(pTagSchema) > tversion) { + tsdbError( + "vgId:%d failed to update tag value of table %s since version out of date, client tag version %d server tag " + "version %d", + REPO_ID(pRepo), TABLE_CHAR_NAME(pTable), tversion, schemaVersion(pTable->tagSchema)); + return TSDB_CODE_TDB_TAG_VER_OUT_OF_DATE; + } + if (schemaColAt(pTagSchema, DEFAULT_TAG_INDEX_COLUMN)->colId == htons(pMsg->colId)) { + tsdbRemoveTableFromIndex(pMeta, pTable); + } + // TODO: remove table from index if it is the first column of tag + tdSetKVRowDataOfCol(&pTable->tagVal, htons(pMsg->colId), htons(pMsg->type), pMsg->data); + if (schemaColAt(pTagSchema, DEFAULT_TAG_INDEX_COLUMN)->colId == htons(pMsg->colId)) { + tsdbAddTableIntoIndex(pMeta, pTable); + } + return TSDB_CODE_SUCCESS; } -/** - * Initialize the meta handle - * ASSUMPTIONS: VALID PARAMETER - */ -STsdbMeta *tsdbInitMeta(char *rootDir, int32_t maxTables, void *pRepo) { - STsdbMeta *pMeta = (STsdbMeta *)malloc(sizeof(STsdbMeta)); - if (pMeta == NULL) return NULL; - - pMeta->maxTables = maxTables; - pMeta->nTables = 0; - pMeta->superList = NULL; - pMeta->tables = (STable **)calloc(maxTables, sizeof(STable *)); - pMeta->maxRowBytes = 0; - pMeta->maxCols = 0; - pMeta->pRepo = pRepo; +// ------------------ INTERNAL FUNCTIONS ------------------ +STsdbMeta *tsdbNewMeta(STsdbCfg *pCfg) { + STsdbMeta *pMeta = (STsdbMeta *)calloc(1, sizeof(*pMeta)); + if (pMeta == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + goto _err; + } + + int code = pthread_rwlock_init(&pMeta->rwLock, NULL); + if (code != 0) { + tsdbError("vgId:%d failed to init TSDB meta r/w lock since %s", pCfg->tsdbId, strerror(code)); + terrno = TAOS_SYSTEM_ERROR(code); + goto _err; + } + + pMeta->tables = (STable **)calloc(pCfg->maxTables, sizeof(STable *)); if (pMeta->tables == NULL) { - free(pMeta); - return NULL; + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + goto _err; } - pMeta->map = taosHashInit(maxTables * TSDB_META_HASH_FRACTION, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BIGINT), false); - if (pMeta->map == NULL) { - free(pMeta->tables); - free(pMeta); - return NULL; + pMeta->superList = tdListNew(sizeof(STable *)); + if (pMeta->superList == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + goto _err; } - pMeta->mfh = tsdbInitMetaFile(rootDir, maxTables, tsdbRestoreTable, tsdbOrgMeta, pMeta); - if (pMeta->mfh == NULL) { - taosHashCleanup(pMeta->map); - free(pMeta->tables); - free(pMeta); - return NULL; + pMeta->uidMap = taosHashInit(pCfg->maxTables, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BIGINT), false); + if (pMeta->uidMap == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + goto _err; } return pMeta; + +_err: + tsdbFreeMeta(pMeta); + return NULL; } -int32_t tsdbFreeMeta(STsdbMeta *pMeta) { - STsdbRepo *pRepo = (STsdbRepo *)pMeta->pRepo; - if (pMeta == NULL) return 0; +void tsdbFreeMeta(STsdbMeta *pMeta) { + if (pMeta) { + taosHashCleanup(pMeta->uidMap); + tdListFree(pMeta->superList); + tfree(pMeta->tables); + pthread_rwlock_destroy(&pMeta->rwLock); + free(pMeta); + } +} - tsdbCloseMetaFile(pMeta->mfh); +int tsdbOpenMeta(STsdbRepo *pRepo) { + char * fname = NULL; + STsdbMeta *pMeta = pRepo->tsdbMeta; + ASSERT(pMeta != NULL); - for (int i = 1; i < pMeta->maxTables; i++) { - if (pMeta->tables[i] != NULL) { - STable *pTable = pMeta->tables[i]; - if (pTable->type == TSDB_STREAM_TABLE) (*pRepo->appH.cqDropFunc)(pTable->cqhandle); - tsdbFreeTable(pTable); - } + fname = tsdbGetMetaFileName(pRepo->rootDir); + if (fname == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + goto _err; } - free(pMeta->tables); - - STable *pTable = pMeta->superList; - while (pTable != NULL) { - STable *pTemp = pTable; - pTable = pTemp->next; - tsdbFreeTable(pTemp); + pMeta->pStore = tdOpenKVStore(fname, tsdbRestoreTable, tsdbOrgMeta, (void *)pRepo); + if (pMeta->pStore == NULL) { + tsdbError("vgId:%d failed to open TSDB meta while open the kv store since %s", REPO_ID(pRepo), tstrerror(terrno)); + goto _err; } - taosHashCleanup(pMeta->map); + tsdbTrace("vgId:%d open TSDB meta succeed", REPO_ID(pRepo)); + tfree(fname); + return 0; + +_err: + tfree(fname); + return -1; +} + +int tsdbCloseMeta(STsdbRepo *pRepo) { + STsdbCfg * pCfg = &pRepo->config; + STsdbMeta *pMeta = pRepo->tsdbMeta; + SListNode *pNode = NULL; + STable * pTable = NULL; + + if (pMeta == NULL) return 0; + tdCloseKVStore(pMeta->pStore); + for (int i = 1; i < pCfg->maxTables; i++) { + tsdbFreeTable(pMeta->tables[i]); + } - free(pMeta); + while ((pNode = tdListPopHead(pMeta->superList)) != NULL) { + tdListNodeGetData(pMeta->superList, pNode, (void *)(&pTable)); + tsdbFreeTable(pTable); + listNodeFree(pNode); + } + tsdbTrace("vgId:%d TSDB meta is closed", REPO_ID(pRepo)); return 0; } -// Get the newest table schema -STSchema *tsdbGetTableSchema(STsdbMeta *pMeta, STable *pTable) { +STSchema *tsdbGetTableSchema(STable *pTable) { if (pTable->type == TSDB_NORMAL_TABLE || pTable->type == TSDB_SUPER_TABLE || pTable->type == TSDB_STREAM_TABLE) { return pTable->schema[pTable->numOfSchemas - 1]; } else if (pTable->type == TSDB_CHILD_TABLE) { - STable *pSuper = tsdbGetTableByUid(pMeta, pTable->superUid); + STable *pSuper = pTable->pSuper; if (pSuper == NULL) return NULL; - return pSuper->schema[pSuper->numOfSchemas-1]; + return pSuper->schema[pSuper->numOfSchemas - 1]; } else { return NULL; } } -static int tsdbCompareSchemaVersion(const void *key1, const void *key2) { - if (*(int16_t *)key1 < (*(STSchema **)key2)->version) { - return -1; - } else if (*(int16_t *)key1 > (*(STSchema **)key2)->version) { - return 1; - } else { - return 0; - } +STable *tsdbGetTableByUid(STsdbMeta *pMeta, uint64_t uid) { + void *ptr = taosHashGet(pMeta->uidMap, (char *)(&uid), sizeof(uid)); + + if (ptr == NULL) return NULL; + + return *(STable **)ptr; } -STSchema *tsdbGetTableSchemaByVersion(STsdbMeta *pMeta, STable *pTable, int16_t version) { - STable *pSearchTable = NULL; - if (pTable->type == TSDB_CHILD_TABLE) { - pSearchTable = tsdbGetTableByUid(pMeta, pTable->superUid); - } else { - pSearchTable = pTable; - } - ASSERT(pSearchTable != NULL); +STSchema *tsdbGetTableSchemaByVersion(STable *pTable, int16_t version) { + STable *pSearchTable = (pTable->type == TSDB_CHILD_TABLE) ? pTable->pSuper : pTable; + if (pSearchTable == NULL) return NULL; void *ptr = taosbsearch(&version, pSearchTable->schema, pSearchTable->numOfSchemas, sizeof(STSchema *), tsdbCompareSchemaVersion, TD_EQ); @@ -268,11 +464,11 @@ STSchema *tsdbGetTableSchemaByVersion(STsdbMeta *pMeta, STable *pTable, int16_t return *(STSchema **)ptr; } -STSchema * tsdbGetTableTagSchema(STsdbMeta *pMeta, STable *pTable) { +STSchema *tsdbGetTableTagSchema(STable *pTable) { if (pTable->type == TSDB_SUPER_TABLE) { return pTable->tagSchema; } else if (pTable->type == TSDB_CHILD_TABLE) { - STable *pSuper = tsdbGetTableByUid(pMeta, pTable->superUid); + STable *pSuper = pTable->pSuper; if (pSuper == NULL) return NULL; return pSuper->tagSchema; } else { @@ -280,37 +476,148 @@ STSchema * tsdbGetTableTagSchema(STsdbMeta *pMeta, STable *pTable) { } } -void* tsdbGetTableTagVal(TsdbRepoT* repo, const STableId* id, int32_t colId, int16_t type, int16_t bytes) { - STsdbMeta* pMeta = tsdbGetMeta(repo); - STable* pTable = tsdbGetTableByUid(pMeta, id->uid); +int tsdbUpdateTable(STsdbRepo *pRepo, STable *pTable, STableCfg *pCfg) { + // TODO: this function can only be called when there is no query and commit on this table + ASSERT(TABLE_TYPE(pTable) != TSDB_CHILD_TABLE); + bool changed = false; + STsdbMeta *pMeta = pRepo->tsdbMeta; - STSchema *pSchema = tsdbGetTableTagSchema(pMeta, pTable); - STColumn *pCol = tdGetColOfID(pSchema, colId); - if (pCol == NULL) { - return NULL; // No matched tag volumn + if (pTable->type == TSDB_SUPER_TABLE) { + if (schemaVersion(pTable->tagSchema) < schemaVersion(pCfg->tagSchema)) { + if (tsdbUpdateTableTagSchema(pTable, pCfg->tagSchema) < 0) { + tsdbError("vgId:%d failed to update table %s tag schema since %s", REPO_ID(pRepo), TABLE_CHAR_NAME(pTable), + tstrerror(terrno)); + return -1; + } + } + changed = true; } - - char* val = tdGetKVRowValOfCol(pTable->tagVal, colId); - assert(type == pCol->type && bytes == pCol->bytes); - - if (val != NULL && IS_VAR_DATA_TYPE(type)) { - assert(varDataLen(val) < pCol->bytes); + + STSchema *pTSchema = tsdbGetTableSchema(pTable); + if (schemaVersion(pTSchema) < schemaVersion(pCfg->schema)) { + if (pTable->numOfSchemas < TSDB_MAX_TABLE_SCHEMAS) { + pTable->schema[pTable->numOfSchemas++] = tdDupSchema(pCfg->schema); + } else { + ASSERT(pTable->numOfSchemas == TSDB_MAX_TABLE_SCHEMAS); + STSchema *tSchema = tdDupSchema(pCfg->schema); + tdFreeSchema(pTable->schema[0]); + memmove(pTable->schema, pTable->schema + 1, sizeof(STSchema *) * (TSDB_MAX_TABLE_SCHEMAS - 1)); + pTable->schema[pTable->numOfSchemas - 1] = tSchema; + } + + pMeta->maxRowBytes = MAX(pMeta->maxRowBytes, dataRowMaxBytesFromSchema(pCfg->schema)); + pMeta->maxCols = MAX(pMeta->maxCols, schemaNCols(pCfg->schema)); + + changed = true; } - - return val; + + if (changed) { + int tlen = tsdbGetTableEncodeSize(TSDB_UPDATE_META, pTable); + void *buf = tsdbAllocBytes(pRepo, tlen); + tsdbInsertTableAct(pRepo, TSDB_UPDATE_META, buf, pTable); + } + + return 0; } -char* tsdbGetTableName(TsdbRepoT *repo, const STableId* id) { - STsdbMeta* pMeta = tsdbGetMeta(repo); - STable* pTable = tsdbGetTableByUid(pMeta, id->uid); - - if (pTable == NULL) { - return NULL; +int tsdbWLockRepoMeta(STsdbRepo *pRepo) { + int code = pthread_rwlock_wrlock(&(pRepo->tsdbMeta->rwLock)); + if (code != 0) { + tsdbError("vgId:%d failed to write lock TSDB meta since %s", REPO_ID(pRepo), strerror(code)); + terrno = TAOS_SYSTEM_ERROR(code); + return -1; + } + + return 0; +} + +int tsdbRLockRepoMeta(STsdbRepo *pRepo) { + int code = pthread_rwlock_rdlock(&(pRepo->tsdbMeta->rwLock)); + if (code != 0) { + tsdbError("vgId:%d failed to read lock TSDB meta since %s", REPO_ID(pRepo), strerror(code)); + terrno = TAOS_SYSTEM_ERROR(code); + return -1; + } + + return 0; +} + +int tsdbUnlockRepoMeta(STsdbRepo *pRepo) { + int code = pthread_rwlock_unlock(&(pRepo->tsdbMeta->rwLock)); + if (code != 0) { + tsdbError("vgId:%d failed to unlock TSDB meta since %s", REPO_ID(pRepo), strerror(code)); + terrno = TAOS_SYSTEM_ERROR(code); + return -1; + } + + return 0; +} + +void tsdbRefTable(STable *pTable) { T_REF_INC(pTable); } + +void tsdbUnRefTable(STable *pTable) { + if (T_REF_DEC(pTable) == 0) { + if (TABLE_TYPE(pTable) == TSDB_CHILD_TABLE) { + tsdbUnRefTable(pTable->pSuper); + } + tsdbFreeTable(pTable); + } +} + +// ------------------ LOCAL FUNCTIONS ------------------ +static int tsdbCompareSchemaVersion(const void *key1, const void *key2) { + if (*(int16_t *)key1 < schemaVersion(*(STSchema **)key2)) { + return -1; + } else if (*(int16_t *)key1 > schemaVersion(*(STSchema **)key2)) { + return 1; } else { - return (char*) pTable->name; + return 0; } } +static int tsdbRestoreTable(void *pHandle, void *cont, int contLen) { + STsdbRepo *pRepo = (STsdbRepo *)pHandle; + STable * pTable = NULL; + + if (!taosCheckChecksumWhole((uint8_t *)cont, contLen)) { + terrno = TSDB_CODE_TDB_FILE_CORRUPTED; + return -1; + } + + tsdbDecodeTable(cont, &pTable); + + if (tsdbAddTableToMeta(pRepo, pTable, false) < 0) { + tsdbFreeTable(pTable); + return -1; + } + + tsdbTrace("vgId:%d table %s tid %d uid %" PRIu64 " is restored from file", REPO_ID(pRepo), TABLE_CHAR_NAME(pTable), + TABLE_TID(pTable), TABLE_UID(pTable)); + return 0; +} + +static void tsdbOrgMeta(void *pHandle) { + STsdbRepo *pRepo = (STsdbRepo *)pHandle; + STsdbMeta *pMeta = pRepo->tsdbMeta; + STsdbCfg * pCfg = &pRepo->config; + + for (int i = 1; i < pCfg->maxTables; i++) { + STable *pTable = pMeta->tables[i]; + if (pTable != NULL && pTable->type == TSDB_CHILD_TABLE) { + tsdbAddTableIntoIndex(pMeta, pTable); + } + } +} + +static char *getTagIndexKey(const void *pData) { + STable *pTable = *(STable **)pData; + + STSchema *pSchema = tsdbGetTableTagSchema(pTable); + STColumn *pCol = schemaColAt(pSchema, DEFAULT_TAG_INDEX_COLUMN); + void * res = tdGetKVRowValOfCol(pTable->tagVal, pCol->colId); + return res; +} + static STable *tsdbNewTable(STableCfg *pCfg, bool isSuper) { STable *pTable = NULL; size_t tsize = 0; @@ -321,19 +628,8 @@ static STable *tsdbNewTable(STableCfg *pCfg, bool isSuper) { goto _err; } - pTable->type = pCfg->type; - pTable->numOfSchemas = 0; - if (isSuper) { pTable->type = TSDB_SUPER_TABLE; - pTable->tableId.uid = pCfg->superUid; - pTable->tableId.tid = -1; - pTable->superUid = TSDB_INVALID_SUPER_TABLE_ID; - pTable->schema = (STSchema **)malloc(sizeof(STSchema *) * TSDB_MAX_TABLE_SCHEMAS); - pTable->numOfSchemas = 1; - pTable->schema[0] = tdDupSchema(pCfg->schema); - pTable->tagSchema = tdDupSchema(pCfg->tagSchema); - tsize = strnlen(pCfg->sname, TSDB_TABLE_NAME_LEN - 1); pTable->name = calloc(1, tsize + VARSTR_HEADER_SIZE + 1); if (pTable->name == NULL) { @@ -341,20 +637,30 @@ static STable *tsdbNewTable(STableCfg *pCfg, bool isSuper) { goto _err; } STR_WITH_SIZE_TO_VARSTR(pTable->name, pCfg->sname, tsize); - - STColumn *pColSchema = schemaColAt(pTable->tagSchema, 0); - pTable->pIndex = tSkipListCreate(TSDB_SUPER_TABLE_SL_LEVEL, pColSchema->type, pColSchema->bytes, 1, 0, 0, - getTagIndexKey); // Allow duplicate key, no lock + TABLE_UID(pTable) = pCfg->superUid; + TABLE_TID(pTable) = -1; + TABLE_SUID(pTable) = -1; + pTable->pSuper = NULL; + pTable->numOfSchemas = 1; + pTable->schema[0] = tdDupSchema(pCfg->schema); + if (pTable->schema[0] == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + goto _err; + } + pTable->tagSchema = tdDupSchema(pCfg->tagSchema); + if (pTable->tagSchema == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + goto _err; + } + pTable->tagVal = NULL; + STColumn *pCol = schemaColAt(pTable->tagSchema, DEFAULT_TAG_INDEX_COLUMN); + pTable->pIndex = tSkipListCreate(TSDB_SUPER_TABLE_SL_LEVEL, colType(pCol), colBytes(pCol), 1, 0, 1, getTagIndexKey); if (pTable->pIndex == NULL) { terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; goto _err; } } else { pTable->type = pCfg->type; - pTable->tableId.uid = pCfg->tableId.uid; - pTable->tableId.tid = pCfg->tableId.tid; - pTable->lastKey = TSKEY_INITIAL_VAL; - tsize = strnlen(pCfg->name, TSDB_TABLE_NAME_LEN - 1); pTable->name = calloc(1, tsize + VARSTR_HEADER_SIZE + 1); if (pTable->name == NULL) { @@ -362,25 +668,39 @@ static STable *tsdbNewTable(STableCfg *pCfg, bool isSuper) { goto _err; } STR_WITH_SIZE_TO_VARSTR(pTable->name, pCfg->name, tsize); + TABLE_UID(pTable) = pCfg->tableId.uid; + TABLE_TID(pTable) = pCfg->tableId.tid; if (pCfg->type == TSDB_CHILD_TABLE) { - pTable->superUid = pCfg->superUid; + TABLE_SUID(pTable) = pCfg->superUid; pTable->tagVal = tdKVRowDup(pCfg->tagValues); + if (pTable->tagVal == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + goto _err; + } } else { - pTable->schema = (STSchema **)malloc(sizeof(STSchema *) * TSDB_MAX_TABLE_SCHEMAS); + TABLE_SUID(pTable) = -1; pTable->numOfSchemas = 1; pTable->schema[0] = tdDupSchema(pCfg->schema); + if (pTable->schema[0] == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + goto _err; + } - if (pCfg->type == TSDB_NORMAL_TABLE) { - pTable->superUid = -1; - } else { - ASSERT(pCfg->type == TSDB_STREAM_TABLE); - pTable->superUid = -1; + if (TABLE_TYPE(pTable) == TSDB_STREAM_TABLE) { pTable->sql = strdup(pCfg->sql); + if (pTable->sql == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + goto _err; + } } } + + pTable->lastKey = TSKEY_INITIAL_VAL; } + T_REF_INC(pTable); + return pTable; _err: @@ -388,421 +708,475 @@ _err: return NULL; } +static void tsdbFreeTable(STable *pTable) { + if (pTable) { + tsdbTrace("table %s is destroyed", TABLE_CHAR_NAME(pTable)); + tfree(TABLE_NAME(pTable)); + if (TABLE_TYPE(pTable) != TSDB_CHILD_TABLE) { + for (int i = 0; i < TSDB_MAX_TABLE_SCHEMAS; i++) { + tdFreeSchema(pTable->schema[i]); + } + + if (TABLE_TYPE(pTable) == TSDB_SUPER_TABLE) { + tdFreeSchema(pTable->tagSchema); + } + } + + kvRowFree(pTable->tagVal); + + tSkipListDestroy(pTable->pIndex); + tfree(pTable->sql); + free(pTable); + } +} + static int tsdbUpdateTableTagSchema(STable *pTable, STSchema *newSchema) { ASSERT(pTable->type == TSDB_SUPER_TABLE); ASSERT(schemaVersion(pTable->tagSchema) < schemaVersion(newSchema)); STSchema *pOldSchema = pTable->tagSchema; STSchema *pNewSchema = tdDupSchema(newSchema); - if (pNewSchema == NULL) return TSDB_CODE_TDB_OUT_OF_MEMORY; + if (pNewSchema == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + return -1; + } pTable->tagSchema = pNewSchema; tdFreeSchema(pOldSchema); - return TSDB_CODE_SUCCESS; + return 0; } -int tsdbUpdateTable(STsdbMeta *pMeta, STable *pTable, STableCfg *pCfg) { - ASSERT(pTable->type != TSDB_CHILD_TABLE); - bool isChanged = false; +static int tsdbAddTableToMeta(STsdbRepo *pRepo, STable *pTable, bool addIdx) { + STsdbMeta *pMeta = pRepo->tsdbMeta; - if (pTable->type == TSDB_SUPER_TABLE) { - if (schemaVersion(pTable->tagSchema) < schemaVersion(pCfg->tagSchema)) { - int32_t code = tsdbUpdateTableTagSchema(pTable, pCfg->tagSchema); - if (code != TSDB_CODE_SUCCESS) return code; - } - isChanged = true; + if (addIdx && tsdbWLockRepoMeta(pRepo) < 0) { + tsdbError("vgId:%d failed to add table %s to meta since %s", REPO_ID(pRepo), TABLE_CHAR_NAME(pTable), + tstrerror(terrno)); + return -1; } - STSchema *pTSchema = tsdbGetTableSchema(pMeta, pTable); - if (schemaVersion(pTSchema) < schemaVersion(pCfg->schema)) { - if (pTable->numOfSchemas < TSDB_MAX_TABLE_SCHEMAS) { - pTable->schema[pTable->numOfSchemas++] = tdDupSchema(pCfg->schema); - } else { - ASSERT(pTable->numOfSchemas == TSDB_MAX_TABLE_SCHEMAS); - STSchema *tSchema = tdDupSchema(pCfg->schema); - tdFreeSchema(pTable->schema[0]); - memmove(pTable->schema, pTable->schema+1, sizeof(STSchema *) * (TSDB_MAX_TABLE_SCHEMAS - 1)); - pTable->schema[pTable->numOfSchemas-1] = tSchema; + if (TABLE_TYPE(pTable) == TSDB_SUPER_TABLE) { + if (tdListAppend(pMeta->superList, (void *)(&pTable)) < 0) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + tsdbError("vgId:%d failed to add table %s to meta since %s", REPO_ID(pRepo), TABLE_CHAR_NAME(pTable), + tstrerror(terrno)); + goto _err; } + } else { + if (TABLE_TYPE(pTable) == TSDB_CHILD_TABLE && addIdx) { // add STABLE to the index + if (tsdbAddTableIntoIndex(pMeta, pTable) < 0) { + tsdbTrace("vgId:%d failed to add table %s to meta while add table to index since %s", REPO_ID(pRepo), + TABLE_CHAR_NAME(pTable), tstrerror(terrno)); + goto _err; + } + } + pMeta->tables[TABLE_TID(pTable)] = pTable; + pMeta->nTables++; + } - STSchema *lSchema = pTable->schema[pTable->numOfSchemas - 1]; - if (schemaNCols(lSchema) > pMeta->maxCols) pMeta->maxCols = schemaNCols(lSchema); - int bytes = dataRowMaxBytesFromSchema(lSchema); - if (bytes > pMeta->maxRowBytes) pMeta->maxRowBytes = bytes; - - isChanged = true; + if (taosHashPut(pMeta->uidMap, (char *)(&pTable->tableId.uid), sizeof(pTable->tableId.uid), (void *)(&pTable), + sizeof(pTable)) < 0) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + tsdbError("vgId:%d failed to add table %s to meta while put into uid map since %s", REPO_ID(pRepo), + TABLE_CHAR_NAME(pTable), tstrerror(terrno)); + goto _err; } - if (isChanged) { - char *buf = malloc(1024 * 1024); - int bufLen = 0; - tsdbEncodeTable(pTable, buf, &bufLen); - tsdbInsertMetaRecord(pMeta->mfh, pTable->tableId.uid, buf, bufLen); - free(buf); + if (TABLE_TYPE(pTable) != TSDB_CHILD_TABLE) { + STSchema *pSchema = tsdbGetTableSchema(pTable); + if (schemaNCols(pSchema) > pMeta->maxCols) pMeta->maxCols = schemaNCols(pSchema); + if (schemaTLen(pSchema) > pMeta->maxRowBytes) pMeta->maxRowBytes = schemaTLen(pSchema); } - return TSDB_CODE_SUCCESS; + if (addIdx && tsdbUnlockRepoMeta(pRepo) < 0) return -1; + + tsdbTrace("vgId:%d table %s tid %d uid %" PRIu64 " is added to meta", REPO_ID(pRepo), TABLE_CHAR_NAME(pTable), + TABLE_TID(pTable), TABLE_UID(pTable)); + return 0; + +_err: + tsdbRemoveTableFromMeta(pRepo, pTable, false, false); + if (addIdx) tsdbUnlockRepoMeta(pRepo); + return -1; } -int tsdbCreateTable(TsdbRepoT *repo, STableCfg *pCfg) { - STsdbRepo *pRepo = (STsdbRepo *)repo; +static void tsdbRemoveTableFromMeta(STsdbRepo *pRepo, STable *pTable, bool rmFromIdx, bool lock) { STsdbMeta *pMeta = pRepo->tsdbMeta; + SListIter lIter = {0}; + SListNode *pNode = NULL; + STable * tTable = NULL; + STsdbCfg * pCfg = &(pRepo->config); + + STSchema *pSchema = tsdbGetTableSchema(pTable); + int maxCols = schemaNCols(pSchema); + int maxRowBytes = schemaTLen(pSchema); + + if (lock) tsdbWLockRepoMeta(pRepo); + + if (TABLE_TYPE(pTable) == TSDB_SUPER_TABLE) { + tdListInitIter(pMeta->superList, &lIter, TD_LIST_BACKWARD); + + while ((pNode = tdListNext(&lIter)) != NULL) { + tdListNodeGetData(pMeta->superList, pNode, (void *)(&tTable)); + if (pTable == tTable) { + tdListPopNode(pMeta->superList, pNode); + free(pNode); + break; + } + } + } else { + pMeta->tables[pTable->tableId.tid] = NULL; + if (TABLE_TYPE(pTable) == TSDB_CHILD_TABLE && rmFromIdx) { + tsdbRemoveTableFromIndex(pMeta, pTable); + } - if (tsdbCheckTableCfg(pCfg) < 0) return -1; - - STable *pTable = tsdbGetTableByUid(pMeta, pCfg->tableId.uid); - if (pTable != NULL) { - tsdbError("vgId:%d table %s already exists, tid %d uid %" PRId64, pRepo->config.tsdbId, pTable->name->data, - pTable->tableId.tid, pTable->tableId.uid); - return TSDB_CODE_TDB_TABLE_ALREADY_EXIST; + pMeta->nTables--; } - STable *super = NULL; - int newSuper = 0; + taosHashRemove(pMeta->uidMap, (char *)(&(TABLE_UID(pTable))), sizeof(TABLE_UID(pTable))); - if (pCfg->type == TSDB_CHILD_TABLE) { - super = tsdbGetTableByUid(pMeta, pCfg->superUid); - if (super == NULL) { // super table not exists, try to create it - newSuper = 1; - super = tsdbNewTable(pCfg, true); - if (super == NULL) return -1; - } else { - if (super->type != TSDB_SUPER_TABLE) return -1; - if (super->tableId.uid != pCfg->superUid) return -1; - tsdbUpdateTable(pMeta, super, pCfg); + if (maxCols == pMeta->maxCols || maxRowBytes == pMeta->maxRowBytes) { + maxCols = 0; + maxRowBytes = 0; + for (int i = 0; i < pCfg->maxTables; i++) { + STable *pTable = pMeta->tables[i]; + if (pTable != NULL) { + pSchema = tsdbGetTableSchema(pTable); + maxCols = MAX(maxCols, schemaNCols(pSchema)); + maxRowBytes = MAX(maxRowBytes, schemaTLen(pSchema)); + } } } - STable *table = tsdbNewTable(pCfg, false); - if (table == NULL) { - if (newSuper) { - tsdbFreeTable(super); - return -1; - } - } - - table->lastKey = TSKEY_INITIAL_VAL; - - // Register to meta - if (newSuper) { - tsdbAddTableToMeta(pMeta, super, true); - tsdbTrace("vgId:%d, super table %s is created! uid:%" PRId64, pRepo->config.tsdbId, super->name->data, - super->tableId.uid); - } - tsdbAddTableToMeta(pMeta, table, true); - tsdbTrace("vgId:%d, table %s is created! tid:%d, uid:%" PRId64, pRepo->config.tsdbId, table->name->data, - table->tableId.tid, table->tableId.uid); + if (lock) tsdbUnlockRepoMeta(pRepo); + tsdbTrace("vgId:%d table %s is removed from meta", REPO_ID(pRepo), TABLE_CHAR_NAME(pTable)); + tsdbUnRefTable(pTable); +} - // Write to meta file - int bufLen = 0; - char *buf = malloc(1024*1024); - if (newSuper) { - tsdbEncodeTable(super, buf, &bufLen); - tsdbInsertMetaRecord(pMeta->mfh, super->tableId.uid, buf, bufLen); - } +static int tsdbAddTableIntoIndex(STsdbMeta *pMeta, STable *pTable) { + ASSERT(pTable->type == TSDB_CHILD_TABLE && pTable != NULL); + STable *pSTable = tsdbGetTableByUid(pMeta, TABLE_SUID(pTable)); + ASSERT(pSTable != NULL); - tsdbEncodeTable(table, buf, &bufLen); - tsdbInsertMetaRecord(pMeta->mfh, table->tableId.uid, buf, bufLen); - tfree(buf); + pTable->pSuper = pSTable; - return 0; -} + int32_t level = 0; + int32_t headSize = 0; -/** - * Check if a table is valid to insert. - * @return NULL for invalid and the pointer to the table if valid - */ -STable *tsdbIsValidTableToInsert(STsdbMeta *pMeta, STableId tableId) { - STable *pTable = tsdbGetTableByUid(pMeta, tableId.uid); - if (pTable == NULL) { - return NULL; + tSkipListNewNodeInfo(pSTable->pIndex, &level, &headSize); + + // NOTE: do not allocate the space for key, since in each skip list node, only keep the pointer to pTable, not the + // actual key value, and the key value will be retrieved during query through the pTable and getTagIndexKey function + SSkipListNode *pNode = calloc(1, headSize + sizeof(STable *)); + if (pNode == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + return -1; } + pNode->level = level; - if (TSDB_TABLE_IS_SUPER_TABLE(pTable)) return NULL; - if (pTable->tableId.tid != tableId.tid) return NULL; + memcpy(SL_GET_NODE_DATA(pNode), &pTable, sizeof(STable *)); - return pTable; + tSkipListPut(pSTable->pIndex, pNode); + T_REF_INC(pSTable); + return 0; } -STableCfg *tsdbCreateTableCfgFromMsg(SMDCreateTableMsg *pMsg) { - if (pMsg == NULL) return NULL; - SSchema * pSchema = (SSchema *)pMsg->data; - int16_t numOfCols = htons(pMsg->numOfColumns); - int16_t numOfTags = htons(pMsg->numOfTags); - STSchemaBuilder schemaBuilder = {0}; - - STableCfg *pCfg = (STableCfg *)calloc(1, sizeof(STableCfg)); - if (pCfg == NULL) return NULL; +static int tsdbRemoveTableFromIndex(STsdbMeta *pMeta, STable *pTable) { + ASSERT(pTable->type == TSDB_CHILD_TABLE && pTable != NULL); - if (tsdbInitTableCfg(pCfg, pMsg->tableType, htobe64(pMsg->uid), htonl(pMsg->sid)) < 0) goto _err; - if (tdInitTSchemaBuilder(&schemaBuilder, htonl(pMsg->sversion)) < 0) goto _err; + STable *pSTable = pTable->pSuper; + ASSERT(pSTable != NULL); - for (int i = 0; i < numOfCols; i++) { - tdAddColToSchema(&schemaBuilder, pSchema[i].type, htons(pSchema[i].colId), htons(pSchema[i].bytes)); - } - if (tsdbTableSetSchema(pCfg, tdGetSchemaFromBuilder(&schemaBuilder), false) < 0) goto _err; - if (tsdbTableSetName(pCfg, pMsg->tableId, true) < 0) goto _err; + STSchema *pSchema = tsdbGetTableTagSchema(pTable); + STColumn *pCol = schemaColAt(pSchema, DEFAULT_TAG_INDEX_COLUMN); - if (numOfTags > 0) { - // Decode tag schema - tdResetTSchemaBuilder(&schemaBuilder, htonl(pMsg->tversion)); - for (int i = numOfCols; i < numOfCols + numOfTags; i++) { - tdAddColToSchema(&schemaBuilder, pSchema[i].type, htons(pSchema[i].colId), htons(pSchema[i].bytes)); - } - if (tsdbTableSetTagSchema(pCfg, tdGetSchemaFromBuilder(&schemaBuilder), false) < 0) goto _err; - if (tsdbTableSetSName(pCfg, pMsg->superTableId, true) < 0) goto _err; - if (tsdbTableSetSuperUid(pCfg, htobe64(pMsg->superTableUid)) < 0) goto _err; + char * key = tdGetKVRowValOfCol(pTable->tagVal, pCol->colId); + SArray *res = tSkipListGet(pSTable->pIndex, key); - // Decode tag values - if (pMsg->tagDataLen) { - int accBytes = 0; - char *pTagData = pMsg->data + (numOfCols + numOfTags) * sizeof(SSchema); + size_t size = taosArrayGetSize(res); + ASSERT(size > 0); - SKVRowBuilder kvRowBuilder = {0}; - if (tdInitKVRowBuilder(&kvRowBuilder) < 0) goto _err; - for (int i = numOfCols; i < numOfCols + numOfTags; i++) { - tdAddColToKVRow(&kvRowBuilder, htons(pSchema[i].colId), pSchema[i].type, pTagData + accBytes); - accBytes += htons(pSchema[i].bytes); - } + for (int32_t i = 0; i < size; ++i) { + SSkipListNode *pNode = taosArrayGetP(res, i); - tsdbTableSetTagValue(pCfg, tdGetKVRowFromBuilder(&kvRowBuilder), false); - tdDestroyKVRowBuilder(&kvRowBuilder); + // STableIndexElem* pElem = (STableIndexElem*) SL_GET_NODE_DATA(pNode); + if (*(STable **)SL_GET_NODE_DATA(pNode) == pTable) { // this is the exact what we need + tSkipListRemoveNode(pSTable->pIndex, pNode); } } - if (pMsg->tableType == TSDB_STREAM_TABLE) { - char *sql = pMsg->data + (numOfCols + numOfTags) * sizeof(SSchema); - tsdbTableSetStreamSql(pCfg, sql, true); + taosArrayDestroy(res); + return 0; +} + +static int tsdbInitTableCfg(STableCfg *config, ETableType type, uint64_t uid, int32_t tid) { + if (type != TSDB_CHILD_TABLE && type != TSDB_NORMAL_TABLE && type != TSDB_STREAM_TABLE) { + terrno = TSDB_CODE_TDB_INVALID_TABLE_TYPE; + return -1; } - tdDestroyTSchemaBuilder(&schemaBuilder); + memset((void *)config, 0, sizeof(*config)); - return pCfg; + config->type = type; + config->superUid = TSDB_INVALID_SUPER_TABLE_ID; + config->tableId.uid = uid; + config->tableId.tid = tid; + return 0; +} -_err: - tdDestroyTSchemaBuilder(&schemaBuilder); - tsdbClearTableCfg(pCfg); - tfree(pCfg); - return NULL; +static int tsdbTableSetSchema(STableCfg *config, STSchema *pSchema, bool dup) { + if (dup) { + config->schema = tdDupSchema(pSchema); + if (config->schema == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + return -1; + } + } else { + config->schema = pSchema; + } + return 0; } -// int32_t tsdbDropTableImpl(STsdbMeta *pMeta, STableId tableId) { -int tsdbDropTable(TsdbRepoT *repo, STableId tableId) { - STsdbRepo *pRepo = (STsdbRepo *)repo; - if (pRepo == NULL) return -1; +static int tsdbTableSetName(STableCfg *config, char *name, bool dup) { + if (dup) { + config->name = strdup(name); + if (config->name == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + return -1; + } + } else { + config->name = name; + } - STsdbMeta *pMeta = pRepo->tsdbMeta; - if (pMeta == NULL) return -1; + return 0; +} - STable *pTable = tsdbGetTableByUid(pMeta, tableId.uid); - if (pTable == NULL) { - tsdbError("vgId:%d, failed to drop table since table not exists! tid:%d, uid:%" PRId64, pRepo->config.tsdbId, - tableId.tid, tableId.uid); +static int tsdbTableSetTagSchema(STableCfg *config, STSchema *pSchema, bool dup) { + if (config->type != TSDB_CHILD_TABLE) { + terrno = TSDB_CODE_TDB_INVALID_CREATE_TB_MSG; return -1; } - if (pTable->cqhandle != NULL) { - pRepo->appH.cqDropFunc(pTable->cqhandle); + if (dup) { + config->tagSchema = tdDupSchema(pSchema); + if (config->tagSchema == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + return -1; + } + } else { + config->tagSchema = pSchema; } + return 0; +} - tsdbTrace("vgId:%d, table %s is dropped! tid:%d, uid:%" PRId64, pRepo->config.tsdbId, pTable->name->data, - tableId.tid, tableId.uid); - if (tsdbRemoveTableFromMeta(pMeta, pTable, true) < 0) return -1; +static int tsdbTableSetSName(STableCfg *config, char *sname, bool dup) { + if (config->type != TSDB_CHILD_TABLE) { + terrno = TSDB_CODE_TDB_INVALID_CREATE_TB_MSG; + return -1; + } + if (dup) { + config->sname = strdup(sname); + if (config->sname == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + return -1; + } + } else { + config->sname = sname; + } return 0; - } -// int32_t tsdbInsertRowToTableImpl(SSkipListNode *pNode, STable *pTable) { -// tSkipListPut(pTable->mem->pData, pNode); -// return 0; -// } - -static void tsdbFreeMemTable(SMemTable *pMemTable) { - if (pMemTable) { - tSkipListDestroy(pMemTable->pData); +static int tsdbTableSetSuperUid(STableCfg *config, uint64_t uid) { + if (config->type != TSDB_CHILD_TABLE || uid == TSDB_INVALID_SUPER_TABLE_ID) { + terrno = TSDB_CODE_TDB_INVALID_CREATE_TB_MSG; + return -1; } - free(pMemTable); + config->superUid = uid; + return 0; } -static int tsdbFreeTable(STable *pTable) { - if (pTable == NULL) return 0; +static int tsdbTableSetTagValue(STableCfg *config, SKVRow row, bool dup) { + if (config->type != TSDB_CHILD_TABLE) { + terrno = TSDB_CODE_TDB_INVALID_CREATE_TB_MSG; + return -1; + } - if (pTable->type == TSDB_CHILD_TABLE) { - kvRowFree(pTable->tagVal); - } else { - if (pTable->schema) { - for (int i = 0; i < pTable->numOfSchemas; i++) tdFreeSchema(pTable->schema[i]); - free(pTable->schema); + if (dup) { + config->tagValues = tdKVRowDup(row); + if (config->tagValues == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + return -1; } + } else { + config->tagValues = row; } - if (pTable->type == TSDB_STREAM_TABLE) { - tfree(pTable->sql); - } + return 0; +} - // Free content - if (TSDB_TABLE_IS_SUPER_TABLE(pTable)) { - tdFreeSchema(pTable->tagSchema); - tSkipListDestroy(pTable->pIndex); +static int tsdbTableSetStreamSql(STableCfg *config, char *sql, bool dup) { + if (config->type != TSDB_STREAM_TABLE) { + terrno = TSDB_CODE_TDB_INVALID_CREATE_TB_MSG; + return -1; } - tsdbFreeMemTable(pTable->mem); - tsdbFreeMemTable(pTable->imem); + if (dup) { + config->sql = strdup(sql); + if (config->sql == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + return -1; + } + } else { + config->sql = sql; + } - tfree(pTable->name); - free(pTable); return 0; } -static int32_t tsdbCheckTableCfg(STableCfg *pCfg) { - // TODO - return 0; +void tsdbClearTableCfg(STableCfg *config) { + if (config) { + if (config->schema) tdFreeSchema(config->schema); + if (config->tagSchema) tdFreeSchema(config->tagSchema); + if (config->tagValues) kvRowFree(config->tagValues); + tfree(config->name); + tfree(config->sname); + tfree(config->sql); + free(config); + } } -STable *tsdbGetTableByUid(STsdbMeta *pMeta, uint64_t uid) { - void *ptr = taosHashGet(pMeta->map, (char *)(&uid), sizeof(uid)); +static int tsdbEncodeTableName(void **buf, tstr *name) { + int tlen = 0; - if (ptr == NULL) return NULL; + tlen += taosEncodeFixedI16(buf, name->len); + if (buf != NULL) { + memcpy(*buf, name->data, name->len); + *buf = POINTER_SHIFT(*buf, name->len); + } + tlen += name->len; - return *(STable **)ptr; + return tlen; } -static int tsdbAddTableToMeta(STsdbMeta *pMeta, STable *pTable, bool addIdx) { - STsdbRepo *pRepo = (STsdbRepo *)pMeta->pRepo; - if (pTable->type == TSDB_SUPER_TABLE) { - // add super table to the linked list - if (pMeta->superList == NULL) { - pMeta->superList = pTable; - pTable->next = NULL; - pTable->prev = NULL; - } else { - pTable->next = pMeta->superList; - pTable->prev = NULL; - pTable->next->prev = pTable; - pMeta->superList = pTable; - } - } else { - // add non-super table to the array - pMeta->tables[pTable->tableId.tid] = pTable; - if (pTable->type == TSDB_CHILD_TABLE && addIdx) { // add STABLE to the index - tsdbAddTableIntoIndex(pMeta, pTable); - } - if (pTable->type == TSDB_STREAM_TABLE && addIdx) { - pTable->cqhandle = (*pRepo->appH.cqCreateFunc)(pRepo->appH.cqH, pTable->tableId.uid, pTable->tableId.tid, pTable->sql, tsdbGetTableSchema(pMeta, pTable)); - } - - pMeta->nTables++; - } +static void *tsdbDecodeTableName(void *buf, tstr **name) { + VarDataLenT len = 0; - // Update the pMeta->maxCols and pMeta->maxRowBytes - if (pTable->type == TSDB_SUPER_TABLE || pTable->type == TSDB_NORMAL_TABLE || pTable->type == TSDB_STREAM_TABLE) { - if (schemaNCols(pTable->schema[pTable->numOfSchemas - 1]) > pMeta->maxCols) - pMeta->maxCols = schemaNCols(pTable->schema[pTable->numOfSchemas - 1]); - int bytes = dataRowMaxBytesFromSchema(pTable->schema[pTable->numOfSchemas - 1]); - if (bytes > pMeta->maxRowBytes) pMeta->maxRowBytes = bytes; + buf = taosDecodeFixedI16(buf, &len); + *name = calloc(1, sizeof(tstr) + len + 1); + if (*name == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + return NULL; } + (*name)->len = len; + memcpy((*name)->data, buf, len); - if (taosHashPut(pMeta->map, (char *)(&pTable->tableId.uid), sizeof(pTable->tableId.uid), (void *)(&pTable), sizeof(pTable)) < 0) { - return -1; - } - return 0; + buf = POINTER_SHIFT(buf, len); + return buf; } -static int tsdbRemoveTableFromMeta(STsdbMeta *pMeta, STable *pTable, bool rmFromIdx) { - if (pTable->type == TSDB_SUPER_TABLE) { - SSkipListIterator *pIter = tSkipListCreateIter(pTable->pIndex); - while (tSkipListIterNext(pIter)) { - STableIndexElem *pEle = (STableIndexElem *)SL_GET_NODE_DATA(tSkipListIterGet(pIter)); - STable *tTable = pEle->pTable; +static int tsdbEncodeTable(void **buf, STable *pTable) { + ASSERT(pTable != NULL); + int tlen = 0; - ASSERT(tTable != NULL && tTable->type == TSDB_CHILD_TABLE); + tlen += taosEncodeFixedU8(buf, pTable->type); + tlen += tsdbEncodeTableName(buf, pTable->name); + tlen += taosEncodeFixedU64(buf, TABLE_UID(pTable)); + tlen += taosEncodeFixedI32(buf, TABLE_TID(pTable)); - tsdbRemoveTableFromMeta(pMeta, tTable, false); + if (TABLE_TYPE(pTable) == TSDB_CHILD_TABLE) { + tlen += taosEncodeFixedU64(buf, TABLE_SUID(pTable)); + tlen += tdEncodeKVRow(buf, pTable->tagVal); + } else { + tlen += taosEncodeFixedU8(buf, pTable->numOfSchemas); + for (int i = 0; i < pTable->numOfSchemas; i++) { + tlen += tdEncodeSchema(buf, pTable->schema[i]); } - tSkipListDestroyIter(pIter); + if (TABLE_TYPE(pTable) == TSDB_SUPER_TABLE) { + tlen += tdEncodeSchema(buf, pTable->tagSchema); + } - if (pTable->prev != NULL) { - pTable->prev->next = pTable->next; - if (pTable->next != NULL) { - pTable->next->prev = pTable->prev; - } - } else { - pMeta->superList = pTable->next; + if (TABLE_TYPE(pTable) == TSDB_STREAM_TABLE) { + tlen += taosEncodeString(buf, pTable->sql); } + } + + return tlen; +} + +static void *tsdbDecodeTable(void *buf, STable **pRTable) { + STable *pTable = (STable *)calloc(1, sizeof(STable)); + if (pTable == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + return NULL; + } + uint8_t type = 0; + + buf = taosDecodeFixedU8(buf, &type); + pTable->type = type; + buf = tsdbDecodeTableName(buf, &(pTable->name)); + buf = taosDecodeFixedU64(buf, &TABLE_UID(pTable)); + buf = taosDecodeFixedI32(buf, &TABLE_TID(pTable)); + + if (TABLE_TYPE(pTable) == TSDB_CHILD_TABLE) { + buf = taosDecodeFixedU64(buf, &TABLE_SUID(pTable)); + buf = tdDecodeKVRow(buf, &(pTable->tagVal)); } else { - pMeta->tables[pTable->tableId.tid] = NULL; - if (pTable->type == TSDB_CHILD_TABLE && rmFromIdx) { - tsdbRemoveTableFromIndex(pMeta, pTable); + buf = taosDecodeFixedU8(buf, &(pTable->numOfSchemas)); + for (int i = 0; i < pTable->numOfSchemas; i++) { + buf = tdDecodeSchema(buf, &(pTable->schema[i])); } - if (pTable->type == TSDB_STREAM_TABLE && rmFromIdx) { - // TODO + + if (TABLE_TYPE(pTable) == TSDB_SUPER_TABLE) { + buf = tdDecodeSchema(buf, &(pTable->tagSchema)); + STColumn *pCol = schemaColAt(pTable->tagSchema, DEFAULT_TAG_INDEX_COLUMN); + pTable->pIndex = + tSkipListCreate(TSDB_SUPER_TABLE_SL_LEVEL, colType(pCol), colBytes(pCol), 1, 0, 1, getTagIndexKey); + if (pTable->pIndex == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + tsdbFreeTable(pTable); + return NULL; + } } - pMeta->nTables--; + if (TABLE_TYPE(pTable) == TSDB_STREAM_TABLE) { + buf = taosDecodeString(buf, &(pTable->sql)); + } } - taosHashRemove(pMeta->map, (char *)(&(pTable->tableId.uid)), sizeof(pTable->tableId.uid)); - tsdbFreeTable(pTable); - return 0; + T_REF_INC(pTable); + + *pRTable = pTable; + + return buf; } -int tsdbAddTableIntoIndex(STsdbMeta *pMeta, STable *pTable) { - assert(pTable->type == TSDB_CHILD_TABLE && pTable != NULL); - STable* pSTable = tsdbGetTableByUid(pMeta, pTable->superUid); - assert(pSTable != NULL); - - int32_t level = 0; - int32_t headSize = 0; - - tSkipListNewNodeInfo(pSTable->pIndex, &level, &headSize); - - // NOTE: do not allocate the space for key, since in each skip list node, only keep the pointer to pTable, not the - // actual key value, and the key value will be retrieved during query through the pTable and getTagIndexKey function - SSkipListNode* pNode = calloc(1, headSize + sizeof(STableIndexElem)); - pNode->level = level; - - SSkipList* list = pSTable->pIndex; - STableIndexElem* elem = (STableIndexElem*) (SL_GET_NODE_DATA(pNode)); - - elem->pTable = pTable; - elem->pMeta = pMeta; - - tSkipListPut(list, pNode); - return 0; +static int tsdbGetTableEncodeSize(int8_t act, STable *pTable) { + int tlen = sizeof(SListNode) + sizeof(SActObj); + if (act == TSDB_UPDATE_META) tlen += (sizeof(SActCont) + tsdbEncodeTable(NULL, pTable) + sizeof(TSCKSUM)); + + return tlen; } -int tsdbRemoveTableFromIndex(STsdbMeta *pMeta, STable *pTable) { - assert(pTable->type == TSDB_CHILD_TABLE && pTable != NULL); - - STable* pSTable = tsdbGetTableByUid(pMeta, pTable->superUid); - assert(pSTable != NULL); - - STSchema* pSchema = tsdbGetTableTagSchema(pMeta, pTable); - STColumn* pCol = &pSchema->columns[DEFAULT_TAG_INDEX_COLUMN]; - - char* key = tdGetKVRowValOfCol(pTable->tagVal, pCol->colId); - SArray* res = tSkipListGet(pSTable->pIndex, key); - - size_t size = taosArrayGetSize(res); - assert(size > 0); - - for(int32_t i = 0; i < size; ++i) { - SSkipListNode* pNode = taosArrayGetP(res, i); - - STableIndexElem* pElem = (STableIndexElem*) SL_GET_NODE_DATA(pNode); - if (pElem->pTable == pTable) { // this is the exact what we need - tSkipListRemoveNode(pSTable->pIndex, pNode); - } +static void *tsdbInsertTableAct(STsdbRepo *pRepo, int8_t act, void *buf, STable *pTable) { + SListNode *pNode = (SListNode *)buf; + SActObj * pAct = (SActObj *)(pNode->data); + SActCont * pCont = (SActCont *)POINTER_SHIFT(pAct, sizeof(*pAct)); + void * pBuf = (void *)pCont; + + pNode->prev = pNode->next = NULL; + pAct->act = act; + pAct->uid = TABLE_UID(pTable); + + if (act == TSDB_UPDATE_META) { + pBuf = (void *)(pCont->cont); + pCont->len = tsdbEncodeTable(&pBuf, pTable) + sizeof(TSCKSUM); + taosCalcChecksumAppend(0, (uint8_t *)pCont->cont, pCont->len); + pBuf = POINTER_SHIFT(pBuf, sizeof(TSCKSUM)); } - - taosArrayDestroy(res); - return 0; -} + tdListAppendNode(pRepo->mem->actList, pNode); -char *getTSTupleKey(const void * data) { - SDataRow row = (SDataRow)data; - return POINTER_SHIFT(row, TD_DATA_ROW_HEAD_SIZE); + return pBuf; } \ No newline at end of file diff --git a/src/tsdb/src/tsdbMetaFile.c b/src/tsdb/src/tsdbMetaFile.c deleted file mode 100644 index 921db8674aff5dd4463c122e277adb76d09fe9b1..0000000000000000000000000000000000000000 --- a/src/tsdb/src/tsdbMetaFile.c +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Copyright (c) 2019 TAOS Data, Inc. - * - * 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 . - */ -#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; -} \ No newline at end of file diff --git a/src/tsdb/src/tsdbRWHelper.c b/src/tsdb/src/tsdbRWHelper.c index add484b5f4136b2776e47e0baa4547fd606f1705..c1bfa2939b4fe1c1990c13a58f6466d75080ba74 100644 --- a/src/tsdb/src/tsdbRWHelper.c +++ b/src/tsdb/src/tsdbRWHelper.c @@ -14,137 +14,47 @@ */ #include "os.h" -#include "tsdbMain.h" -#include "tchecksum.h" -#include "tscompression.h" #include "talgo.h" +#include "tchecksum.h" #include "tcoding.h" +#include "tscompression.h" +#include "tsdbMain.h" -// Local function definitions -// static int tsdbCheckHelperCfg(SHelperCfg *pCfg); -static int tsdbInitHelperFile(SRWHelper *pHelper); -// static void tsdbClearHelperFile(SHelperFile *pHFile); -static bool tsdbShouldCreateNewLast(SRWHelper *pHelper); -static int tsdbWriteBlockToFile(SRWHelper *pHelper, SFile *pFile, SDataCols *pDataCols, int rowsToWrite, - SCompBlock *pCompBlock, bool isLast, bool isSuperBlock); -static int compareKeyBlock(const void *arg1, const void *arg2); -static int tsdbMergeDataWithBlock(SRWHelper *pHelper, int blkIdx, SDataCols *pDataCols); -static int tsdbInsertSuperBlock(SRWHelper *pHelper, SCompBlock *pCompBlock, int blkIdx); -static int tsdbAddSubBlock(SRWHelper *pHelper, SCompBlock *pCompBlock, int blkIdx, int rowsAdded); -static int tsdbUpdateSuperBlock(SRWHelper *pHelper, SCompBlock *pCompBlock, int blkIdx); -static int tsdbGetRowsInRange(SDataCols *pDataCols, TSKEY minKey, TSKEY maxKey); -static void tsdbResetHelperBlock(SRWHelper *pHelper); - -// ---------- Operations on Helper File part -static void tsdbResetHelperFileImpl(SRWHelper *pHelper) { - memset((void *)&pHelper->files, 0, sizeof(pHelper->files)); - pHelper->files.fid = -1; - pHelper->files.headF.fd = -1; - pHelper->files.dataF.fd = -1; - pHelper->files.lastF.fd = -1; - pHelper->files.nHeadF.fd = -1; - pHelper->files.nLastF.fd = -1; -} - -static int tsdbInitHelperFile(SRWHelper *pHelper) { - // pHelper->compIdxSize = sizeof(SCompIdx) * pHelper->config.maxTables + sizeof(TSCKSUM); - size_t tsize = sizeof(SCompIdx) * pHelper->config.maxTables + sizeof(TSCKSUM); - pHelper->pCompIdx = (SCompIdx *)tmalloc(tsize); - if (pHelper->pCompIdx == NULL) return -1; - - tsdbResetHelperFileImpl(pHelper); - return 0; -} - -static void tsdbDestroyHelperFile(SRWHelper *pHelper) { - tsdbCloseHelperFile(pHelper, false); - tzfree(pHelper->pCompIdx); -} - -// ---------- Operations on Helper Table part -static void tsdbResetHelperTableImpl(SRWHelper *pHelper) { - memset((void *)&pHelper->tableInfo, 0, sizeof(SHelperTable)); - pHelper->hasOldLastBlock = false; -} - -static void tsdbResetHelperTable(SRWHelper *pHelper) { - tsdbResetHelperBlock(pHelper); - tsdbResetHelperTableImpl(pHelper); - helperClearState(pHelper, (TSDB_HELPER_TABLE_SET|TSDB_HELPER_INFO_LOAD)); -} - -static void tsdbInitHelperTable(SRWHelper *pHelper) { - tsdbResetHelperTableImpl(pHelper); -} - -static void tsdbDestroyHelperTable(SRWHelper *pHelper) { tzfree((void *)pHelper->pCompInfo); } - -// ---------- Operations on Helper Block part -static void tsdbResetHelperBlockImpl(SRWHelper *pHelper) { - tdResetDataCols(pHelper->pDataCols[0]); - tdResetDataCols(pHelper->pDataCols[1]); -} - -static void tsdbResetHelperBlock(SRWHelper *pHelper) { - tsdbResetHelperBlockImpl(pHelper); - // helperClearState(pHelper, TSDB_HELPER_) -} - -static int tsdbInitHelperBlock(SRWHelper *pHelper) { - pHelper->pDataCols[0] = tdNewDataCols(pHelper->config.maxRowSize, pHelper->config.maxCols, pHelper->config.maxRows); - pHelper->pDataCols[1] = tdNewDataCols(pHelper->config.maxRowSize, pHelper->config.maxCols, pHelper->config.maxRows); - if (pHelper->pDataCols[0] == NULL || pHelper->pDataCols[1] == NULL) return -1; - - tsdbResetHelperBlockImpl(pHelper); - - return 0; -} - -static void tsdbDestroyHelperBlock(SRWHelper *pHelper) { - tzfree(pHelper->pCompData); - tdFreeDataCols(pHelper->pDataCols[0]); - tdFreeDataCols(pHelper->pDataCols[1]); -} - -static int tsdbInitHelper(SRWHelper *pHelper, STsdbRepo *pRepo, tsdb_rw_helper_t type) { - if (pHelper == NULL || pRepo == NULL) return -1; - - memset((void *)pHelper, 0, sizeof(*pHelper)); - - // Init global configuration - pHelper->config.type = type; - pHelper->config.maxTables = pRepo->config.maxTables; - pHelper->config.maxRowSize = pRepo->tsdbMeta->maxRowBytes; - pHelper->config.maxRows = pRepo->config.maxRowsPerFileBlock; - pHelper->config.maxCols = pRepo->tsdbMeta->maxCols; - pHelper->config.minRowsPerFileBlock = pRepo->config.minRowsPerFileBlock; - pHelper->config.maxRowsPerFileBlock = pRepo->config.maxRowsPerFileBlock; - pHelper->config.compress = pRepo->config.compression; - - pHelper->state = TSDB_HELPER_CLEAR_STATE; - - // Init file part - if (tsdbInitHelperFile(pHelper) < 0) goto _err; - - // Init table part - tsdbInitHelperTable(pHelper); - - // Init block part - if (tsdbInitHelperBlock(pHelper) < 0) goto _err; - - pHelper->pBuffer = - tmalloc(sizeof(SCompData) + (sizeof(SCompCol) + sizeof(TSCKSUM) + COMP_OVERFLOW_BYTES) * pHelper->config.maxCols + - pHelper->config.maxRowSize * pHelper->config.maxRowsPerFileBlock + sizeof(TSCKSUM)); - if (pHelper->pBuffer == NULL) goto _err; - - return 0; - -_err: - tsdbDestroyHelper(pHelper); - return -1; -} - -// ------------------------------------------ OPERATIONS FOR OUTSIDE ------------------------------------------ +static bool tsdbShouldCreateNewLast(SRWHelper *pHelper); +static int tsdbWriteBlockToFile(SRWHelper *pHelper, SFile *pFile, SDataCols *pDataCols, int rowsToWrite, + SCompBlock *pCompBlock, bool isLast, bool isSuperBlock); +static int compareKeyBlock(const void *arg1, const void *arg2); +static int tsdbMergeDataWithBlock(SRWHelper *pHelper, int blkIdx, SDataCols *pDataCols); +static int compTSKEY(const void *key1, const void *key2); +static int tsdbAdjustInfoSizeIfNeeded(SRWHelper *pHelper, size_t esize); +static int tsdbInsertSuperBlock(SRWHelper *pHelper, SCompBlock *pCompBlock, int blkIdx); +static int tsdbAddSubBlock(SRWHelper *pHelper, SCompBlock *pCompBlock, int blkIdx, int rowsAdded); +static int tsdbUpdateSuperBlock(SRWHelper *pHelper, SCompBlock *pCompBlock, int blkIdx); +static int tsdbGetRowsInRange(SDataCols *pDataCols, TSKEY minKey, TSKEY maxKey); +static void tsdbResetHelperFileImpl(SRWHelper *pHelper); +static int tsdbInitHelperFile(SRWHelper *pHelper); +static void tsdbDestroyHelperFile(SRWHelper *pHelper); +static void tsdbResetHelperTableImpl(SRWHelper *pHelper); +static void tsdbResetHelperTable(SRWHelper *pHelper); +static void tsdbInitHelperTable(SRWHelper *pHelper); +static void tsdbDestroyHelperTable(SRWHelper *pHelper); +static void tsdbResetHelperBlockImpl(SRWHelper *pHelper); +static void tsdbResetHelperBlock(SRWHelper *pHelper); +static int tsdbInitHelperBlock(SRWHelper *pHelper); +static int tsdbInitHelper(SRWHelper *pHelper, STsdbRepo *pRepo, tsdb_rw_helper_t type); +static int comparColIdCompCol(const void *arg1, const void *arg2); +static int comparColIdDataCol(const void *arg1, const void *arg2); +static int tsdbLoadSingleColumnData(int fd, SCompBlock *pCompBlock, SCompCol *pCompCol, void *buf); +static int tsdbLoadSingleBlockDataCols(SRWHelper *pHelper, SCompBlock *pCompBlock, int16_t *colIds, int numOfColIds, + SDataCols *pDataCols); +static int tsdbCheckAndDecodeColumnData(SDataCol *pDataCol, char *content, int32_t len, int8_t comp, int numOfRows, + int maxPoints, char *buffer, int bufferSize); +static int tsdbLoadBlockDataImpl(SRWHelper *pHelper, SCompBlock *pCompBlock, SDataCols *pDataCols); +static int tsdbEncodeSCompIdx(void **buf, SCompIdx *pIdx); +static void *tsdbDecodeSCompIdx(void *buf, SCompIdx *pIdx); +static void tsdbDestroyHelperBlock(SRWHelper *pHelper); + +// ---------------------- INTERNAL FUNCTIONS ---------------------- int tsdbInitReadHelper(SRWHelper *pHelper, STsdbRepo *pRepo) { return tsdbInitHelper(pHelper, pRepo, TSDB_READ_HELPER); } @@ -180,7 +90,6 @@ void tsdbResetHelper(SRWHelper *pHelper) { } } -// ------------ Operations for read/write purpose int tsdbSetAndOpenHelperFile(SRWHelper *pHelper, SFileGroup *pGroup) { ASSERT(pHelper != NULL && pGroup != NULL); @@ -194,33 +103,35 @@ int tsdbSetAndOpenHelperFile(SRWHelper *pHelper, SFileGroup *pGroup) { pHelper->files.headF = pGroup->files[TSDB_FILE_TYPE_HEAD]; pHelper->files.dataF = pGroup->files[TSDB_FILE_TYPE_DATA]; pHelper->files.lastF = pGroup->files[TSDB_FILE_TYPE_LAST]; - if (TSDB_HELPER_TYPE(pHelper) == TSDB_WRITE_HELPER) { - char *fnameDup = strdup(pHelper->files.headF.fname); - if (fnameDup == NULL) return -1; - char *dataDir = dirname(fnameDup); - - tsdbGetFileName(dataDir, pHelper->files.fid, ".h", pHelper->files.nHeadF.fname); - tsdbGetFileName(dataDir, pHelper->files.fid, ".l", pHelper->files.nLastF.fname); - free((void *)fnameDup); + if (helperType(pHelper) == TSDB_WRITE_HELPER) { + tsdbGetDataFileName(pHelper->pRepo, pGroup->fileId, TSDB_FILE_TYPE_NHEAD, pHelper->files.nHeadF.fname); + tsdbGetDataFileName(pHelper->pRepo, pGroup->fileId, TSDB_FILE_TYPE_NLAST, pHelper->files.nLastF.fname); } // Open the files if (tsdbOpenFile(&(pHelper->files.headF), O_RDONLY) < 0) goto _err; - if (TSDB_HELPER_TYPE(pHelper) == TSDB_WRITE_HELPER) { + if (helperType(pHelper) == TSDB_WRITE_HELPER) { if (tsdbOpenFile(&(pHelper->files.dataF), O_RDWR) < 0) goto _err; if (tsdbOpenFile(&(pHelper->files.lastF), O_RDWR) < 0) goto _err; // Create and open .h if (tsdbOpenFile(&(pHelper->files.nHeadF), O_WRONLY | O_CREAT) < 0) return -1; - // size_t tsize = TSDB_FILE_HEAD_SIZE + sizeof(SCompIdx) * pHelper->config.maxTables + sizeof(TSCKSUM); - if (tsendfile(pHelper->files.nHeadF.fd, pHelper->files.headF.fd, NULL, TSDB_FILE_HEAD_SIZE) < TSDB_FILE_HEAD_SIZE) + // size_t tsize = TSDB_FILE_HEAD_SIZE + sizeof(SCompIdx) * pCfg->maxTables + sizeof(TSCKSUM); + if (tsendfile(pHelper->files.nHeadF.fd, pHelper->files.headF.fd, NULL, TSDB_FILE_HEAD_SIZE) < TSDB_FILE_HEAD_SIZE) { + tsdbError("vgId:%d failed to sendfile %d bytes from file %s to %s since %s", REPO_ID(pHelper->pRepo), + TSDB_FILE_HEAD_SIZE, pHelper->files.headF.fname, pHelper->files.nHeadF.fname, strerror(errno)); + errno = TAOS_SYSTEM_ERROR(errno); goto _err; + } // Create and open .l file if should if (tsdbShouldCreateNewLast(pHelper)) { if (tsdbOpenFile(&(pHelper->files.nLastF), O_WRONLY | O_CREAT) < 0) goto _err; if (tsendfile(pHelper->files.nLastF.fd, pHelper->files.lastF.fd, NULL, TSDB_FILE_HEAD_SIZE) < TSDB_FILE_HEAD_SIZE) - goto _err; + tsdbError("vgId:%d failed to sendfile %d bytes from file %s to %s since %s", REPO_ID(pHelper->pRepo), + TSDB_FILE_HEAD_SIZE, pHelper->files.lastF.fname, pHelper->files.nLastF.fname, strerror(errno)); + terrno = TAOS_SYSTEM_ERROR(errno); + goto _err; } } else { if (tsdbOpenFile(&(pHelper->files.dataF), O_RDONLY) < 0) goto _err; @@ -231,50 +142,55 @@ int tsdbSetAndOpenHelperFile(SRWHelper *pHelper, SFileGroup *pGroup) { return tsdbLoadCompIdx(pHelper, NULL); - _err: +_err: return -1; } int tsdbCloseHelperFile(SRWHelper *pHelper, bool hasError) { if (pHelper->files.headF.fd > 0) { - fsync(pHelper->files.headF.fd); close(pHelper->files.headF.fd); pHelper->files.headF.fd = -1; } if (pHelper->files.dataF.fd > 0) { - if (!hasError) tsdbUpdateFileHeader(&(pHelper->files.dataF), 0); - fsync(pHelper->files.dataF.fd); + if (helperType(pHelper) == TSDB_WRITE_HELPER) { + tsdbUpdateFileHeader(&(pHelper->files.dataF), 0); + fsync(pHelper->files.dataF.fd); + } close(pHelper->files.dataF.fd); pHelper->files.dataF.fd = -1; } if (pHelper->files.lastF.fd > 0) { - fsync(pHelper->files.lastF.fd); - close(pHelper->files.lastF.fd); + if (helperType(pHelper) == TSDB_WRITE_HELPER) { + fsync(pHelper->files.lastF.fd); + close(pHelper->files.lastF.fd); + } pHelper->files.lastF.fd = -1; } - if (pHelper->files.nHeadF.fd > 0) { - if (!hasError) tsdbUpdateFileHeader(&(pHelper->files.nHeadF), 0); - fsync(pHelper->files.nHeadF.fd); - close(pHelper->files.nHeadF.fd); - pHelper->files.nHeadF.fd = -1; - if (hasError) { - remove(pHelper->files.nHeadF.fname); - } else { - rename(pHelper->files.nHeadF.fname, pHelper->files.headF.fname); - pHelper->files.headF.info = pHelper->files.nHeadF.info; + if (helperType(pHelper) == TSDB_WRITE_HELPER) { + if (pHelper->files.nHeadF.fd > 0) { + if (!hasError) tsdbUpdateFileHeader(&(pHelper->files.nHeadF), 0); + fsync(pHelper->files.nHeadF.fd); + close(pHelper->files.nHeadF.fd); + pHelper->files.nHeadF.fd = -1; + if (hasError) { + remove(pHelper->files.nHeadF.fname); + } else { + rename(pHelper->files.nHeadF.fname, pHelper->files.headF.fname); + pHelper->files.headF.info = pHelper->files.nHeadF.info; + } } - } - - if (pHelper->files.nLastF.fd > 0) { - if (!hasError) tsdbUpdateFileHeader(&(pHelper->files.nLastF), 0); - fsync(pHelper->files.nLastF.fd); - close(pHelper->files.nLastF.fd); - pHelper->files.nLastF.fd = -1; - if (hasError) { - remove(pHelper->files.nLastF.fname); - } else { - rename(pHelper->files.nLastF.fname, pHelper->files.lastF.fname); - pHelper->files.lastF.info = pHelper->files.nLastF.info; + + if (pHelper->files.nLastF.fd > 0) { + if (!hasError) tsdbUpdateFileHeader(&(pHelper->files.nLastF), 0); + fsync(pHelper->files.nLastF.fd); + close(pHelper->files.nLastF.fd); + pHelper->files.nLastF.fd = -1; + if (hasError) { + remove(pHelper->files.nLastF.fname); + } else { + rename(pHelper->files.nLastF.fname, pHelper->files.lastF.fname); + pHelper->files.lastF.info = pHelper->files.nLastF.info; + } } } return 0; @@ -289,7 +205,7 @@ void tsdbSetHelperTable(SRWHelper *pHelper, STable *pTable, STsdbRepo *pRepo) { pHelper->tableInfo.tid = pTable->tableId.tid; pHelper->tableInfo.uid = pTable->tableId.uid; - STSchema *pSchema = tsdbGetTableSchema(pRepo->tsdbMeta, pTable); + STSchema *pSchema = tsdbGetTableSchema(pTable); pHelper->tableInfo.sversion = schemaVersion(pSchema); tdInitDataCols(pHelper->pDataCols[0], pSchema); @@ -306,18 +222,20 @@ void tsdbSetHelperTable(SRWHelper *pHelper, STable *pTable, STsdbRepo *pRepo) { /** * Write part of of points from pDataCols to file - * + * * @return: number of points written to file successfully * -1 for failure */ int tsdbWriteDataBlock(SRWHelper *pHelper, SDataCols *pDataCols) { - ASSERT(TSDB_HELPER_TYPE(pHelper) == TSDB_WRITE_HELPER); + ASSERT(helperType(pHelper) == TSDB_WRITE_HELPER); ASSERT(pDataCols->numOfRows > 0); SCompBlock compBlock; int rowsToWrite = 0; TSKEY keyFirst = dataColsKeyFirst(pDataCols); + STsdbCfg *pCfg = &pHelper->pRepo->config; + ASSERT(helperHasState(pHelper, TSDB_HELPER_IDX_LOAD)); SCompIdx *pIdx = pHelper->pCompIdx + pHelper->tableInfo.tid; // for change purpose @@ -331,7 +249,7 @@ int tsdbWriteDataBlock(SRWHelper *pHelper, SDataCols *pDataCols) { SFile *pWFile = NULL; bool isLast = false; - if (rowsToWrite >= pHelper->config.minRowsPerFileBlock) { + if (rowsToWrite >= pCfg->minRowsPerFileBlock) { pWFile = &(pHelper->files.dataF); } else { isLast = true; @@ -342,8 +260,8 @@ int tsdbWriteDataBlock(SRWHelper *pHelper, SDataCols *pDataCols) { if (tsdbInsertSuperBlock(pHelper, &compBlock, pIdx->numOfBlocks) < 0) goto _err; } else { // (Has old data) AND ((has last block) OR (key overlap)), need to merge the block - SCompBlock *pCompBlock = taosbsearch((void *)(&keyFirst), (void *)(pHelper->pCompInfo->blocks), - pIdx->numOfBlocks, sizeof(SCompBlock), compareKeyBlock, TD_GE); + SCompBlock *pCompBlock = taosbsearch((void *)(&keyFirst), (void *)(pHelper->pCompInfo->blocks), pIdx->numOfBlocks, + sizeof(SCompBlock), compareKeyBlock, TD_GE); int blkIdx = (pCompBlock == NULL) ? (pIdx->numOfBlocks - 1) : (pCompBlock - pHelper->pCompInfo->blocks); @@ -358,10 +276,11 @@ int tsdbWriteDataBlock(SRWHelper *pHelper, SDataCols *pDataCols) { rowsToWrite = tsdbMergeDataWithBlock(pHelper, blkIdx, pDataCols); if (rowsToWrite < 0) goto _err; - } else { // Save as a super block in the middle - rowsToWrite = tsdbGetRowsInRange(pDataCols, 0, pCompBlock->keyFirst-1); + } else { // Save as a super block in the middle + rowsToWrite = tsdbGetRowsInRange(pDataCols, 0, pCompBlock->keyFirst - 1); ASSERT(rowsToWrite > 0); - if (tsdbWriteBlockToFile(pHelper, &(pHelper->files.dataF), pDataCols, rowsToWrite, &compBlock, false, true) < 0) goto _err; + if (tsdbWriteBlockToFile(pHelper, &(pHelper->files.dataF), pDataCols, rowsToWrite, &compBlock, false, true) < 0) + goto _err; if (tsdbInsertSuperBlock(pHelper, &compBlock, blkIdx) < 0) goto _err; } } @@ -374,8 +293,10 @@ _err: } int tsdbMoveLastBlockIfNeccessary(SRWHelper *pHelper) { - ASSERT(TSDB_HELPER_TYPE(pHelper) == TSDB_WRITE_HELPER); - SCompIdx *pIdx = pHelper->pCompIdx + pHelper->tableInfo.tid; + STsdbCfg *pCfg = &pHelper->pRepo->config; + + ASSERT(helperType(pHelper) == TSDB_WRITE_HELPER); + SCompIdx * pIdx = pHelper->pCompIdx + pHelper->tableInfo.tid; SCompBlock compBlock; if ((pHelper->files.nLastF.fd > 0) && (pHelper->hasOldLastBlock)) { if (tsdbLoadCompInfo(pHelper, NULL) < 0) return -1; @@ -386,7 +307,7 @@ int tsdbMoveLastBlockIfNeccessary(SRWHelper *pHelper) { if (pCompBlock->numOfSubBlocks > 1) { if (tsdbLoadBlockData(pHelper, blockAtIdx(pHelper, pIdx->numOfBlocks - 1), NULL) < 0) return -1; ASSERT(pHelper->pDataCols[0]->numOfRows > 0 && - pHelper->pDataCols[0]->numOfRows < pHelper->config.minRowsPerFileBlock); + pHelper->pDataCols[0]->numOfRows < pCfg->minRowsPerFileBlock); if (tsdbWriteBlockToFile(pHelper, &(pHelper->files.nLastF), pHelper->pDataCols[0], pHelper->pDataCols[0]->numOfRows, &compBlock, true, true) < 0) return -1; @@ -436,25 +357,26 @@ int tsdbWriteCompInfo(SRWHelper *pHelper) { } int tsdbWriteCompIdx(SRWHelper *pHelper) { - ASSERT(TSDB_HELPER_TYPE(pHelper) == TSDB_WRITE_HELPER); + STsdbCfg *pCfg = &pHelper->pRepo->config; + + ASSERT(helperType(pHelper) == TSDB_WRITE_HELPER); off_t offset = lseek(pHelper->files.nHeadF.fd, 0, SEEK_END); if (offset < 0) return -1; SFile *pFile = &(pHelper->files.nHeadF); pFile->info.offset = offset; - // TODO: change the implementation of pHelper->pBuffer void *buf = pHelper->pBuffer; - for (uint32_t i = 0; i < pHelper->config.maxTables; i++) { + for (uint32_t i = 0; i < pCfg->maxTables; i++) { SCompIdx *pCompIdx = pHelper->pCompIdx + i; if (pCompIdx->offset > 0) { int drift = POINTER_DISTANCE(buf, pHelper->pBuffer); if (tsizeof(pHelper->pBuffer) - drift < 128) { - pHelper->pBuffer = trealloc(pHelper->pBuffer, tsizeof(pHelper->pBuffer)*2); + pHelper->pBuffer = trealloc(pHelper->pBuffer, tsizeof(pHelper->pBuffer) * 2); } buf = POINTER_SHIFT(pHelper->pBuffer, drift); - buf = taosEncodeVariantU32(buf, i); - buf = tsdbEncodeSCompIdx(buf, pCompIdx); + taosEncodeVariantU32(&buf, i); + tsdbEncodeSCompIdx(&buf, pCompIdx); } } @@ -467,42 +389,59 @@ int tsdbWriteCompIdx(SRWHelper *pHelper) { } int tsdbLoadCompIdx(SRWHelper *pHelper, void *target) { + STsdbCfg *pCfg = &(pHelper->pRepo->config); + ASSERT(pHelper->state == TSDB_HELPER_FILE_SET_AND_OPEN); if (!helperHasState(pHelper, TSDB_HELPER_IDX_LOAD)) { // If not load from file, just load it in object SFile *pFile = &(pHelper->files.headF); - int fd = pFile->fd; + int fd = pFile->fd; memset(pHelper->pCompIdx, 0, tsizeof(pHelper->pCompIdx)); if (pFile->info.offset > 0) { ASSERT(pFile->info.offset > TSDB_FILE_HEAD_SIZE); - if (lseek(fd, pFile->info.offset, SEEK_SET) < 0) return -1; - if ((pHelper->pBuffer = trealloc(pHelper->pBuffer, pFile->info.len)) == NULL) return -1; - if (tread(fd, (void *)(pHelper->pBuffer), pFile->info.len) < pFile->info.len) + if (lseek(fd, pFile->info.offset, SEEK_SET) < 0) { + tsdbError("vgId:%d failed to lseek file %s to %u since %s", REPO_ID(pHelper->pRepo), pFile->fname, + pFile->info.offset, strerror(errno)); + terrno = TAOS_SYSTEM_ERROR(errno); + return -1; + } + if ((pHelper->pBuffer = trealloc(pHelper->pBuffer, pFile->info.len)) == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; return -1; + } + if (tread(fd, (void *)(pHelper->pBuffer), pFile->info.len) < pFile->info.len) { + tsdbError("vgId:%d failed to read %d bytes from file %s since %s", REPO_ID(pHelper->pRepo), pFile->info.len, + pFile->fname, strerror(errno)); + terrno = TAOS_SYSTEM_ERROR(errno); + return -1; + } if (!taosCheckChecksumWhole((uint8_t *)(pHelper->pBuffer), pFile->info.len)) { - // TODO: File is broken, try to deal with it + tsdbError("vgId:%d file %s SCompIdx part is corrupted. offset %u len %u", REPO_ID(pHelper->pRepo), pFile->fname, + pFile->info.offset, pFile->info.len); + terrno = TSDB_CODE_TDB_FILE_CORRUPTED; return -1; } // Decode it void *ptr = pHelper->pBuffer; - while (((char *)ptr - (char *)pHelper->pBuffer) < (pFile->info.len - sizeof(TSCKSUM))) { + while (POINTER_DISTANCE(ptr, pHelper->pBuffer) < (pFile->info.len - sizeof(TSCKSUM))) { uint32_t tid = 0; if ((ptr = taosDecodeVariantU32(ptr, &tid)) == NULL) return -1; - ASSERT(tid > 0 && tid < pHelper->config.maxTables); + ASSERT(tid > 0 && tid < pCfg->maxTables); if ((ptr = tsdbDecodeSCompIdx(ptr, pHelper->pCompIdx + tid)) == NULL) return -1; - ASSERT((char *)ptr - (char *)pHelper->pBuffer <= pFile->info.len - sizeof(TSCKSUM)); + ASSERT(POINTER_DISTANCE(ptr, pHelper->pBuffer) <= pFile->info.len - sizeof(TSCKSUM)); } - ASSERT(((char *)ptr - (char *)pHelper->pBuffer) == (pFile->info.len - sizeof(TSCKSUM))); - if (lseek(fd, TSDB_FILE_HEAD_SIZE, SEEK_SET) < 0) return -1; + if (lseek(fd, TSDB_FILE_HEAD_SIZE, SEEK_SET) < 0) { + terrno = TAOS_SYSTEM_ERROR(errno); + return -1; + } } - } helperSetState(pHelper, TSDB_HELPER_IDX_LOAD); @@ -582,53 +521,12 @@ void tsdbGetDataStatis(SRWHelper *pHelper, SDataStatis *pStatis, int numOfCols) } } -static int comparColIdCompCol(const void *arg1, const void *arg2) { - return (*(int16_t *)arg1) - ((SCompCol *)arg2)->colId; -} - -static int comparColIdDataCol(const void *arg1, const void *arg2) { - return (*(int16_t *)arg1) - ((SDataCol *)arg2)->colId; -} - -static int tsdbLoadSingleColumnData(int fd, SCompBlock *pCompBlock, SCompCol *pCompCol, void *buf) { - size_t tsize = sizeof(SCompData) + sizeof(SCompCol) * pCompBlock->numOfCols; - if (lseek(fd, pCompBlock->offset + tsize + pCompCol->offset, SEEK_SET) < 0) return -1; - if (tread(fd, buf, pCompCol->len) < pCompCol->len) return -1; - - return 0; -} - -static int tsdbLoadSingleBlockDataCols(SRWHelper *pHelper, SCompBlock *pCompBlock, int16_t *colIds, int numOfColIds, - SDataCols *pDataCols) { - if (tsdbLoadCompData(pHelper, pCompBlock, NULL) < 0) return -1; - int fd = (pCompBlock->last) ? pHelper->files.lastF.fd : pHelper->files.dataF.fd; - - void *ptr = NULL; - for (int i = 0; i < numOfColIds; i++) { - int16_t colId = colIds[i]; - - ptr = bsearch((void *)&colId, (void *)pHelper->pCompData->cols, pHelper->pCompData->numOfCols, sizeof(SCompCol), comparColIdCompCol); - if (ptr == NULL) continue; - SCompCol *pCompCol = (SCompCol *)ptr; - - ptr = bsearch((void *)&colId, (void *)(pDataCols->cols), pDataCols->numOfCols, sizeof(SDataCol), comparColIdDataCol); - ASSERT(ptr != NULL); - SDataCol *pDataCol = (SDataCol *)ptr; - - pDataCol->len = pCompCol->len; - if (tsdbLoadSingleColumnData(fd, pCompBlock, pCompCol, pDataCol->pData) < 0) return -1; - } - - return 0; -} - -// Load specific column data from file int tsdbLoadBlockDataCols(SRWHelper *pHelper, SDataCols *pDataCols, int blkIdx, int16_t *colIds, int numOfColIds) { SCompBlock *pCompBlock = pHelper->pCompInfo->blocks + blkIdx; - ASSERT(pCompBlock->numOfSubBlocks >= 1); // Must be super block + ASSERT(pCompBlock->numOfSubBlocks >= 1); // Must be super block - int numOfSubBlocks = pCompBlock->numOfSubBlocks; + int numOfSubBlocks = pCompBlock->numOfSubBlocks; SCompBlock *pStartBlock = (numOfSubBlocks == 1) ? pCompBlock : (SCompBlock *)((char *)pHelper->pCompInfo->blocks + pCompBlock->offset); @@ -642,95 +540,6 @@ int tsdbLoadBlockDataCols(SRWHelper *pHelper, SDataCols *pDataCols, int blkIdx, return 0; } -static int tsdbCheckAndDecodeColumnData(SDataCol *pDataCol, char *content, int32_t len, int8_t comp, int numOfRows, - int maxPoints, char *buffer, int bufferSize) { - // Verify by checksum - if (!taosCheckChecksumWhole((uint8_t *)content, len)) return -1; - - // Decode the data - if (comp) { - // // Need to decompress - pDataCol->len = (*(tDataTypeDesc[pDataCol->type].decompFunc))( - content, len - sizeof(TSCKSUM), numOfRows, pDataCol->pData, pDataCol->spaceSize, comp, buffer, bufferSize); - if (pDataCol->type == TSDB_DATA_TYPE_BINARY || pDataCol->type == TSDB_DATA_TYPE_NCHAR) { - dataColSetOffset(pDataCol, numOfRows); - } - } else { - // No need to decompress, just memcpy it - pDataCol->len = len - sizeof(TSCKSUM); - memcpy(pDataCol->pData, content, pDataCol->len); - if (pDataCol->type == TSDB_DATA_TYPE_BINARY || pDataCol->type == TSDB_DATA_TYPE_NCHAR) { - dataColSetOffset(pDataCol, numOfRows); - } - } - return 0; -} - -/** - * Interface to read the data of a sub-block OR the data of a super-block of which (numOfSubBlocks == 1) - */ -static int tsdbLoadBlockDataImpl(SRWHelper *pHelper, SCompBlock *pCompBlock, SDataCols *pDataCols) { - ASSERT(pCompBlock->numOfSubBlocks <= 1); - - ASSERT(tsizeof(pHelper->pBuffer) >= pCompBlock->len); - - SCompData *pCompData = (SCompData *)pHelper->pBuffer; - - int fd = (pCompBlock->last) ? pHelper->files.lastF.fd : pHelper->files.dataF.fd; - if (lseek(fd, pCompBlock->offset, SEEK_SET) < 0) goto _err; - if (tread(fd, (void *)pCompData, pCompBlock->len) < pCompBlock->len) goto _err; - ASSERT(pCompData->numOfCols == pCompBlock->numOfCols); - - int32_t tsize = sizeof(SCompData) + sizeof(SCompCol) * pCompBlock->numOfCols + sizeof(TSCKSUM); - if (!taosCheckChecksumWhole((uint8_t *)pCompData, tsize)) goto _err; - - pDataCols->numOfRows = pCompBlock->numOfRows; - - // Recover the data - int ccol = 0; - int dcol = 0; - while (dcol < pDataCols->numOfCols) { - SDataCol *pDataCol = &(pDataCols->cols[dcol]); - if (ccol >= pCompData->numOfCols) { - // Set current column as NULL and forward - dataColSetNEleNull(pDataCol, pCompBlock->numOfRows, pDataCols->maxPoints); - dcol++; - continue; - } - - SCompCol *pCompCol = &(pCompData->cols[ccol]); - - if (pCompCol->colId == pDataCol->colId) { - if (pCompBlock->algorithm == TWO_STAGE_COMP) { - int zsize = pDataCol->bytes * pCompBlock->numOfRows + COMP_OVERFLOW_BYTES; - if (pCompCol->type == TSDB_DATA_TYPE_BINARY || pCompCol->type == TSDB_DATA_TYPE_NCHAR) { - zsize += (sizeof(VarDataLenT) * pCompBlock->numOfRows); - } - pHelper->compBuffer = trealloc(pHelper->compBuffer, zsize); - if (pHelper->compBuffer == NULL) goto _err; - } - if (tsdbCheckAndDecodeColumnData(pDataCol, (char *)pCompData + tsize + pCompCol->offset, pCompCol->len, - pCompBlock->algorithm, pCompBlock->numOfRows, pDataCols->maxPoints, - pHelper->compBuffer, tsizeof(pHelper->compBuffer)) < 0) - goto _err; - dcol++; - ccol++; - } else if (pCompCol->colId < pDataCol->colId) { - ccol++; - } else { - // Set current column as NULL and forward - dataColSetNEleNull(pDataCol, pCompBlock->numOfRows, pDataCols->maxPoints); - dcol++; - } - } - - return 0; - -_err: - return -1; -} - -// Load the whole block data int tsdbLoadBlockData(SRWHelper *pHelper, SCompBlock *pCompBlock, SDataCols *target) { // SCompBlock *pCompBlock = pHelper->pCompInfo->blocks + blkIdx; @@ -754,6 +563,7 @@ _err: return -1; } +// ---------------------- INTERNAL FUNCTIONS ---------------------- static bool tsdbShouldCreateNewLast(SRWHelper *pHelper) { ASSERT(pHelper->files.lastF.fd > 0); struct stat st; @@ -762,24 +572,29 @@ static bool tsdbShouldCreateNewLast(SRWHelper *pHelper) { return false; } -static int tsdbWriteBlockToFile(SRWHelper *pHelper, SFile *pFile, SDataCols *pDataCols, int rowsToWrite, SCompBlock *pCompBlock, - bool isLast, bool isSuperBlock) { - ASSERT(rowsToWrite > 0 && rowsToWrite <= pDataCols->numOfRows && rowsToWrite <= pHelper->config.maxRowsPerFileBlock); - ASSERT(isLast ? rowsToWrite < pHelper->config.minRowsPerFileBlock : true); - +static int tsdbWriteBlockToFile(SRWHelper *pHelper, SFile *pFile, SDataCols *pDataCols, int rowsToWrite, + SCompBlock *pCompBlock, bool isLast, bool isSuperBlock) { + STsdbCfg *pCfg = &(pHelper->pRepo->config); SCompData *pCompData = (SCompData *)(pHelper->pBuffer); - int64_t offset = 0; + int64_t offset = 0; + + ASSERT(rowsToWrite > 0 && rowsToWrite <= pDataCols->numOfRows && rowsToWrite <= pCfg->maxRowsPerFileBlock); + ASSERT(isLast ? rowsToWrite < pCfg->minRowsPerFileBlock : true); + offset = lseek(pFile->fd, 0, SEEK_END); - if (offset < 0) goto _err; + if (offset < 0) { + tsdbError("vgId:%d failed to write block to file %s since %s", REPO_ID(pHelper->pRepo), pFile->fname, strerror(errno)); + terrno = TAOS_SYSTEM_ERROR(errno); + goto _err; + } int nColsNotAllNull = 0; for (int ncol = 0; ncol < pDataCols->numOfCols; ncol++) { SDataCol *pDataCol = pDataCols->cols + ncol; SCompCol *pCompCol = pCompData->cols + nColsNotAllNull; - if (isNEleNull(pDataCol, rowsToWrite)) { - // all data to commit are NULL, just ignore it + if (isNEleNull(pDataCol, rowsToWrite)) { // all data to commit are NULL, just ignore it continue; } @@ -815,15 +630,18 @@ static int tsdbWriteBlockToFile(SRWHelper *pHelper, SFile *pFile, SDataCols *pDa int32_t tlen = dataColGetNEleLen(pDataCol, rowsToWrite); - if (pHelper->config.compress) { - if (pHelper->config.compress == TWO_STAGE_COMP) { + if (pCfg->compression) { + if (pCfg->compression == TWO_STAGE_COMP) { pHelper->compBuffer = trealloc(pHelper->compBuffer, tlen + COMP_OVERFLOW_BYTES); - if (pHelper->compBuffer == NULL) goto _err; + if (pHelper->compBuffer == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + goto _err; + } } pCompCol->len = (*(tDataTypeDesc[pDataCol->type].compFunc))( - (char *)pDataCol->pData, tlen, rowsToWrite, tptr, tsizeof(pHelper->pBuffer) - lsize, - pHelper->config.compress, pHelper->compBuffer, tsizeof(pHelper->compBuffer)); + (char *)pDataCol->pData, tlen, rowsToWrite, tptr, tsizeof(pHelper->pBuffer) - lsize, pCfg->compression, + pHelper->compBuffer, tsizeof(pHelper->compBuffer)); } else { pCompCol->len = tlen; memcpy(tptr, pDataCol->pData, pCompCol->len); @@ -845,12 +663,17 @@ static int tsdbWriteBlockToFile(SRWHelper *pHelper, SFile *pFile, SDataCols *pDa taosCalcChecksumAppend(0, (uint8_t *)pCompData, tsize); // Write the whole block to file - if (twrite(pFile->fd, (void *)pCompData, lsize) < lsize) goto _err; + if (twrite(pFile->fd, (void *)pCompData, lsize) < lsize) { + tsdbError("vgId:%d failed to write %d bytes to file %s since %s", REPO_ID(helperRepo(pHelper)), lsize, pFile->fname, + strerror(errno)); + terrno = TAOS_SYSTEM_ERROR(errno); + goto _err; + } // Update pCompBlock membership vairables pCompBlock->last = isLast; pCompBlock->offset = offset; - pCompBlock->algorithm = pHelper->config.compress; + pCompBlock->algorithm = pCfg->compression; pCompBlock->numOfRows = rowsToWrite; pCompBlock->sversion = pHelper->tableInfo.sversion; pCompBlock->len = (int32_t)lsize; @@ -859,9 +682,15 @@ static int tsdbWriteBlockToFile(SRWHelper *pHelper, SFile *pFile, SDataCols *pDa pCompBlock->keyFirst = dataColsKeyFirst(pDataCols); pCompBlock->keyLast = dataColsKeyAt(pDataCols, rowsToWrite - 1); + tsdbTrace("vgId:%d tid:%d a block of data is written to file %s, offset %" PRId64 + " numOfRows %d len %d numOfCols %" PRId16 " keyFirst %" PRId64 " keyLast %" PRId64, + REPO_ID(helperRepo(pHelper)), pHelper->tableInfo.tid, pFile->fname, (int64_t)(pCompBlock->offset), + (int)(pCompBlock->numOfRows), pCompBlock->len, pCompBlock->numOfCols, pCompBlock->keyFirst, + pCompBlock->keyLast); + return 0; - _err: +_err: return -1; } @@ -878,15 +707,11 @@ static int compareKeyBlock(const void *arg1, const void *arg2) { return 0; } -// static FORCE_INLINE int compKeyFunc(const void *arg1, const void *arg2) { -// return ((*(TSKEY *)arg1) - (*(TSKEY *)arg2)); -// } - -// Merge the data with a block in file static int tsdbMergeDataWithBlock(SRWHelper *pHelper, int blkIdx, SDataCols *pDataCols) { // TODO: set pHelper->hasOldBlock int rowsWritten = 0; SCompBlock compBlock = {0}; + STsdbCfg * pCfg = &pHelper->pRepo->config; ASSERT(pDataCols->numOfRows > 0); TSKEY keyFirst = dataColsKeyFirst(pDataCols); @@ -899,13 +724,14 @@ static int tsdbMergeDataWithBlock(SRWHelper *pHelper, int blkIdx, SDataCols *pDa ASSERT(keyFirst >= blockAtIdx(pHelper, blkIdx)->keyFirst); // ASSERT(compareKeyBlock((void *)&keyFirst, (void *)pCompBlock) == 0); - if (keyFirst > blockAtIdx(pHelper, blkIdx)->keyLast) { // Merge with the last block by append - ASSERT(blockAtIdx(pHelper, blkIdx)->numOfRows < pHelper->config.minRowsPerFileBlock && blkIdx == pIdx->numOfBlocks-1); - int defaultRowsToWrite = pHelper->config.maxRowsPerFileBlock * 4 / 5; // TODO: make a interface + if (keyFirst > blockAtIdx(pHelper, blkIdx)->keyLast) { // Merge with the last block by append + ASSERT(blockAtIdx(pHelper, blkIdx)->numOfRows < pCfg->minRowsPerFileBlock && + blkIdx == pIdx->numOfBlocks - 1); + int defaultRowsToWrite = pCfg->maxRowsPerFileBlock * 4 / 5; // TODO: make a interface rowsWritten = MIN((defaultRowsToWrite - blockAtIdx(pHelper, blkIdx)->numOfRows), pDataCols->numOfRows); if ((blockAtIdx(pHelper, blkIdx)->numOfSubBlocks < TSDB_MAX_SUBBLOCKS) && - (blockAtIdx(pHelper, blkIdx)->numOfRows + rowsWritten < pHelper->config.minRowsPerFileBlock) && + (blockAtIdx(pHelper, blkIdx)->numOfRows + rowsWritten < pCfg->minRowsPerFileBlock) && (pHelper->files.nLastF.fd) < 0) { if (tsdbWriteBlockToFile(pHelper, &(pHelper->files.lastF), pDataCols, rowsWritten, &compBlock, true, false) < 0) goto _err; @@ -918,15 +744,15 @@ static int tsdbMergeDataWithBlock(SRWHelper *pHelper, int blkIdx, SDataCols *pDa if (tdMergeDataCols(pHelper->pDataCols[0], pDataCols, rowsWritten) < 0) goto _err; // Write SFile *pWFile = NULL; - bool isLast = false; - if (pHelper->pDataCols[0]->numOfRows >= pHelper->config.minRowsPerFileBlock) { + bool isLast = false; + if (pHelper->pDataCols[0]->numOfRows >= pCfg->minRowsPerFileBlock) { pWFile = &(pHelper->files.dataF); } else { isLast = true; pWFile = (pHelper->files.nLastF.fd > 0) ? &(pHelper->files.nLastF) : &(pHelper->files.lastF); } - if (tsdbWriteBlockToFile(pHelper, pWFile, pHelper->pDataCols[0], - pHelper->pDataCols[0]->numOfRows, &compBlock, isLast, true) < 0) + if (tsdbWriteBlockToFile(pHelper, pWFile, pHelper->pDataCols[0], pHelper->pDataCols[0]->numOfRows, &compBlock, + isLast, true) < 0) goto _err; if (tsdbUpdateSuperBlock(pHelper, &compBlock, blkIdx) < 0) goto _err; } @@ -940,9 +766,10 @@ static int tsdbMergeDataWithBlock(SRWHelper *pHelper, int blkIdx, SDataCols *pDa TSKEY keyLimit = (blkIdx == pIdx->numOfBlocks - 1) ? INT64_MAX : blockAtIdx(pHelper, blkIdx + 1)->keyFirst - 1; // rows1: number of rows must merge in this block - int rows1 = tsdbGetRowsInRange(pDataCols, blockAtIdx(pHelper, blkIdx)->keyFirst, blockAtIdx(pHelper, blkIdx)->keyLast); + int rows1 = + tsdbGetRowsInRange(pDataCols, blockAtIdx(pHelper, blkIdx)->keyFirst, blockAtIdx(pHelper, blkIdx)->keyLast); // rows2: max number of rows the block can have more - int rows2 = pHelper->config.maxRowsPerFileBlock - blockAtIdx(pHelper, blkIdx)->numOfRows; + int rows2 = pCfg->maxRowsPerFileBlock - blockAtIdx(pHelper, blkIdx)->numOfRows; // rows3: number of rows between this block and the next block int rows3 = tsdbGetRowsInRange(pDataCols, blockAtIdx(pHelper, blkIdx)->keyFirst, keyLimit); @@ -950,7 +777,7 @@ static int tsdbMergeDataWithBlock(SRWHelper *pHelper, int blkIdx, SDataCols *pDa if ((rows2 >= rows1) && (blockAtIdx(pHelper, blkIdx)->numOfSubBlocks < TSDB_MAX_SUBBLOCKS) && ((!blockAtIdx(pHelper, blkIdx)->last) || - ((rows1 + blockAtIdx(pHelper, blkIdx)->numOfRows < pHelper->config.minRowsPerFileBlock) && + ((rows1 + blockAtIdx(pHelper, blkIdx)->numOfRows < pCfg->minRowsPerFileBlock) && (pHelper->files.nLastF.fd < 0)))) { rowsWritten = rows1; bool isLast = false; @@ -972,14 +799,14 @@ static int tsdbMergeDataWithBlock(SRWHelper *pHelper, int blkIdx, SDataCols *pDa rowsWritten = rows3; - int iter1 = 0; // iter over pHelper->pDataCols[0] - int iter2 = 0; // iter over pDataCols + int iter1 = 0; // iter over pHelper->pDataCols[0] + int iter2 = 0; // iter over pDataCols int round = 0; // tdResetDataCols(pHelper->pDataCols[1]); while (true) { if (iter1 >= pHelper->pDataCols[0]->numOfRows && iter2 >= rows3) break; tdMergeTwoDataCols(pHelper->pDataCols[1], pHelper->pDataCols[0], &iter1, pHelper->pDataCols[0]->numOfRows, - pDataCols, &iter2, rowsWritten, pHelper->config.maxRowsPerFileBlock * 4 / 5); + pDataCols, &iter2, rowsWritten, pCfg->maxRowsPerFileBlock * 4 / 5); ASSERT(pHelper->pDataCols[1]->numOfRows > 0); if (tsdbWriteBlockToFile(pHelper, &(pHelper->files.dataF), pHelper->pDataCols[1], pHelper->pDataCols[1]->numOfRows, &compBlock, false, true) < 0) @@ -997,7 +824,7 @@ static int tsdbMergeDataWithBlock(SRWHelper *pHelper, int blkIdx, SDataCols *pDa return rowsWritten; - _err: +_err: return -1; } @@ -1012,7 +839,6 @@ static int compTSKEY(const void *key1, const void *key2) { } static int tsdbAdjustInfoSizeIfNeeded(SRWHelper *pHelper, size_t esize) { - if (tsizeof((void *)pHelper->pCompInfo) <= esize) { size_t tsize = esize + sizeof(SCompBlock) * 16; pHelper->pCompInfo = (SCompInfo *)trealloc(pHelper->pCompInfo, tsize); @@ -1058,6 +884,9 @@ static int tsdbInsertSuperBlock(SRWHelper *pHelper, SCompBlock *pCompBlock, int ASSERT(pHelper->pCompInfo->blocks[0].keyLast < pHelper->pCompInfo->blocks[1].keyFirst); } + tsdbTrace("vgId:%d tid:%d a super block is inserted at index %d", REPO_ID(pHelper->pRepo), pHelper->tableInfo.tid, + blkIdx); + return 0; _err: @@ -1075,7 +904,7 @@ static int tsdbAddSubBlock(SRWHelper *pHelper, SCompBlock *pCompBlock, int blkId size_t spaceNeeded = (pSCompBlock->numOfSubBlocks == 1) ? pIdx->len + sizeof(SCompBlock) * 2 : pIdx->len + sizeof(SCompBlock); - if (tsdbAdjustInfoSizeIfNeeded(pHelper, spaceNeeded) < 0) goto _err; + if (tsdbAdjustInfoSizeIfNeeded(pHelper, spaceNeeded) < 0) goto _err; pSCompBlock = pHelper->pCompInfo->blocks + blkIdx; @@ -1092,7 +921,6 @@ static int tsdbAddSubBlock(SRWHelper *pHelper, SCompBlock *pCompBlock, int blkId } } - *(SCompBlock *)((char *)(pHelper->pCompInfo) + pSCompBlock->offset + pSCompBlock->len) = *pCompBlock; pSCompBlock->numOfSubBlocks++; @@ -1112,7 +940,7 @@ static int tsdbAddSubBlock(SRWHelper *pHelper, SCompBlock *pCompBlock, int blkId } } - if (ptr == NULL) ptr = POINTER_SHIFT(pHelper->pCompInfo, pIdx->len-sizeof(TSCKSUM)); + if (ptr == NULL) ptr = POINTER_SHIFT(pHelper->pCompInfo, pIdx->len - sizeof(TSCKSUM)); size_t tsize = pIdx->len - ((char *)ptr - (char *)(pHelper->pCompInfo)); if (tsize > 0) { @@ -1141,6 +969,8 @@ static int tsdbAddSubBlock(SRWHelper *pHelper, SCompBlock *pCompBlock, int blkId pIdx->maxKey = pHelper->pCompInfo->blocks[pIdx->numOfBlocks - 1].keyLast; pIdx->hasLast = pHelper->pCompInfo->blocks[pIdx->numOfBlocks - 1].last; + tsdbTrace("vgId:%d tid:%d a subblock is added at index %d", REPO_ID(pHelper->pRepo), pHelper->tableInfo.tid, blkIdx); + return 0; _err: @@ -1179,6 +1009,9 @@ static int tsdbUpdateSuperBlock(SRWHelper *pHelper, SCompBlock *pCompBlock, int pIdx->maxKey = pHelper->pCompInfo->blocks[pIdx->numOfBlocks - 1].keyLast; pIdx->hasLast = pHelper->pCompInfo->blocks[pIdx->numOfBlocks - 1].last; + tsdbTrace("vgId:%d tid:%d a super block is updated at index %d", REPO_ID(pHelper->pRepo), pHelper->tableInfo.tid, + blkIdx); + return 0; } @@ -1206,71 +1039,295 @@ static int tsdbGetRowsInRange(SDataCols *pDataCols, TSKEY minKey, TSKEY maxKey) return ((TSKEY *)ptr2 - (TSKEY *)ptr1) + 1; } -void *tsdbEncodeSCompIdx(void *buf, SCompIdx *pIdx) { - buf = taosEncodeVariantU32(buf, pIdx->len); - buf = taosEncodeVariantU32(buf, pIdx->offset); - buf = taosEncodeFixedU8(buf, pIdx->hasLast); - buf = taosEncodeVariantU32(buf, pIdx->numOfBlocks); - buf = taosEncodeFixedU64(buf, pIdx->uid); - buf = taosEncodeFixedU64(buf, pIdx->maxKey); +static void tsdbResetHelperFileImpl(SRWHelper *pHelper) { + memset((void *)&pHelper->files, 0, sizeof(pHelper->files)); + pHelper->files.fid = -1; + pHelper->files.headF.fd = -1; + pHelper->files.dataF.fd = -1; + pHelper->files.lastF.fd = -1; + pHelper->files.nHeadF.fd = -1; + pHelper->files.nLastF.fd = -1; +} - return buf; +static int tsdbInitHelperFile(SRWHelper *pHelper) { + STsdbCfg *pCfg = &pHelper->pRepo->config; + size_t tsize = sizeof(SCompIdx) * pCfg->maxTables + sizeof(TSCKSUM); + pHelper->pCompIdx = (SCompIdx *)tmalloc(tsize); + if (pHelper->pCompIdx == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + return -1; + } + + tsdbResetHelperFileImpl(pHelper); + return 0; } -void *tsdbDecodeSCompIdx(void *buf, SCompIdx *pIdx) { - uint8_t hasLast = 0; - uint32_t numOfBlocks = 0; - uint64_t value = 0; +static void tsdbDestroyHelperFile(SRWHelper *pHelper) { + tsdbCloseHelperFile(pHelper, false); + tsdbResetHelperFileImpl(pHelper); + tzfree(pHelper->pCompIdx); +} - if ((buf = taosDecodeVariantU32(buf, &(pIdx->len))) == NULL) return NULL; - if ((buf = taosDecodeVariantU32(buf, &(pIdx->offset))) == NULL) return NULL; - if ((buf = taosDecodeFixedU8(buf, &(hasLast))) == NULL) return NULL; - pIdx->hasLast = hasLast; - if ((buf = taosDecodeVariantU32(buf, &(numOfBlocks))) == NULL) return NULL; - pIdx->numOfBlocks = numOfBlocks; - if ((buf = taosDecodeFixedU64(buf, &value)) == NULL) return NULL; - pIdx->uid = (int64_t)value; - if ((buf = taosDecodeFixedU64(buf, &value)) == NULL) return NULL; - pIdx->maxKey = (TSKEY)value; +// ---------- Operations on Helper Table part +static void tsdbResetHelperTableImpl(SRWHelper *pHelper) { + memset((void *)&pHelper->tableInfo, 0, sizeof(SHelperTable)); + pHelper->hasOldLastBlock = false; +} - return buf; +static void tsdbResetHelperTable(SRWHelper *pHelper) { + tsdbResetHelperBlock(pHelper); + tsdbResetHelperTableImpl(pHelper); + helperClearState(pHelper, (TSDB_HELPER_TABLE_SET | TSDB_HELPER_INFO_LOAD)); +} + +static void tsdbInitHelperTable(SRWHelper *pHelper) { tsdbResetHelperTableImpl(pHelper); } + +static void tsdbDestroyHelperTable(SRWHelper *pHelper) { tzfree((void *)pHelper->pCompInfo); } + +// ---------- Operations on Helper Block part +static void tsdbResetHelperBlockImpl(SRWHelper *pHelper) { + tdResetDataCols(pHelper->pDataCols[0]); + tdResetDataCols(pHelper->pDataCols[1]); } -int tsdbUpdateFileHeader(SFile *pFile, uint32_t version) { - char buf[TSDB_FILE_HEAD_SIZE] = "\0"; +static void tsdbResetHelperBlock(SRWHelper *pHelper) { + tsdbResetHelperBlockImpl(pHelper); + // helperClearState(pHelper, TSDB_HELPER_) +} - void *pBuf = (void *)buf; - pBuf = taosEncodeFixedU32(pBuf, version); - pBuf = tsdbEncodeSFileInfo(pBuf, &(pFile->info)); +static int tsdbInitHelperBlock(SRWHelper *pHelper) { + STsdbRepo *pRepo = helperRepo(pHelper); + STsdbMeta *pMeta = pHelper->pRepo->tsdbMeta; + + pHelper->pDataCols[0] = + tdNewDataCols(pMeta->maxRowBytes, pMeta->maxCols, pRepo->config.maxRowsPerFileBlock); + pHelper->pDataCols[1] = + tdNewDataCols(pMeta->maxRowBytes, pMeta->maxCols, pRepo->config.maxRowsPerFileBlock); + if (pHelper->pDataCols[0] == NULL || pHelper->pDataCols[1] == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + return -1; + } - taosCalcChecksumAppend(0, (uint8_t *)buf, TSDB_FILE_HEAD_SIZE); + tsdbResetHelperBlockImpl(pHelper); - if (lseek(pFile->fd, 0, SEEK_SET) < 0) return -1; - if (twrite(pFile->fd, (void *)buf, TSDB_FILE_HEAD_SIZE) < TSDB_FILE_HEAD_SIZE) return -1; + return 0; +} + +static void tsdbDestroyHelperBlock(SRWHelper *pHelper) { + tzfree(pHelper->pCompData); + tdFreeDataCols(pHelper->pDataCols[0]); + tdFreeDataCols(pHelper->pDataCols[1]); +} + +static int tsdbInitHelper(SRWHelper *pHelper, STsdbRepo *pRepo, tsdb_rw_helper_t type) { + STsdbCfg *pCfg = &pRepo->config; + memset((void *)pHelper, 0, sizeof(*pHelper)); + STsdbMeta *pMeta = pRepo->tsdbMeta; + + helperType(pHelper) = type; + helperRepo(pHelper) = pRepo; + helperState(pHelper) = TSDB_HELPER_CLEAR_STATE; + + // Init file part + if (tsdbInitHelperFile(pHelper) < 0) goto _err; + + // Init table part + tsdbInitHelperTable(pHelper); + + // Init block part + if (tsdbInitHelperBlock(pHelper) < 0) goto _err; + + // TODO: pMeta->maxRowBytes and pMeta->maxCols may change here causing invalid write + pHelper->pBuffer = + tmalloc(sizeof(SCompData) + (sizeof(SCompCol) + sizeof(TSCKSUM) + COMP_OVERFLOW_BYTES) * pMeta->maxCols + + pMeta->maxRowBytes * pCfg->maxRowsPerFileBlock + sizeof(TSCKSUM)); + if (pHelper->pBuffer == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + goto _err; + } return 0; + +_err: + tsdbDestroyHelper(pHelper); + return -1; } +static int comparColIdCompCol(const void *arg1, const void *arg2) { + return (*(int16_t *)arg1) - ((SCompCol *)arg2)->colId; +} +static int comparColIdDataCol(const void *arg1, const void *arg2) { + return (*(int16_t *)arg1) - ((SDataCol *)arg2)->colId; +} -void *tsdbEncodeSFileInfo(void *buf, const STsdbFileInfo *pInfo) { - buf = taosEncodeFixedU32(buf, pInfo->offset); - buf = taosEncodeFixedU32(buf, pInfo->len); - buf = taosEncodeFixedU64(buf, pInfo->size); - buf = taosEncodeFixedU64(buf, pInfo->tombSize); - buf = taosEncodeFixedU32(buf, pInfo->totalBlocks); - buf = taosEncodeFixedU32(buf, pInfo->totalSubBlocks); +static int tsdbLoadSingleColumnData(int fd, SCompBlock *pCompBlock, SCompCol *pCompCol, void *buf) { + size_t tsize = sizeof(SCompData) + sizeof(SCompCol) * pCompBlock->numOfCols; + if (lseek(fd, pCompBlock->offset + tsize + pCompCol->offset, SEEK_SET) < 0) return -1; + if (tread(fd, buf, pCompCol->len) < pCompCol->len) return -1; - return buf; + return 0; } -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)); +static int tsdbLoadSingleBlockDataCols(SRWHelper *pHelper, SCompBlock *pCompBlock, int16_t *colIds, int numOfColIds, + SDataCols *pDataCols) { + if (tsdbLoadCompData(pHelper, pCompBlock, NULL) < 0) return -1; + int fd = (pCompBlock->last) ? pHelper->files.lastF.fd : pHelper->files.dataF.fd; + + void *ptr = NULL; + for (int i = 0; i < numOfColIds; i++) { + int16_t colId = colIds[i]; + + ptr = bsearch((void *)&colId, (void *)pHelper->pCompData->cols, pHelper->pCompData->numOfCols, sizeof(SCompCol), + comparColIdCompCol); + if (ptr == NULL) continue; + SCompCol *pCompCol = (SCompCol *)ptr; + + ptr = + bsearch((void *)&colId, (void *)(pDataCols->cols), pDataCols->numOfCols, sizeof(SDataCol), comparColIdDataCol); + ASSERT(ptr != NULL); + SDataCol *pDataCol = (SDataCol *)ptr; + + pDataCol->len = pCompCol->len; + if (tsdbLoadSingleColumnData(fd, pCompBlock, pCompCol, pDataCol->pData) < 0) return -1; + } + + return 0; +} + +static int tsdbCheckAndDecodeColumnData(SDataCol *pDataCol, char *content, int32_t len, int8_t comp, int numOfRows, + int maxPoints, char *buffer, int bufferSize) { + // Verify by checksum + if (!taosCheckChecksumWhole((uint8_t *)content, len)) return -1; + + // Decode the data + if (comp) { + // // Need to decompress + pDataCol->len = (*(tDataTypeDesc[pDataCol->type].decompFunc))( + content, len - sizeof(TSCKSUM), numOfRows, pDataCol->pData, pDataCol->spaceSize, comp, buffer, bufferSize); + if (pDataCol->type == TSDB_DATA_TYPE_BINARY || pDataCol->type == TSDB_DATA_TYPE_NCHAR) { + dataColSetOffset(pDataCol, numOfRows); + } + } else { + // No need to decompress, just memcpy it + pDataCol->len = len - sizeof(TSCKSUM); + memcpy(pDataCol->pData, content, pDataCol->len); + if (pDataCol->type == TSDB_DATA_TYPE_BINARY || pDataCol->type == TSDB_DATA_TYPE_NCHAR) { + dataColSetOffset(pDataCol, numOfRows); + } + } + return 0; +} + +static int tsdbLoadBlockDataImpl(SRWHelper *pHelper, SCompBlock *pCompBlock, SDataCols *pDataCols) { + ASSERT(pCompBlock->numOfSubBlocks <= 1); + + ASSERT(tsizeof(pHelper->pBuffer) >= pCompBlock->len); + + SCompData *pCompData = (SCompData *)pHelper->pBuffer; + + SFile *pFile = (pCompBlock->last) ? &(pHelper->files.lastF) : &(pHelper->files.dataF); + + int fd = pFile->fd; + if (lseek(fd, pCompBlock->offset, SEEK_SET) < 0) { + tsdbError("vgId:%d tid:%d failed to lseek file %s since %s", REPO_ID(pHelper->pRepo), pHelper->tableInfo.tid, + pFile->fname, strerror(errno)); + terrno = TAOS_SYSTEM_ERROR(errno); + goto _err; + } + if (tread(fd, (void *)pCompData, pCompBlock->len) < pCompBlock->len) { + tsdbError("vgId:%d failed to read %d bytes from file %s since %s", REPO_ID(pHelper->pRepo), pCompBlock->len, + pFile->fname, strerror(errno)); + terrno = TAOS_SYSTEM_ERROR(errno); + goto _err; + } + ASSERT(pCompData->numOfCols == pCompBlock->numOfCols); + + int32_t tsize = sizeof(SCompData) + sizeof(SCompCol) * pCompBlock->numOfCols + sizeof(TSCKSUM); + if (!taosCheckChecksumWhole((uint8_t *)pCompData, tsize)) { + tsdbError("vgId:%d file %s block data is corrupted offset %" PRId64 " len %d", REPO_ID(pHelper->pRepo), + pFile->fname, (int64_t)(pCompBlock->offset), pCompBlock->len); + terrno = TSDB_CODE_TDB_FILE_CORRUPTED; + goto _err; + } + + pDataCols->numOfRows = pCompBlock->numOfRows; + + // Recover the data + int ccol = 0; + int dcol = 0; + while (dcol < pDataCols->numOfCols) { + SDataCol *pDataCol = &(pDataCols->cols[dcol]); + if (ccol >= pCompData->numOfCols) { + // Set current column as NULL and forward + dataColSetNEleNull(pDataCol, pCompBlock->numOfRows, pDataCols->maxPoints); + dcol++; + continue; + } + + SCompCol *pCompCol = &(pCompData->cols[ccol]); + + if (pCompCol->colId == pDataCol->colId) { + if (pCompBlock->algorithm == TWO_STAGE_COMP) { + int zsize = pDataCol->bytes * pCompBlock->numOfRows + COMP_OVERFLOW_BYTES; + if (pCompCol->type == TSDB_DATA_TYPE_BINARY || pCompCol->type == TSDB_DATA_TYPE_NCHAR) { + zsize += (sizeof(VarDataLenT) * pCompBlock->numOfRows); + } + pHelper->compBuffer = trealloc(pHelper->compBuffer, zsize); + if (pHelper->compBuffer == NULL) { + terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; + goto _err; + } + } + if (tsdbCheckAndDecodeColumnData(pDataCol, (char *)pCompData + tsize + pCompCol->offset, pCompCol->len, + pCompBlock->algorithm, pCompBlock->numOfRows, pDataCols->maxPoints, + pHelper->compBuffer, tsizeof(pHelper->compBuffer)) < 0) + goto _err; + dcol++; + ccol++; + } else if (pCompCol->colId < pDataCol->colId) { + ccol++; + } else { + // Set current column as NULL and forward + dataColSetNEleNull(pDataCol, pCompBlock->numOfRows, pDataCols->maxPoints); + dcol++; + } + } + + return 0; + +_err: + return -1; +} + +static int tsdbEncodeSCompIdx(void **buf, SCompIdx *pIdx) { + int tlen = 0; + + tlen += taosEncodeVariantU32(buf, pIdx->len); + tlen += taosEncodeVariantU32(buf, pIdx->offset); + tlen += taosEncodeFixedU8(buf, pIdx->hasLast); + tlen += taosEncodeVariantU32(buf, pIdx->numOfBlocks); + tlen += taosEncodeFixedU64(buf, pIdx->uid); + tlen += taosEncodeFixedU64(buf, pIdx->maxKey); + + return tlen; +} + +static void *tsdbDecodeSCompIdx(void *buf, SCompIdx *pIdx) { + uint8_t hasLast = 0; + uint32_t numOfBlocks = 0; + uint64_t value = 0; + + if ((buf = taosDecodeVariantU32(buf, &(pIdx->len))) == NULL) return NULL; + if ((buf = taosDecodeVariantU32(buf, &(pIdx->offset))) == NULL) return NULL; + if ((buf = taosDecodeFixedU8(buf, &(hasLast))) == NULL) return NULL; + pIdx->hasLast = hasLast; + if ((buf = taosDecodeVariantU32(buf, &(numOfBlocks))) == NULL) return NULL; + pIdx->numOfBlocks = numOfBlocks; + if ((buf = taosDecodeFixedU64(buf, &value)) == NULL) return NULL; + pIdx->uid = (int64_t)value; + if ((buf = taosDecodeFixedU64(buf, &value)) == NULL) return NULL; + pIdx->maxKey = (TSKEY)value; return buf; -} \ No newline at end of file +} diff --git a/src/tsdb/src/tsdbRead.c b/src/tsdb/src/tsdbRead.c index 46ed3eaf844478c69affc8e53a565b9a473aead6..d1981943e6359334cd53c0d17176cc6785e3a617 100644 --- a/src/tsdb/src/tsdbRead.c +++ b/src/tsdb/src/tsdbRead.c @@ -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) { diff --git a/src/tsdb/tests/tsdbTests.cpp b/src/tsdb/tests/tsdbTests.cpp index e26caa4ae7bd28841bdcb5fd27bee1dd4cc53744..0c42ca1ee373e7ce02584ad613464cadf423f999 100644 --- a/src/tsdb/tests/tsdbTests.cpp +++ b/src/tsdb/tests/tsdbTests.cpp @@ -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 diff --git a/src/util/inc/tcoding.h b/src/util/inc/tcoding.h index e22c959a568a9008cf74f0c75fafda3daea35c49..907c69bf016f863e0e1a785209b30ce32c9c89b6 100644 --- a/src/util/inc/tcoding.h +++ b/src/util/inc/tcoding.h @@ -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) { diff --git a/src/util/inc/tkvstore.h b/src/util/inc/tkvstore.h index a57d0e95cfe65048a90356677a021e698ee2daaa..346e567c41e0a209b7dde96de55faa74a704f9b3 100644 --- a/src/util/inc/tkvstore.h +++ b/src/util/inc/tkvstore.h @@ -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; diff --git a/src/util/inc/tlist.h b/src/util/inc/tlist.h index 9e4dfe45801ed448e6c55a6e69c87b22e9e77b88..a4ed9311e24bf5098f9cca8c05edd0998b8d6253 100644 --- a/src/util/inc/tlist.h +++ b/src/util/inc/tlist.h @@ -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); diff --git a/src/util/inc/tref.h b/src/util/inc/tref.h index 9483c1cc35e6d01c7b49c993d34f0c03ad950fdd..fa2517e19a16942fd874cab1fff00262c1b90722 100644 --- a/src/util/inc/tref.h +++ b/src/util/inc/tref.h @@ -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 { \ diff --git a/src/util/src/hash.c b/src/util/src/hash.c index 95d0ce70817bc3a9ac8b731734ea30144c7e72ce..1de013c416ca25080bb6edaf00a93cb324bf3668 100644 --- a/src/util/src/hash.c +++ b/src/util/src/hash.c @@ -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; diff --git a/src/util/src/tkvstore.c b/src/util/src/tkvstore.c index 8e7b9b30f1550e0f3d8f1c9668a7417ed89e540e..ee34ca68fd47198d2006f4bf7cd7ff47ea11c760 100644 --- a/src/util/src/tkvstore.c +++ b/src/util/src/tkvstore.c @@ -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 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; + } + + 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) { - pStore->info.tombSize += (pRecord->size + sizeof(SKVRecord)); + if (pRecord != NULL) { // just to insert + pStore->info.tombSize += pRecord->size; + } else { + pStore->info.nRecords++; } - // TODO + 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; } \ No newline at end of file diff --git a/src/util/src/tlist.c b/src/util/src/tlist.c index bdb12a59f9776eaf2924c6c08c35c1b204e2065a..f402c2307e68cee6100a28e53dce1935af44fb3f 100644 --- a/src/util/src/tlist.c +++ b/src/util/src/tlist.c @@ -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) { diff --git a/src/util/src/tlog.c b/src/util/src/tlog.c index c4597d86ede2a8052bb908382a2806f3fbc574af..599cf3262b61359b05a71087a3b6ad2dde4139cb 100644 --- a/src/util/src/tlog.c +++ b/src/util/src/tlog.c @@ -428,8 +428,12 @@ void taosPrintLongString(const char *flags, int32_t dflag, const char *format, . buffer[len] = 0; if ((dflag & DEBUG_FILE) && tsLogObj.logHandle && tsLogObj.logHandle->fd >= 0) { - taosPushLogBuffer(tsLogObj.logHandle, buffer, len); - + if (tsAsyncLog) { + taosPushLogBuffer(tsLogObj.logHandle, buffer, len); + } else { + twrite(tsLogObj.logHandle->fd, buffer, len); + } + if (tsLogObj.maxLines > 0) { atomic_add_fetch_32(&tsLogObj.lines, 1); diff --git a/src/util/src/tskiplist.c b/src/util/src/tskiplist.c index 4872c9298aa58ebad9c118b343573f724e8c4021..3a474fe6c15629953dda23fc525362037cf4221a 100644 --- a/src/util/src/tskiplist.c +++ b/src/util/src/tskiplist.c @@ -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); diff --git a/src/util/src/tutil.c b/src/util/src/tutil.c index f8fca7392cd5a6dc9496ef67b6ae046910518b1a..aa5bfe322a9e0912ae13eecdaa75783505986648 100644 --- a/src/util/src/tutil.c +++ b/src/util/src/tutil.c @@ -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) { diff --git a/src/util/tests/codingTests.cpp b/src/util/tests/codingTests.cpp index 57e21a828c21d340ea998c3a4689ede772322f80..0cd9524646f0bae67c8e24234d1a204302f90350 100644 --- a/src/util/tests/codingTests.cpp +++ b/src/util/tests/codingTests.cpp @@ -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(buf), value); - void *ptr2 = taosDecodeFixedU16(static_cast(buf), &value_check); + void *pBuf = (void *)buf; - return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2)); + int tlen = taosEncodeFixedU16(static_cast(&pBuf), value); + void *ptr = taosDecodeFixedU16(static_cast(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(buf), value); - void *ptr2 = taosDecodeFixedI16(static_cast(buf), &value_check); + void *pBuf = (void *)buf; + + int tlen = taosEncodeFixedI16(static_cast(&pBuf), value); + void *ptr = taosDecodeFixedI16(static_cast(buf), &value_check); - return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2)); + 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(buf), value); - void *ptr2 = taosDecodeFixedU32(static_cast(buf), &value_check); + void *pBuf = (void *)buf; + + int tlen = taosEncodeFixedU32(static_cast(&pBuf), value); + void *ptr = taosDecodeFixedU32(static_cast(buf), &value_check); - return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2)); + 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(buf), value); - void *ptr2 = taosDecodeFixedI32(static_cast(buf), &value_check); + void *pBuf = (void *)buf; - return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2)); + int tlen = taosEncodeFixedI32(static_cast(&pBuf), value); + void *ptr = taosDecodeFixedI32(static_cast(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(buf), value); - void *ptr2 = taosDecodeFixedU64(static_cast(buf), &value_check); + void *pBuf = (void *)buf; + + int tlen = taosEncodeFixedU64(static_cast(&pBuf), value); + void *ptr = taosDecodeFixedU64(static_cast(buf), &value_check); - return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2)); + 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(buf), value); - void *ptr2 = taosDecodeFixedI64(static_cast(buf), &value_check); + void *pBuf = (void *)buf; + + int tlen = taosEncodeFixedI64(static_cast(&pBuf), value); + void *ptr = taosDecodeFixedI64(static_cast(buf), &value_check); - return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2)); + 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(buf), value); - void *ptr2 = taosDecodeVariantU16(static_cast(buf), &value_check); + void *pBuf = (void *)buf; - return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2)); + int tlen = taosEncodeVariantU16(static_cast(&pBuf), value); + void *ptr = taosDecodeVariantU16(static_cast(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(buf), value); - void *ptr2 = taosDecodeVariantI16(static_cast(buf), &value_check); + void *pBuf = (void *)buf; + + int tlen = taosEncodeVariantI16(static_cast(&pBuf), value); + void *ptr = taosDecodeVariantI16(static_cast(buf), &value_check); - return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2)); + 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(buf), value); - void *ptr2 = taosDecodeVariantU32(static_cast(buf), &value_check); + void *pBuf = (void *)buf; + + int tlen = taosEncodeVariantU32(static_cast(&pBuf), value); + void *ptr = taosDecodeVariantU32(static_cast(buf), &value_check); - return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2)); + 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(buf), value); - void *ptr2 = taosDecodeVariantI32(static_cast(buf), &value_check); + void *pBuf = (void *)buf; - return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2)); + int tlen = taosEncodeVariantI32(static_cast(&pBuf), value); + void *ptr = taosDecodeVariantI32(static_cast(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(buf), value); - void *ptr2 = taosDecodeVariantU64(static_cast(buf), &value_check); + void *pBuf = (void *)buf; + + int tlen = taosEncodeVariantU64(static_cast(&pBuf), value); + void *ptr = taosDecodeVariantU64(static_cast(buf), &value_check); - return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2)); + 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(buf), value); - void *ptr2 = taosDecodeVariantI64(static_cast(buf), &value_check); + void *pBuf = (void *)buf; + + int tlen = taosEncodeVariantI64(static_cast(&pBuf), value); + void *ptr = taosDecodeVariantI64(static_cast(buf), &value_check); - return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2)); + return ((ptr != NULL) && (value == value_check) && (pBuf == ptr) && POINTER_DISTANCE(pBuf, buf) == tlen); } TEST(codingTest, fixed_encode_decode) { diff --git a/src/vnode/src/vnodeMain.c b/src/vnode/src/vnodeMain.c index 8987b82b51765391686754fa78429bdea0faaaf3..6c8f23b424983ebeca2f688961b6e4811bd96a23 100644 --- a/src/vnode/src/vnodeMain.c +++ b/src/vnode/src/vnodeMain.c @@ -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; diff --git a/src/vnode/src/vnodeWrite.c b/src/vnode/src/vnodeWrite.c index a6a43a81aacef592db16d0dddf522a8b28433379..769ef03bf6b0806b5699d51e26b8eb1a71e83ff0 100644 --- a/src/vnode/src/vnodeWrite.c +++ b/src/vnode/src/vnodeWrite.c @@ -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,47 @@ 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; + // TODO: disposed in tsdb + // STableCfg *pCfg = tsdbCreateTableCfgFromMsg((SMDCreateTableMsg *)pCont); + // if (pCfg == NULL) return terrno; + // if (tsdbCreateTable(pVnode->tsdb, pCfg) < 0) code = terrno; + + // tsdbClearTableCfg(pCfg); + vTrace("vgId:%d, alter table msg is received", pVnode->vgId); + 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) { diff --git a/tests/examples/c/stream.c b/tests/examples/c/stream.c old mode 100755 new mode 100644 diff --git a/tests/pytest/stable/query_after_reset-multi-threading.py b/tests/pytest/stable/query_after_reset-multi-threading.py new file mode 100644 index 0000000000000000000000000000000000000000..a177f589d166117c0d8de61a01a34040a1b1103b --- /dev/null +++ b/tests/pytest/stable/query_after_reset-multi-threading.py @@ -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()) diff --git a/tests/script/general/alter/insert2.sim b/tests/script/general/alter/insert2.sim index c3283c856bf3974e1f607d68de7ee569884d5359..28948b69d231952f3baae0d79a75c1f2c9c6fb60 100644 --- a/tests/script/general/alter/insert2.sim +++ b/tests/script/general/alter/insert2.sim @@ -180,11 +180,9 @@ if $data28 != null then endi print ======== step4 -sleep 2500 sql alter table tb drop column d sql alter table tb drop column e sql insert into tb values(now-19d, -19, 6, 3, 0) -sleep 3000 sql select * from tb order by ts desc if $rows != 4 then return -1 @@ -287,10 +285,8 @@ if $data38 != null then endi print ======== step5 -sleep 2500 sql alter table tb drop column g sql insert into tb values(now-16d, -16, 9, 5) -sleep 3000 sql select count(f) from tb if $data00 != 5 then return -1 @@ -421,10 +417,8 @@ if $data48 != null then endi print ======== step6 -sleep 2500 sql alter table tb drop column f sql insert into tb values(now-13d, -13, 7) -sleep 3000 sql select * from tb order by ts desc if $rows != 6 then return -1 @@ -551,10 +545,8 @@ if $data58 != null then endi print ======== step7 -sleep 2500 sql alter table tb drop column h sql insert into tb values(now-10d, -10) -sleep 3000 sql select * from tb order by ts desc if $rows != 7 then return -1 diff --git a/tests/script/general/parser/limit2.sim b/tests/script/general/parser/limit2.sim index d16ee29cf789f2e1fe362ee32db8fc10f823ae3e..d22c786aa3001e6f7e275466bd5426b7e275b53c 100644 --- a/tests/script/general/parser/limit2.sim +++ b/tests/script/general/parser/limit2.sim @@ -69,8 +69,6 @@ print ====== tables created print ================== restart server to commit data into disk system sh/exec.sh -n dnode1 -s stop -x SIGINT - -return sleep 5000 system sh/exec.sh -n dnode1 -s start print ================== server restart completed diff --git a/tests/script/jenkins/basic.txt b/tests/script/jenkins/basic.txt index 79cb1551e1c37a9ffe30782db886ee5849dbfd95..9cb9dc594e06f294c4e9be5f9ef92e1d904147e5 100644 --- a/tests/script/jenkins/basic.txt +++ b/tests/script/jenkins/basic.txt @@ -159,21 +159,6 @@ cd ../../../debug; make ./test.sh -f general/stable/values.sim ./test.sh -f general/stable/vnode3.sim -./test.sh -f general/stream/metrics_1.sim -./test.sh -f general/stream/metrics_del.sim -./test.sh -f general/stream/metrics_n.sim -./test.sh -f general/stream/metrics_replica1_vnoden.sim -#./test.sh -f general/stream/new_stream.sim -./test.sh -f general/stream/restart_stream.sim -./test.sh -f general/stream/stream_1.sim -./test.sh -f general/stream/stream_2.sim -./test.sh -f general/stream/stream_3.sim -./test.sh -f general/stream/stream_restart.sim -./test.sh -f general/stream/table_1.sim -./test.sh -f general/stream/table_del.sim -./test.sh -f general/stream/table_n.sim -./test.sh -f general/stream/table_replica1_vnoden.sim - ./test.sh -f general/table/autocreate.sim ./test.sh -f general/table/basic1.sim ./test.sh -f general/table/basic2.sim @@ -323,6 +308,21 @@ cd ../../../debug; make ./test.sh -f unique/vnode/replica3_repeat.sim ./test.sh -f unique/vnode/replica3_vgroup.sim +./test.sh -f general/stream/metrics_1.sim +./test.sh -f general/stream/metrics_del.sim +./test.sh -f general/stream/metrics_n.sim +./test.sh -f general/stream/metrics_replica1_vnoden.sim +#./test.sh -f general/stream/new_stream.sim +./test.sh -f general/stream/restart_stream.sim +./test.sh -f general/stream/stream_1.sim +./test.sh -f general/stream/stream_2.sim +./test.sh -f general/stream/stream_3.sim +./test.sh -f general/stream/stream_restart.sim +./test.sh -f general/stream/table_1.sim +./test.sh -f general/stream/table_del.sim +./test.sh -f general/stream/table_n.sim +./test.sh -f general/stream/table_replica1_vnoden.sim + ./test.sh -f unique/arbitrator/check_cluster_cfg_para.sim ./test.sh -f unique/arbitrator/dn2_mn1_cache_file_sync.sim ./test.sh -f unique/arbitrator/dn3_mn1_full_createTableFail.sim @@ -337,7 +337,9 @@ cd ../../../debug; make ./test.sh -f unique/arbitrator/dn3_mn1_vnode_corruptFile_offline.sim ./test.sh -f unique/arbitrator/dn3_mn1_vnode_corruptFile_online.sim ./test.sh -f unique/arbitrator/dn3_mn1_vnode_noCorruptFile_offline.sim -#./test.sh -f unique/arbitrator/dn3_mn1_vnode_delDir.sim +./test.sh -f unique/arbitrator/dn3_mn1_vnode_delDir.sim +./test.sh -f unique/arbitrator/dn3_mn1_r2_vnode_delDir.sim +./test.sh -f unique/arbitrator/dn3_mn1_r3_vnode_delDir.sim ./test.sh -f unique/arbitrator/dn3_mn1_vnode_nomaster.sim ./test.sh -f unique/arbitrator/dn3_mn2_killDnode.sim ./test.sh -f unique/arbitrator/insert_duplicationTs.sim diff --git a/tests/script/unique/arbitrator/dn3_mn1_r2_vnode_delDir.sim b/tests/script/unique/arbitrator/dn3_mn1_r2_vnode_delDir.sim new file mode 100644 index 0000000000000000000000000000000000000000..807709b6752a91c1b47d12f5e608480ea721181a --- /dev/null +++ b/tests/script/unique/arbitrator/dn3_mn1_r2_vnode_delDir.sim @@ -0,0 +1,357 @@ +system sh/stop_dnodes.sh +system sh/deploy.sh -n dnode1 -i 1 +system sh/deploy.sh -n dnode2 -i 2 +system sh/deploy.sh -n dnode3 -i 3 +system sh/deploy.sh -n dnode4 -i 4 + +system sh/cfg.sh -n dnode1 -c numOfMnodes -v 1 +system sh/cfg.sh -n dnode2 -c numOfMnodes -v 1 +system sh/cfg.sh -n dnode3 -c numOfMnodes -v 1 +system sh/cfg.sh -n dnode4 -c numOfMnodes -v 1 + +system sh/cfg.sh -n dnode1 -c walLevel -v 2 +system sh/cfg.sh -n dnode2 -c walLevel -v 2 +system sh/cfg.sh -n dnode3 -c walLevel -v 2 +system sh/cfg.sh -n dnode4 -c walLevel -v 2 + +system sh/cfg.sh -n dnode1 -c balanceInterval -v 10 +system sh/cfg.sh -n dnode2 -c balanceInterval -v 10 +system sh/cfg.sh -n dnode3 -c balanceInterval -v 10 +system sh/cfg.sh -n dnode4 -c balanceInterval -v 10 + +system sh/cfg.sh -n dnode1 -c numOfTotalVnodes -v 4 +system sh/cfg.sh -n dnode2 -c numOfTotalVnodes -v 4 +system sh/cfg.sh -n dnode3 -c numOfTotalVnodes -v 4 +system sh/cfg.sh -n dnode4 -c numOfTotalVnodes -v 4 + +system sh/cfg.sh -n dnode1 -c alternativeRole -v 1 +system sh/cfg.sh -n dnode2 -c alternativeRole -v 2 +system sh/cfg.sh -n dnode3 -c alternativeRole -v 2 +system sh/cfg.sh -n dnode4 -c alternativeRole -v 2 + +system sh/cfg.sh -n dnode1 -c maxtablesPerVnode -v 4 +system sh/cfg.sh -n dnode2 -c maxtablesPerVnode -v 4 +system sh/cfg.sh -n dnode3 -c maxtablesPerVnode -v 4 +system sh/cfg.sh -n dnode4 -c maxtablesPerVnode -v 4 + +system sh/cfg.sh -n dnode1 -c arbitrator -v $arbitrator +system sh/cfg.sh -n dnode2 -c arbitrator -v $arbitrator +system sh/cfg.sh -n dnode3 -c arbitrator -v $arbitrator +system sh/cfg.sh -n dnode4 -c arbitrator -v $arbitrator + +print ============== step0: start tarbitrator +system sh/exec_tarbitrator.sh -s start + +print ============== step1: start dnode1, only deploy mnode +system sh/exec.sh -n dnode1 -s start +sleep 3000 +sql connect + +print ============== step2: start dnode2/dnode3/dnode4 and add into cluster , then create database with replica 2, and create table, insert data +system sh/exec.sh -n dnode2 -s start +system sh/exec.sh -n dnode3 -s start +sql create dnode $hostname2 +sql create dnode $hostname3 +sleep 3000 + +$totalTableNum = 10 +$sleepTimer = 3000 + +$db = db +sql create database $db replica 2 maxTables $totalTableNum +sql use $db + +# create table , insert data +$stb = stb +sql create table $stb (ts timestamp, c1 int) tags(t1 int) +$rowNum = 100 +$tblNum = $totalTableNum +$totalRows = 0 +$tsStart = 1420041600000 + +$i = 0 +while $i < $tblNum + $tb = tb . $i + sql create table $tb using $stb tags( $i ) + + $x = 0 + while $x < $rowNum + $ts = $tsStart + $x + sql insert into $tb values ( $ts + 0a , $x ) ( $ts + 1a , $x ) ( $ts + 2a , $x ) ( $ts + 3a , $x ) ( $ts + 4a , $x ) ( $ts + 5a , $x ) ( $ts + 6a , $x ) ( $ts + 7a , $x ) ( $ts + 8a , $x ) ( $ts + 9a , $x ) ( $ts + 10a , $x ) ( $ts + 11a , $x ) ( $ts + 12a , $x ) ( $ts + 13a , $x ) ( $ts + 14a , $x ) ( $ts + 15a , $x ) ( $ts + 16a , $x ) ( $ts + 17a , $x ) ( $ts + 18a , $x ) ( $ts + 19a , $x ) ( $ts + 20a , $x ) ( $ts + 21a , $x ) ( $ts + 22a , $x ) ( $ts + 23a , $x ) ( $ts + 24a , $x ) ( $ts + 25a , $x ) ( $ts + 26a , $x ) ( $ts + 27a , $x ) ( $ts + 28a , $x ) ( $ts + 29a , $x ) ( $ts + 30a , $x ) ( $ts + 31a , $x ) ( $ts + 32a , $x ) ( $ts + 33a , $x ) ( $ts + 34a , $x ) ( $ts + 25a , $x ) ( $ts + 26a , $x ) ( $ts + 27a , $x ) ( $ts + 28a , $x ) ( $ts + 29a , $x ) ( $ts + 30a , $x ) ( $ts + 31a , $x ) ( $ts + 32a , $x ) ( $ts + 33a , $x ) ( $ts + 34a , $x ) ( $ts + 35a , $x ) ( $ts + 36a , $x ) ( $ts + 37a , $x ) ( $ts + 38a , $x ) ( $ts + 39a , $x ) ( $ts + 40a , $x ) ( $ts + 41a , $x ) ( $ts + 42a , $x ) ( $ts + 43a , $x ) ( $ts + 44a , $x ) ( $ts + 45a , $x ) ( $ts + 46a , $x ) ( $ts + 47a , $x ) ( $ts + 48a , $x ) ( $ts + 49a , $x ) ( $ts + 50a , $x ) ( $ts + 51a , $x ) ( $ts + 52a , $x ) ( $ts + 53a , $x ) ( $ts + 54a , $x ) ( $ts + 55a , $x ) ( $ts + 56a , $x ) ( $ts + 57a , $x ) ( $ts + 58a , $x ) ( $ts + 59a , $x ) + $x = $x + 60 + endw + $totalRows = $totalRows + $x + print info: inserted $x rows into $tb and totalRows: $totalRows + $i = $i + 1 +endw + +sql select count(*) from $stb +print data00 $data00 +if $data00 != $totalRows then + return -1 +endi + +print ============== step3: stop dnode3, and remove its vnodeX subdirector +system sh/exec.sh -n dnode3 -s stop -x SIGINT +#sleep $sleepTimer + +$loopCnt = 0 +wait_dnode3_offline_0: +$loopCnt = $loopCnt + 1 +if $loopCnt == 10 then + return -1 +endi + +sql show dnodes +if $rows != 3 then + sleep 2000 + goto wait_dnode3_offline_0 +endi +print $data0_1 $data1_1 $data2_1 $data3_1 $data4_1 +print $data0_2 $data1_2 $data2_2 $data3_2 $data4_2 +print $data0_3 $data1_3 $data2_3 $data3_3 $data4_3 +print $data0_4 $data1_4 $data2_4 $data3_4 $data4_4 +$dnode1Status = $data4_1 +$dnode2Status = $data4_2 +$dnode3Status = $data4_3 +$dnode4Status = $data4_4 + +if $dnode3Status != offline then + sleep 2000 + goto wait_dnode3_offline_0 +endi + +$loopCnt = 0 +wait_dnode3_vgroup_offline: +$loopCnt = $loopCnt + 1 +if $loopCnt == 10 then + return -1 +endi + +sql show vgroups +if $rows != 1 then + sleep 2000 + goto wait_dnode3_vgroup_offline +endi +print show vgroups: +print $data0_1 $data1_1 $data2_1 $data3_1 $data4_1 $data5_1 $data6_1 $data7_1 $data8_1 $data9_1 +print $data0_2 $data1_2 $data2_2 $data3_2 $data4_2 $data5_2 $data6_2 $data7_2 $data8_2 $data9_2 +print $data0_3 $data1_3 $data2_3 $data3_3 $data4_3 $data5_3 $data6_3 $data7_3 $data8_3 $data9_3 +$dnode3Vtatus = $data4_2 +$dnode2Vtatus = $data7_2 + +if $dnode3Vtatus != offline then + sleep 2000 + goto wait_dnode3_vgroup_offline +endi +if $dnode2Vtatus != master then + sleep 2000 + goto wait_dnode3_vgroup_offline +endi + +system rm -rf ../../../sim/dnode3/data +#system rm -rf ../../../sim/dnode3/data/vnode/* + +sql select count(*) from $stb +print data00 $data00 +if $data00 != $totalRows then + return -1 +endi + +print ============== step4: restart dnode3, waiting sync end +system sh/exec.sh -n dnode3 -s start +#sleep $sleepTimer + +$loopCnt = 0 +wait_dnode3_reready: +$loopCnt = $loopCnt + 1 +if $loopCnt == 10 then + return -1 +endi + +sql show dnodes +if $rows != 3 then + sleep 2000 + goto wait_dnode3_reready +endi +print $data0_1 $data1_1 $data2_1 $data3_1 $data4_1 +print $data0_2 $data1_2 $data2_2 $data3_2 $data4_2 +print $data0_3 $data1_3 $data2_3 $data3_3 $data4_3 +print $data0_4 $data1_4 $data2_4 $data3_4 $data4_4 +$dnode1Status = $data4_1 +$dnode2Status = $data4_2 +$dnode3Status = $data4_3 +$dnode4Status = $data4_4 + +if $dnode3Status != ready then + sleep 2000 + goto wait_dnode3_reready +endi + +$loopCnt = 0 +wait_dnode3_vgroup_slave: +$loopCnt = $loopCnt + 1 +if $loopCnt == 10 then + return -1 +endi + +sql show vgroups +if $rows != 1 then + sleep 2000 + goto wait_dnode3_vgroup_slave +endi +print show vgroups: +print $data0_1 $data1_1 $data2_1 $data3_1 $data4_1 $data5_1 $data6_1 $data7_1 $data8_1 $data9_1 +print $data0_2 $data1_2 $data2_2 $data3_2 $data4_2 $data5_2 $data6_2 $data7_2 $data8_2 $data9_2 +print $data0_3 $data1_3 $data2_3 $data3_3 $data4_3 $data5_3 $data6_3 $data7_3 $data8_3 $data9_3 +$dnode3Vtatus = $data4_2 +$dnode2Vtatus = $data7_2 + +print dnode2Vtatus: $dnode3Vtatus +print dnode3Vtatus: $dnode3Vtatus +if $dnode3Vtatus != slave then + sleep 2000 + goto wait_dnode3_vgroup_slave +endi +if $dnode2Vtatus != master then + sleep 2000 + goto wait_dnode3_vgroup_slave +endi + +sql select count(*) from $stb +print data00 $data00 +if $data00 != $totalRows then + return -1 +endi + +print ============== step5: stop dnode2, and remove its vnode +system sh/exec.sh -n dnode2 -s stop -x SIGINT +sleep $sleepTimer + +$loopCnt = 0 +wait_dnode2_offline: +$loopCnt = $loopCnt + 1 +if $loopCnt == 10 then + return -1 +endi + +sql show dnodes +if $rows != 3 then + sleep 2000 + goto wait_dnode2_offline +endi +print $data0_1 $data1_1 $data2_1 $data3_1 $data4_1 +print $data0_2 $data1_2 $data2_2 $data3_2 $data4_2 +print $data0_3 $data1_3 $data2_3 $data3_3 $data4_3 +print $data0_4 $data1_4 $data2_4 $data3_4 $data4_4 +$dnode1Status = $data4_1 +$dnode2Status = $data4_2 +$dnode3Status = $data4_3 +$dnode4Status = $data4_4 + +if $dnode2Status != offline then + sleep 2000 + goto wait_dnode2_offline +endi +if $dnode3Status != ready then + sleep 2000 + goto wait_dnode2_offline +endi + +system rm -rf ../../../sim/dnode2/data +#system rm -rf ../../../sim/dnode2/data/vnode/* +#system rm -rf ../../../sim/dnode3/data/vnode/* + +sql select count(*) from $stb +print data00 $data00 +if $data00 != $totalRows then + return -1 +endi + + +print ============== step6: restart dnode2, and check rows +system sh/exec.sh -n dnode2 -s start +#sleep $sleepTimer + +$loopCnt = 0 +wait_dnode2_reready: +$loopCnt = $loopCnt + 1 +if $loopCnt == 10 then + return -1 +endi + +sql show dnodes +if $rows != 3 then + sleep 2000 + goto wait_dnode2_reready +endi +print $data0_1 $data1_1 $data2_1 $data3_1 $data4_1 +print $data0_2 $data1_2 $data2_2 $data3_2 $data4_2 +print $data0_3 $data1_3 $data2_3 $data3_3 $data4_3 +print $data0_4 $data1_4 $data2_4 $data3_4 $data4_4 +$dnode1Status = $data4_1 +$dnode2Status = $data4_2 +$dnode3Status = $data4_3 +$dnode4Status = $data4_4 + +if $dnode3Status != ready then + sleep 2000 + goto wait_dnode2_reready +endi +if $dnode2Status != ready then + sleep 2000 + goto wait_dnode2_reready +endi + +$loopCnt = 0 +wait_dnode2_vgroup_slave: +$loopCnt = $loopCnt + 1 +if $loopCnt == 10 then + return -1 +endi + +sql show vgroups +if $rows != 1 then + sleep 2000 + goto wait_dnode2_vgroup_slave +endi +print show vgroups: +print $data0_1 $data1_1 $data2_1 $data3_1 $data4_1 $data5_1 $data6_1 $data7_1 $data8_1 $data9_1 +print $data0_2 $data1_2 $data2_2 $data3_2 $data4_2 $data5_2 $data6_2 $data7_2 $data8_2 $data9_2 +print $data0_3 $data1_3 $data2_3 $data3_3 $data4_3 $data5_3 $data6_3 $data7_3 $data8_3 $data9_3 +$dnode3Vtatus = $data4_2 +$dnode2Vtatus = $data7_2 + +print dnode4Vtatus: $dnode4Vtatus +print dnode3Vtatus: $dnode3Vtatus +if $dnode3Vtatus != master then + sleep 2000 + goto wait_dnode2_vgroup_slave +endi +if $dnode2Vtatus != slave then + sleep 2000 + goto wait_dnode2_vgroup_slave +endi + +# check using select +sql select count(*) from $stb +print data00 $data00 +if $data00 != $totalRows then + return -1 +endi + +sql insert into $tb values ( now , 20000 ) ( now + 1a, 20001 ) ( now + 2a, 20002 ) +$totalRows = $totalRows + 3 + +sql select count(*) from $stb +print data00 $data00 +if $data00 != $totalRows then + return -1 +endi + +system sh/exec.sh -n dnode3 -s stop -x SIGINT +sql select count(*) from $stb +print data00 $data00 +if $data00 != $totalRows then + return -1 +endi \ No newline at end of file diff --git a/tests/script/unique/arbitrator/dn3_mn1_r3_vnode_delDir.sim b/tests/script/unique/arbitrator/dn3_mn1_r3_vnode_delDir.sim new file mode 100644 index 0000000000000000000000000000000000000000..a05681ece231a4b47dfdb89d6ec95a36a1a651a1 --- /dev/null +++ b/tests/script/unique/arbitrator/dn3_mn1_r3_vnode_delDir.sim @@ -0,0 +1,407 @@ +system sh/stop_dnodes.sh +system sh/deploy.sh -n dnode1 -i 1 +system sh/deploy.sh -n dnode2 -i 2 +system sh/deploy.sh -n dnode3 -i 3 +system sh/deploy.sh -n dnode4 -i 4 + +system sh/cfg.sh -n dnode1 -c numOfMnodes -v 1 +system sh/cfg.sh -n dnode2 -c numOfMnodes -v 1 +system sh/cfg.sh -n dnode3 -c numOfMnodes -v 1 +system sh/cfg.sh -n dnode4 -c numOfMnodes -v 1 + +system sh/cfg.sh -n dnode1 -c walLevel -v 2 +system sh/cfg.sh -n dnode2 -c walLevel -v 2 +system sh/cfg.sh -n dnode3 -c walLevel -v 2 +system sh/cfg.sh -n dnode4 -c walLevel -v 2 + +system sh/cfg.sh -n dnode1 -c balanceInterval -v 10 +system sh/cfg.sh -n dnode2 -c balanceInterval -v 10 +system sh/cfg.sh -n dnode3 -c balanceInterval -v 10 +system sh/cfg.sh -n dnode4 -c balanceInterval -v 10 + +system sh/cfg.sh -n dnode1 -c numOfTotalVnodes -v 4 +system sh/cfg.sh -n dnode2 -c numOfTotalVnodes -v 4 +system sh/cfg.sh -n dnode3 -c numOfTotalVnodes -v 4 +system sh/cfg.sh -n dnode4 -c numOfTotalVnodes -v 4 + +system sh/cfg.sh -n dnode1 -c alternativeRole -v 1 +system sh/cfg.sh -n dnode2 -c alternativeRole -v 2 +system sh/cfg.sh -n dnode3 -c alternativeRole -v 2 +system sh/cfg.sh -n dnode4 -c alternativeRole -v 2 + +system sh/cfg.sh -n dnode1 -c maxtablesPerVnode -v 4 +system sh/cfg.sh -n dnode2 -c maxtablesPerVnode -v 4 +system sh/cfg.sh -n dnode3 -c maxtablesPerVnode -v 4 +system sh/cfg.sh -n dnode4 -c maxtablesPerVnode -v 4 + +system sh/cfg.sh -n dnode1 -c arbitrator -v $arbitrator +system sh/cfg.sh -n dnode2 -c arbitrator -v $arbitrator +system sh/cfg.sh -n dnode3 -c arbitrator -v $arbitrator +system sh/cfg.sh -n dnode4 -c arbitrator -v $arbitrator + +print ============== step0: start tarbitrator +system sh/exec_tarbitrator.sh -s start + +print ============== step1: start dnode1, only deploy mnode +system sh/exec.sh -n dnode1 -s start +sleep 3000 +sql connect + +print ============== step2: start dnode2/dnode3/dnode4 and add into cluster , then create database with replica 3, and create table, insert data +system sh/exec.sh -n dnode2 -s start +system sh/exec.sh -n dnode3 -s start +system sh/exec.sh -n dnode4 -s start +sql create dnode $hostname2 +sql create dnode $hostname3 +sql create dnode $hostname4 +sleep 3000 + +$totalTableNum = 10 +$sleepTimer = 3000 + +$db = db +sql create database $db replica 3 maxTables $totalTableNum +sql use $db + +# create table , insert data +$stb = stb +sql create table $stb (ts timestamp, c1 int) tags(t1 int) +$rowNum = 100 +$tblNum = $totalTableNum +$totalRows = 0 +$tsStart = 1420041600000 + +$i = 0 +while $i < $tblNum + $tb = tb . $i + sql create table $tb using $stb tags( $i ) + + $x = 0 + while $x < $rowNum + $ts = $tsStart + $x + sql insert into $tb values ( $ts + 0a , $x ) ( $ts + 1a , $x ) ( $ts + 2a , $x ) ( $ts + 3a , $x ) ( $ts + 4a , $x ) ( $ts + 5a , $x ) ( $ts + 6a , $x ) ( $ts + 7a , $x ) ( $ts + 8a , $x ) ( $ts + 9a , $x ) ( $ts + 10a , $x ) ( $ts + 11a , $x ) ( $ts + 12a , $x ) ( $ts + 13a , $x ) ( $ts + 14a , $x ) ( $ts + 15a , $x ) ( $ts + 16a , $x ) ( $ts + 17a , $x ) ( $ts + 18a , $x ) ( $ts + 19a , $x ) ( $ts + 20a , $x ) ( $ts + 21a , $x ) ( $ts + 22a , $x ) ( $ts + 23a , $x ) ( $ts + 24a , $x ) ( $ts + 25a , $x ) ( $ts + 26a , $x ) ( $ts + 27a , $x ) ( $ts + 28a , $x ) ( $ts + 29a , $x ) ( $ts + 30a , $x ) ( $ts + 31a , $x ) ( $ts + 32a , $x ) ( $ts + 33a , $x ) ( $ts + 34a , $x ) ( $ts + 25a , $x ) ( $ts + 26a , $x ) ( $ts + 27a , $x ) ( $ts + 28a , $x ) ( $ts + 29a , $x ) ( $ts + 30a , $x ) ( $ts + 31a , $x ) ( $ts + 32a , $x ) ( $ts + 33a , $x ) ( $ts + 34a , $x ) ( $ts + 35a , $x ) ( $ts + 36a , $x ) ( $ts + 37a , $x ) ( $ts + 38a , $x ) ( $ts + 39a , $x ) ( $ts + 40a , $x ) ( $ts + 41a , $x ) ( $ts + 42a , $x ) ( $ts + 43a , $x ) ( $ts + 44a , $x ) ( $ts + 45a , $x ) ( $ts + 46a , $x ) ( $ts + 47a , $x ) ( $ts + 48a , $x ) ( $ts + 49a , $x ) ( $ts + 50a , $x ) ( $ts + 51a , $x ) ( $ts + 52a , $x ) ( $ts + 53a , $x ) ( $ts + 54a , $x ) ( $ts + 55a , $x ) ( $ts + 56a , $x ) ( $ts + 57a , $x ) ( $ts + 58a , $x ) ( $ts + 59a , $x ) + $x = $x + 60 + endw + $totalRows = $totalRows + $x + print info: inserted $x rows into $tb and totalRows: $totalRows + $i = $i + 1 +endw + +sql select count(*) from $stb +print data00 $data00 +if $data00 != $totalRows then + return -1 +endi + +print ============== step3: stop dnode4, and remove its vnodeX subdirector +system sh/exec.sh -n dnode4 -s stop -x SIGINT +sleep $sleepTimer + +$loopCnt = 0 +wait_dnode4_offline_0: +$loopCnt = $loopCnt + 1 +if $loopCnt == 10 then + return -1 +endi + +sql show dnodes +if $rows != 4 then + sleep 2000 + goto wait_dnode4_offline_0 +endi +print $data0_1 $data1_1 $data2_1 $data3_1 $data4_1 +print $data0_2 $data1_2 $data2_2 $data3_2 $data4_2 +print $data0_3 $data1_3 $data2_3 $data3_3 $data4_3 +print $data0_4 $data1_4 $data2_4 $data3_4 $data4_4 +$dnode1Status = $data4_1 +$dnode2Status = $data4_2 +$dnode3Status = $data4_3 +$dnode4Status = $data4_4 + +if $dnode4Status != offline then + sleep 2000 + goto wait_dnode4_offline_0 +endi + +$loopCnt = 0 +wait_dnode4_vgroup_offline: +$loopCnt = $loopCnt + 1 +if $loopCnt == 10 then + return -1 +endi + +sql show vgroups +if $rows != 1 then + sleep 2000 + goto wait_dnode4_vgroup_offline +endi +print show vgroups: +print $data0_1 $data1_1 $data2_1 $data3_1 $data4_1 $data5_1 $data6_1 $data7_1 $data8_1 $data9_1 +print $data0_2 $data1_2 $data2_2 $data3_2 $data4_2 $data5_2 $data6_2 $data7_2 $data8_2 $data9_2 +print $data0_3 $data1_3 $data2_3 $data3_3 $data4_3 $data5_3 $data6_3 $data7_3 $data8_3 $data9_3 +$dnode4Vtatus = $data4_2 +$dnode3Vtatus = $data7_2 + +if $dnode4Vtatus != offline then + sleep 2000 + goto wait_dnode4_vgroup_offline +endi +if $dnode3Vtatus != master then + sleep 2000 + goto wait_dnode4_vgroup_offline +endi + +system rm -rf ../../../sim/dnode4/data +#system rm -rf ../../../sim/dnode4/data/vnode/* + +sql select count(*) from $stb +print data00 $data00 +if $data00 != $totalRows then + return -1 +endi + +print ============== step4: restart dnode4, waiting sync end +system sh/exec.sh -n dnode4 -s start +#sleep $sleepTimer + +$loopCnt = 0 +wait_dnode4_reready: +$loopCnt = $loopCnt + 1 +if $loopCnt == 10 then + return -1 +endi + +sql show dnodes +if $rows != 4 then + sleep 2000 + goto wait_dnode4_reready +endi +print $data0_1 $data1_1 $data2_1 $data3_1 $data4_1 +print $data0_2 $data1_2 $data2_2 $data3_2 $data4_2 +print $data0_3 $data1_3 $data2_3 $data3_3 $data4_3 +print $data0_4 $data1_4 $data2_4 $data3_4 $data4_4 +$dnode1Status = $data4_1 +$dnode2Status = $data4_2 +$dnode3Status = $data4_3 +$dnode4Status = $data4_4 + +if $dnode4Status != ready then + sleep 2000 + goto wait_dnode4_reready +endi + +$loopCnt = 0 +wait_dnode4_vgroup_slave: +$loopCnt = $loopCnt + 1 +if $loopCnt == 10 then + return -1 +endi + +sql show vgroups +if $rows != 1 then + sleep 2000 + goto wait_dnode4_vgroup_slave +endi +print show vgroups: +print $data0_1 $data1_1 $data2_1 $data3_1 $data4_1 $data5_1 $data6_1 $data7_1 $data8_1 $data9_1 +print $data0_2 $data1_2 $data2_2 $data3_2 $data4_2 $data5_2 $data6_2 $data7_2 $data8_2 $data9_2 +print $data0_3 $data1_3 $data2_3 $data3_3 $data4_3 $data5_3 $data6_3 $data7_3 $data8_3 $data9_3 +$dnode4Vtatus = $data4_2 +$dnode3Vtatus = $data7_2 + +print dnode4Vtatus: $dnode4Vtatus +print dnode3Vtatus: $dnode3Vtatus +if $dnode4Vtatus != slave then + sleep 2000 + goto wait_dnode4_vgroup_slave +endi +if $dnode3Vtatus != master then + sleep 2000 + goto wait_dnode4_vgroup_slave +endi + +sql select count(*) from $stb +print data00 $data00 +if $data00 != $totalRows then + return -1 +endi + +print ============== step5: stop dnode3/dnode2, and remove its vnode +system sh/exec.sh -n dnode2 -s stop -x SIGINT +system sh/exec.sh -n dnode3 -s stop -x SIGINT +sleep $sleepTimer + +$loopCnt = 0 +wait_dnode23_offline: +$loopCnt = $loopCnt + 1 +if $loopCnt == 10 then + return -1 +endi + +sql show dnodes +if $rows != 4 then + sleep 2000 + goto wait_dnode23_offline +endi +print $data0_1 $data1_1 $data2_1 $data3_1 $data4_1 +print $data0_2 $data1_2 $data2_2 $data3_2 $data4_2 +print $data0_3 $data1_3 $data2_3 $data3_3 $data4_3 +print $data0_4 $data1_4 $data2_4 $data3_4 $data4_4 +$dnode1Status = $data4_1 +$dnode2Status = $data4_2 +$dnode3Status = $data4_3 +$dnode4Status = $data4_4 + +if $dnode2Status != offline then + sleep 2000 + goto wait_dnode23_offline +endi +if $dnode3Status != offline then + sleep 2000 + goto wait_dnode23_offline +endi +if $dnode4Status != ready then + sleep 2000 + goto wait_dnode23_offline +endi + +system rm -rf ../../../sim/dnode2/data +system rm -rf ../../../sim/dnode3/data +#system rm -rf ../../../sim/dnode2/data/vnode/* +#system rm -rf ../../../sim/dnode3/data/vnode/* + +print ============== step6: restart dnode2/dnode3, and check rows +system sh/exec.sh -n dnode2 -s start +system sh/exec.sh -n dnode3 -s start +sleep $sleepTimer + +$loopCnt = 0 +wait_dnode23_reready: +$loopCnt = $loopCnt + 1 +if $loopCnt == 10 then + return -1 +endi + +sql show dnodes +if $rows != 4 then + sleep 2000 + goto wait_dnode23_reready +endi +print $data0_1 $data1_1 $data2_1 $data3_1 $data4_1 +print $data0_2 $data1_2 $data2_2 $data3_2 $data4_2 +print $data0_3 $data1_3 $data2_3 $data3_3 $data4_3 +print $data0_4 $data1_4 $data2_4 $data3_4 $data4_4 +$dnode1Status = $data4_1 +$dnode2Status = $data4_2 +$dnode3Status = $data4_3 +$dnode4Status = $data4_4 + +if $dnode2Status != ready then + sleep 2000 + goto wait_dnode23_reready +endi +if $dnode3Status != ready then + sleep 2000 + goto wait_dnode23_reready +endi +if $dnode4Status != ready then + sleep 2000 + goto wait_dnode23_reready +endi + +$loopCnt = 0 +wait_dnode4_vgroup_master: +$loopCnt = $loopCnt + 1 +if $loopCnt == 10 then + return -1 +endi + +sql show vgroups +if $rows != 1 then + sleep 2000 + goto wait_dnode4_vgroup_master +endi +print show vgroups: +print $data0_1 $data1_1 $data2_1 $data3_1 $data4_1 $data5_1 $data6_1 $data7_1 $data8_1 $data9_1 +print $data0_2 $data1_2 $data2_2 $data3_2 $data4_2 $data5_2 $data6_2 $data7_2 $data8_2 $data9_2 +print $data0_3 $data1_3 $data2_3 $data3_3 $data4_3 $data5_3 $data6_3 $data7_3 $data8_3 $data9_3 +$dnode4Vtatus = $data4_2 +$dnode3Vtatus = $data7_2 + +print dnode4Vtatus: $dnode4Vtatus +print dnode3Vtatus: $dnode3Vtatus +if $dnode4Vtatus != master then + sleep 2000 + goto wait_dnode4_vgroup_master +endi +if $dnode3Vtatus != slave then + sleep 2000 + goto wait_dnode4_vgroup_master +endi + +# check using select +sql select count(*) from $stb +print data00 $data00 +if $data00 != $totalRows then + return -1 +endi + +sql insert into $tb values ( now , 20000 ) ( now + 1a, 20001 ) ( now + 2a, 20002 ) +$totalRows = $totalRows + 3 + +sql select count(*) from $stb +print data00 $data00 +if $data00 != $totalRows then + return -1 +endi + + +print ============== step7: stop dnode3/dnode2, and cluster unable to provide services +system sh/exec.sh -n dnode2 -s stop -x SIGINT +system sh/exec.sh -n dnode3 -s stop -x SIGINT +sleep 3000 +sql_error select count(*) from $stb + +print ============== step8: restart dnode2, and cluster Still unable to provide services +system sh/exec.sh -n dnode2 -s start +sleep 3000 +sql_error select count(*) from $stb + +print ============== step9: restart dnode3, and cluster Resume service delivery +system sh/exec.sh -n dnode3 -s start + +$loopCnt = 0 +wait_dnode4_vgroup_master_2: +$loopCnt = $loopCnt + 1 +if $loopCnt == 10 then + return -1 +endi + +sql show vgroups +if $rows != 1 then + sleep 2000 + goto wait_dnode4_vgroup_master_2 +endi +print show vgroups: +print $data0_1 $data1_1 $data2_1 $data3_1 $data4_1 $data5_1 $data6_1 $data7_1 $data8_1 $data9_1 +print $data0_2 $data1_2 $data2_2 $data3_2 $data4_2 $data5_2 $data6_2 $data7_2 $data8_2 $data9_2 +print $data0_3 $data1_3 $data2_3 $data3_3 $data4_3 $data5_3 $data6_3 $data7_3 $data8_3 $data9_3 +$dnode4Vtatus = $data4_2 +$dnode3Vtatus = $data7_2 + +print dnode4Vtatus: $dnode4Vtatus +print dnode3Vtatus: $dnode3Vtatus +if $dnode4Vtatus != master then + sleep 2000 + goto wait_dnode4_vgroup_master_2 +endi +if $dnode3Vtatus != slave then + sleep 2000 + goto wait_dnode4_vgroup_master_2 +endi + +sql select count(*) from $stb +print data00 $data00 +if $data00 != $totalRows then + return -1 +endi diff --git a/tests/script/unique/arbitrator/dn3_mn1_vnode_delDir.sim b/tests/script/unique/arbitrator/dn3_mn1_vnode_delDir.sim index 82f2aad07b79858379e4b3d9e8355b1ad693f1d1..cf20122d4c6a4a4d0b795af287bd156fe1681708 100644 --- a/tests/script/unique/arbitrator/dn3_mn1_vnode_delDir.sim +++ b/tests/script/unique/arbitrator/dn3_mn1_vnode_delDir.sim @@ -7,6 +7,7 @@ system sh/deploy.sh -n dnode4 -i 4 system sh/cfg.sh -n dnode1 -c numOfMnodes -v 1 system sh/cfg.sh -n dnode2 -c numOfMnodes -v 1 system sh/cfg.sh -n dnode3 -c numOfMnodes -v 1 +system sh/cfg.sh -n dnode4 -c numOfMnodes -v 1 system sh/cfg.sh -n dnode1 -c walLevel -v 2 system sh/cfg.sh -n dnode2 -c walLevel -v 2 @@ -32,11 +33,11 @@ system sh/cfg.sh -n dnode1 -c maxtablesPerVnode -v 4 system sh/cfg.sh -n dnode2 -c maxtablesPerVnode -v 4 system sh/cfg.sh -n dnode3 -c maxtablesPerVnode -v 4 system sh/cfg.sh -n dnode4 -c maxtablesPerVnode -v 4 -system sh/cfg.sh -n dnode5 -c maxtablesPerVnode -v 4 system sh/cfg.sh -n dnode1 -c arbitrator -v $arbitrator system sh/cfg.sh -n dnode2 -c arbitrator -v $arbitrator system sh/cfg.sh -n dnode3 -c arbitrator -v $arbitrator +system sh/cfg.sh -n dnode4 -c arbitrator -v $arbitrator print ============== step0: start tarbitrator system sh/exec_tarbitrator.sh -s start @@ -46,7 +47,7 @@ system sh/exec.sh -n dnode1 -s start sleep 3000 sql connect -print ============== step2: start dnode2/dnode3/dnode4 and add into cluster , then create database with replica 2, and create table, insert data +print ============== step2: start dnode2/dnode3/dnode4 and add into cluster , then create database with replica 3, and create table, insert data system sh/exec.sh -n dnode2 -s start system sh/exec.sh -n dnode3 -s start system sh/exec.sh -n dnode4 -s start @@ -96,7 +97,14 @@ endi print ============== step3: stop dnode4, and remove its vnodeX subdirector system sh/exec.sh -n dnode4 -s stop -x SIGINT sleep $sleepTimer + +$loopCnt = 0 wait_dnode4_offline_0: +$loopCnt = $loopCnt + 1 +if $loopCnt == 10 then + return -1 +endi + sql show dnodes if $rows != 4 then sleep 2000 @@ -105,21 +113,25 @@ endi print $data0_1 $data1_1 $data2_1 $data3_1 $data4_1 print $data0_2 $data1_2 $data2_2 $data3_2 $data4_2 print $data0_3 $data1_3 $data2_3 $data3_3 $data4_3 -#print $data0_4 $data1_4 $data2_4 $data3_4 $data4_4 -#print $data0_5 $data1_5 $data2_5 $data3_5 $data4_5 -#print $data0_6 $data1_6 $data2_6 $data3_6 $data4_6 -#$dnode1Status = $data4_1 +print $data0_4 $data1_4 $data2_4 $data3_4 $data4_4 +$dnode1Status = $data4_1 $dnode2Status = $data4_2 $dnode3Status = $data4_3 $dnode4Status = $data4_4 -#$dnode5Status = $data4_5 if $dnode4Status != offline then sleep 2000 goto wait_dnode4_offline_0 endi + +$loopCnt = 0 wait_dnode4_vgroup_offline: +$loopCnt = $loopCnt + 1 +if $loopCnt == 10 then + return -1 +endi + sql show vgroups if $rows != 1 then sleep 2000 @@ -141,14 +153,19 @@ if $dnode3Vtatus != master then goto wait_dnode4_vgroup_offline endi - system rm -rf ../../../sim/dnode4/data/vnode/* -sleep 1000 print ============== step4: restart dnode4, waiting sync end system sh/exec.sh -n dnode4 -s start sleep $sleepTimer + +$loopCnt = 0 wait_dnode4_reready: +$loopCnt = $loopCnt + 1 +if $loopCnt == 10 then + return -1 +endi + sql show dnodes if $rows != 4 then sleep 2000 @@ -157,21 +174,24 @@ endi print $data0_1 $data1_1 $data2_1 $data3_1 $data4_1 print $data0_2 $data1_2 $data2_2 $data3_2 $data4_2 print $data0_3 $data1_3 $data2_3 $data3_3 $data4_3 -#print $data0_4 $data1_4 $data2_4 $data3_4 $data4_4 -#print $data0_5 $data1_5 $data2_5 $data3_5 $data4_5 -#print $data0_6 $data1_6 $data2_6 $data3_6 $data4_6 -#$dnode1Status = $data4_1 +print $data0_4 $data1_4 $data2_4 $data3_4 $data4_4 +$dnode1Status = $data4_1 $dnode2Status = $data4_2 $dnode3Status = $data4_3 $dnode4Status = $data4_4 -#$dnode5Status = $data4_5 if $dnode4Status != ready then sleep 2000 goto wait_dnode4_reready endi +$loopCnt = 0 wait_dnode4_vgroup_slave: +$loopCnt = $loopCnt + 1 +if $loopCnt == 10 then + return -1 +endi + sql show vgroups if $rows != 1 then sleep 2000 @@ -195,47 +215,87 @@ if $dnode3Vtatus != master then goto wait_dnode4_vgroup_slave endi -print ============== step5: stop dnode3/dnode2, and check rows -system sh/exec.sh -n dnode2 -s stop -system sh/exec.sh -n dnode3 -s stop +print ============== step5: stop dnode3, and remove its vnodeX subdirector +system sh/exec.sh -n dnode3 -s stop -x SIGINT sleep $sleepTimer -wait_dnode23_offline: +$loopCnt = 0 +wait_dnode3_offline: +$loopCnt = $loopCnt + 1 +if $loopCnt == 10 then + return -1 +endi + sql show dnodes if $rows != 4 then sleep 2000 - goto wait_dnode23_offline + goto wait_dnode3_offline endi print $data0_1 $data1_1 $data2_1 $data3_1 $data4_1 print $data0_2 $data1_2 $data2_2 $data3_2 $data4_2 print $data0_3 $data1_3 $data2_3 $data3_3 $data4_3 print $data0_4 $data1_4 $data2_4 $data3_4 $data4_4 -#print $data0_5 $data1_5 $data2_5 $data3_5 $data4_5 -#print $data0_6 $data1_6 $data2_6 $data3_6 $data4_6 -#$dnode1Status = $data4_1 +$dnode1Status = $data4_1 $dnode2Status = $data4_2 $dnode3Status = $data4_3 $dnode4Status = $data4_4 -#$dnode5Status = $data4_5 -if $dnode2Status != offline then +if $dnode2Status != ready then sleep 2000 - goto wait_dnode23_offline + goto wait_dnode3_offline endi if $dnode3Status != offline then sleep 2000 - goto wait_dnode23_offline + goto wait_dnode3_offline endi if $dnode4Status != ready then sleep 2000 - goto wait_dnode23_offline + goto wait_dnode3_offline +endi + +system rm -rf ../../../sim/dnode3/data/vnode/* + +print ============== step6: restart dnode3, and check rows +system sh/exec.sh -n dnode3 -s start +sleep $sleepTimer + +$loopCnt = 0 +wait_dnode3_reready: +$loopCnt = $loopCnt + 1 +if $loopCnt == 10 then + return -1 +endi + +sql show dnodes +if $rows != 4 then + sleep 2000 + goto wait_dnode3_reready +endi +print $data0_1 $data1_1 $data2_1 $data3_1 $data4_1 +print $data0_2 $data1_2 $data2_2 $data3_2 $data4_2 +print $data0_3 $data1_3 $data2_3 $data3_3 $data4_3 +print $data0_4 $data1_4 $data2_4 $data3_4 $data4_4 +$dnode1Status = $data4_1 +$dnode2Status = $data4_2 +$dnode3Status = $data4_3 +$dnode4Status = $data4_4 + +if $dnode3Status != ready then + sleep 2000 + goto wait_dnode3_reready +endi + +$loopCnt = 0 +wait_dnode3_vgroup_slave: +$loopCnt = $loopCnt + 1 +if $loopCnt == 10 then + return -1 endi -wait_dnode4_vgroup_master: sql show vgroups if $rows != 1 then sleep 2000 - goto wait_dnode4_vgroup_master + goto wait_dnode3_vgroup_slave endi print show vgroups: print $data0_1 $data1_1 $data2_1 $data3_1 $data4_1 $data5_1 $data6_1 $data7_1 $data8_1 $data9_1 @@ -248,11 +308,11 @@ print dnode4Vtatus: $dnode4Vtatus print dnode3Vtatus: $dnode3Vtatus if $dnode4Vtatus != master then sleep 2000 - goto wait_dnode4_vgroup_master + goto wait_dnode3_vgroup_slave endi -if $dnode3Vtatus != offline then +if $dnode3Vtatus != slave then sleep 2000 - goto wait_dnode4_vgroup_master + goto wait_dnode3_vgroup_slave endi # check using select @@ -271,3 +331,128 @@ if $data00 != $totalRows then return -1 endi +print ============== step7: stop dnode2, and remove its vnodeX subdirector +system sh/exec.sh -n dnode2 -s stop -x SIGINT +sleep $sleepTimer + +$loopCnt = 0 +wait_dnode2_offline: +$loopCnt = $loopCnt + 1 +if $loopCnt == 10 then + return -1 +endi + +sql show dnodes +if $rows != 4 then + sleep 2000 + goto wait_dnode2_offline +endi +print $data0_1 $data1_1 $data2_1 $data3_1 $data4_1 +print $data0_2 $data1_2 $data2_2 $data3_2 $data4_2 +print $data0_3 $data1_3 $data2_3 $data3_3 $data4_3 +print $data0_4 $data1_4 $data2_4 $data3_4 $data4_4 +$dnode1Status = $data4_1 +$dnode2Status = $data4_2 +$dnode3Status = $data4_3 +$dnode4Status = $data4_4 + +if $dnode2Status != offline then + sleep 2000 + goto wait_dnode2_offline +endi +if $dnode3Status != ready then + sleep 2000 + goto wait_dnode2_offline +endi +if $dnode4Status != ready then + sleep 2000 + goto wait_dnode2_offline +endi + +system rm -rf ../../../sim/dnode2/data/vnode/* + +print ============== step8: restart dnode2, and check rows +system sh/exec.sh -n dnode2 -s start +sleep $sleepTimer + +$loopCnt = 0 +wait_dnode2_reready: +$loopCnt = $loopCnt + 1 +if $loopCnt == 10 then + return -1 +endi + +sql show dnodes +if $rows != 4 then + sleep 2000 + goto wait_dnode2_reready +endi +print $data0_1 $data1_1 $data2_1 $data3_1 $data4_1 +print $data0_2 $data1_2 $data2_2 $data3_2 $data4_2 +print $data0_3 $data1_3 $data2_3 $data3_3 $data4_3 +print $data0_4 $data1_4 $data2_4 $data3_4 $data4_4 +$dnode1Status = $data4_1 +$dnode2Status = $data4_2 +$dnode3Status = $data4_3 +$dnode4Status = $data4_4 + +if $dnode2Status != ready then + sleep 2000 + goto wait_dnode2_reready +endi + +$loopCnt = 0 +wait_dnode2_vgroup_slave: +$loopCnt = $loopCnt + 1 +if $loopCnt == 10 then + return -1 +endi + +sql show vgroups +if $rows != 1 then + sleep 2000 + goto wait_dnode2_vgroup_slave +endi +print show vgroups: +print $data0_1 $data1_1 $data2_1 $data3_1 $data4_1 $data5_1 $data6_1 $data7_1 $data8_1 $data9_1 +print $data0_2 $data1_2 $data2_2 $data3_2 $data4_2 $data5_2 $data6_2 $data7_2 $data8_2 $data9_2 +print $data0_3 $data1_3 $data2_3 $data3_3 $data4_3 $data5_3 $data6_3 $data7_3 $data8_3 $data9_3 +$dnode4Vtatus = $data4_2 +$dnode3Vtatus = $data7_2 + +print dnode4Vtatus: $dnode4Vtatus +print dnode3Vtatus: $dnode3Vtatus +if $dnode4Vtatus != master then + sleep 2000 + goto wait_dnode2_vgroup_slave +endi +if $dnode3Vtatus != slave then + sleep 2000 + goto wait_dnode2_vgroup_slave +endi + +# check using select +sql select count(*) from $stb +print data00 $data00 +if $data00 != $totalRows then + return -1 +endi + +sql insert into $tb values ( now , 20000 ) ( now + 1a, 20001 ) ( now + 2a, 20002 ) +$totalRows = $totalRows + 3 + +sql select count(*) from $stb +print data00 $data00 +if $data00 != $totalRows then + return -1 +endi + + + + + + + + + + diff --git a/tests/script/unique/arbitrator/testSuite.sim b/tests/script/unique/arbitrator/testSuite.sim index 53160812b0ed1f2b863ee66e8ad8b03e2e80e0c7..b6678633276aa3bc7f22c325fede37a8660d3f9c 100644 --- a/tests/script/unique/arbitrator/testSuite.sim +++ b/tests/script/unique/arbitrator/testSuite.sim @@ -12,7 +12,9 @@ run unique/arbitrator/dn3_mn1_vnode_change.sim run unique/arbitrator/dn3_mn1_vnode_corruptFile_offline.sim run unique/arbitrator/dn3_mn1_vnode_corruptFile_online.sim run unique/arbitrator/dn3_mn1_vnode_noCorruptFile_offline.sim -####run unique/arbitrator/dn3_mn1_vnode_delDir.sim # unsupport +run unique/arbitrator/dn3_mn1_vnode_delDir.sim +run unique/arbitrator/dn3_mn1_r2_vnode_delDir.sim +run unique/arbitrator/dn3_mn1_r3_vnode_delDir.sim run unique/arbitrator/dn3_mn1_vnode_nomaster.sim run unique/arbitrator/dn3_mn2_killDnode.sim run unique/arbitrator/insert_duplicationTs.sim @@ -34,4 +36,4 @@ run unique/arbitrator/sync_replica2_dropTable.sim run unique/arbitrator/sync_replica3_alterTable_add.sim run unique/arbitrator/sync_replica3_alterTable_drop.sim run unique/arbitrator/sync_replica3_dropDb.sim -run unique/arbitrator/sync_replica3_dropTable.sim \ No newline at end of file +run unique/arbitrator/sync_replica3_dropTable.sim diff --git a/tests/tsim/src/simExe.c b/tests/tsim/src/simExe.c index aba9714f0acb38916be25640009aba54af9881c9..048ee0486642217b5b8093b8c1571092c5017a39 100644 --- a/tests/tsim/src/simExe.c +++ b/tests/tsim/src/simExe.c @@ -652,6 +652,7 @@ bool simExecuteNativeSqlCommand(SScript *script, char *rest, bool isSlow) { if (line->errorJump == SQL_JUMP_TRUE) { script->linePos = line->jump; + taos_free_result(pSql); return true; } taosMsleep(1000);