Merge branch '3.0' of github.com:taosdata/tdengine into 3.0
This commit is contained in:
commit
5a4f137b14
|
@ -50,6 +50,11 @@ if(${BUILD_WITH_LUCENE})
|
||||||
cat("${CMAKE_SUPPORT_DIR}/lucene_CMakeLists.txt.in" ${DEPS_TMP_FILE})
|
cat("${CMAKE_SUPPORT_DIR}/lucene_CMakeLists.txt.in" ${DEPS_TMP_FILE})
|
||||||
endif(${BUILD_WITH_LUCENE})
|
endif(${BUILD_WITH_LUCENE})
|
||||||
|
|
||||||
|
## NuRaft
|
||||||
|
if(${BUILD_WITH_NURAFT})
|
||||||
|
cat("${CMAKE_SUPPORT_DIR}/nuraft_CMakeLists.txt.in" ${DEPS_TMP_FILE})
|
||||||
|
endif(${BUILD_WITH_NURAFT})
|
||||||
|
|
||||||
## download dependencies
|
## download dependencies
|
||||||
configure_file(${DEPS_TMP_FILE} "${CMAKE_SOURCE_DIR}/deps/deps-download/CMakeLists.txt")
|
configure_file(${DEPS_TMP_FILE} "${CMAKE_SOURCE_DIR}/deps/deps-download/CMakeLists.txt")
|
||||||
execute_process(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" .
|
execute_process(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" .
|
||||||
|
@ -69,4 +74,7 @@ target_include_directories(api INTERFACE "include/client")
|
||||||
# src
|
# src
|
||||||
add_subdirectory(source)
|
add_subdirectory(source)
|
||||||
|
|
||||||
|
# docs
|
||||||
|
add_subdirectory(docs)
|
||||||
|
|
||||||
# tests (TODO)
|
# tests (TODO)
|
||||||
|
|
|
@ -142,7 +142,7 @@ pipeline {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// stage('Parallel test stage') {
|
// stage('Parallel test stage') {
|
||||||
// //only build pr
|
// skip defaultCheckout
|
||||||
// options { skipDefaultCheckout() }
|
// options { skipDefaultCheckout() }
|
||||||
// when {
|
// when {
|
||||||
// allOf{
|
// allOf{
|
||||||
|
|
|
@ -16,7 +16,7 @@ option(
|
||||||
option(
|
option(
|
||||||
BUILD_WITH_ROCKSDB
|
BUILD_WITH_ROCKSDB
|
||||||
"If build with rocksdb"
|
"If build with rocksdb"
|
||||||
OFF
|
ON
|
||||||
)
|
)
|
||||||
|
|
||||||
option(
|
option(
|
||||||
|
@ -25,8 +25,20 @@ option(
|
||||||
OFF
|
OFF
|
||||||
)
|
)
|
||||||
|
|
||||||
|
option(
|
||||||
|
BUILD_WITH_NURAFT
|
||||||
|
"If build with NuRaft"
|
||||||
|
OFF
|
||||||
|
)
|
||||||
|
|
||||||
option(
|
option(
|
||||||
BUILD_DEPENDENCY_TESTS
|
BUILD_DEPENDENCY_TESTS
|
||||||
"If build dependency tests"
|
"If build dependency tests"
|
||||||
OFF
|
OFF
|
||||||
|
)
|
||||||
|
|
||||||
|
option(
|
||||||
|
BUILD_DOCS
|
||||||
|
"If use doxygen build documents"
|
||||||
|
ON
|
||||||
)
|
)
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
# NuRaft
|
||||||
|
ExternalProject_Add(NuRaft
|
||||||
|
GIT_REPOSITORY https://github.com/eBay/NuRaft.git
|
||||||
|
GIT_TAG v1.3.0
|
||||||
|
SOURCE_DIR "${CMAKE_SOURCE_DIR}/deps/nuraft"
|
||||||
|
BINARY_DIR "${CMAKE_SOURCE_DIR}/deps/nuraft"
|
||||||
|
CONFIGURE_COMMAND "./prepare.sh"
|
||||||
|
BUILD_COMMAND ""
|
||||||
|
INSTALL_COMMAND ""
|
||||||
|
TEST_COMMAND ""
|
||||||
|
)
|
|
@ -67,6 +67,12 @@ if(${BUILD_WITH_LUCENE})
|
||||||
add_subdirectory(lucene)
|
add_subdirectory(lucene)
|
||||||
endif(${BUILD_WITH_LUCENE})
|
endif(${BUILD_WITH_LUCENE})
|
||||||
|
|
||||||
|
# NuRaft
|
||||||
|
if(${BUILD_WITH_NURAFT})
|
||||||
|
add_subdirectory(nuraft)
|
||||||
|
endif(${BUILD_WITH_NURAFT})
|
||||||
|
|
||||||
|
|
||||||
# ================================================================================================
|
# ================================================================================================
|
||||||
# DEPENDENCY TEST
|
# DEPENDENCY TEST
|
||||||
# ================================================================================================
|
# ================================================================================================
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Generate API documentation
|
||||||
|
## https://vicrucann.github.io/tutorials/quick-cmake-doxygen/
|
||||||
|
if(${BUILD_DOCS})
|
||||||
|
find_package(Doxygen)
|
||||||
|
if (DOXYGEN_FOUND)
|
||||||
|
# Build the doc
|
||||||
|
set(DOXYGEN_IN ${CMAKE_SOURCE_DIR}/docs/Doxyfile.in)
|
||||||
|
set(DOXYGEN_OUT ${CMAKE_BINARY_DIR}/Doxyfile)
|
||||||
|
|
||||||
|
configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT} @ONLY)
|
||||||
|
message("Doxygen build start")
|
||||||
|
|
||||||
|
add_custom_target(
|
||||||
|
tdengine_doxygen ALL
|
||||||
|
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT}
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
COMMENT "Generating API doxumentation with Doxygen"
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
else(DOXYGEN_FOUND)
|
||||||
|
message("Doxygen need to be installed to generate the doxygen documentation")
|
||||||
|
endif(DOXYGEN_FOUND)
|
||||||
|
endif(${BUILD_DOCS})
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_TREQUEST_H_
|
||||||
|
#define _TD_TREQUEST_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ------------------------ TYPES EXPOSED ------------------------ */
|
||||||
|
typedef struct SRequest SRequest;
|
||||||
|
typedef struct SReqBatch SReqBatch;
|
||||||
|
typedef struct SReqBatchIter SReqBatchIter;
|
||||||
|
|
||||||
|
// SRequest
|
||||||
|
|
||||||
|
// SReqBatch
|
||||||
|
|
||||||
|
// SReqBatchIter
|
||||||
|
void tdInitRBIter(SReqBatchIter *pIter, SReqBatch *pReqBatch);
|
||||||
|
const SRequest *tdRBIterNext(SReqBatchIter *pIter);
|
||||||
|
void tdClearRBIter(SReqBatchIter *pIter);
|
||||||
|
|
||||||
|
/* ------------------------ TYPES DEFINITION ------------------------ */
|
||||||
|
struct SReqBatchIter {
|
||||||
|
int iReq;
|
||||||
|
SReqBatch *pReqBatch;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*_TD_TREQUEST_H_*/
|
|
@ -26,13 +26,13 @@ extern "C" {
|
||||||
typedef int32_t SyncNodeId;
|
typedef int32_t SyncNodeId;
|
||||||
typedef int32_t SyncGroupId;
|
typedef int32_t SyncGroupId;
|
||||||
typedef int64_t SyncIndex;
|
typedef int64_t SyncIndex;
|
||||||
typedef uint64_t SSyncTerm;
|
typedef uint64_t SyncTerm;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
TAOS_SYNC_ROLE_FOLLOWER = 0,
|
TAOS_SYNC_STATE_FOLLOWER = 0,
|
||||||
TAOS_SYNC_ROLE_CANDIDATE = 1,
|
TAOS_SYNC_STATE_CANDIDATE = 1,
|
||||||
TAOS_SYNC_ROLE_LEADER = 2,
|
TAOS_SYNC_STATE_LEADER = 2,
|
||||||
} ESyncRole;
|
} ESyncState;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
void* data;
|
void* data;
|
||||||
|
@ -55,19 +55,19 @@ typedef struct {
|
||||||
int32_t selfIndex;
|
int32_t selfIndex;
|
||||||
int32_t replica;
|
int32_t replica;
|
||||||
SNodeInfo node[TSDB_MAX_REPLICA];
|
SNodeInfo node[TSDB_MAX_REPLICA];
|
||||||
ESyncRole role[TSDB_MAX_REPLICA];
|
ESyncState role[TSDB_MAX_REPLICA];
|
||||||
} SNodesRole;
|
} SNodesRole;
|
||||||
|
|
||||||
typedef struct SSyncFSM {
|
typedef struct SSyncFSM {
|
||||||
void* pData;
|
void* pData;
|
||||||
|
|
||||||
// apply committed log, bufs will be free by raft module
|
// apply committed log, bufs will be free by sync module
|
||||||
int32_t (*applyLog)(struct SSyncFSM* fsm, SyncIndex index, const SSyncBuffer* buf, void* pData);
|
int32_t (*applyLog)(struct SSyncFSM* fsm, SyncIndex index, const SSyncBuffer* buf, void* pData);
|
||||||
|
|
||||||
// cluster commit callback
|
// cluster commit callback
|
||||||
int32_t (*onClusterChanged)(struct SSyncFSM* fsm, const SSyncCluster* cluster, void* pData);
|
int32_t (*onClusterChanged)(struct SSyncFSM* fsm, const SSyncCluster* cluster, void* pData);
|
||||||
|
|
||||||
// fsm return snapshot in ppBuf, bufs will be free by raft module
|
// fsm return snapshot in ppBuf, bufs will be free by sync module
|
||||||
// TODO: getSnapshot SHOULD be async?
|
// TODO: getSnapshot SHOULD be async?
|
||||||
int32_t (*getSnapshot)(struct SSyncFSM* fsm, SSyncBuffer** ppBuf, int32_t* objId, bool* isLast);
|
int32_t (*getSnapshot)(struct SSyncFSM* fsm, SSyncBuffer** ppBuf, int32_t* objId, bool* isLast);
|
||||||
|
|
||||||
|
@ -89,19 +89,30 @@ typedef struct SSyncLogStore {
|
||||||
// write log with given index
|
// write log with given index
|
||||||
int32_t (*logWrite)(struct SSyncLogStore* logStore, SyncIndex index, SSyncBuffer* pBuf);
|
int32_t (*logWrite)(struct SSyncLogStore* logStore, SyncIndex index, SSyncBuffer* pBuf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* read log from given index(included) with limit, return the actual num in nBuf,
|
||||||
|
* pBuf will be free in sync module
|
||||||
|
**/
|
||||||
|
int32_t (*logRead)(struct SSyncLogStore* logStore, SyncIndex index, int limit,
|
||||||
|
SSyncBuffer* pBuf, int* nBuf);
|
||||||
|
|
||||||
// mark log with given index has been commtted
|
// mark log with given index has been commtted
|
||||||
int32_t (*logCommit)(struct SSyncLogStore* logStore, SyncIndex index);
|
int32_t (*logCommit)(struct SSyncLogStore* logStore, SyncIndex index);
|
||||||
|
|
||||||
// prune log before given index
|
// prune log before given index(not included)
|
||||||
int32_t (*logPrune)(struct SSyncLogStore* logStore, SyncIndex index);
|
int32_t (*logPrune)(struct SSyncLogStore* logStore, SyncIndex index);
|
||||||
|
|
||||||
// rollback log after given index
|
// rollback log after given index(included)
|
||||||
int32_t (*logRollback)(struct SSyncLogStore* logStore, SyncIndex index);
|
int32_t (*logRollback)(struct SSyncLogStore* logStore, SyncIndex index);
|
||||||
|
|
||||||
|
// return last index of log
|
||||||
|
SyncIndex (*logLastIndex)(struct SSyncLogStore* logStore);
|
||||||
} SSyncLogStore;
|
} SSyncLogStore;
|
||||||
|
|
||||||
typedef struct SSyncServerState {
|
typedef struct SSyncServerState {
|
||||||
SyncNodeId voteFor;
|
SyncNodeId voteFor;
|
||||||
SSyncTerm term;
|
SyncTerm term;
|
||||||
|
SyncIndex commitIndex;
|
||||||
} SSyncServerState;
|
} SSyncServerState;
|
||||||
|
|
||||||
typedef struct SSyncClusterConfig {
|
typedef struct SSyncClusterConfig {
|
||||||
|
@ -122,9 +133,9 @@ typedef struct SStateManager {
|
||||||
|
|
||||||
int32_t (*readServerState)(struct SStateManager* stateMng, SSyncServerState* state);
|
int32_t (*readServerState)(struct SStateManager* stateMng, SSyncServerState* state);
|
||||||
|
|
||||||
// void (*saveCluster)(struct SStateManager* stateMng, const SSyncClusterConfig* cluster);
|
void (*saveCluster)(struct SStateManager* stateMng, const SSyncClusterConfig* cluster);
|
||||||
|
|
||||||
// const SSyncClusterConfig* (*readCluster)(struct SStateManager* stateMng);
|
const SSyncClusterConfig* (*readCluster)(struct SStateManager* stateMng);
|
||||||
} SStateManager;
|
} SStateManager;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -146,13 +157,13 @@ SSyncNode* syncStart(const SSyncInfo*);
|
||||||
void syncReconfig(const SSyncNode*, const SSyncCluster*);
|
void syncReconfig(const SSyncNode*, const SSyncCluster*);
|
||||||
void syncStop(const SSyncNode*);
|
void syncStop(const SSyncNode*);
|
||||||
|
|
||||||
int32_t syncPropose(SSyncNode* syncNode, SSyncBuffer buffer, void* pData, bool isWeak);
|
int32_t syncPropose(SSyncNode* syncNode, const SSyncBuffer* pBuf, void* pData, bool isWeak);
|
||||||
|
|
||||||
// int32_t syncAddNode(SSyncNode syncNode, const SNodeInfo *pNode);
|
int32_t syncAddNode(SSyncNode syncNode, const SNodeInfo *pNode);
|
||||||
|
|
||||||
// int32_t syncRemoveNode(SSyncNode syncNode, const SNodeInfo *pNode);
|
int32_t syncRemoveNode(SSyncNode syncNode, const SNodeInfo *pNode);
|
||||||
|
|
||||||
extern int32_t syncDebugFlag;
|
extern int32_t sDebugFlag;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ extern "C" {
|
||||||
|
|
||||||
void taosRemoveDir(const char *dirname);
|
void taosRemoveDir(const char *dirname);
|
||||||
bool taosDirExist(char *dirname);
|
bool taosDirExist(char *dirname);
|
||||||
bool taosMkDir(char *dirname);
|
bool taosMkDir(const char *dirname);
|
||||||
void taosRemoveOldFiles(char *dirname, int32_t keepDays);
|
void taosRemoveOldFiles(char *dirname, int32_t keepDays);
|
||||||
bool taosExpandDir(char *dirname, char *outname, int32_t maxlen);
|
bool taosExpandDir(char *dirname, char *outname, int32_t maxlen);
|
||||||
bool taosRealPath(char *dirname, int32_t maxlen);
|
bool taosRealPath(char *dirname, int32_t maxlen);
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_META_IMPL_H_
|
||||||
|
#define _TD_META_IMPL_H_
|
||||||
|
|
||||||
|
#include "os.h"
|
||||||
|
|
||||||
|
#include "taosmsg.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
typedef uint64_t tb_uid_t;
|
||||||
|
|
||||||
|
/* ------------------------ SMetaOptions ------------------------ */
|
||||||
|
struct SMetaOptions {
|
||||||
|
size_t lruCacheSize; // LRU cache size
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ------------------------ STbOptions ------------------------ */
|
||||||
|
#define META_NORMAL_TABLE ((uint8_t)1)
|
||||||
|
#define META_SUPER_TABLE ((uint8_t)2)
|
||||||
|
#define META_CHILD_TABLE ((uint8_t)3)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
} SSMAOptions;
|
||||||
|
|
||||||
|
// super table options
|
||||||
|
typedef struct {
|
||||||
|
tb_uid_t uid;
|
||||||
|
STSchema* pSchema;
|
||||||
|
STSchema* pTagSchema;
|
||||||
|
} SSTbOptions;
|
||||||
|
|
||||||
|
// child table options
|
||||||
|
typedef struct {
|
||||||
|
tb_uid_t suid;
|
||||||
|
SKVRow tags;
|
||||||
|
} SCTbOptions;
|
||||||
|
|
||||||
|
// normal table options
|
||||||
|
typedef struct {
|
||||||
|
STSchema* pSchame;
|
||||||
|
} SNTbOptions;
|
||||||
|
|
||||||
|
struct STbOptions {
|
||||||
|
uint8_t type;
|
||||||
|
char* name;
|
||||||
|
uint32_t ttl; // time to live in (SECONDS)
|
||||||
|
SSMAOptions bsma; // Block-wise sma
|
||||||
|
union {
|
||||||
|
SSTbOptions stbOptions;
|
||||||
|
SNTbOptions ntbOptions;
|
||||||
|
SCTbOptions ctbOptions;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*_TD_META_IMPL_H_*/
|
|
@ -16,81 +16,36 @@
|
||||||
#ifndef _TD_META_H_
|
#ifndef _TD_META_H_
|
||||||
#define _TD_META_H_
|
#define _TD_META_H_
|
||||||
|
|
||||||
#include "taosmsg.h"
|
#include "impl/metaImpl.h"
|
||||||
|
|
||||||
#include "os.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ------------------------ APIs Exposed ------------------------ */
|
|
||||||
|
|
||||||
// Types exported
|
// Types exported
|
||||||
typedef uint64_t tb_uid_t;
|
typedef struct SMeta SMeta;
|
||||||
typedef struct SMeta SMeta;
|
typedef struct SMetaOptions SMetaOptions;
|
||||||
typedef struct SMetaOpts SMetaOpts;
|
typedef struct STbOptions STbOptions;
|
||||||
typedef struct SMetaQueryHandle SMetaQueryHandle;
|
|
||||||
typedef struct SMetaQueryOpts SMetaQueryOpts;
|
|
||||||
typedef struct STableOpts STableOpts;
|
|
||||||
|
|
||||||
// SMeta operations
|
// SMeta operations
|
||||||
int metaCreate(const char *path);
|
SMeta *metaOpen(const char *path, const SMetaOptions *);
|
||||||
void metaDestroy(const char *path);
|
|
||||||
SMeta *metaOpen(SMetaOpts *);
|
|
||||||
void metaClose(SMeta *);
|
void metaClose(SMeta *);
|
||||||
int metaCreateTable(SMeta *, const STableOpts *);
|
void metaRemove(const char *path);
|
||||||
int metaDropTable(SMeta *, uint64_t tuid_t);
|
int metaCreateTable(SMeta *pMeta, const STbOptions *);
|
||||||
int metaAlterTable(SMeta *, void *);
|
int metaDropTable(SMeta *pMeta, tb_uid_t uid);
|
||||||
int metaCommit(SMeta *);
|
int metaCommit(SMeta *);
|
||||||
|
|
||||||
// Options
|
// Options
|
||||||
SMetaOpts *metaOptionsCreate();
|
void metaOptionsInit(SMetaOptions *);
|
||||||
void metaOptionsDestroy(SMetaOpts *);
|
void metaOptionsClear(SMetaOptions *);
|
||||||
void metaOptionsSetCache(SMetaOpts *, size_t capacity);
|
|
||||||
|
|
||||||
// SMetaQueryHandle
|
|
||||||
SMetaQueryHandle *metaQueryHandleCreate(SMetaQueryOpts *);
|
|
||||||
void metaQueryHandleDestroy(SMetaQueryHandle *);
|
|
||||||
|
|
||||||
// SMetaQueryOpts
|
|
||||||
SMetaQueryOpts *metaQueryOptionsCreate();
|
|
||||||
void metaQueryOptionsDestroy(SMetaQueryOpts *);
|
|
||||||
|
|
||||||
// STableOpts
|
// STableOpts
|
||||||
#define META_TABLE_OPTS_DECLARE(name) STableOpts name = {0}
|
#define META_TABLE_OPTS_DECLARE(name) STableOpts name = {0}
|
||||||
void metaNormalTableOptsInit(STableOpts *, const char *name, const STSchema *pSchema);
|
void metaNormalTableOptsInit(STbOptions *, const char *name, const STSchema *pSchema);
|
||||||
void metaSuperTableOptsInit(STableOpts *, const char *name, tb_uid_t uid, const STSchema *pSchema,
|
void metaSuperTableOptsInit(STbOptions *, const char *name, tb_uid_t uid, const STSchema *pSchema,
|
||||||
const STSchema *pTagSchema);
|
const STSchema *pTagSchema);
|
||||||
void metaChildTableOptsInit(STableOpts *, const char *name, tb_uid_t suid, const SKVRow tags);
|
void metaChildTableOptsInit(STbOptions *, const char *name, tb_uid_t suid, const SKVRow tags);
|
||||||
void metaTableOptsClear(STableOpts *);
|
void metaTableOptsClear(STbOptions *);
|
||||||
|
|
||||||
/* ------------------------ Impl should hidden ------------------------ */
|
|
||||||
typedef enum { META_INIT_TABLE = 0, META_SUPER_TABLE = 1, META_CHILD_TABLE = 2, META_NORMAL_TABLE = 3 } EMetaTableT;
|
|
||||||
typedef struct SSuperTableOpts {
|
|
||||||
tb_uid_t uid;
|
|
||||||
STSchema *pSchema; // (ts timestamp, a int)
|
|
||||||
STSchema *pTagSchema; // (tag1 binary(10), tag2 int)
|
|
||||||
} SSuperTableOpts;
|
|
||||||
|
|
||||||
typedef struct SChildTableOpts {
|
|
||||||
tb_uid_t suid; // super table uid
|
|
||||||
SKVRow tags; // tag value of the child table
|
|
||||||
} SChildTableOpts;
|
|
||||||
|
|
||||||
typedef struct SNormalTableOpts {
|
|
||||||
STSchema *pSchema;
|
|
||||||
} SNormalTableOpts;
|
|
||||||
|
|
||||||
struct STableOpts {
|
|
||||||
int8_t type;
|
|
||||||
char * name;
|
|
||||||
union {
|
|
||||||
SSuperTableOpts superOpts;
|
|
||||||
SChildTableOpts childOpts;
|
|
||||||
SNormalTableOpts normalOpts;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct STsdbOptions {
|
struct STsdbOptions {
|
||||||
|
size_t lruCacheSize;
|
||||||
/* TODO */
|
/* TODO */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,14 +17,80 @@
|
||||||
#define _TD_VNODE_H_
|
#define _TD_VNODE_H_
|
||||||
|
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
#include "taosmsg.h"
|
#include "trequest.h"
|
||||||
#include "trpc.h"
|
|
||||||
|
#include "meta.h"
|
||||||
|
#include "tq.h"
|
||||||
|
#include "tsdb.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct SVnode SVnode;
|
/* ------------------------ TYPES EXPOSED ------------------------ */
|
||||||
|
typedef struct SVnode SVnode;
|
||||||
|
typedef struct SVnodeOptions SVnodeOptions;
|
||||||
|
|
||||||
|
/* ------------------------ SVnode ------------------------ */
|
||||||
|
SVnode *vnodeOpen(const char *path, const SVnodeOptions *pVnodeOptions);
|
||||||
|
void vnodeClose(SVnode *pVnode);
|
||||||
|
void vnodeDestroy(const char *path);
|
||||||
|
int vnodeProcessWriteReqs(SVnode *pVnode, SReqBatch *pReqBatch);
|
||||||
|
int vnodeApplyWriteRequest(SVnode *pVnode, const SRequest *pRequest);
|
||||||
|
int vnodeProcessReadReq(SVnode *pVnode, SRequest *pReq);
|
||||||
|
int vnodeProcessSyncReq(SVnode *pVnode, SRequest *pReq);
|
||||||
|
|
||||||
|
/* ------------------------ SVnodeOptions ------------------------ */
|
||||||
|
void vnodeOptionsInit(SVnodeOptions *);
|
||||||
|
void vnodeOptionsClear(SVnodeOptions *);
|
||||||
|
|
||||||
|
/* ------------------------ STRUCT DEFINITIONS ------------------------ */
|
||||||
|
struct SVnodeOptions {
|
||||||
|
/**
|
||||||
|
* @brief write buffer size in BYTES
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
uint64_t wsize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief time to live of tables in this vnode
|
||||||
|
* in SECONDS
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
uint32_t ttl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief if time-series requests eventual consistency
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
bool isWeak;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief if the allocator is heap allcator or arena allocator
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
bool isHeapAllocator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief TSDB options
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
STsdbOptions tsdbOptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief META options
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
SMetaOptions metaOptions;
|
||||||
|
// STqOptions tqOptions; // TODO
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ------------------------ FOR COMPILE ------------------------ */
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
|
||||||
|
#include "taosmsg.h"
|
||||||
|
#include "trpc.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char db[TSDB_FULL_DB_NAME_LEN];
|
char db[TSDB_FULL_DB_NAME_LEN];
|
||||||
|
@ -71,8 +137,6 @@ typedef struct {
|
||||||
int32_t vnodeInit(SVnodePara);
|
int32_t vnodeInit(SVnodePara);
|
||||||
void vnodeCleanup();
|
void vnodeCleanup();
|
||||||
|
|
||||||
SVnode *vnodeOpen(int32_t vgId, const char *path);
|
|
||||||
void vnodeClose(SVnode *pVnode);
|
|
||||||
int32_t vnodeAlter(SVnode *pVnode, const SVnodeCfg *pCfg);
|
int32_t vnodeAlter(SVnode *pVnode, const SVnodeCfg *pCfg);
|
||||||
SVnode *vnodeCreate(int32_t vgId, const char *path, const SVnodeCfg *pCfg);
|
SVnode *vnodeCreate(int32_t vgId, const char *path, const SVnodeCfg *pCfg);
|
||||||
void vnodeDrop(SVnode *pVnode);
|
void vnodeDrop(SVnode *pVnode);
|
||||||
|
@ -86,6 +150,8 @@ int32_t vnodeAppendMsg(SVnodeMsg *pMsg, SRpcMsg *pRpcMsg);
|
||||||
void vnodeCleanupMsg(SVnodeMsg *pMsg);
|
void vnodeCleanupMsg(SVnodeMsg *pMsg);
|
||||||
void vnodeProcessMsg(SVnode *pVnode, SVnodeMsg *pMsg, EVnMsgType msgType);
|
void vnodeProcessMsg(SVnode *pVnode, SVnodeMsg *pMsg, EVnMsgType msgType);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License, version 3
|
|
||||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _TD_AMALLOC_H_
|
|
||||||
#define _TD_AMALLOC_H_
|
|
||||||
|
|
||||||
#include "os.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define AMALLOC_APIS \
|
|
||||||
void *(*malloc)(void *, size_t size); \
|
|
||||||
void *(*calloc)(void *, size_t nmemb, size_t size); \
|
|
||||||
void *(*realloc)(void *, size_t size); \
|
|
||||||
void (*free)(void *ptr);
|
|
||||||
|
|
||||||
// Interfaces to implement
|
|
||||||
typedef struct {
|
|
||||||
AMALLOC_APIS
|
|
||||||
} SMemAllocatorIf;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
void *impl;
|
|
||||||
AMALLOC_APIS
|
|
||||||
} SMemAllocator;
|
|
||||||
|
|
||||||
#define amalloc(allocator, size) ((allocator) ? (*((allocator)->malloc))((allocator)->impl, (size)) : malloc(size))
|
|
||||||
#define acalloc(allocator, nmemb, size) \
|
|
||||||
((allocator) ? (*((allocator)->calloc))((allocator)->impl, (nmemb), (size)) : calloc((nmemb), (size)))
|
|
||||||
#define arealloc(allocator, ptr, size) \
|
|
||||||
((allocator) ? (*((allocator)->realloc))((allocator)->impl, (ptr), (size)) : realloc((ptr), (size)))
|
|
||||||
#define afree(allocator, ptr, size) ((allocator) ? (*((allocator)->free))((allocator)->impl, (ptr), (size)) : free(ptr))
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /*_TD_AMALLOC_H_*/
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_MALLOCATOR_H_
|
||||||
|
#define _TD_MALLOCATOR_H_
|
||||||
|
|
||||||
|
#include "os.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct SMemAllocator SMemAllocator;
|
||||||
|
|
||||||
|
#define MALLOCATOR_APIS \
|
||||||
|
void *(*malloc)(SMemAllocator *, size_t size); \
|
||||||
|
void *(*calloc)(SMemAllocator *, size_t nmemb, size_t size); \
|
||||||
|
void *(*realloc)(SMemAllocator *, void *ptr, size_t size); \
|
||||||
|
void (*free)(SMemAllocator *, void *ptr); \
|
||||||
|
size_t (*usage)(SMemAllocator *);
|
||||||
|
|
||||||
|
// Interfaces to implement
|
||||||
|
typedef struct {
|
||||||
|
MALLOCATOR_APIS
|
||||||
|
} SMemAllocatorIf;
|
||||||
|
|
||||||
|
struct SMemAllocator {
|
||||||
|
void * impl;
|
||||||
|
size_t usize;
|
||||||
|
MALLOCATOR_APIS
|
||||||
|
};
|
||||||
|
|
||||||
|
// heap allocator
|
||||||
|
SMemAllocator *tdCreateHeapAllocator();
|
||||||
|
void tdDestroyHeapAllocator(SMemAllocator *pMemAllocator);
|
||||||
|
|
||||||
|
// arena allocator
|
||||||
|
SMemAllocator *tdCreateArenaAllocator(size_t size);
|
||||||
|
void tdDestroyArenaAllocator(SMemAllocator *);
|
||||||
|
|
||||||
|
#define mMalloc(pMemAllocator, size) (*(pMemAllocator->malloc))(pMemAllocator, size)
|
||||||
|
#define mCalloc(pMemAllocator, nmemb, size) (*(pMemAllocator->calloc))(pMemAllocator, nmemb, size)
|
||||||
|
#define mRealloc(pMemAllocator, ptr, size) (*(pMemAllocator->realloc))(pMemAllocator, ptr, size)
|
||||||
|
#define mFree(pMemAllocator, ptr) (*(pMemAllocator->free))(pMemAllocator, ptr)
|
||||||
|
#define mUsage(pMemAllocator) (*(pMemAllocator->usage))(pMemAllocator)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*_TD_MALLOCATOR_H_*/
|
|
@ -376,7 +376,7 @@ static void *dnodeOpenVnodeFunc(void *param) {
|
||||||
|
|
||||||
char path[PATH_MAX + 20] = {0};
|
char path[PATH_MAX + 20] = {0};
|
||||||
snprintf(path, sizeof(path),"%s/vnode%d", tsVnodeDir, pVnode->vgId);
|
snprintf(path, sizeof(path),"%s/vnode%d", tsVnodeDir, pVnode->vgId);
|
||||||
SVnode *pImpl = vnodeOpen(pVnode->vgId, path);
|
SVnode *pImpl = vnodeOpen(path, NULL);
|
||||||
if (pImpl == NULL) {
|
if (pImpl == NULL) {
|
||||||
dError("vgId:%d, failed to open vnode by thread:%d", pVnode->vgId, pThread->threadIndex);
|
dError("vgId:%d, failed to open vnode by thread:%d", pVnode->vgId, pThread->threadIndex);
|
||||||
pThread->failed++;
|
pThread->failed++;
|
||||||
|
|
|
@ -7,6 +7,7 @@ target_include_directories(
|
||||||
)
|
)
|
||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
vnode
|
vnode
|
||||||
|
PUBLIC os
|
||||||
PUBLIC transport
|
PUBLIC transport
|
||||||
PUBLIC meta
|
PUBLIC meta
|
||||||
PUBLIC tq
|
PUBLIC tq
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_VNODE_ALLOCATOR_POOL_H_
|
||||||
|
#define _TD_VNODE_ALLOCATOR_POOL_H_
|
||||||
|
|
||||||
|
#include "vnode.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int nexta;
|
||||||
|
int enda;
|
||||||
|
SMemAllocator *free[3];
|
||||||
|
SMemAllocator *used[3];
|
||||||
|
} SVAllocatorPool;
|
||||||
|
|
||||||
|
int vnodeOpenAllocatorPool(SVnode *pVnode);
|
||||||
|
void vnodeCloseAllocatorPool(SVnode *pVnode);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*_TD_VNODE_ALLOCATOR_POOL_H_*/
|
|
@ -16,13 +16,14 @@
|
||||||
#ifndef _TD_VNODE_COMMIT_H_
|
#ifndef _TD_VNODE_COMMIT_H_
|
||||||
#define _TD_VNODE_COMMIT_H_
|
#define _TD_VNODE_COMMIT_H_
|
||||||
|
|
||||||
#include "vnodeInt.h"
|
#include "vnode.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int vnodeAsyncCommit(SVnode *pVnode);
|
bool vnodeShouldCommit(SVnode *pVnode);
|
||||||
|
int vnodeAsyncCommit(SVnode *pVnode);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_VNODE_DEF_H_
|
||||||
|
#define _TD_VNODE_DEF_H_
|
||||||
|
|
||||||
|
#include "mallocator.h"
|
||||||
|
#include "sync.h"
|
||||||
|
#include "tlockfree.h"
|
||||||
|
|
||||||
|
#include "vnode.h"
|
||||||
|
#include "vnodeAllocatorPool.h"
|
||||||
|
#include "vnodeCommit.h"
|
||||||
|
#include "vnodeFileSystem.h"
|
||||||
|
#include "vnodeOptions.h"
|
||||||
|
#include "vnodeStateMgr.h"
|
||||||
|
#include "vnodeSync.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct SVnode {
|
||||||
|
char* path;
|
||||||
|
SVnodeOptions options;
|
||||||
|
SVState state;
|
||||||
|
SVAllocatorPool* pool;
|
||||||
|
SMemAllocator* inuse;
|
||||||
|
SMeta* pMeta;
|
||||||
|
STsdb* pTsdb;
|
||||||
|
STQ* pTq;
|
||||||
|
SVnodeSync* pSync;
|
||||||
|
SVnodeFS* pFs;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*_TD_VNODE_DEF_H_*/
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_VNODE_FILE_SYSTEM_H_
|
||||||
|
#define _TD_VNODE_FILE_SYSTEM_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
} SVnodeFS;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*_TD_VNODE_FILE_SYSTEM_H_*/
|
|
@ -18,7 +18,6 @@
|
||||||
|
|
||||||
#include "vnode.h"
|
#include "vnode.h"
|
||||||
|
|
||||||
#include "amalloc.h"
|
|
||||||
#include "meta.h"
|
#include "meta.h"
|
||||||
#include "sync.h"
|
#include "sync.h"
|
||||||
#include "tlog.h"
|
#include "tlog.h"
|
||||||
|
@ -39,16 +38,6 @@ extern int32_t vDebugFlag;
|
||||||
#define vDebug(...) { if (vDebugFlag & DEBUG_DEBUG) { taosPrintLog("VND ", vDebugFlag, __VA_ARGS__); }}
|
#define vDebug(...) { if (vDebugFlag & DEBUG_DEBUG) { taosPrintLog("VND ", vDebugFlag, __VA_ARGS__); }}
|
||||||
#define vTrace(...) { if (vDebugFlag & DEBUG_TRACE) { taosPrintLog("VND ", vDebugFlag, __VA_ARGS__); }}
|
#define vTrace(...) { if (vDebugFlag & DEBUG_TRACE) { taosPrintLog("VND ", vDebugFlag, __VA_ARGS__); }}
|
||||||
|
|
||||||
typedef struct SVnode {
|
|
||||||
int32_t vgId;
|
|
||||||
SVnodeCfg cfg;
|
|
||||||
SMeta *pMeta;
|
|
||||||
STsdb *pTsdb;
|
|
||||||
STQ *pTQ;
|
|
||||||
SWal *pWal;
|
|
||||||
SSyncNode *pSync;
|
|
||||||
} SVnode;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -16,40 +16,12 @@
|
||||||
#ifndef _TD_VNODE_MEM_ALLOCATOR_H_
|
#ifndef _TD_VNODE_MEM_ALLOCATOR_H_
|
||||||
#define _TD_VNODE_MEM_ALLOCATOR_H_
|
#define _TD_VNODE_MEM_ALLOCATOR_H_
|
||||||
|
|
||||||
#include "vnodeInt.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct SVnodeMemAllocator SVnodeMemAllocator;
|
|
||||||
|
|
||||||
SVnodeMemAllocator *VMACreate(size_t size /* base size */, size_t ssize /* step size */,
|
|
||||||
size_t threshold /* threshold size when full*/);
|
|
||||||
void VMADestroy(SVnodeMemAllocator *pvma);
|
|
||||||
void VMAReset(SVnodeMemAllocator *pvma);
|
|
||||||
void * VMAMalloc(SVnodeMemAllocator *pvma, size_t size);
|
|
||||||
void VMAFree(SVnodeMemAllocator *pvma, void *ptr);
|
|
||||||
bool VMAIsFull(SVnodeMemAllocator *pvma);
|
|
||||||
|
|
||||||
// ------------------ FOR TEST ONLY ------------------
|
|
||||||
typedef struct SVMANode {
|
|
||||||
struct SVMANode *prev;
|
|
||||||
size_t tsize;
|
|
||||||
size_t used;
|
|
||||||
char data[];
|
|
||||||
} SVMANode;
|
|
||||||
|
|
||||||
struct SVnodeMemAllocator {
|
|
||||||
bool full; // if allocator is full
|
|
||||||
size_t threshold; // threshold;
|
|
||||||
size_t ssize; // step size to allocate
|
|
||||||
SVMANode *inuse; // inuse node to allocate
|
|
||||||
SVMANode node; // basic node to use
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /*_TD_VNODE_MEM_ALLOCATOR_H_*/
|
#endif /*_TD_VNODE_MEM_ALLOCATOR_H_*/
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_VNODE_OPTIONS_H_
|
||||||
|
#define _TD_VNODE_OPTIONS_H_
|
||||||
|
|
||||||
|
#include "vnode.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern const SVnodeOptions defaultVnodeOptions;
|
||||||
|
|
||||||
|
int vnodeValidateOptions(const SVnodeOptions *);
|
||||||
|
void vnodeOptionsCopy(SVnodeOptions *pDest, const SVnodeOptions *pSrc);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*_TD_VNODE_OPTIONS_H_*/
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_VNODE_REQUEST_H_
|
||||||
|
#define _TD_VNODE_REQUEST_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*_TD_VNODE_REQUEST_H_*/
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_VNODE_STATE_MGR_H_
|
||||||
|
#define _TD_VNODE_STATE_MGR_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
} SVState;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*_TD_VNODE_STATE_MGR_H_*/
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_VNODE_SYNC_H_
|
||||||
|
#define _TD_VNODE_SYNC_H_
|
||||||
|
|
||||||
|
#include "sync.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* data */
|
||||||
|
} SVnodeSync;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*_TD_VNODE_SYNC_H_*/
|
|
@ -16,10 +16,11 @@
|
||||||
#ifndef _TD_VNODE_WRITE_H_
|
#ifndef _TD_VNODE_WRITE_H_
|
||||||
#define _TD_VNODE_WRITE_H_
|
#define _TD_VNODE_WRITE_H_
|
||||||
|
|
||||||
|
#include "vnode.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
#include "vnodeInt.h"
|
|
||||||
|
|
||||||
void vnodeProcessWriteMsg(SVnode* pVnode, SVnodeMsg* pMsg);
|
void vnodeProcessWriteMsg(SVnode* pVnode, SVnodeMsg* pMsg);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "vnodeDef.h"
|
||||||
|
|
||||||
|
int vnodeOpenAllocatorPool(SVnode *pVnode) {
|
||||||
|
// TODO
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vnodeCloseAllocatorPool(SVnode *pVnode) {
|
||||||
|
if (pVnode->pool) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------ STATIC METHODS ------------------------ */
|
||||||
|
static SVAllocatorPool *vapCreate() {
|
||||||
|
SVAllocatorPool *pPool = NULL;
|
||||||
|
/* TODO */
|
||||||
|
return pPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vapDestroy() {
|
||||||
|
// TODO
|
||||||
|
}
|
|
@ -13,13 +13,15 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "vnodeInt.h"
|
#include "vnodeDef.h"
|
||||||
|
|
||||||
static int vnodeStartCommit(SVnode *pVnode);
|
static int vnodeStartCommit(SVnode *pVnode);
|
||||||
static int vnodeEndCommit(SVnode *pVnode);
|
static int vnodeEndCommit(SVnode *pVnode);
|
||||||
|
|
||||||
|
bool vnodeShouldCommit(SVnode *pVnode) { return false; }
|
||||||
|
|
||||||
int vnodeAsyncCommit(SVnode *pVnode) {
|
int vnodeAsyncCommit(SVnode *pVnode) {
|
||||||
#if 0
|
#if 0
|
||||||
if (vnodeStartCommit(pVnode) < 0) {
|
if (vnodeStartCommit(pVnode) < 0) {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "vnodeDef.h"
|
|
@ -20,8 +20,6 @@
|
||||||
int32_t vnodeInit(SVnodePara para) { return 0; }
|
int32_t vnodeInit(SVnodePara para) { return 0; }
|
||||||
void vnodeCleanup() {}
|
void vnodeCleanup() {}
|
||||||
|
|
||||||
SVnode *vnodeOpen(int32_t vgId, const char *path) { return NULL; }
|
|
||||||
void vnodeClose(SVnode *pVnode) {}
|
|
||||||
int32_t vnodeAlter(SVnode *pVnode, const SVnodeCfg *pCfg) { return 0; }
|
int32_t vnodeAlter(SVnode *pVnode, const SVnodeCfg *pCfg) { return 0; }
|
||||||
SVnode *vnodeCreate(int32_t vgId, const char *path, const SVnodeCfg *pCfg) { return NULL; }
|
SVnode *vnodeCreate(int32_t vgId, const char *path, const SVnodeCfg *pCfg) { return NULL; }
|
||||||
void vnodeDrop(SVnode *pVnode) {}
|
void vnodeDrop(SVnode *pVnode) {}
|
||||||
|
@ -69,4 +67,4 @@ void vnodeProcessMsg(SVnode *pVnode, SVnodeMsg *pMsg, EVnMsgType msgType) {
|
||||||
case VN_MSG_TYPE_FETCH:
|
case VN_MSG_TYPE_FETCH:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "vnodeDef.h"
|
||||||
|
|
||||||
|
static SVnode *vnodeNew(const char *path, const SVnodeOptions *pVnodeOptions);
|
||||||
|
static void vnodeFree(SVnode *pVnode);
|
||||||
|
static int vnodeOpenImpl(SVnode *pVnode);
|
||||||
|
static void vnodeCloseImpl(SVnode *pVnode);
|
||||||
|
|
||||||
|
SVnode *vnodeOpen(const char *path, const SVnodeOptions *pVnodeOptions) {
|
||||||
|
SVnode *pVnode = NULL;
|
||||||
|
|
||||||
|
// Set default options
|
||||||
|
if (pVnodeOptions == NULL) {
|
||||||
|
pVnodeOptions = &defaultVnodeOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate options
|
||||||
|
if (vnodeValidateOptions(pVnodeOptions) < 0) {
|
||||||
|
// TODO
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the handle
|
||||||
|
pVnode = vnodeNew(path, pVnodeOptions);
|
||||||
|
if (pVnode == NULL) {
|
||||||
|
// TODO: handle error
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
taosMkDir(path);
|
||||||
|
|
||||||
|
// Open the vnode
|
||||||
|
if (vnodeOpenImpl(pVnode) < 0) {
|
||||||
|
// TODO: handle error
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pVnode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vnodeClose(SVnode *pVnode) {
|
||||||
|
if (pVnode) {
|
||||||
|
vnodeCloseImpl(pVnode);
|
||||||
|
vnodeFree(pVnode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vnodeDestroy(const char *path) { taosRemoveDir(path); }
|
||||||
|
|
||||||
|
/* ------------------------ STATIC METHODS ------------------------ */
|
||||||
|
static SVnode *vnodeNew(const char *path, const SVnodeOptions *pVnodeOptions) {
|
||||||
|
SVnode *pVnode = NULL;
|
||||||
|
|
||||||
|
pVnode = (SVnode *)calloc(1, sizeof(*pVnode));
|
||||||
|
if (pVnode == NULL) {
|
||||||
|
// TODO
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pVnode->path = strdup(path);
|
||||||
|
vnodeOptionsCopy(&(pVnode->options), pVnodeOptions);
|
||||||
|
|
||||||
|
return pVnode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vnodeFree(SVnode *pVnode) {
|
||||||
|
if (pVnode) {
|
||||||
|
tfree(pVnode->path);
|
||||||
|
free(pVnode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vnodeOpenImpl(SVnode *pVnode) {
|
||||||
|
char dir[TSDB_FILENAME_LEN];
|
||||||
|
|
||||||
|
// Open allocator pool
|
||||||
|
if (vnodeOpenAllocatorPool(pVnode) < 0) {
|
||||||
|
// TODO: handle error
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open meta
|
||||||
|
sprintf(dir, "%s/meta", pVnode->path);
|
||||||
|
pVnode->pMeta = metaOpen(dir, &(pVnode->options.metaOptions));
|
||||||
|
if (pVnode->pMeta == NULL) {
|
||||||
|
// TODO: handle error
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open tsdb
|
||||||
|
sprintf(dir, "%s/tsdb", pVnode->path);
|
||||||
|
pVnode->pTsdb = tsdbOpen(dir, &(pVnode->options.tsdbOptions));
|
||||||
|
if (pVnode->pTsdb == NULL) {
|
||||||
|
// TODO: handle error
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Open TQ
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vnodeCloseImpl(SVnode *pVnode) {
|
||||||
|
if (pVnode) {
|
||||||
|
vnodeCloseAllocatorPool(pVnode);
|
||||||
|
// TODO: Close TQ
|
||||||
|
tsdbClose(pVnode->pTsdb);
|
||||||
|
metaClose(pVnode->pMeta);
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,112 +13,88 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "vnodeMemAllocator.h"
|
#include "vnodeDef.h"
|
||||||
|
|
||||||
#define VMA_IS_FULL(pvma) \
|
#define VNODE_HEAP_ALLOCATOR 0
|
||||||
(((pvma)->inuse != &((pvma)->node)) || ((pvma)->inuse->tsize - (pvma)->inuse->used < (pvma)->threshold))
|
#define VNODE_ARENA_ALLOCATOR 1
|
||||||
|
|
||||||
static SVMANode *VMANodeNew(size_t size);
|
typedef struct {
|
||||||
static void VMANodeFree(SVMANode *node);
|
uint64_t tsize;
|
||||||
|
uint64_t used;
|
||||||
|
} SVHeapAllocator;
|
||||||
|
|
||||||
SVnodeMemAllocator *VMACreate(size_t size, size_t ssize, size_t threshold) {
|
typedef struct SVArenaNode {
|
||||||
SVnodeMemAllocator *pvma = NULL;
|
struct SVArenaNode *prev;
|
||||||
|
void * nptr;
|
||||||
|
char data[];
|
||||||
|
} SVArenaNode;
|
||||||
|
|
||||||
if (size < threshold) {
|
typedef struct {
|
||||||
|
SVArenaNode *inuse;
|
||||||
|
SVArenaNode node;
|
||||||
|
} SVArenaAllocator;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int8_t type;
|
||||||
|
uint64_t tsize;
|
||||||
|
T_REF_DECLARE()
|
||||||
|
union {
|
||||||
|
SVHeapAllocator vha;
|
||||||
|
SVArenaAllocator vaa;
|
||||||
|
};
|
||||||
|
} SVMemAllocator;
|
||||||
|
|
||||||
|
SMemAllocator *vnodeCreateMemAllocator(int8_t type, uint64_t tsize, uint64_t ssize /* step size only for arena */) {
|
||||||
|
SMemAllocator * pma;
|
||||||
|
uint64_t msize;
|
||||||
|
SVMemAllocator *pva;
|
||||||
|
|
||||||
|
msize = sizeof(*pma) + sizeof(SVMemAllocator);
|
||||||
|
if (type == VNODE_ARENA_ALLOCATOR) {
|
||||||
|
msize += tsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
pma = (SMemAllocator *)calloc(1, msize);
|
||||||
|
if (pma == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pvma = (SVnodeMemAllocator *)malloc(sizeof(*pvma) + size);
|
pma->impl = POINTER_SHIFT(pma, sizeof(*pma));
|
||||||
if (pvma) {
|
pva = (SVMemAllocator *)(pma->impl);
|
||||||
pvma->full = false;
|
pva->type = type;
|
||||||
pvma->threshold = threshold;
|
pva->tsize = tsize;
|
||||||
pvma->ssize = ssize;
|
|
||||||
pvma->inuse = &(pvma->node);
|
|
||||||
|
|
||||||
pvma->inuse->prev = NULL;
|
if (type == VNODE_HEAP_ALLOCATOR) {
|
||||||
pvma->inuse->tsize = size;
|
pma->malloc = NULL;
|
||||||
pvma->inuse->used = 0;
|
pma->calloc = NULL;
|
||||||
|
pma->realloc = NULL;
|
||||||
|
pma->free = NULL;
|
||||||
|
pma->usage = NULL;
|
||||||
|
} else if (type == VNODE_ARENA_ALLOCATOR) {
|
||||||
|
pma->malloc = NULL;
|
||||||
|
pma->calloc = NULL;
|
||||||
|
pma->realloc = NULL;
|
||||||
|
pma->free = NULL;
|
||||||
|
pma->usage = NULL;
|
||||||
|
} else {
|
||||||
|
ASSERT(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pvma;
|
return pma;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMADestroy(SVnodeMemAllocator *pvma) {
|
void vnodeDestroyMemAllocator(SMemAllocator *pma) {
|
||||||
if (pvma) {
|
// TODO
|
||||||
VMAReset(pvma);
|
|
||||||
free(pvma);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMAReset(SVnodeMemAllocator *pvma) {
|
void vnodeRefMemAllocator(SMemAllocator *pma) {
|
||||||
while (pvma->inuse != &(pvma->node)) {
|
// TODO
|
||||||
SVMANode *node = pvma->inuse;
|
|
||||||
pvma->inuse = node->prev;
|
|
||||||
VMANodeFree(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
pvma->inuse->used = 0;
|
|
||||||
pvma->full = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void *VMAMalloc(SVnodeMemAllocator *pvma, size_t size) {
|
void vnodeUnrefMemAllocator(SMemAllocator *pma) {
|
||||||
void * ptr = NULL;
|
// TODO
|
||||||
size_t tsize = size + sizeof(size_t);
|
|
||||||
|
|
||||||
if (pvma->inuse->tsize - pvma->inuse->used < tsize) {
|
|
||||||
SVMANode *pNode = VMANodeNew(MAX(pvma->ssize, tsize));
|
|
||||||
if (pNode == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pNode->prev = pvma->inuse;
|
|
||||||
pvma->inuse = pNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr = pvma->inuse->data + pvma->inuse->used;
|
|
||||||
pvma->inuse->used += tsize;
|
|
||||||
*(size_t *)ptr = size;
|
|
||||||
ptr = POINTER_SHIFT(ptr, sizeof(size_t));
|
|
||||||
|
|
||||||
pvma->full = VMA_IS_FULL(pvma);
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMAFree(SVnodeMemAllocator *pvma, void *ptr) {
|
/* ------------------------ Heap Allocator IMPL ------------------------ */
|
||||||
if (ptr) {
|
|
||||||
size_t size = *(size_t *)POINTER_SHIFT(ptr, -sizeof(size_t));
|
|
||||||
if (POINTER_SHIFT(ptr, size) == pvma->inuse->data + pvma->inuse->used) {
|
|
||||||
pvma->inuse->used -= (size + sizeof(size_t));
|
|
||||||
|
|
||||||
if ((pvma->inuse->used == 0) && (pvma->inuse != &(pvma->node))) {
|
/* ------------------------ Arena Allocator IMPL ------------------------ */
|
||||||
SVMANode *node = pvma->inuse;
|
|
||||||
pvma->inuse = node->prev;
|
|
||||||
VMANodeFree(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
pvma->full = VMA_IS_FULL(pvma);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VMAIsFull(SVnodeMemAllocator *pvma) { return pvma->full; }
|
|
||||||
|
|
||||||
static SVMANode *VMANodeNew(size_t size) {
|
|
||||||
SVMANode *node = NULL;
|
|
||||||
|
|
||||||
node = (SVMANode *)malloc(sizeof(*node) + size);
|
|
||||||
if (node) {
|
|
||||||
node->prev = NULL;
|
|
||||||
node->tsize = size;
|
|
||||||
node->used = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void VMANodeFree(SVMANode *node) {
|
|
||||||
if (node) {
|
|
||||||
free(node);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "vnodeDef.h"
|
||||||
|
|
||||||
|
const SVnodeOptions defaultVnodeOptions = {0}; /* TODO */
|
||||||
|
|
||||||
|
void vnodeOptionsInit(SVnodeOptions *pVnodeOptions) { /* TODO */
|
||||||
|
vnodeOptionsCopy(pVnodeOptions, &defaultVnodeOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vnodeOptionsClear(SVnodeOptions *pVnodeOptions) { /* TODO */
|
||||||
|
}
|
||||||
|
|
||||||
|
int vnodeValidateOptions(const SVnodeOptions *pVnodeOptions) {
|
||||||
|
// TODO
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vnodeOptionsCopy(SVnodeOptions *pDest, const SVnodeOptions *pSrc) {
|
||||||
|
memcpy((void *)pDest, (void *)pSrc, sizeof(SVnodeOptions));
|
||||||
|
}
|
|
@ -13,5 +13,4 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define _DEFAULT_SOURCE
|
#include "vnodeDef.h"
|
||||||
#include "vnodeRead.h"
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
|
@ -13,5 +13,50 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define _DEFAULT_SOURCE
|
#include "vnodeDef.h"
|
||||||
#include "vnodeWrite.h"
|
|
||||||
|
int vnodeProcessWriteReqs(SVnode *pVnode, SReqBatch *pReqBatch) {
|
||||||
|
/* TODO */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vnodeApplyWriteRequest(SVnode *pVnode, const SRequest *pRequest) {
|
||||||
|
int reqType; /* TODO */
|
||||||
|
size_t reqSize; /* TODO */
|
||||||
|
uint64_t reqVersion = 0; /* TODO */
|
||||||
|
int code = 0;
|
||||||
|
|
||||||
|
// Copy the request to vnode buffer
|
||||||
|
SRequest *pReq = mMalloc(pVnode->inuse, reqSize);
|
||||||
|
if (pReq == NULL) {
|
||||||
|
// TODO: handle error
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(pReq, pRequest, reqSize);
|
||||||
|
|
||||||
|
// Push the request to TQ so consumers can consume
|
||||||
|
tqPushMsg(pVnode->pTq, pReq, 0);
|
||||||
|
|
||||||
|
// Process the request
|
||||||
|
switch (reqType) {
|
||||||
|
case TSDB_MSG_TYPE_CREATE_TABLE:
|
||||||
|
code = metaCreateTable(pVnode->pMeta, NULL /* TODO */);
|
||||||
|
break;
|
||||||
|
case TSDB_MSG_TYPE_DROP_TABLE:
|
||||||
|
code = metaDropTable(pVnode->pMeta, 0 /* TODO */);
|
||||||
|
break;
|
||||||
|
/* TODO */
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vnodeShouldCommit(pVnode)) {
|
||||||
|
if (vnodeAsyncCommit(pVnode) < 0) {
|
||||||
|
// TODO: handle error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------ STATIC METHODS ------------------------ */
|
|
@ -1,9 +1,7 @@
|
||||||
# vnodeMemAllocatorTest
|
# Vnode API test
|
||||||
add_executable(VMATest "")
|
add_executable(vnodeApiTests "")
|
||||||
target_sources(VMATest
|
target_sources(vnodeApiTests
|
||||||
PRIVATE
|
PRIVATE
|
||||||
"../src/vnodeMemAllocator.c"
|
"vnodeApiTests.cpp"
|
||||||
"vnodeMemAllocatorTest.cpp"
|
|
||||||
)
|
)
|
||||||
target_include_directories(VMATest PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../inc")
|
target_link_libraries(vnodeApiTests vnode gtest gtest_main)
|
||||||
target_link_libraries(VMATest os gtest_main vnode)
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "vnode.h"
|
||||||
|
|
||||||
|
TEST(vnodeApiTest, vnodeOpen_vnodeClose_test) {
|
||||||
|
// Create and open a vnode
|
||||||
|
SVnode *pVnode = vnodeOpen("vnode1", NULL);
|
||||||
|
ASSERT_NE(pVnode, nullptr);
|
||||||
|
|
||||||
|
// Close the vnode
|
||||||
|
vnodeClose(pVnode);
|
||||||
|
}
|
|
@ -1,22 +0,0 @@
|
||||||
#include <gtest/gtest.h>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include "vnodeMemAllocator.h"
|
|
||||||
|
|
||||||
TEST(VMATest, basic_create_and_destroy_test) {
|
|
||||||
SVnodeMemAllocator *vma = VMACreate(1024, 512, 64);
|
|
||||||
EXPECT_TRUE(vma != nullptr);
|
|
||||||
EXPECT_EQ(vma->full, false);
|
|
||||||
EXPECT_EQ(vma->ssize, 512);
|
|
||||||
EXPECT_EQ(vma->threshold, 64);
|
|
||||||
EXPECT_EQ(vma->inuse->tsize, 1024);
|
|
||||||
VMADestroy(vma);
|
|
||||||
|
|
||||||
vma = VMACreate(1024, 512, 1024);
|
|
||||||
EXPECT_TRUE(vma != nullptr);
|
|
||||||
VMADestroy(vma);
|
|
||||||
|
|
||||||
vma = VMACreate(1024, 512, 1025);
|
|
||||||
EXPECT_TRUE(vma == nullptr);
|
|
||||||
VMADestroy(vma);
|
|
||||||
}
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_META_CACHE_H_
|
||||||
|
#define _TD_META_CACHE_H_
|
||||||
|
|
||||||
|
#include "rocksdb/c.h"
|
||||||
|
|
||||||
|
#include "meta.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef rocksdb_cache_t meta_cache_t;
|
||||||
|
|
||||||
|
int metaOpenCache(SMeta *pMeta);
|
||||||
|
void metaCloseCache(SMeta *pMeta);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*_TD_META_CACHE_H_*/
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_META_DB_H_
|
||||||
|
#define _TD_META_DB_H_
|
||||||
|
|
||||||
|
#include "rocksdb/c.h"
|
||||||
|
|
||||||
|
#include "meta.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
rocksdb_t *tbDb; // uid -> tb obj
|
||||||
|
rocksdb_t *nameDb; // name -> uid
|
||||||
|
rocksdb_t *tagDb; // uid -> tag
|
||||||
|
rocksdb_t *schemaDb; // uid+version -> schema
|
||||||
|
rocksdb_t *mapDb; // suid -> uid_list
|
||||||
|
} meta_db_t;
|
||||||
|
|
||||||
|
int metaOpenDB(SMeta *pMeta);
|
||||||
|
void metaCloseDB(SMeta *pMeta);
|
||||||
|
int metaSaveTableToDB(SMeta *pMeta, const STbOptions *pTbOptions);
|
||||||
|
int metaRemoveTableFromDb(SMeta *pMeta, tb_uid_t uid);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*_TD_META_DB_H_*/
|
|
@ -16,22 +16,26 @@
|
||||||
#ifndef _TD_META_DEF_H_
|
#ifndef _TD_META_DEF_H_
|
||||||
#define _TD_META_DEF_H_
|
#define _TD_META_DEF_H_
|
||||||
|
|
||||||
#include "metaUid.h"
|
#include "meta.h"
|
||||||
#include "tkv.h"
|
#include "metaCache.h"
|
||||||
|
#include "metaDB.h"
|
||||||
|
#include "metaIdx.h"
|
||||||
|
#include "metaOptions.h"
|
||||||
|
#include "metaTbOptions.h"
|
||||||
|
#include "metaTbTag.h"
|
||||||
|
#include "metaTbUid.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct SMeta {
|
struct SMeta {
|
||||||
STableUidGenerator uidGenerator;
|
char* path; // path of current meta
|
||||||
|
SMetaOptions options; // meta option
|
||||||
STkvDb* tableDb; // uid->table obj
|
meta_db_t* pDB; // raw data db
|
||||||
STkvDb* tbnameDb; // tbname --> uid
|
meta_index_t* pIdx; // tag index
|
||||||
STkvDb* schemaDb; // uid+version --> schema
|
meta_cache_t* pCache; // LRU cache
|
||||||
STkvDb* tagDb; // uid --> tag
|
STbUidGenerator uidGnrt; // meta table UID generator
|
||||||
STkvDb* tagIdx; // TODO: need to integrate lucene or our own
|
|
||||||
// STkvCache* metaCache; // TODO: add a global cache here
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_META_IDX_H_
|
||||||
|
#define _TD_META_IDX_H_
|
||||||
|
|
||||||
|
#include "rocksdb/c.h"
|
||||||
|
|
||||||
|
#include "meta.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef rocksdb_t meta_index_t;
|
||||||
|
|
||||||
|
int metaOpenIdx(SMeta *pMeta);
|
||||||
|
void metaCloseIdx(SMeta *pMeta);
|
||||||
|
int metaSaveTableToIdx(SMeta *pMeta, const STbOptions *pTbOptions);
|
||||||
|
int metaRemoveTableFromIdx(SMeta *pMeta, tb_uid_t uid);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*_TD_META_IDX_H_*/
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_META_OPTIONS_H_
|
||||||
|
#define _TD_META_OPTIONS_H_
|
||||||
|
|
||||||
|
#include "meta.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern const SMetaOptions defaultMetaOptions;
|
||||||
|
|
||||||
|
int metaValidateOptions(const SMetaOptions *);
|
||||||
|
void metaOptionsCopy(SMetaOptions *pDest, const SMetaOptions *pSrc);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*_TD_META_OPTIONS_H_*/
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_META_QUERY_H_
|
||||||
|
#define _TD_META_QUERY_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*_TD_META_QUERY_H_*/
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_META_TABLE_OPTIONS_H_
|
||||||
|
#define _TD_META_TABLE_OPTIONS_H_
|
||||||
|
|
||||||
|
#include "meta.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int metaValidateTbOptions(SMeta *pMeta, const STbOptions *);
|
||||||
|
size_t metaEncodeTbObjFromTbOptions(const STbOptions *, void *pBuf, size_t bsize);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*_TD_META_TABLE_OPTIONS_H_*/
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_META_TB_TAG_H_
|
||||||
|
#define _TD_META_TB_TAG_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*_TD_META_TB_TAG_H_*/
|
|
@ -23,20 +23,17 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ------------------------ APIS EXPOSED ------------------------ */
|
/* ------------------------ APIS EXPOSED ------------------------ */
|
||||||
typedef struct STableUidGenerator STableUidGenerator;
|
typedef struct STbUidGenerator {
|
||||||
|
tb_uid_t nextUid;
|
||||||
|
} STbUidGenerator;
|
||||||
|
|
||||||
|
// STableUidGenerator
|
||||||
|
int metaOpenUidGnrt(SMeta *pMeta);
|
||||||
|
void metaCloseUidGnrt(SMeta *pMeta);
|
||||||
|
|
||||||
// tb_uid_t
|
// tb_uid_t
|
||||||
#define IVLD_TB_UID 0
|
#define IVLD_TB_UID 0
|
||||||
tb_uid_t generateUid(STableUidGenerator *);
|
tb_uid_t metaGenerateUid(SMeta *pMeta);
|
||||||
|
|
||||||
// STableUidGenerator
|
|
||||||
void tableUidGeneratorInit(STableUidGenerator *, tb_uid_t suid);
|
|
||||||
#define tableUidGeneratorClear(ug)
|
|
||||||
|
|
||||||
/* ------------------------ FOR TEST AND COMPILE ONLY ------------------------ */
|
|
||||||
struct STableUidGenerator {
|
|
||||||
tb_uid_t nextUid;
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "meta.h"
|
||||||
|
#include "metaDef.h"
|
||||||
|
|
||||||
|
int metaOpenCache(SMeta *pMeta) {
|
||||||
|
// TODO
|
||||||
|
if (pMeta->options.lruCacheSize) {
|
||||||
|
pMeta->pCache = rocksdb_cache_create_lru(pMeta->options.lruCacheSize);
|
||||||
|
if (pMeta->pCache == NULL) {
|
||||||
|
// TODO: handle error
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void metaCloseCache(SMeta *pMeta) {
|
||||||
|
if (pMeta->pCache) {
|
||||||
|
rocksdb_cache_destroy(pMeta->pCache);
|
||||||
|
pMeta->pCache = NULL;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "meta.h"
|
||||||
|
|
||||||
|
int metaCommit(SMeta *pMeta) {
|
||||||
|
// TODO
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,199 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "metaDef.h"
|
||||||
|
|
||||||
|
static void metaSaveSchemaDB(SMeta *pMeta, tb_uid_t uid, STSchema *pSchema);
|
||||||
|
static void metaGetSchemaDBKey(char key[], tb_uid_t uid, int sversion);
|
||||||
|
static int metaSaveMapDB(SMeta *pMeta, tb_uid_t suid, tb_uid_t uid);
|
||||||
|
|
||||||
|
#define SCHEMA_KEY_LEN (sizeof(tb_uid_t) + sizeof(int))
|
||||||
|
|
||||||
|
#define META_OPEN_DB_IMPL(pDB, options, dir, err) \
|
||||||
|
do { \
|
||||||
|
pDB = rocksdb_open(options, dir, &err); \
|
||||||
|
if (pDB == NULL) { \
|
||||||
|
metaCloseDB(pMeta); \
|
||||||
|
rocksdb_options_destroy(options); \
|
||||||
|
return -1; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
int metaOpenDB(SMeta *pMeta) {
|
||||||
|
char dir[128];
|
||||||
|
char * err = NULL;
|
||||||
|
rocksdb_options_t *options = rocksdb_options_create();
|
||||||
|
|
||||||
|
if (pMeta->pCache) {
|
||||||
|
rocksdb_options_set_row_cache(options, pMeta->pCache);
|
||||||
|
}
|
||||||
|
rocksdb_options_set_create_if_missing(options, 1);
|
||||||
|
|
||||||
|
pMeta->pDB = (meta_db_t *)calloc(1, sizeof(*(pMeta->pDB)));
|
||||||
|
if (pMeta->pDB == NULL) {
|
||||||
|
// TODO: handle error
|
||||||
|
rocksdb_options_destroy(options);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// tbDb
|
||||||
|
sprintf(dir, "%s/tb_db", pMeta->path);
|
||||||
|
META_OPEN_DB_IMPL(pMeta->pDB->tbDb, options, dir, err);
|
||||||
|
|
||||||
|
// nameDb
|
||||||
|
sprintf(dir, "%s/name_db", pMeta->path);
|
||||||
|
META_OPEN_DB_IMPL(pMeta->pDB->nameDb, options, dir, err);
|
||||||
|
|
||||||
|
// tagDb
|
||||||
|
sprintf(dir, "%s/tag_db", pMeta->path);
|
||||||
|
META_OPEN_DB_IMPL(pMeta->pDB->tagDb, options, dir, err);
|
||||||
|
|
||||||
|
// schemaDb
|
||||||
|
sprintf(dir, "%s/schema_db", pMeta->path);
|
||||||
|
META_OPEN_DB_IMPL(pMeta->pDB->schemaDb, options, dir, err);
|
||||||
|
|
||||||
|
// mapDb
|
||||||
|
sprintf(dir, "%s/map_db", pMeta->path);
|
||||||
|
META_OPEN_DB_IMPL(pMeta->pDB->mapDb, options, dir, err);
|
||||||
|
|
||||||
|
rocksdb_options_destroy(options);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define META_CLOSE_DB_IMPL(pDB) \
|
||||||
|
do { \
|
||||||
|
if (pDB) { \
|
||||||
|
rocksdb_close(pDB); \
|
||||||
|
pDB = NULL; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
void metaCloseDB(SMeta *pMeta) {
|
||||||
|
if (pMeta->pDB) {
|
||||||
|
META_CLOSE_DB_IMPL(pMeta->pDB->mapDb);
|
||||||
|
META_CLOSE_DB_IMPL(pMeta->pDB->schemaDb);
|
||||||
|
META_CLOSE_DB_IMPL(pMeta->pDB->tagDb);
|
||||||
|
META_CLOSE_DB_IMPL(pMeta->pDB->nameDb);
|
||||||
|
META_CLOSE_DB_IMPL(pMeta->pDB->tbDb);
|
||||||
|
free(pMeta->pDB);
|
||||||
|
pMeta->pDB = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int metaSaveTableToDB(SMeta *pMeta, const STbOptions *pTbOptions) {
|
||||||
|
tb_uid_t uid;
|
||||||
|
char * err = NULL;
|
||||||
|
size_t size;
|
||||||
|
char pBuf[1024]; // TODO
|
||||||
|
|
||||||
|
rocksdb_writeoptions_t *wopt = rocksdb_writeoptions_create();
|
||||||
|
|
||||||
|
// Generate a uid for child and normal table
|
||||||
|
if (pTbOptions->type == META_SUPER_TABLE) {
|
||||||
|
uid = pTbOptions->stbOptions.uid;
|
||||||
|
} else {
|
||||||
|
uid = metaGenerateUid(pMeta);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save tbname -> uid to tbnameDB
|
||||||
|
rocksdb_put(pMeta->pDB->nameDb, wopt, pTbOptions->name, strlen(pTbOptions->name), (char *)(&uid), sizeof(uid), &err);
|
||||||
|
|
||||||
|
// Save uid -> tb_obj to tbDB
|
||||||
|
size = metaEncodeTbObjFromTbOptions(pTbOptions, pBuf, 1024);
|
||||||
|
rocksdb_put(pMeta->pDB->tbDb, wopt, (char *)(&uid), sizeof(uid), pBuf, size, &err);
|
||||||
|
|
||||||
|
switch (pTbOptions->type) {
|
||||||
|
case META_NORMAL_TABLE:
|
||||||
|
// save schemaDB
|
||||||
|
metaSaveSchemaDB(pMeta, uid, pTbOptions->ntbOptions.pSchame);
|
||||||
|
break;
|
||||||
|
case META_SUPER_TABLE:
|
||||||
|
// save schemaDB
|
||||||
|
metaSaveSchemaDB(pMeta, uid, pTbOptions->stbOptions.pSchema);
|
||||||
|
|
||||||
|
// save mapDB (really need?)
|
||||||
|
rocksdb_put(pMeta->pDB->mapDb, wopt, (char *)(&uid), sizeof(uid), "", 0, &err);
|
||||||
|
break;
|
||||||
|
case META_CHILD_TABLE:
|
||||||
|
// save tagDB
|
||||||
|
rocksdb_put(pMeta->pDB->tagDb, wopt, (char *)(&uid), sizeof(uid), pTbOptions->ctbOptions.tags,
|
||||||
|
kvRowLen(pTbOptions->ctbOptions.tags), &err);
|
||||||
|
|
||||||
|
// save mapDB
|
||||||
|
metaSaveMapDB(pMeta, pTbOptions->ctbOptions.suid, uid);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ASSERT(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
rocksdb_writeoptions_destroy(wopt);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int metaRemoveTableFromDb(SMeta *pMeta, tb_uid_t uid) {
|
||||||
|
/* TODO */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------ STATIC METHODS ------------------------ */
|
||||||
|
static void metaSaveSchemaDB(SMeta *pMeta, tb_uid_t uid, STSchema *pSchema) {
|
||||||
|
char key[64];
|
||||||
|
char pBuf[1024];
|
||||||
|
char * ppBuf = pBuf;
|
||||||
|
size_t vsize;
|
||||||
|
char * err = NULL;
|
||||||
|
|
||||||
|
rocksdb_writeoptions_t *wopt = rocksdb_writeoptions_create();
|
||||||
|
|
||||||
|
metaGetSchemaDBKey(key, uid, schemaVersion(pSchema));
|
||||||
|
vsize = tdEncodeSchema((void **)(&ppBuf), pSchema);
|
||||||
|
rocksdb_put(pMeta->pDB->schemaDb, wopt, key, SCHEMA_KEY_LEN, pBuf, vsize, &err);
|
||||||
|
|
||||||
|
rocksdb_writeoptions_destroy(wopt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void metaGetSchemaDBKey(char *key, tb_uid_t uid, int sversion) {
|
||||||
|
*(tb_uid_t *)key = uid;
|
||||||
|
*(int *)POINTER_SHIFT(key, sizeof(tb_uid_t)) = sversion;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int metaSaveMapDB(SMeta *pMeta, tb_uid_t suid, tb_uid_t uid) {
|
||||||
|
size_t vlen;
|
||||||
|
char * val;
|
||||||
|
char * err = NULL;
|
||||||
|
|
||||||
|
rocksdb_readoptions_t *ropt = rocksdb_readoptions_create();
|
||||||
|
val = rocksdb_get(pMeta->pDB->mapDb, ropt, (char *)(&suid), sizeof(suid), &vlen, &err);
|
||||||
|
rocksdb_readoptions_destroy(ropt);
|
||||||
|
|
||||||
|
void *nval = malloc(vlen + sizeof(uid));
|
||||||
|
if (nval == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vlen) {
|
||||||
|
memcpy(nval, val, vlen);
|
||||||
|
}
|
||||||
|
memcpy(POINTER_SHIFT(nval, vlen), (void *)(&uid), sizeof(uid));
|
||||||
|
|
||||||
|
rocksdb_writeoptions_t *wopt = rocksdb_writeoptions_create();
|
||||||
|
|
||||||
|
rocksdb_put(pMeta->pDB->mapDb, wopt, (char *)(&suid), sizeof(suid), nval, vlen + sizeof(uid), &err);
|
||||||
|
|
||||||
|
rocksdb_writeoptions_destroy(wopt);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "metaDef.h"
|
||||||
|
|
||||||
|
int metaOpenIdx(SMeta *pMeta) {
|
||||||
|
char idxDir[128]; // TODO
|
||||||
|
char * err = NULL;
|
||||||
|
rocksdb_options_t *options = rocksdb_options_create();
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
sprintf(idxDir, "%s/index", pMeta->path);
|
||||||
|
|
||||||
|
if (pMeta->pCache) {
|
||||||
|
rocksdb_options_set_row_cache(options, pMeta->pCache);
|
||||||
|
}
|
||||||
|
rocksdb_options_set_create_if_missing(options, 1);
|
||||||
|
|
||||||
|
pMeta->pIdx = rocksdb_open(options, idxDir, &err);
|
||||||
|
if (pMeta->pIdx == NULL) {
|
||||||
|
// TODO: handle error
|
||||||
|
rocksdb_options_destroy(options);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rocksdb_options_destroy(options);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void metaCloseIdx(SMeta *pMeta) { /* TODO */
|
||||||
|
if (pMeta->pIdx) {
|
||||||
|
rocksdb_close(pMeta->pIdx);
|
||||||
|
pMeta->pIdx = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int metaSaveTableToIdx(SMeta *pMeta, const STbOptions *pTbOptions) {
|
||||||
|
// TODO
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -13,75 +13,134 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "meta.h"
|
|
||||||
#include "metaDef.h"
|
|
||||||
#include "tcoding.h"
|
#include "tcoding.h"
|
||||||
|
|
||||||
static int metaCreateSuperTable(SMeta *pMeta, const char *tbname, const SSuperTableOpts *pSuperTableOpts);
|
#include "meta.h"
|
||||||
static int metaCreateChildTable(SMeta *pMeta, const char *tbname, const SChildTableOpts *pChildTableOpts);
|
#include "metaDB.h"
|
||||||
static int metaCreateNormalTable(SMeta *pMeta, const char *tbname, const SNormalTableOpts *pNormalTableOpts);
|
#include "metaDef.h"
|
||||||
|
#include "metaOptions.h"
|
||||||
|
|
||||||
SMeta *metaOpen(SMetaOpts *pMetaOpts) {
|
static SMeta *metaNew(const char *path, const SMetaOptions *pMetaOptions);
|
||||||
|
static void metaFree(SMeta *pMeta);
|
||||||
|
static int metaOpenImpl(SMeta *pMeta);
|
||||||
|
static void metaCloseImpl(SMeta *pMeta);
|
||||||
|
|
||||||
|
SMeta *metaOpen(const char *path, const SMetaOptions *pMetaOptions) {
|
||||||
SMeta *pMeta = NULL;
|
SMeta *pMeta = NULL;
|
||||||
|
|
||||||
|
// Set default options
|
||||||
|
if (pMetaOptions == NULL) {
|
||||||
|
pMetaOptions = &defaultMetaOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate the options
|
||||||
|
if (metaValidateOptions(pMetaOptions) < 0) {
|
||||||
|
// TODO: deal with error
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate handle
|
||||||
|
pMeta = metaNew(path, pMetaOptions);
|
||||||
|
if (pMeta == NULL) {
|
||||||
|
// TODO: handle error
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create META path (TODO)
|
||||||
|
taosMkDir(path);
|
||||||
|
|
||||||
|
// Open meta
|
||||||
|
if (metaOpenImpl(pMeta) < 0) {
|
||||||
|
metaFree(pMeta);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pMeta;
|
||||||
|
}
|
||||||
|
|
||||||
|
void metaClose(SMeta *pMeta) {
|
||||||
|
if (pMeta) {
|
||||||
|
metaCloseImpl(pMeta);
|
||||||
|
metaFree(pMeta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void metaRemove(const char *path) { taosRemoveDir(path); }
|
||||||
|
|
||||||
|
/* ------------------------ STATIC METHODS ------------------------ */
|
||||||
|
static SMeta *metaNew(const char *path, const SMetaOptions *pMetaOptions) {
|
||||||
|
SMeta *pMeta;
|
||||||
|
size_t psize = strlen(path);
|
||||||
|
|
||||||
pMeta = (SMeta *)calloc(1, sizeof(*pMeta));
|
pMeta = (SMeta *)calloc(1, sizeof(*pMeta));
|
||||||
if (pMeta == NULL) {
|
if (pMeta == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: check if file exists and handle the error
|
pMeta->path = strdup(path);
|
||||||
taosMkDir("meta");
|
if (pMeta->path == NULL) {
|
||||||
|
metaFree(pMeta);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// Open tableDb
|
metaOptionsCopy(&(pMeta->options), pMetaOptions);
|
||||||
STkvOpts *tableDbOpts = tkvOptsCreate();
|
|
||||||
tkvOptsSetCreateIfMissing(tableDbOpts, 1);
|
|
||||||
pMeta->tableDb = tkvOpen(tableDbOpts, "meta/table_db");
|
|
||||||
tkvOptsDestroy(tableDbOpts);
|
|
||||||
|
|
||||||
// Open tbnameDb
|
|
||||||
STkvOpts *tbnameDbOpts = tkvOptsCreate();
|
|
||||||
tkvOptsSetCreateIfMissing(tbnameDbOpts, 1);
|
|
||||||
pMeta->tbnameDb = tkvOpen(tbnameDbOpts, "meta/tbname_db");
|
|
||||||
tkvOptsDestroy(tbnameDbOpts);
|
|
||||||
|
|
||||||
// Open schemaDb
|
|
||||||
STkvOpts *schemaDbOpts = tkvOptsCreate();
|
|
||||||
tkvOptsSetCreateIfMissing(schemaDbOpts, 1);
|
|
||||||
pMeta->schemaDb = tkvOpen(schemaDbOpts, "meta/schema_db");
|
|
||||||
tkvOptsDestroy(schemaDbOpts);
|
|
||||||
|
|
||||||
// Open tagDb
|
|
||||||
STkvOpts *tagDbOpts = tkvOptsCreate();
|
|
||||||
tkvOptsSetCreateIfMissing(tagDbOpts, 1);
|
|
||||||
pMeta->tagDb = tkvOpen(tagDbOpts, "meta/tag_db");
|
|
||||||
tkvOptsDestroy(tagDbOpts);
|
|
||||||
|
|
||||||
// Open tagIdx
|
|
||||||
STkvOpts *tagIdxDbOpts = tkvOptsCreate();
|
|
||||||
tkvOptsSetCreateIfMissing(tagIdxDbOpts, 1);
|
|
||||||
pMeta->tagIdx = tkvOpen(tagIdxDbOpts, "meta/tag_idx_db");
|
|
||||||
tkvOptsDestroy(tagIdxDbOpts);
|
|
||||||
|
|
||||||
// TODO: need to figure out how to persist the START UID
|
|
||||||
tableUidGeneratorInit(&(pMeta->uidGenerator), IVLD_TB_UID);
|
|
||||||
return pMeta;
|
return pMeta;
|
||||||
}
|
};
|
||||||
|
|
||||||
void metaClose(SMeta *pMeta) {
|
static void metaFree(SMeta *pMeta) {
|
||||||
if (pMeta) {
|
if (pMeta) {
|
||||||
tableUidGeneratorClear(&pMeta->uidGenerator);
|
tfree(pMeta->path);
|
||||||
|
|
||||||
tkvClose(pMeta->tagIdx);
|
|
||||||
tkvClose(pMeta->tagDb);
|
|
||||||
tkvClose(pMeta->schemaDb);
|
|
||||||
tkvClose(pMeta->tbnameDb);
|
|
||||||
tkvClose(pMeta->tableDb);
|
|
||||||
|
|
||||||
free(pMeta);
|
free(pMeta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int metaCreateTable(SMeta *pMeta, const STableOpts *pTableOpts) {
|
static int metaOpenImpl(SMeta *pMeta) {
|
||||||
|
// Open meta cache
|
||||||
|
if (metaOpenCache(pMeta) < 0) {
|
||||||
|
// TODO: handle error
|
||||||
|
metaCloseImpl(pMeta);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open meta db
|
||||||
|
if (metaOpenDB(pMeta) < 0) {
|
||||||
|
// TODO: handle error
|
||||||
|
metaCloseImpl(pMeta);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open meta index
|
||||||
|
if (metaOpenIdx(pMeta) < 0) {
|
||||||
|
// TODO: handle error
|
||||||
|
metaCloseImpl(pMeta);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open meta table uid generator
|
||||||
|
if (metaOpenUidGnrt(pMeta) < 0) {
|
||||||
|
// TODO: handle error
|
||||||
|
metaCloseImpl(pMeta);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void metaCloseImpl(SMeta *pMeta) {
|
||||||
|
metaCloseUidGnrt(pMeta);
|
||||||
|
metaCloseIdx(pMeta);
|
||||||
|
metaCloseDB(pMeta);
|
||||||
|
metaCloseCache(pMeta);
|
||||||
|
}
|
||||||
|
|
||||||
|
// OLD -------------------------------------------------------------------
|
||||||
|
#if 0
|
||||||
|
static int metaCreateSuperTable(SMeta *pMeta, const char *tbname, const SSuperTableOpts *pSuperTableOpts);
|
||||||
|
static int metaCreateChildTable(SMeta *pMeta, const char *tbname, const SChildTableOpts *pChildTableOpts);
|
||||||
|
static int metaCreateNormalTable(SMeta *pMeta, const char *tbname, const SNormalTableOpts *pNormalTableOpts);
|
||||||
|
|
||||||
|
int metaCreateTable(SMeta *pMeta, const STableOptions *pTableOpts) {
|
||||||
size_t vallen;
|
size_t vallen;
|
||||||
char * pUid;
|
char * pUid;
|
||||||
|
|
||||||
|
@ -107,7 +166,6 @@ int metaCreateTable(SMeta *pMeta, const STableOpts *pTableOpts) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------ STATIC METHODS ------------------------ */
|
|
||||||
static int metaCreateSuperTable(SMeta *pMeta, const char *tbname, const SSuperTableOpts *pSuperTableOpts) {
|
static int metaCreateSuperTable(SMeta *pMeta, const char *tbname, const SSuperTableOpts *pSuperTableOpts) {
|
||||||
size_t vallen;
|
size_t vallen;
|
||||||
size_t keylen;
|
size_t keylen;
|
||||||
|
@ -213,13 +271,13 @@ static int metaCreateNormalTable(SMeta *pMeta, const char *tbname, const SNormal
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void metaNormalTableOptsInit(STableOpts *pTableOpts, const char *name, const STSchema *pSchema) {
|
void metaNormalTableOptsInit(STableOptions *pTableOpts, const char *name, const STSchema *pSchema) {
|
||||||
pTableOpts->type = META_NORMAL_TABLE;
|
pTableOpts->type = META_NORMAL_TABLE;
|
||||||
pTableOpts->name = strdup(name);
|
pTableOpts->name = strdup(name);
|
||||||
pTableOpts->normalOpts.pSchema = tdDupSchema(pSchema);
|
pTableOpts->normalOpts.pSchema = tdDupSchema(pSchema);
|
||||||
}
|
}
|
||||||
|
|
||||||
void metaSuperTableOptsInit(STableOpts *pTableOpts, const char *name, tb_uid_t uid, const STSchema *pSchema,
|
void metaSuperTableOptsInit(STableOptions *pTableOpts, const char *name, tb_uid_t uid, const STSchema *pSchema,
|
||||||
const STSchema *pTagSchema) {
|
const STSchema *pTagSchema) {
|
||||||
pTableOpts->type = META_SUPER_TABLE;
|
pTableOpts->type = META_SUPER_TABLE;
|
||||||
pTableOpts->name = strdup(name);
|
pTableOpts->name = strdup(name);
|
||||||
|
@ -228,14 +286,14 @@ void metaSuperTableOptsInit(STableOpts *pTableOpts, const char *name, tb_uid_t u
|
||||||
pTableOpts->superOpts.pTagSchema = tdDupSchema(pTagSchema);
|
pTableOpts->superOpts.pTagSchema = tdDupSchema(pTagSchema);
|
||||||
}
|
}
|
||||||
|
|
||||||
void metaChildTableOptsInit(STableOpts *pTableOpts, const char *name, tb_uid_t suid, const SKVRow tags) {
|
void metaChildTableOptsInit(STableOptions *pTableOpts, const char *name, tb_uid_t suid, const SKVRow tags) {
|
||||||
pTableOpts->type = META_CHILD_TABLE;
|
pTableOpts->type = META_CHILD_TABLE;
|
||||||
pTableOpts->name = strdup(name);
|
pTableOpts->name = strdup(name);
|
||||||
pTableOpts->childOpts.suid = suid;
|
pTableOpts->childOpts.suid = suid;
|
||||||
pTableOpts->childOpts.tags = tdKVRowDup(tags);
|
pTableOpts->childOpts.tags = tdKVRowDup(tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void metaTableOptsClear(STableOpts *pTableOpts) {
|
void metaTableOptsClear(STableOptions *pTableOpts) {
|
||||||
switch (pTableOpts->type) {
|
switch (pTableOpts->type) {
|
||||||
case META_NORMAL_TABLE:
|
case META_NORMAL_TABLE:
|
||||||
tfree(pTableOpts->name);
|
tfree(pTableOpts->name);
|
||||||
|
@ -258,3 +316,5 @@ void metaTableOptsClear(STableOpts *pTableOpts) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void metaDestroy(const char *path) { taosRemoveDir(path); }
|
void metaDestroy(const char *path) { taosRemoveDir(path); }
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "metaDef.h"
|
||||||
|
|
||||||
|
const SMetaOptions defaultMetaOptions = {.lruCacheSize = 0};
|
||||||
|
|
||||||
|
/* ------------------------ EXPOSED METHODS ------------------------ */
|
||||||
|
void metaOptionsInit(SMetaOptions *pMetaOptions) { metaOptionsCopy(pMetaOptions, &defaultMetaOptions); }
|
||||||
|
|
||||||
|
void metaOptionsClear(SMetaOptions *pMetaOptions) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
int metaValidateOptions(const SMetaOptions *pMetaOptions) {
|
||||||
|
// TODO
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void metaOptionsCopy(SMetaOptions *pDest, const SMetaOptions *pSrc) { memcpy(pDest, pSrc, sizeof(*pSrc)); }
|
||||||
|
|
||||||
|
/* ------------------------ STATIC METHODS ------------------------ */
|
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "metaDef.h"
|
||||||
|
|
||||||
|
int metaCreateTable(SMeta *pMeta, const STbOptions *pTbOptions) {
|
||||||
|
// Validate the tbOptions
|
||||||
|
if (metaValidateTbOptions(pMeta, pTbOptions) < 0) {
|
||||||
|
// TODO: handle error
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: add atomicity
|
||||||
|
|
||||||
|
if (metaSaveTableToDB(pMeta, pTbOptions) < 0) {
|
||||||
|
// TODO: handle error
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (metaSaveTableToIdx(pMeta, pTbOptions) < 0) {
|
||||||
|
// TODO: handle error
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int metaDropTable(SMeta *pMeta, tb_uid_t uid) {
|
||||||
|
if (metaRemoveTableFromIdx(pMeta, uid) < 0) {
|
||||||
|
// TODO: handle error
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (metaRemoveTableFromIdx(pMeta, uid) < 0) {
|
||||||
|
// TODO
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "metaDef.h"
|
||||||
|
#include "tcoding.h"
|
||||||
|
|
||||||
|
int metaValidateTbOptions(SMeta *pMeta, const STbOptions *pTbOptions) {
|
||||||
|
// TODO
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t metaEncodeTbObjFromTbOptions(const STbOptions *pTbOptions, void *pBuf, size_t bsize) {
|
||||||
|
void **ppBuf = &pBuf;
|
||||||
|
int tlen = 0;
|
||||||
|
|
||||||
|
tlen += taosEncodeFixedU8(ppBuf, pTbOptions->type);
|
||||||
|
tlen += taosEncodeString(ppBuf, pTbOptions->name);
|
||||||
|
tlen += taosEncodeFixedU32(ppBuf, pTbOptions->ttl);
|
||||||
|
|
||||||
|
switch (pTbOptions->type) {
|
||||||
|
case META_SUPER_TABLE:
|
||||||
|
tlen += taosEncodeFixedU64(ppBuf, pTbOptions->stbOptions.uid);
|
||||||
|
tlen += tdEncodeSchema(ppBuf, pTbOptions->stbOptions.pTagSchema);
|
||||||
|
// TODO: encode schema version array
|
||||||
|
break;
|
||||||
|
case META_CHILD_TABLE:
|
||||||
|
tlen += taosEncodeFixedU64(ppBuf, pTbOptions->ctbOptions.suid);
|
||||||
|
break;
|
||||||
|
case META_NORMAL_TABLE:
|
||||||
|
// TODO: encode schema version array
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tlen;
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
|
@ -13,14 +13,18 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "metaUid.h"
|
#include "meta.h"
|
||||||
|
#include "metaDef.h"
|
||||||
|
|
||||||
tb_uid_t generateUid(STableUidGenerator *pGen) {
|
int metaOpenUidGnrt(SMeta *pMeta) {
|
||||||
// Generate a new table UID
|
// Init a generator
|
||||||
return ++(pGen->nextUid);
|
pMeta->uidGnrt.nextUid = IVLD_TB_UID;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tableUidGeneratorInit(STableUidGenerator *pGen, tb_uid_t suid) {
|
void metaCloseUidGnrt(SMeta *pMeta) { /* TODO */ }
|
||||||
// Init a generator
|
|
||||||
pGen->nextUid = suid;
|
tb_uid_t metaGenerateUid(SMeta *pMeta) {
|
||||||
|
// Generate a new table UID
|
||||||
|
return ++(pMeta->uidGnrt.nextUid);
|
||||||
}
|
}
|
|
@ -1,24 +1,24 @@
|
||||||
add_executable(metaTest "")
|
# add_executable(metaTest "")
|
||||||
target_sources(metaTest
|
# target_sources(metaTest
|
||||||
PRIVATE
|
# PRIVATE
|
||||||
"../src/metaMain.c"
|
# "../src/metaMain.c"
|
||||||
"../src/metaUid.c"
|
# "../src/metaUid.c"
|
||||||
"metaTests.cpp"
|
# "metaTests.cpp"
|
||||||
)
|
# )
|
||||||
target_include_directories(metaTest
|
# target_include_directories(metaTest
|
||||||
PUBLIC
|
# PUBLIC
|
||||||
"${CMAKE_SOURCE_DIR}/include/server/vnode/meta"
|
# "${CMAKE_SOURCE_DIR}/include/server/vnode/meta"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/../inc"
|
# "${CMAKE_CURRENT_SOURCE_DIR}/../inc"
|
||||||
)
|
# )
|
||||||
target_link_libraries(metaTest
|
# target_link_libraries(metaTest
|
||||||
os
|
# os
|
||||||
util
|
# util
|
||||||
common
|
# common
|
||||||
gtest_main
|
# gtest_main
|
||||||
tkv
|
# tkv
|
||||||
)
|
# )
|
||||||
enable_testing()
|
# enable_testing()
|
||||||
add_test(
|
# add_test(
|
||||||
NAME meta_test
|
# NAME meta_test
|
||||||
COMMAND metaTest
|
# COMMAND metaTest
|
||||||
)
|
# )
|
|
@ -1,3 +1,4 @@
|
||||||
|
#if 0
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -38,7 +39,7 @@ static SKVRow metaGetSimpleTags() {
|
||||||
|
|
||||||
TEST(MetaTest, DISABLED_meta_create_1m_normal_tables_test) {
|
TEST(MetaTest, DISABLED_meta_create_1m_normal_tables_test) {
|
||||||
// Open Meta
|
// Open Meta
|
||||||
SMeta *meta = metaOpen(NULL);
|
SMeta *meta = metaOpen(NULL, NULL);
|
||||||
std::cout << "Meta is opened!" << std::endl;
|
std::cout << "Meta is opened!" << std::endl;
|
||||||
|
|
||||||
// Create 1000000 normal tables
|
// Create 1000000 normal tables
|
||||||
|
@ -100,4 +101,5 @@ TEST(MetaTest, meta_create_1m_child_tables_test) {
|
||||||
// Destroy Meta
|
// Destroy Meta
|
||||||
metaDestroy("meta");
|
metaDestroy("meta");
|
||||||
std::cout << "Meta is destroyed!" << std::endl;
|
std::cout << "Meta is destroyed!" << std::endl;
|
||||||
}
|
}
|
||||||
|
#endif
|
|
@ -24,18 +24,18 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define TQ_BUCKET_SIZE 0xFF
|
#define TQ_BUCKET_MASK 0xFF
|
||||||
|
#define TQ_BUCKET_SIZE 256
|
||||||
|
|
||||||
#define TQ_PAGE_SIZE 4096
|
#define TQ_PAGE_SIZE 4096
|
||||||
//key + offset + size
|
//key + offset + size
|
||||||
#define TQ_IDX_ENTRY_SIZE 24
|
#define TQ_IDX_SIZE 24
|
||||||
|
//4096 / 24
|
||||||
inline static int TqMaxEntryOnePage() { //170
|
#define TQ_MAX_IDX_ONE_PAGE 170
|
||||||
return TQ_PAGE_SIZE / TQ_IDX_ENTRY_SIZE;
|
//24 * 170
|
||||||
}
|
#define TQ_IDX_PAGE_BODY_SIZE 4080
|
||||||
|
//4096 - 4080
|
||||||
inline static int TqEmptyTail() { //16
|
#define TQ_IDX_PAGE_HEAD_SIZE 16
|
||||||
return TQ_PAGE_SIZE - TqMaxEntryOnePage();
|
|
||||||
}
|
|
||||||
|
|
||||||
#define TQ_ACTION_CONST 0
|
#define TQ_ACTION_CONST 0
|
||||||
#define TQ_ACTION_INUSE 1
|
#define TQ_ACTION_INUSE 1
|
||||||
|
@ -92,19 +92,17 @@ int32_t tqStoreClose(TqMetaStore*);
|
||||||
//int32_t tqStoreDelete(TqMetaStore*);
|
//int32_t tqStoreDelete(TqMetaStore*);
|
||||||
//int32_t TqStoreCommitAll(TqMetaStore*);
|
//int32_t TqStoreCommitAll(TqMetaStore*);
|
||||||
int32_t tqStorePersist(TqMetaStore*);
|
int32_t tqStorePersist(TqMetaStore*);
|
||||||
|
//clean deleted idx and data from persistent file
|
||||||
|
int32_t tqStoreCompact(TqMetaStore*);
|
||||||
|
|
||||||
void* tqHandleGet(TqMetaStore*, int64_t key);
|
void* tqHandleGet(TqMetaStore*, int64_t key);
|
||||||
int32_t tqHandleMovePut(TqMetaStore*, int64_t key, void* value);
|
int32_t tqHandleMovePut(TqMetaStore*, int64_t key, void* value);
|
||||||
int32_t tqHandleCopyPut(TqMetaStore*, int64_t key, void* value, size_t vsize);
|
int32_t tqHandleCopyPut(TqMetaStore*, int64_t key, void* value, size_t vsize);
|
||||||
//do commit
|
|
||||||
int32_t tqHandleCommit(TqMetaStore*, int64_t key);
|
|
||||||
//delete uncommitted
|
|
||||||
int32_t tqHandleAbort(TqMetaStore*, int64_t key);
|
|
||||||
//delete committed kv pair
|
//delete committed kv pair
|
||||||
//notice that a delete action still needs to be committed
|
//notice that a delete action still needs to be committed
|
||||||
int32_t tqHandleDel(TqMetaStore*, int64_t key);
|
int32_t tqHandleDel(TqMetaStore*, int64_t key);
|
||||||
//delete both committed and uncommitted
|
int32_t tqHandleCommit(TqMetaStore*, int64_t key);
|
||||||
int32_t tqHandleClear(TqMetaStore*, int64_t key);
|
int32_t tqHandleAbort(TqMetaStore*, int64_t key);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,9 @@
|
||||||
//
|
//
|
||||||
//handle management message
|
//handle management message
|
||||||
//
|
//
|
||||||
|
|
||||||
|
int tqGetgHandleSSize(const TqGroupHandle *gHandle);
|
||||||
|
|
||||||
static int tqProtoCheck(TmqMsgHead *pMsg) {
|
static int tqProtoCheck(TmqMsgHead *pMsg) {
|
||||||
return pMsg->protoVer == 0;
|
return pMsg->protoVer == 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,19 +27,46 @@ static int32_t tqHandlePutCommitted(TqMetaStore*, int64_t key, void* value);
|
||||||
static void* tqHandleGetUncommitted(TqMetaStore*, int64_t key);
|
static void* tqHandleGetUncommitted(TqMetaStore*, int64_t key);
|
||||||
|
|
||||||
static inline void tqLinkUnpersist(TqMetaStore *pMeta, TqMetaList* pNode) {
|
static inline void tqLinkUnpersist(TqMetaStore *pMeta, TqMetaList* pNode) {
|
||||||
if(pNode->unpersistNext == NULL) {
|
if(pNode->unpersistNext == NULL) {
|
||||||
pNode->unpersistNext = pMeta->unpersistHead->unpersistNext;
|
pNode->unpersistNext = pMeta->unpersistHead->unpersistNext;
|
||||||
pNode->unpersistPrev = pMeta->unpersistHead;
|
pNode->unpersistPrev = pMeta->unpersistHead;
|
||||||
pMeta->unpersistHead->unpersistNext->unpersistPrev = pNode;
|
pMeta->unpersistHead->unpersistNext->unpersistPrev = pNode;
|
||||||
pMeta->unpersistHead->unpersistNext = pNode;
|
pMeta->unpersistHead->unpersistNext = pNode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int tqSeekLastPage(int fd) {
|
||||||
|
int offset = lseek(fd, 0, SEEK_END);
|
||||||
|
int pageNo = offset / TQ_PAGE_SIZE;
|
||||||
|
int curPageOffset = pageNo * TQ_PAGE_SIZE;
|
||||||
|
return lseek(fd, curPageOffset, SEEK_SET);
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct TqMetaPageBuf {
|
//TODO: the struct is tightly coupled with index entry
|
||||||
int16_t offset;
|
typedef struct TqIdxPageHead {
|
||||||
char buffer[TQ_PAGE_SIZE];
|
int16_t writeOffset;
|
||||||
} TqMetaPageBuf;
|
int8_t unused[14];
|
||||||
|
} TqIdxPageHead;
|
||||||
|
|
||||||
|
typedef struct TqIdxPageBuf {
|
||||||
|
TqIdxPageHead head;
|
||||||
|
char buffer[TQ_IDX_PAGE_BODY_SIZE];
|
||||||
|
} TqIdxPageBuf;
|
||||||
|
|
||||||
|
static inline int tqReadLastPage(int fd, TqIdxPageBuf* pBuf) {
|
||||||
|
int offset = tqSeekLastPage(fd);
|
||||||
|
int nBytes;
|
||||||
|
if((nBytes = read(fd, pBuf, TQ_PAGE_SIZE)) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(nBytes == 0) {
|
||||||
|
memset(pBuf, 0, TQ_PAGE_SIZE);
|
||||||
|
pBuf->head.writeOffset = TQ_IDX_PAGE_HEAD_SIZE;
|
||||||
|
}
|
||||||
|
ASSERT(nBytes == 0 || nBytes == pBuf->head.writeOffset);
|
||||||
|
|
||||||
|
return lseek(fd, offset, SEEK_SET);
|
||||||
|
}
|
||||||
|
|
||||||
TqMetaStore* tqStoreOpen(const char* path,
|
TqMetaStore* tqStoreOpen(const char* path,
|
||||||
int serializer(const void* pObj, TqSerializedHead** ppHead),
|
int serializer(const void* pObj, TqSerializedHead** ppHead),
|
||||||
|
@ -103,27 +130,30 @@ TqMetaStore* tqStoreOpen(const char* path,
|
||||||
pMeta->deleter = deleter;
|
pMeta->deleter = deleter;
|
||||||
|
|
||||||
//read idx file and load into memory
|
//read idx file and load into memory
|
||||||
char idxBuf[TQ_PAGE_SIZE];
|
TqIdxPageBuf idxBuf;
|
||||||
TqSerializedHead* serializedObj = malloc(TQ_PAGE_SIZE);
|
TqSerializedHead* serializedObj = malloc(TQ_PAGE_SIZE);
|
||||||
if(serializedObj == NULL) {
|
if(serializedObj == NULL) {
|
||||||
//TODO:memory insufficient
|
//TODO:memory insufficient
|
||||||
}
|
}
|
||||||
int idxRead;
|
int idxRead;
|
||||||
int allocated = TQ_PAGE_SIZE;
|
int allocated = TQ_PAGE_SIZE;
|
||||||
while((idxRead = read(idxFd, idxBuf, TQ_PAGE_SIZE))) {
|
bool readEnd = false;
|
||||||
|
while((idxRead = read(idxFd, &idxBuf, TQ_PAGE_SIZE))) {
|
||||||
if(idxRead == -1) {
|
if(idxRead == -1) {
|
||||||
//TODO: handle error
|
//TODO: handle error
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
}
|
}
|
||||||
|
ASSERT(idxBuf.head.writeOffset == idxRead);
|
||||||
//loop read every entry
|
//loop read every entry
|
||||||
for(int i = 0; i < idxRead; i += TQ_IDX_ENTRY_SIZE) {
|
for(int i = 0; i < idxBuf.head.writeOffset - TQ_IDX_PAGE_HEAD_SIZE; i += TQ_IDX_SIZE) {
|
||||||
TqMetaList *pNode = malloc(sizeof(TqMetaList));
|
TqMetaList *pNode = malloc(sizeof(TqMetaList));
|
||||||
if(pNode == NULL) {
|
if(pNode == NULL) {
|
||||||
//TODO: free memory and return error
|
//TODO: free memory and return error
|
||||||
}
|
}
|
||||||
memset(pNode, 0, sizeof(TqMetaList));
|
memset(pNode, 0, sizeof(TqMetaList));
|
||||||
memcpy(&pNode->handle, &idxBuf[i], TQ_IDX_ENTRY_SIZE);
|
memcpy(&pNode->handle, &idxBuf.buffer[i], TQ_IDX_SIZE);
|
||||||
lseek(fileFd, pNode->handle.offset, SEEK_CUR);
|
|
||||||
|
lseek(fileFd, pNode->handle.offset, SEEK_SET);
|
||||||
if(allocated < pNode->handle.serializedSize) {
|
if(allocated < pNode->handle.serializedSize) {
|
||||||
void *ptr = realloc(serializedObj, pNode->handle.serializedSize);
|
void *ptr = realloc(serializedObj, pNode->handle.serializedSize);
|
||||||
if(ptr == NULL) {
|
if(ptr == NULL) {
|
||||||
|
@ -154,9 +184,9 @@ TqMetaStore* tqStoreOpen(const char* path,
|
||||||
} else {
|
} else {
|
||||||
pNode->handle.valueInUse = TQ_DELETE_TOKEN;
|
pNode->handle.valueInUse = TQ_DELETE_TOKEN;
|
||||||
}
|
}
|
||||||
serializedObj = POINTER_SHIFT(serializedObj, serializedObj->ssize);
|
TqSerializedHead* ptr = POINTER_SHIFT(serializedObj, serializedObj->ssize);
|
||||||
if(serializedObj->ssize != sizeof(TqSerializedHead)) {
|
if(ptr->ssize != sizeof(TqSerializedHead)) {
|
||||||
pMeta->deserializer(serializedObj, &pNode->handle.valueInTxn);
|
pMeta->deserializer(ptr, &pNode->handle.valueInTxn);
|
||||||
} else {
|
} else {
|
||||||
pNode->handle.valueInTxn = TQ_DELETE_TOKEN;
|
pNode->handle.valueInTxn = TQ_DELETE_TOKEN;
|
||||||
}
|
}
|
||||||
|
@ -165,7 +195,7 @@ TqMetaStore* tqStoreOpen(const char* path,
|
||||||
}
|
}
|
||||||
|
|
||||||
//put into list
|
//put into list
|
||||||
int bucketKey = pNode->handle.key & TQ_BUCKET_SIZE;
|
int bucketKey = pNode->handle.key & TQ_BUCKET_MASK;
|
||||||
TqMetaList* pBucketNode = pMeta->bucket[bucketKey];
|
TqMetaList* pBucketNode = pMeta->bucket[bucketKey];
|
||||||
if(pBucketNode == NULL) {
|
if(pBucketNode == NULL) {
|
||||||
pMeta->bucket[bucketKey] = pNode;
|
pMeta->bucket[bucketKey] = pNode;
|
||||||
|
@ -174,15 +204,18 @@ TqMetaStore* tqStoreOpen(const char* path,
|
||||||
pMeta->bucket[bucketKey] = pNode;
|
pMeta->bucket[bucketKey] = pNode;
|
||||||
} else {
|
} else {
|
||||||
while(pBucketNode->next &&
|
while(pBucketNode->next &&
|
||||||
pBucketNode->next->handle.key == pNode->handle.key) {
|
pBucketNode->next->handle.key != pNode->handle.key) {
|
||||||
pBucketNode = pBucketNode->next;
|
pBucketNode = pBucketNode->next;
|
||||||
}
|
}
|
||||||
if(pBucketNode->next) {
|
if(pBucketNode->next) {
|
||||||
ASSERT(pBucketNode->next->handle.key == pNode->handle.key);
|
ASSERT(pBucketNode->next->handle.key == pNode->handle.key);
|
||||||
TqMetaList *pNodeTmp = pBucketNode->next;
|
TqMetaList *pNodeFound = pBucketNode->next;
|
||||||
pBucketNode->next = pNodeTmp->next;
|
pNode->next = pNodeFound->next;
|
||||||
pBucketNode = pNodeTmp;
|
pBucketNode->next = pNode;
|
||||||
|
pBucketNode = pNodeFound;
|
||||||
} else {
|
} else {
|
||||||
|
pNode->next = pMeta->bucket[bucketKey];
|
||||||
|
pMeta->bucket[bucketKey] = pNode;
|
||||||
pBucketNode = NULL;
|
pBucketNode = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -264,8 +297,8 @@ int32_t tqStoreDelete(TqMetaStore* pMeta) {
|
||||||
|
|
||||||
//TODO: wrap in tfile
|
//TODO: wrap in tfile
|
||||||
int32_t tqStorePersist(TqMetaStore* pMeta) {
|
int32_t tqStorePersist(TqMetaStore* pMeta) {
|
||||||
char writeBuf[TQ_PAGE_SIZE];
|
TqIdxPageBuf idxBuf;
|
||||||
int64_t* bufPtr = (int64_t*)writeBuf;
|
int64_t* bufPtr = (int64_t*)idxBuf.buffer;
|
||||||
TqMetaList *pHead = pMeta->unpersistHead;
|
TqMetaList *pHead = pMeta->unpersistHead;
|
||||||
TqMetaList *pNode = pHead->unpersistNext;
|
TqMetaList *pNode = pHead->unpersistNext;
|
||||||
TqSerializedHead *pSHead = malloc(sizeof(TqSerializedHead));
|
TqSerializedHead *pSHead = malloc(sizeof(TqSerializedHead));
|
||||||
|
@ -278,6 +311,17 @@ int32_t tqStorePersist(TqMetaStore* pMeta) {
|
||||||
pSHead->ssize = sizeof(TqSerializedHead);
|
pSHead->ssize = sizeof(TqSerializedHead);
|
||||||
int allocatedSize = sizeof(TqSerializedHead);
|
int allocatedSize = sizeof(TqSerializedHead);
|
||||||
int offset = lseek(pMeta->fileFd, 0, SEEK_CUR);
|
int offset = lseek(pMeta->fileFd, 0, SEEK_CUR);
|
||||||
|
|
||||||
|
tqReadLastPage(pMeta->idxFd, &idxBuf);
|
||||||
|
|
||||||
|
if(idxBuf.head.writeOffset == TQ_PAGE_SIZE) {
|
||||||
|
lseek(pMeta->idxFd, 0, SEEK_END);
|
||||||
|
memset(&idxBuf, 0, TQ_PAGE_SIZE);
|
||||||
|
idxBuf.head.writeOffset = TQ_IDX_PAGE_HEAD_SIZE;
|
||||||
|
} else {
|
||||||
|
bufPtr = POINTER_SHIFT(&idxBuf, idxBuf.head.writeOffset);
|
||||||
|
}
|
||||||
|
|
||||||
while(pHead != pNode) {
|
while(pHead != pNode) {
|
||||||
int nBytes = 0;
|
int nBytes = 0;
|
||||||
|
|
||||||
|
@ -308,18 +352,23 @@ int32_t tqStorePersist(TqMetaStore* pMeta) {
|
||||||
ASSERT(nBytesTxn == pSHead->ssize);
|
ASSERT(nBytesTxn == pSHead->ssize);
|
||||||
nBytes += nBytesTxn;
|
nBytes += nBytesTxn;
|
||||||
}
|
}
|
||||||
|
pNode->handle.offset = offset;
|
||||||
|
offset += nBytes;
|
||||||
|
|
||||||
//write idx file
|
//write idx file
|
||||||
//TODO: endian check and convert
|
//TODO: endian check and convert
|
||||||
*(bufPtr++) = pNode->handle.key;
|
*(bufPtr++) = pNode->handle.key;
|
||||||
*(bufPtr++) = pNode->handle.offset;
|
*(bufPtr++) = pNode->handle.offset;
|
||||||
*(bufPtr++) = (int64_t)nBytes;
|
*(bufPtr++) = (int64_t)nBytes;
|
||||||
if((char*)(bufPtr + 3) > writeBuf + TQ_PAGE_SIZE) {
|
idxBuf.head.writeOffset += TQ_IDX_SIZE;
|
||||||
nBytes = write(pMeta->idxFd, writeBuf, sizeof(writeBuf));
|
|
||||||
|
if(idxBuf.head.writeOffset >= TQ_PAGE_SIZE) {
|
||||||
|
nBytes = write(pMeta->idxFd, &idxBuf, TQ_PAGE_SIZE);
|
||||||
//TODO: handle error with tfile
|
//TODO: handle error with tfile
|
||||||
ASSERT(nBytes == sizeof(writeBuf));
|
ASSERT(nBytes == TQ_PAGE_SIZE);
|
||||||
memset(writeBuf, 0, TQ_PAGE_SIZE);
|
memset(&idxBuf, 0, TQ_PAGE_SIZE);
|
||||||
bufPtr = (int64_t*)writeBuf;
|
idxBuf.head.writeOffset = TQ_IDX_PAGE_HEAD_SIZE;
|
||||||
|
bufPtr = (int64_t*)&idxBuf.buffer;
|
||||||
}
|
}
|
||||||
//remove from unpersist list
|
//remove from unpersist list
|
||||||
pHead->unpersistNext = pNode->unpersistNext;
|
pHead->unpersistNext = pNode->unpersistNext;
|
||||||
|
@ -331,7 +380,7 @@ int32_t tqStorePersist(TqMetaStore* pMeta) {
|
||||||
if(pNode->handle.valueInUse == TQ_DELETE_TOKEN &&
|
if(pNode->handle.valueInUse == TQ_DELETE_TOKEN &&
|
||||||
pNode->handle.valueInTxn == NULL
|
pNode->handle.valueInTxn == NULL
|
||||||
) {
|
) {
|
||||||
int bucketKey = pNode->handle.key & TQ_BUCKET_SIZE;
|
int bucketKey = pNode->handle.key & TQ_BUCKET_MASK;
|
||||||
TqMetaList* pBucketHead = pMeta->bucket[bucketKey];
|
TqMetaList* pBucketHead = pMeta->bucket[bucketKey];
|
||||||
if(pBucketHead == pNode) {
|
if(pBucketHead == pNode) {
|
||||||
pMeta->bucket[bucketKey] = pNode->next;
|
pMeta->bucket[bucketKey] = pNode->next;
|
||||||
|
@ -351,11 +400,11 @@ int32_t tqStorePersist(TqMetaStore* pMeta) {
|
||||||
|
|
||||||
//write left bytes
|
//write left bytes
|
||||||
free(pSHead);
|
free(pSHead);
|
||||||
if((char*)bufPtr != writeBuf) {
|
//TODO: write new version in tfile
|
||||||
int used = (char*)bufPtr - writeBuf;
|
if((char*)bufPtr != idxBuf.buffer) {
|
||||||
int nBytes = write(pMeta->idxFd, writeBuf, used);
|
int nBytes = write(pMeta->idxFd, &idxBuf, idxBuf.head.writeOffset);
|
||||||
//TODO: handle error in tfile
|
//TODO: handle error in tfile
|
||||||
ASSERT(nBytes == used);
|
ASSERT(nBytes == idxBuf.head.writeOffset);
|
||||||
}
|
}
|
||||||
//TODO: using fsync in tfile
|
//TODO: using fsync in tfile
|
||||||
fsync(pMeta->idxFd);
|
fsync(pMeta->idxFd);
|
||||||
|
@ -364,7 +413,7 @@ int32_t tqStorePersist(TqMetaStore* pMeta) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t tqHandlePutCommitted(TqMetaStore* pMeta, int64_t key, void* value) {
|
static int32_t tqHandlePutCommitted(TqMetaStore* pMeta, int64_t key, void* value) {
|
||||||
int64_t bucketKey = key & TQ_BUCKET_SIZE;
|
int64_t bucketKey = key & TQ_BUCKET_MASK;
|
||||||
TqMetaList* pNode = pMeta->bucket[bucketKey];
|
TqMetaList* pNode = pMeta->bucket[bucketKey];
|
||||||
while(pNode) {
|
while(pNode) {
|
||||||
if(pNode->handle.key == key) {
|
if(pNode->handle.key == key) {
|
||||||
|
@ -397,11 +446,12 @@ static int32_t tqHandlePutCommitted(TqMetaStore* pMeta, int64_t key, void* value
|
||||||
}
|
}
|
||||||
|
|
||||||
void* tqHandleGet(TqMetaStore* pMeta, int64_t key) {
|
void* tqHandleGet(TqMetaStore* pMeta, int64_t key) {
|
||||||
int64_t bucketKey = key & TQ_BUCKET_SIZE;
|
int64_t bucketKey = key & TQ_BUCKET_MASK;
|
||||||
TqMetaList* pNode = pMeta->bucket[bucketKey];
|
TqMetaList* pNode = pMeta->bucket[bucketKey];
|
||||||
while(pNode) {
|
while(pNode) {
|
||||||
if(pNode->handle.key == key) {
|
if(pNode->handle.key == key) {
|
||||||
if(pNode->handle.valueInUse != NULL) {
|
if(pNode->handle.valueInUse != NULL
|
||||||
|
&& pNode->handle.valueInUse != TQ_DELETE_TOKEN) {
|
||||||
return pNode->handle.valueInUse;
|
return pNode->handle.valueInUse;
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -414,7 +464,7 @@ void* tqHandleGet(TqMetaStore* pMeta, int64_t key) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t tqHandleMovePut(TqMetaStore* pMeta, int64_t key, void* value) {
|
int32_t tqHandleMovePut(TqMetaStore* pMeta, int64_t key, void* value) {
|
||||||
int64_t bucketKey = key & TQ_BUCKET_SIZE;
|
int64_t bucketKey = key & TQ_BUCKET_MASK;
|
||||||
TqMetaList* pNode = pMeta->bucket[bucketKey];
|
TqMetaList* pNode = pMeta->bucket[bucketKey];
|
||||||
while(pNode) {
|
while(pNode) {
|
||||||
if(pNode->handle.key == key) {
|
if(pNode->handle.key == key) {
|
||||||
|
@ -452,7 +502,7 @@ int32_t tqHandleCopyPut(TqMetaStore* pMeta, int64_t key, void* value, size_t vsi
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
memcpy(vmem, value, vsize);
|
memcpy(vmem, value, vsize);
|
||||||
int64_t bucketKey = key & TQ_BUCKET_SIZE;
|
int64_t bucketKey = key & TQ_BUCKET_MASK;
|
||||||
TqMetaList* pNode = pMeta->bucket[bucketKey];
|
TqMetaList* pNode = pMeta->bucket[bucketKey];
|
||||||
while(pNode) {
|
while(pNode) {
|
||||||
if(pNode->handle.key == key) {
|
if(pNode->handle.key == key) {
|
||||||
|
@ -484,7 +534,7 @@ int32_t tqHandleCopyPut(TqMetaStore* pMeta, int64_t key, void* value, size_t vsi
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* tqHandleGetUncommitted(TqMetaStore* pMeta, int64_t key) {
|
static void* tqHandleGetUncommitted(TqMetaStore* pMeta, int64_t key) {
|
||||||
int64_t bucketKey = key & TQ_BUCKET_SIZE;
|
int64_t bucketKey = key & TQ_BUCKET_MASK;
|
||||||
TqMetaList* pNode = pMeta->bucket[bucketKey];
|
TqMetaList* pNode = pMeta->bucket[bucketKey];
|
||||||
while(pNode) {
|
while(pNode) {
|
||||||
if(pNode->handle.key == key) {
|
if(pNode->handle.key == key) {
|
||||||
|
@ -502,10 +552,13 @@ static void* tqHandleGetUncommitted(TqMetaStore* pMeta, int64_t key) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t tqHandleCommit(TqMetaStore* pMeta, int64_t key) {
|
int32_t tqHandleCommit(TqMetaStore* pMeta, int64_t key) {
|
||||||
int64_t bucketKey = key & TQ_BUCKET_SIZE;
|
int64_t bucketKey = key & TQ_BUCKET_MASK;
|
||||||
TqMetaList* pNode = pMeta->bucket[bucketKey];
|
TqMetaList* pNode = pMeta->bucket[bucketKey];
|
||||||
while(pNode) {
|
while(pNode) {
|
||||||
if(pNode->handle.key == key) {
|
if(pNode->handle.key == key) {
|
||||||
|
if(pNode->handle.valueInTxn == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
if(pNode->handle.valueInUse
|
if(pNode->handle.valueInUse
|
||||||
&& pNode->handle.valueInUse != TQ_DELETE_TOKEN) {
|
&& pNode->handle.valueInUse != TQ_DELETE_TOKEN) {
|
||||||
pMeta->deleter(pNode->handle.valueInUse);
|
pMeta->deleter(pNode->handle.valueInUse);
|
||||||
|
@ -518,11 +571,11 @@ int32_t tqHandleCommit(TqMetaStore* pMeta, int64_t key) {
|
||||||
pNode = pNode->next;
|
pNode = pNode->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t tqHandleAbort(TqMetaStore* pMeta, int64_t key) {
|
int32_t tqHandleAbort(TqMetaStore* pMeta, int64_t key) {
|
||||||
int64_t bucketKey = key & TQ_BUCKET_SIZE;
|
int64_t bucketKey = key & TQ_BUCKET_MASK;
|
||||||
TqMetaList* pNode = pMeta->bucket[bucketKey];
|
TqMetaList* pNode = pMeta->bucket[bucketKey];
|
||||||
while(pNode) {
|
while(pNode) {
|
||||||
if(pNode->handle.key == key) {
|
if(pNode->handle.key == key) {
|
||||||
|
@ -543,12 +596,13 @@ int32_t tqHandleAbort(TqMetaStore* pMeta, int64_t key) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t tqHandleDel(TqMetaStore* pMeta, int64_t key) {
|
int32_t tqHandleDel(TqMetaStore* pMeta, int64_t key) {
|
||||||
int64_t bucketKey = key & TQ_BUCKET_SIZE;
|
int64_t bucketKey = key & TQ_BUCKET_MASK;
|
||||||
TqMetaList* pNode = pMeta->bucket[bucketKey];
|
TqMetaList* pNode = pMeta->bucket[bucketKey];
|
||||||
while(pNode) {
|
while(pNode) {
|
||||||
if(pNode->handle.valueInTxn
|
if(pNode->handle.valueInTxn != TQ_DELETE_TOKEN) {
|
||||||
&& pNode->handle.valueInTxn != TQ_DELETE_TOKEN) {
|
if(pNode->handle.valueInTxn) {
|
||||||
pMeta->deleter(pNode->handle.valueInTxn);
|
pMeta->deleter(pNode->handle.valueInTxn);
|
||||||
|
}
|
||||||
pNode->handle.valueInTxn = TQ_DELETE_TOKEN;
|
pNode->handle.valueInTxn = TQ_DELETE_TOKEN;
|
||||||
tqLinkUnpersist(pMeta, pNode);
|
tqLinkUnpersist(pMeta, pNode);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -560,34 +614,7 @@ int32_t tqHandleDel(TqMetaStore* pMeta, int64_t key) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t tqHandleClear(TqMetaStore* pMeta, int64_t key) {
|
//TODO: clean deleted idx and data from persistent file
|
||||||
int64_t bucketKey = key & TQ_BUCKET_SIZE;
|
int32_t tqStoreCompact(TqMetaStore *pMeta) {
|
||||||
TqMetaList* pNode = pMeta->bucket[bucketKey];
|
return 0;
|
||||||
bool exist = false;
|
|
||||||
while(pNode) {
|
|
||||||
if(pNode->handle.key == key) {
|
|
||||||
if(pNode->handle.valueInUse != NULL) {
|
|
||||||
exist = true;
|
|
||||||
if(pNode->handle.valueInUse != TQ_DELETE_TOKEN) {
|
|
||||||
pMeta->deleter(pNode->handle.valueInUse);
|
|
||||||
}
|
|
||||||
pNode->handle.valueInUse = TQ_DELETE_TOKEN;
|
|
||||||
}
|
|
||||||
if(pNode->handle.valueInTxn != NULL) {
|
|
||||||
exist = true;
|
|
||||||
if(pNode->handle.valueInTxn != TQ_DELETE_TOKEN) {
|
|
||||||
pMeta->deleter(pNode->handle.valueInTxn);
|
|
||||||
}
|
|
||||||
pNode->handle.valueInTxn = TQ_DELETE_TOKEN;
|
|
||||||
}
|
|
||||||
if(exist) {
|
|
||||||
tqLinkUnpersist(pMeta, pNode);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
pNode = pNode->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -2;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,10 @@ TEST_F(TqMetaTest, copyPutTest) {
|
||||||
|
|
||||||
Foo* pFoo = (Foo*) tqHandleGet(pMeta, 1);
|
Foo* pFoo = (Foo*) tqHandleGet(pMeta, 1);
|
||||||
EXPECT_EQ(pFoo == NULL, true);
|
EXPECT_EQ(pFoo == NULL, true);
|
||||||
|
|
||||||
|
tqHandleCommit(pMeta, 1);
|
||||||
|
pFoo = (Foo*) tqHandleGet(pMeta, 1);
|
||||||
|
EXPECT_EQ(pFoo->a, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TqMetaTest, persistTest) {
|
TEST_F(TqMetaTest, persistTest) {
|
||||||
|
@ -82,8 +86,6 @@ TEST_F(TqMetaTest, persistTest) {
|
||||||
|
|
||||||
pBar = (Foo*)tqHandleGet(pMeta, 2);
|
pBar = (Foo*)tqHandleGet(pMeta, 2);
|
||||||
EXPECT_EQ(pBar == NULL, true);
|
EXPECT_EQ(pBar == NULL, true);
|
||||||
|
|
||||||
//taosRemoveDir(pathName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TqMetaTest, uncommittedTest) {
|
TEST_F(TqMetaTest, uncommittedTest) {
|
||||||
|
@ -130,4 +132,163 @@ TEST_F(TqMetaTest, deleteTest) {
|
||||||
tqHandleCommit(pMeta, 1);
|
tqHandleCommit(pMeta, 1);
|
||||||
pFoo = (Foo*) tqHandleGet(pMeta, 1);
|
pFoo = (Foo*) tqHandleGet(pMeta, 1);
|
||||||
EXPECT_EQ(pFoo == NULL, true);
|
EXPECT_EQ(pFoo == NULL, true);
|
||||||
|
|
||||||
|
tqStoreClose(pMeta);
|
||||||
|
pMeta = tqStoreOpen(pathName,
|
||||||
|
FooSerializer, FooDeserializer, FooDeleter);
|
||||||
|
ASSERT(pMeta);
|
||||||
|
|
||||||
|
pFoo = (Foo*) tqHandleGet(pMeta, 1);
|
||||||
|
EXPECT_EQ(pFoo == NULL, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TqMetaTest, intxnPersist) {
|
||||||
|
Foo* pFoo = (Foo*)malloc(sizeof(Foo));
|
||||||
|
pFoo->a = 3;
|
||||||
|
tqHandleMovePut(pMeta, 1, pFoo);
|
||||||
|
tqHandleCommit(pMeta, 1);
|
||||||
|
|
||||||
|
Foo* pBar = (Foo*)malloc(sizeof(Foo));
|
||||||
|
pBar->a = 4;
|
||||||
|
tqHandleMovePut(pMeta, 1, pBar);
|
||||||
|
|
||||||
|
Foo* pFoo1 = (Foo*)tqHandleGet(pMeta, 1);
|
||||||
|
EXPECT_EQ(pFoo1->a, 3);
|
||||||
|
|
||||||
|
tqStoreClose(pMeta);
|
||||||
|
pMeta = tqStoreOpen(pathName,
|
||||||
|
FooSerializer, FooDeserializer, FooDeleter);
|
||||||
|
ASSERT(pMeta);
|
||||||
|
|
||||||
|
pFoo1 = (Foo*)tqHandleGet(pMeta, 1);
|
||||||
|
EXPECT_EQ(pFoo1->a, 3);
|
||||||
|
|
||||||
|
tqHandleCommit(pMeta, 1);
|
||||||
|
|
||||||
|
pFoo1 = (Foo*)tqHandleGet(pMeta, 1);
|
||||||
|
EXPECT_EQ(pFoo1->a, 4);
|
||||||
|
|
||||||
|
tqStoreClose(pMeta);
|
||||||
|
pMeta = tqStoreOpen(pathName,
|
||||||
|
FooSerializer, FooDeserializer, FooDeleter);
|
||||||
|
ASSERT(pMeta);
|
||||||
|
|
||||||
|
pFoo1 = (Foo*)tqHandleGet(pMeta, 1);
|
||||||
|
EXPECT_EQ(pFoo1->a, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TqMetaTest, multiplePage) {
|
||||||
|
srand(0);
|
||||||
|
std::vector<int> v;
|
||||||
|
for(int i = 0; i < 1000; i++) {
|
||||||
|
v.push_back(rand());
|
||||||
|
Foo foo;
|
||||||
|
foo.a = v[i];
|
||||||
|
tqHandleCopyPut(pMeta, i, &foo, sizeof(Foo));
|
||||||
|
}
|
||||||
|
for(int i = 0; i < 500; i++) {
|
||||||
|
tqHandleCommit(pMeta, i);
|
||||||
|
Foo* pFoo = (Foo*)tqHandleGet(pMeta, i);
|
||||||
|
ASSERT_EQ(pFoo != NULL, true) << " at idx " << i << "\n";
|
||||||
|
EXPECT_EQ(pFoo->a, v[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
tqStoreClose(pMeta);
|
||||||
|
pMeta = tqStoreOpen(pathName,
|
||||||
|
FooSerializer, FooDeserializer, FooDeleter);
|
||||||
|
ASSERT(pMeta);
|
||||||
|
|
||||||
|
for(int i = 500; i < 1000; i++) {
|
||||||
|
tqHandleCommit(pMeta, i);
|
||||||
|
Foo* pFoo = (Foo*)tqHandleGet(pMeta, i);
|
||||||
|
ASSERT_EQ(pFoo != NULL, true) << " at idx " << i << "\n";
|
||||||
|
EXPECT_EQ(pFoo->a, v[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < 1000; i++) {
|
||||||
|
Foo* pFoo = (Foo*)tqHandleGet(pMeta, i);
|
||||||
|
ASSERT_EQ(pFoo != NULL, true) << " at idx " << i << "\n";
|
||||||
|
EXPECT_EQ(pFoo->a, v[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TqMetaTest, multipleRewrite) {
|
||||||
|
srand(0);
|
||||||
|
std::vector<int> v;
|
||||||
|
for(int i = 0; i < 1000; i++) {
|
||||||
|
v.push_back(rand());
|
||||||
|
Foo foo;
|
||||||
|
foo.a = v[i];
|
||||||
|
tqHandleCopyPut(pMeta, i, &foo, sizeof(Foo));
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < 500; i++) {
|
||||||
|
tqHandleCommit(pMeta, i);
|
||||||
|
v[i] = rand();
|
||||||
|
Foo foo;
|
||||||
|
foo.a = v[i];
|
||||||
|
tqHandleCopyPut(pMeta, i, &foo, sizeof(Foo));
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 500; i < 1000; i++) {
|
||||||
|
v[i] = rand();
|
||||||
|
Foo foo;
|
||||||
|
foo.a = v[i];
|
||||||
|
tqHandleCopyPut(pMeta, i, &foo, sizeof(Foo));
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < 1000; i++) {
|
||||||
|
tqHandleCommit(pMeta, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
tqStoreClose(pMeta);
|
||||||
|
pMeta = tqStoreOpen(pathName,
|
||||||
|
FooSerializer, FooDeserializer, FooDeleter);
|
||||||
|
ASSERT(pMeta);
|
||||||
|
|
||||||
|
for(int i = 500; i < 1000; i++) {
|
||||||
|
v[i] = rand();
|
||||||
|
Foo foo;
|
||||||
|
foo.a = v[i];
|
||||||
|
tqHandleCopyPut(pMeta, i, &foo, sizeof(Foo));
|
||||||
|
tqHandleCommit(pMeta, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < 1000; i++) {
|
||||||
|
Foo* pFoo = (Foo*)tqHandleGet(pMeta, i);
|
||||||
|
ASSERT_EQ(pFoo != NULL, true) << " at idx " << i << "\n";
|
||||||
|
EXPECT_EQ(pFoo->a, v[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TqMetaTest, dupCommit) {
|
||||||
|
srand(0);
|
||||||
|
std::vector<int> v;
|
||||||
|
for(int i = 0; i < 1000; i++) {
|
||||||
|
v.push_back(rand());
|
||||||
|
Foo foo;
|
||||||
|
foo.a = v[i];
|
||||||
|
tqHandleCopyPut(pMeta, i, &foo, sizeof(Foo));
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < 1000; i++) {
|
||||||
|
int ret = tqHandleCommit(pMeta, i);
|
||||||
|
EXPECT_EQ(ret, 0);
|
||||||
|
ret = tqHandleCommit(pMeta, i);
|
||||||
|
EXPECT_EQ(ret, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < 1000; i++) {
|
||||||
|
int ret = tqHandleCommit(pMeta, i);
|
||||||
|
EXPECT_EQ(ret, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < 1000; i++) {
|
||||||
|
Foo* pFoo = (Foo*)tqHandleGet(pMeta, i);
|
||||||
|
ASSERT_EQ(pFoo != NULL, true) << " at idx " << i << "\n";
|
||||||
|
EXPECT_EQ(pFoo->a, v[i]);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,8 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _TD_RAFT_INT_H_
|
#ifndef _TD_TSDB_IDX_H_
|
||||||
#define _TD_RAFT_INT_H_
|
#define _TD_TSDB_IDX_H_
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -24,4 +24,4 @@ extern "C" {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /*_TD_RAFT_INT_H_*/
|
#endif /*_TD_TSDB_IDX_H_*/
|
|
@ -20,6 +20,11 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern const STsdbOptions defautlTsdbOptions;
|
||||||
|
|
||||||
|
int tsdbValidateOptions(const STsdbOptions *);
|
||||||
|
void tsdbOptionsCopy(STsdbOptions *pDest, const STsdbOptions *pSrc);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_TSDB_SMA_H_
|
||||||
|
#define _TD_TSDB_SMA_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*_TD_TSDB_SMA_H_*/
|
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
|
@ -13,4 +13,82 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "tsdbDef.h"
|
#include "tsdbDef.h"
|
||||||
|
|
||||||
|
static STsdb *tsdbNew(const char *path, const STsdbOptions *pTsdbOptions);
|
||||||
|
static void tsdbFree(STsdb *pTsdb);
|
||||||
|
static int tsdbOpenImpl(STsdb *pTsdb);
|
||||||
|
static void tsdbCloseImpl(STsdb *pTsdb);
|
||||||
|
|
||||||
|
STsdb *tsdbOpen(const char *path, const STsdbOptions *pTsdbOptions) {
|
||||||
|
STsdb *pTsdb = NULL;
|
||||||
|
|
||||||
|
// Set default TSDB Options
|
||||||
|
if (pTsdbOptions == NULL) {
|
||||||
|
pTsdbOptions = &defautlTsdbOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate the options
|
||||||
|
if (tsdbValidateOptions(pTsdbOptions) < 0) {
|
||||||
|
// TODO: handle error
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the handle
|
||||||
|
pTsdb = tsdbNew(path, pTsdbOptions);
|
||||||
|
if (pTsdb == NULL) {
|
||||||
|
// TODO: handle error
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
taosMkDir(path);
|
||||||
|
|
||||||
|
// Open the TSDB
|
||||||
|
if (tsdbOpenImpl(pTsdb) < 0) {
|
||||||
|
// TODO: handle error
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pTsdb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tsdbClose(STsdb *pTsdb) {
|
||||||
|
if (pTsdb) {
|
||||||
|
tsdbCloseImpl(pTsdb);
|
||||||
|
tsdbFree(pTsdb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tsdbRemove(const char *path) { taosRemoveDir(path); }
|
||||||
|
|
||||||
|
/* ------------------------ STATIC METHODS ------------------------ */
|
||||||
|
static STsdb *tsdbNew(const char *path, const STsdbOptions *pTsdbOptions) {
|
||||||
|
STsdb *pTsdb = NULL;
|
||||||
|
|
||||||
|
pTsdb = (STsdb *)calloc(1, sizeof(STsdb));
|
||||||
|
if (pTsdb == NULL) {
|
||||||
|
// TODO: handle error
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pTsdb->path = strdup(path);
|
||||||
|
tsdbOptionsCopy(&(pTsdb->options), pTsdbOptions);
|
||||||
|
|
||||||
|
return pTsdb;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tsdbFree(STsdb *pTsdb) {
|
||||||
|
if (pTsdb) {
|
||||||
|
tfree(pTsdb->path);
|
||||||
|
free(pTsdb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tsdbOpenImpl(STsdb *pTsdb) {
|
||||||
|
// TODO
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tsdbCloseImpl(STsdb *pTsdb) {
|
||||||
|
// TODO
|
||||||
|
}
|
|
@ -11,4 +11,24 @@
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "tsdbDef.h"
|
||||||
|
|
||||||
|
const STsdbOptions defautlTsdbOptions = {.lruCacheSize = 0};
|
||||||
|
|
||||||
|
int tsdbOptionsInit(STsdbOptions *pTsdbOptions) {
|
||||||
|
// TODO
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tsdbOptionsClear(STsdbOptions *pTsdbOptions) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
int tsdbValidateOptions(const STsdbOptions *pTsdbOptions) {
|
||||||
|
// TODO
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tsdbOptionsCopy(STsdbOptions *pDest, const STsdbOptions *pSrc) { memcpy(pDest, pSrc, sizeof(STsdbOptions)); }
|
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
|
@ -4,6 +4,7 @@ add_library(sync ${SYNC_SRC})
|
||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
sync
|
sync
|
||||||
PUBLIC common
|
PUBLIC common
|
||||||
|
PUBLIC transport
|
||||||
PUBLIC util
|
PUBLIC util
|
||||||
PUBLIC wal
|
PUBLIC wal
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,144 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <cli@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_LIBS_SYNC_RAFT_H
|
||||||
|
#define _TD_LIBS_SYNC_RAFT_H
|
||||||
|
|
||||||
|
#include "sync.h"
|
||||||
|
#include "sync_type.h"
|
||||||
|
#include "raft_message.h"
|
||||||
|
#include "sync_raft_impl.h"
|
||||||
|
#include "sync_raft_quorum.h"
|
||||||
|
|
||||||
|
typedef struct RaftLeaderState {
|
||||||
|
|
||||||
|
} RaftLeaderState;
|
||||||
|
|
||||||
|
typedef struct RaftCandidateState {
|
||||||
|
/* true if in pre-vote phase */
|
||||||
|
bool inPreVote;
|
||||||
|
} RaftCandidateState;
|
||||||
|
|
||||||
|
typedef struct SSyncRaftIOMethods {
|
||||||
|
// send SSyncMessage to node
|
||||||
|
int (*send)(const SSyncMessage* pMsg, const SNodeInfo* pNode);
|
||||||
|
} SSyncRaftIOMethods;
|
||||||
|
|
||||||
|
typedef int (*SyncRaftStepFp)(SSyncRaft* pRaft, const SSyncMessage* pMsg);
|
||||||
|
typedef void (*SyncRaftTickFp)(SSyncRaft* pRaft);
|
||||||
|
|
||||||
|
struct SSyncRaft {
|
||||||
|
// owner sync node
|
||||||
|
SSyncNode* pNode;
|
||||||
|
|
||||||
|
SSyncCluster cluster;
|
||||||
|
|
||||||
|
int selfIndex;
|
||||||
|
SyncNodeId selfId;
|
||||||
|
SyncGroupId selfGroupId;
|
||||||
|
|
||||||
|
SSyncRaftIOMethods io;
|
||||||
|
|
||||||
|
SSyncFSM fsm;
|
||||||
|
SSyncLogStore logStore;
|
||||||
|
SStateManager stateManager;
|
||||||
|
|
||||||
|
union {
|
||||||
|
RaftLeaderState leaderState;
|
||||||
|
RaftCandidateState candidateState;
|
||||||
|
};
|
||||||
|
|
||||||
|
SyncTerm term;
|
||||||
|
SyncNodeId voteFor;
|
||||||
|
|
||||||
|
SSyncRaftLog *log;
|
||||||
|
|
||||||
|
int maxMsgSize;
|
||||||
|
SSyncRaftProgressTracker *tracker;
|
||||||
|
|
||||||
|
ESyncState state;
|
||||||
|
|
||||||
|
// isLearner is true if the local raft node is a learner.
|
||||||
|
bool isLearner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the leader id
|
||||||
|
**/
|
||||||
|
SyncNodeId leaderId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* leadTransferee is id of the leader transfer target when its value is not zero.
|
||||||
|
* Follow the procedure defined in raft thesis 3.10.
|
||||||
|
**/
|
||||||
|
SyncNodeId leadTransferee;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only one conf change may be pending (in the log, but not yet
|
||||||
|
* applied) at a time. This is enforced via pendingConfIndex, which
|
||||||
|
* is set to a value >= the log index of the latest pending
|
||||||
|
* configuration change (if any). Config changes are only allowed to
|
||||||
|
* be proposed if the leader's applied index is greater than this
|
||||||
|
* value.
|
||||||
|
**/
|
||||||
|
SyncIndex pendingConfigIndex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* an estimate of the size of the uncommitted tail of the Raft log. Used to
|
||||||
|
* prevent unbounded log growth. Only maintained by the leader. Reset on
|
||||||
|
* term changes.
|
||||||
|
**/
|
||||||
|
uint32_t uncommittedSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* number of ticks since it reached last electionTimeout when it is leader
|
||||||
|
* or candidate.
|
||||||
|
* number of ticks since it reached last electionTimeout or received a
|
||||||
|
* valid message from current leader when it is a follower.
|
||||||
|
**/
|
||||||
|
uint16_t electionElapsed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* number of ticks since it reached last heartbeatTimeout.
|
||||||
|
* only leader keeps heartbeatElapsed.
|
||||||
|
**/
|
||||||
|
uint16_t heartbeatElapsed;
|
||||||
|
|
||||||
|
bool preVote;
|
||||||
|
bool checkQuorum;
|
||||||
|
|
||||||
|
int heartbeatTimeout;
|
||||||
|
int electionTimeout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* randomizedElectionTimeout is a random number between
|
||||||
|
* [electiontimeout, 2 * electiontimeout - 1]. It gets reset
|
||||||
|
* when raft changes its state to follower or candidate.
|
||||||
|
**/
|
||||||
|
int randomizedElectionTimeout;
|
||||||
|
bool disableProposalForwarding;
|
||||||
|
|
||||||
|
// current tick count since start up
|
||||||
|
uint32_t currentTick;
|
||||||
|
|
||||||
|
SyncRaftStepFp stepFp;
|
||||||
|
|
||||||
|
SyncRaftTickFp tickFp;
|
||||||
|
};
|
||||||
|
|
||||||
|
int32_t syncRaftStart(SSyncRaft* pRaft, const SSyncInfo* pInfo);
|
||||||
|
int32_t syncRaftStep(SSyncRaft* pRaft, const SSyncMessage* pMsg);
|
||||||
|
int32_t syncRaftTick(SSyncRaft* pRaft);
|
||||||
|
|
||||||
|
#endif /* _TD_LIBS_SYNC_RAFT_H */
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <cli@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_LIBS_SYNC_RAFT_CONFIGURATION_H
|
||||||
|
#define _TD_LIBS_SYNC_RAFT_CONFIGURATION_H
|
||||||
|
|
||||||
|
#include "sync.h"
|
||||||
|
#include "sync_type.h"
|
||||||
|
|
||||||
|
// return -1 if cannot find this id
|
||||||
|
int syncRaftConfigurationIndexOfNode(SSyncRaft *pRaft, SyncNodeId id);
|
||||||
|
|
||||||
|
int syncRaftConfigurationVoterCount(SSyncRaft *pRaft);
|
||||||
|
|
||||||
|
#endif /* _TD_LIBS_SYNC_RAFT_CONFIGURATION_H */
|
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <cli@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_LIBS_SYNC_RAFT_LOG_H
|
||||||
|
#define _TD_LIBS_SYNC_RAFT_LOG_H
|
||||||
|
|
||||||
|
#include "sync.h"
|
||||||
|
#include "sync_type.h"
|
||||||
|
|
||||||
|
typedef enum SyncEntryType {
|
||||||
|
SYNC_ENTRY_TYPE_LOG = 1,
|
||||||
|
}SyncEntryType;
|
||||||
|
|
||||||
|
struct SSyncRaftEntry {
|
||||||
|
SyncTerm term;
|
||||||
|
|
||||||
|
SyncIndex index;
|
||||||
|
|
||||||
|
SyncEntryType type;
|
||||||
|
|
||||||
|
SSyncBuffer buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SSyncRaftLog {
|
||||||
|
SyncIndex uncommittedConfigIndex;
|
||||||
|
|
||||||
|
SyncIndex commitIndex;
|
||||||
|
|
||||||
|
SyncIndex appliedIndex;
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
SSyncRaftLog* syncRaftLogOpen();
|
||||||
|
|
||||||
|
SyncIndex syncRaftLogLastIndex(SSyncRaftLog* pLog);
|
||||||
|
|
||||||
|
SyncIndex syncRaftLogSnapshotIndex(SSyncRaftLog* pLog);
|
||||||
|
|
||||||
|
SyncTerm syncRaftLogLastTerm(SSyncRaftLog* pLog);
|
||||||
|
|
||||||
|
bool syncRaftLogIsUptodate(SSyncRaftLog* pLog, SyncIndex index, SyncTerm term);
|
||||||
|
|
||||||
|
int syncRaftLogNumOfPendingConf(SSyncRaftLog* pLog);
|
||||||
|
|
||||||
|
bool syncRaftHasUnappliedLog(SSyncRaftLog* pLog);
|
||||||
|
|
||||||
|
SyncTerm syncRaftLogTermOf(SSyncRaftLog* pLog, SyncIndex index);
|
||||||
|
|
||||||
|
int syncRaftLogAppend(SSyncRaftLog* pLog, SSyncRaftEntry *pEntries, int n);
|
||||||
|
|
||||||
|
int syncRaftLogAcquire(SSyncRaftLog* pLog, SyncIndex index, int maxMsgSize,
|
||||||
|
SSyncRaftEntry **ppEntries, int *n);
|
||||||
|
|
||||||
|
void syncRaftLogRelease(SSyncRaftLog* pLog, SyncIndex index,
|
||||||
|
SSyncRaftEntry *pEntries, int n);
|
||||||
|
|
||||||
|
bool syncRaftLogMatchTerm();
|
||||||
|
|
||||||
|
static FORCE_INLINE bool syncRaftLogIsCommitted(SSyncRaftLog* pLog, SyncIndex index) {
|
||||||
|
return pLog->commitIndex > index;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _TD_LIBS_SYNC_RAFT_LOG_H */
|
|
@ -0,0 +1,237 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <cli@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_LIBS_SYNC_RAFT_MESSAGE_H
|
||||||
|
#define _TD_LIBS_SYNC_RAFT_MESSAGE_H
|
||||||
|
|
||||||
|
#include "sync.h"
|
||||||
|
#include "sync_type.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* below define message type which handled by Raft.
|
||||||
|
*
|
||||||
|
* internal message, which communicate between threads, start with RAFT_MSG_INTERNAL_*.
|
||||||
|
* internal message use pointer only and stack memory, need not to be decode/encode and free.
|
||||||
|
*
|
||||||
|
* outter message start with RAFT_MSG_*, which communicate between cluster peers,
|
||||||
|
* need to implement its decode/encode functions.
|
||||||
|
**/
|
||||||
|
typedef enum RaftMessageType {
|
||||||
|
// client propose a cmd
|
||||||
|
RAFT_MSG_INTERNAL_PROP = 1,
|
||||||
|
|
||||||
|
// node election timeout
|
||||||
|
RAFT_MSG_INTERNAL_ELECTION = 2,
|
||||||
|
|
||||||
|
RAFT_MSG_VOTE = 3,
|
||||||
|
RAFT_MSG_VOTE_RESP = 4,
|
||||||
|
|
||||||
|
RAFT_MSG_APPEND = 5,
|
||||||
|
RAFT_MSG_APPEND_RESP = 6,
|
||||||
|
} RaftMessageType;
|
||||||
|
|
||||||
|
typedef struct RaftMsgInternal_Prop {
|
||||||
|
const SSyncBuffer *pBuf;
|
||||||
|
bool isWeak;
|
||||||
|
void* pData;
|
||||||
|
} RaftMsgInternal_Prop;
|
||||||
|
|
||||||
|
typedef struct RaftMsgInternal_Election {
|
||||||
|
|
||||||
|
} RaftMsgInternal_Election;
|
||||||
|
|
||||||
|
typedef struct RaftMsg_Vote {
|
||||||
|
SyncRaftElectionType cType;
|
||||||
|
SyncIndex lastIndex;
|
||||||
|
SyncTerm lastTerm;
|
||||||
|
} RaftMsg_Vote;
|
||||||
|
|
||||||
|
typedef struct RaftMsg_VoteResp {
|
||||||
|
bool rejected;
|
||||||
|
SyncRaftElectionType cType;
|
||||||
|
} RaftMsg_VoteResp;
|
||||||
|
|
||||||
|
typedef struct RaftMsg_Append_Entries {
|
||||||
|
// index of log entry preceeding new ones
|
||||||
|
SyncIndex index;
|
||||||
|
|
||||||
|
// term of entry at prevIndex
|
||||||
|
SyncTerm term;
|
||||||
|
|
||||||
|
// leader's commit index.
|
||||||
|
SyncIndex commitIndex;
|
||||||
|
|
||||||
|
// size of the log entries array
|
||||||
|
int nEntries;
|
||||||
|
|
||||||
|
// log entries array
|
||||||
|
SSyncRaftEntry* entries;
|
||||||
|
} RaftMsg_Append_Entries;
|
||||||
|
|
||||||
|
typedef struct RaftMsg_Append_Resp {
|
||||||
|
SyncIndex index;
|
||||||
|
} RaftMsg_Append_Resp;
|
||||||
|
|
||||||
|
typedef struct SSyncMessage {
|
||||||
|
RaftMessageType msgType;
|
||||||
|
SyncTerm term;
|
||||||
|
SyncGroupId groupId;
|
||||||
|
SyncNodeId from;
|
||||||
|
|
||||||
|
union {
|
||||||
|
RaftMsgInternal_Prop propose;
|
||||||
|
|
||||||
|
RaftMsgInternal_Election election;
|
||||||
|
|
||||||
|
RaftMsg_Vote vote;
|
||||||
|
RaftMsg_VoteResp voteResp;
|
||||||
|
|
||||||
|
RaftMsg_Append_Entries appendEntries;
|
||||||
|
RaftMsg_Append_Resp appendResp;
|
||||||
|
};
|
||||||
|
} SSyncMessage;
|
||||||
|
|
||||||
|
static FORCE_INLINE SSyncMessage* syncInitPropMsg(SSyncMessage* pMsg, const SSyncBuffer* pBuf, void* pData, bool isWeak) {
|
||||||
|
*pMsg = (SSyncMessage) {
|
||||||
|
.msgType = RAFT_MSG_INTERNAL_PROP,
|
||||||
|
.term = 0,
|
||||||
|
.propose = (RaftMsgInternal_Prop) {
|
||||||
|
.isWeak = isWeak,
|
||||||
|
.pBuf = pBuf,
|
||||||
|
.pData = pData,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return pMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCE_INLINE SSyncMessage* syncInitElectionMsg(SSyncMessage* pMsg, SyncNodeId from) {
|
||||||
|
*pMsg = (SSyncMessage) {
|
||||||
|
.msgType = RAFT_MSG_INTERNAL_ELECTION,
|
||||||
|
.term = 0,
|
||||||
|
.from = from,
|
||||||
|
.election = (RaftMsgInternal_Election) {
|
||||||
|
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return pMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCE_INLINE SSyncMessage* syncNewVoteMsg(SyncGroupId groupId, SyncNodeId from,
|
||||||
|
SyncTerm term, SyncRaftElectionType cType,
|
||||||
|
SyncIndex lastIndex, SyncTerm lastTerm) {
|
||||||
|
SSyncMessage* pMsg = (SSyncMessage*)malloc(sizeof(SSyncMessage));
|
||||||
|
if (pMsg == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
*pMsg = (SSyncMessage) {
|
||||||
|
.groupId = groupId,
|
||||||
|
.from = from,
|
||||||
|
.term = term,
|
||||||
|
.msgType = RAFT_MSG_VOTE,
|
||||||
|
.vote = (RaftMsg_Vote) {
|
||||||
|
.cType = cType,
|
||||||
|
.lastIndex = lastIndex,
|
||||||
|
.lastTerm = lastTerm,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return pMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCE_INLINE SSyncMessage* syncNewVoteRespMsg(SyncGroupId groupId, SyncNodeId from,
|
||||||
|
SyncRaftElectionType cType, bool rejected) {
|
||||||
|
SSyncMessage* pMsg = (SSyncMessage*)malloc(sizeof(SSyncMessage));
|
||||||
|
if (pMsg == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
*pMsg = (SSyncMessage) {
|
||||||
|
.groupId = groupId,
|
||||||
|
.from = from,
|
||||||
|
.msgType = RAFT_MSG_VOTE_RESP,
|
||||||
|
.voteResp = (RaftMsg_VoteResp) {
|
||||||
|
.cType = cType,
|
||||||
|
.rejected = rejected,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return pMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCE_INLINE SSyncMessage* syncNewAppendMsg(SyncGroupId groupId, SyncNodeId from,
|
||||||
|
SyncTerm term, SyncIndex logIndex, SyncTerm logTerm,
|
||||||
|
SyncIndex commitIndex, int nEntries, SSyncRaftEntry* entries) {
|
||||||
|
SSyncMessage* pMsg = (SSyncMessage*)malloc(sizeof(SSyncMessage));
|
||||||
|
if (pMsg == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
*pMsg = (SSyncMessage) {
|
||||||
|
.groupId = groupId,
|
||||||
|
.from = from,
|
||||||
|
.term = term,
|
||||||
|
.msgType = RAFT_MSG_APPEND,
|
||||||
|
.appendEntries = (RaftMsg_Append_Entries) {
|
||||||
|
.index = logIndex,
|
||||||
|
.term = logTerm,
|
||||||
|
.commitIndex = commitIndex,
|
||||||
|
.nEntries = nEntries,
|
||||||
|
.entries = entries,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return pMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCE_INLINE SSyncMessage* syncNewEmptyAppendRespMsg(SyncGroupId groupId, SyncNodeId from, SyncTerm term) {
|
||||||
|
SSyncMessage* pMsg = (SSyncMessage*)malloc(sizeof(SSyncMessage));
|
||||||
|
if (pMsg == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
*pMsg = (SSyncMessage) {
|
||||||
|
.groupId = groupId,
|
||||||
|
.from = from,
|
||||||
|
.term = term,
|
||||||
|
.msgType = RAFT_MSG_APPEND_RESP,
|
||||||
|
.appendResp = (RaftMsg_Append_Resp) {
|
||||||
|
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return pMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCE_INLINE bool syncIsInternalMsg(RaftMessageType msgType) {
|
||||||
|
return msgType == RAFT_MSG_INTERNAL_PROP ||
|
||||||
|
msgType == RAFT_MSG_INTERNAL_ELECTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCE_INLINE bool syncIsPreVoteRespMsg(const SSyncMessage* pMsg) {
|
||||||
|
return pMsg->msgType == RAFT_MSG_VOTE_RESP && pMsg->voteResp.cType == SYNC_RAFT_CAMPAIGN_PRE_ELECTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCE_INLINE bool syncIsPreVoteMsg(const SSyncMessage* pMsg) {
|
||||||
|
return pMsg->msgType == RAFT_MSG_VOTE && pMsg->voteResp.cType == SYNC_RAFT_CAMPAIGN_PRE_ELECTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
void syncFreeMessage(const SSyncMessage* pMsg);
|
||||||
|
|
||||||
|
// message handlers
|
||||||
|
int syncRaftHandleElectionMessage(SSyncRaft* pRaft, const SSyncMessage* pMsg);
|
||||||
|
int syncRaftHandleVoteMessage(SSyncRaft* pRaft, const SSyncMessage* pMsg);
|
||||||
|
int syncRaftHandleVoteRespMessage(SSyncRaft* pRaft, const SSyncMessage* pMsg);
|
||||||
|
int syncRaftHandleAppendEntriesMessage(SSyncRaft* pRaft, const SSyncMessage* pMsg);
|
||||||
|
|
||||||
|
#endif /* _TD_LIBS_SYNC_RAFT_MESSAGE_H */
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <cli@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TD_SYNC_RAFT_REPLICATION_H
|
||||||
|
#define TD_SYNC_RAFT_REPLICATION_H
|
||||||
|
|
||||||
|
#include "sync.h"
|
||||||
|
#include "syncInt.h"
|
||||||
|
#include "sync_type.h"
|
||||||
|
|
||||||
|
int syncRaftReplicate(SSyncRaft* pRaft, int i);
|
||||||
|
|
||||||
|
#endif /* TD_SYNC_RAFT_REPLICATION_H */
|
|
@ -0,0 +1,115 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <cli@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TD_SYNC_RAFT_UNSTABLE_LOG_H
|
||||||
|
#define TD_SYNC_RAFT_UNSTABLE_LOG_H
|
||||||
|
|
||||||
|
#include "sync_type.h"
|
||||||
|
|
||||||
|
/* in-memory unstable raft log storage */
|
||||||
|
struct SSyncRaftUnstableLog {
|
||||||
|
#if 0
|
||||||
|
/* Circular buffer of log entries */
|
||||||
|
RaftEntry *entries;
|
||||||
|
|
||||||
|
/* size of Circular buffer */
|
||||||
|
int size;
|
||||||
|
|
||||||
|
/* Indexes of used slots [front, back) */
|
||||||
|
int front, back;
|
||||||
|
|
||||||
|
/* Index of first entry is offset + 1 */
|
||||||
|
SyncIndex offset;
|
||||||
|
|
||||||
|
/* meta data of snapshot */
|
||||||
|
SSyncRaftUnstableLog snapshot;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return index of last in memory log, return 0 if log is empty
|
||||||
|
**/
|
||||||
|
//SyncIndex syncRaftLogLastIndex(SSyncRaftUnstableLog* pLog);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void raftLogInit(RaftLog* pLog);
|
||||||
|
|
||||||
|
void raftLogClose(RaftLog* pLog);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When startup populating log entrues loaded from disk,
|
||||||
|
* init raft memory log with snapshot index,term and log start idnex.
|
||||||
|
**/
|
||||||
|
/*
|
||||||
|
void raftLogStart(RaftLog* pLog,
|
||||||
|
RaftSnapshotMeta snapshot,
|
||||||
|
SyncIndex startIndex);
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Get the number of entries the log.
|
||||||
|
**/
|
||||||
|
int raftLogNumEntries(const RaftLog* pLog);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return last term of in memory log, return 0 if log is empty
|
||||||
|
**/
|
||||||
|
SyncTerm raftLogLastTerm(RaftLog* pLog);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return term of log with the given index, return 0 if the term of index cannot be found
|
||||||
|
* , errCode will save the error code.
|
||||||
|
**/
|
||||||
|
SyncTerm raftLogTermOf(RaftLog* pLog, SyncIndex index, RaftCode* errCode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the last index of the most recent snapshot. Return 0 if there are no *
|
||||||
|
* snapshots.
|
||||||
|
**/
|
||||||
|
SyncIndex raftLogSnapshotIndex(RaftLog* pLog);
|
||||||
|
|
||||||
|
/* Append a new entry to the log. */
|
||||||
|
int raftLogAppend(RaftLog* pLog,
|
||||||
|
SyncTerm term,
|
||||||
|
const SSyncBuffer *buf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* acquire log from given index onwards.
|
||||||
|
**/
|
||||||
|
/*
|
||||||
|
int raftLogAcquire(RaftLog* pLog,
|
||||||
|
SyncIndex index,
|
||||||
|
RaftEntry **ppEntries,
|
||||||
|
int *n);
|
||||||
|
|
||||||
|
void raftLogRelease(RaftLog* pLog,
|
||||||
|
SyncIndex index,
|
||||||
|
RaftEntry *pEntries,
|
||||||
|
int n);
|
||||||
|
*/
|
||||||
|
/* Delete all entries from the given index (included) onwards. */
|
||||||
|
void raftLogTruncate(RaftLog* pLog, SyncIndex index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* when taking a new snapshot, the function will update the last snapshot information and delete
|
||||||
|
* all entries up last_index - trailing (included). If the log contains no entry
|
||||||
|
* a last_index - trailing, then no entry will be deleted.
|
||||||
|
**/
|
||||||
|
void raftLogSnapshot(RaftLog* pLog, SyncIndex index, SyncIndex trailing);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* TD_SYNC_RAFT_UNSTABLE_LOG_H */
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <cli@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_LIBS_SYNC_INT_H
|
||||||
|
#define _TD_LIBS_SYNC_INT_H
|
||||||
|
|
||||||
|
#include "thash.h"
|
||||||
|
#include "os.h"
|
||||||
|
#include "sync.h"
|
||||||
|
#include "sync_type.h"
|
||||||
|
#include "raft.h"
|
||||||
|
#include "tlog.h"
|
||||||
|
|
||||||
|
#define TAOS_SYNC_MAX_WORKER 3
|
||||||
|
|
||||||
|
typedef struct SSyncWorker {
|
||||||
|
pthread_t thread;
|
||||||
|
} SSyncWorker;
|
||||||
|
|
||||||
|
struct SSyncNode {
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
int32_t refCount;
|
||||||
|
SyncGroupId vgId;
|
||||||
|
SSyncRaft raft;
|
||||||
|
void* syncTimer;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct SSyncManager {
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
|
||||||
|
// sync server rpc
|
||||||
|
void* serverRpc;
|
||||||
|
// rpc server hash table base on FQDN:port key
|
||||||
|
SHashObj* rpcServerTable;
|
||||||
|
|
||||||
|
// sync client rpc
|
||||||
|
void* clientRpc;
|
||||||
|
|
||||||
|
// worker threads
|
||||||
|
SSyncWorker worker[TAOS_SYNC_MAX_WORKER];
|
||||||
|
|
||||||
|
// vgroup hash table
|
||||||
|
SHashObj* vgroupTable;
|
||||||
|
|
||||||
|
// timer manager
|
||||||
|
void* syncTimerManager;
|
||||||
|
|
||||||
|
} SSyncManager;
|
||||||
|
|
||||||
|
extern SSyncManager* gSyncManager;
|
||||||
|
|
||||||
|
#define syncFatal(...) do { if (sDebugFlag & DEBUG_FATAL) { taosPrintLog("SYNC FATAL ", 255, __VA_ARGS__); }} while(0)
|
||||||
|
#define syncError(...) do { if (sDebugFlag & DEBUG_ERROR) { taosPrintLog("SYNC ERROR ", 255, __VA_ARGS__); }} while(0)
|
||||||
|
#define syncWarn(...) do { if (sDebugFlag & DEBUG_WARN) { taosPrintLog("SYNC WARN ", 255, __VA_ARGS__); }} while(0)
|
||||||
|
#define syncInfo(...) do { if (sDebugFlag & DEBUG_INFO) { taosPrintLog("SYNC ", 255, __VA_ARGS__); }} while(0)
|
||||||
|
#define syncDebug(...) do { if (sDebugFlag & DEBUG_DEBUG) { taosPrintLog("SYNC ", sDebugFlag, __VA_ARGS__); }} while(0)
|
||||||
|
#define syncTrace(...) do { if (sDebugFlag & DEBUG_TRACE) { taosPrintLog("SYNC ", sDebugFlag, __VA_ARGS__); }} while(0)
|
||||||
|
|
||||||
|
#endif /* _TD_LIBS_SYNC_INT_H */
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <cli@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_LIBS_SYNC_RAFT_IMPL_H
|
||||||
|
#define _TD_LIBS_SYNC_RAFT_IMPL_H
|
||||||
|
|
||||||
|
#include "sync.h"
|
||||||
|
#include "sync_type.h"
|
||||||
|
#include "raft_message.h"
|
||||||
|
#include "sync_raft_quorum.h"
|
||||||
|
|
||||||
|
void syncRaftBecomeFollower(SSyncRaft* pRaft, SyncTerm term, SyncNodeId leaderId);
|
||||||
|
void syncRaftBecomePreCandidate(SSyncRaft* pRaft);
|
||||||
|
void syncRaftBecomeCandidate(SSyncRaft* pRaft);
|
||||||
|
void syncRaftBecomeLeader(SSyncRaft* pRaft);
|
||||||
|
|
||||||
|
void syncRaftStartElection(SSyncRaft* pRaft, SyncRaftElectionType cType);
|
||||||
|
|
||||||
|
void syncRaftTriggerHeartbeat(SSyncRaft* pRaft);
|
||||||
|
|
||||||
|
void syncRaftRandomizedElectionTimeout(SSyncRaft* pRaft);
|
||||||
|
bool syncRaftIsPromotable(SSyncRaft* pRaft);
|
||||||
|
bool syncRaftIsPastElectionTimeout(SSyncRaft* pRaft);
|
||||||
|
int syncRaftQuorum(SSyncRaft* pRaft);
|
||||||
|
|
||||||
|
SSyncRaftVoteResult syncRaftPollVote(SSyncRaft* pRaft, SyncNodeId id,
|
||||||
|
bool preVote, bool accept,
|
||||||
|
int* rejectNum, int *granted);
|
||||||
|
|
||||||
|
#endif /* _TD_LIBS_SYNC_RAFT_IMPL_H */
|
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <cli@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http: *www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TD_SYNC_RAFT_INFLIGHTS_H
|
||||||
|
#define TD_SYNC_RAFT_INFLIGHTS_H
|
||||||
|
|
||||||
|
#include "sync.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SSyncRaftInflights limits the number of MsgApp (represented by the largest index
|
||||||
|
* contained within) sent to followers but not yet acknowledged by them. Callers
|
||||||
|
* use syncRaftInflightFull() to check whether more messages can be sent,
|
||||||
|
* call syncRaftInflightAdd() whenever they are sending a new append,
|
||||||
|
* and release "quota" via FreeLE() whenever an ack is received.
|
||||||
|
**/
|
||||||
|
typedef struct SSyncRaftInflights {
|
||||||
|
/* the starting index in the buffer */
|
||||||
|
int start;
|
||||||
|
|
||||||
|
/* number of inflights in the buffer */
|
||||||
|
int count;
|
||||||
|
|
||||||
|
/* the size of the buffer */
|
||||||
|
int size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* buffer contains the index of the last entry
|
||||||
|
* inside one message.
|
||||||
|
**/
|
||||||
|
SyncIndex* buffer;
|
||||||
|
} SSyncRaftInflights;
|
||||||
|
|
||||||
|
SSyncRaftInflights* syncRaftOpenInflights(int size);
|
||||||
|
void syncRaftCloseInflights(SSyncRaftInflights*);
|
||||||
|
|
||||||
|
static FORCE_INLINE void syncRaftInflightReset(SSyncRaftInflights* inflights) {
|
||||||
|
inflights->count = 0;
|
||||||
|
inflights->start = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCE_INLINE bool syncRaftInflightFull(SSyncRaftInflights* inflights) {
|
||||||
|
return inflights->count == inflights->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* syncRaftInflightAdd notifies the Inflights that a new message with the given index is being
|
||||||
|
* dispatched. syncRaftInflightFull() must be called prior to syncRaftInflightAdd()
|
||||||
|
* to verify that there is room for one more message,
|
||||||
|
* and consecutive calls to add syncRaftInflightAdd() must provide a
|
||||||
|
* monotonic sequence of indexes.
|
||||||
|
**/
|
||||||
|
void syncRaftInflightAdd(SSyncRaftInflights* inflights, SyncIndex inflightIndex);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* syncRaftInflightFreeLE frees the inflights smaller or equal to the given `to` flight.
|
||||||
|
**/
|
||||||
|
void syncRaftInflightFreeLE(SSyncRaftInflights* inflights, SyncIndex toIndex);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* syncRaftInflightFreeFirstOne releases the first inflight.
|
||||||
|
* This is a no-op if nothing is inflight.
|
||||||
|
**/
|
||||||
|
void syncRaftInflightFreeFirstOne(SSyncRaftInflights* inflights);
|
||||||
|
|
||||||
|
#endif /* TD_SYNC_RAFT_INFLIGHTS_H */
|
|
@ -0,0 +1,237 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <cli@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http: *www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TD_SYNC_RAFT_PROGRESS_H
|
||||||
|
#define TD_SYNC_RAFT_PROGRESS_H
|
||||||
|
|
||||||
|
#include "sync_type.h"
|
||||||
|
#include "sync_raft_inflights.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* State defines how the leader should interact with the follower.
|
||||||
|
*
|
||||||
|
* When in PROGRESS_STATE_PROBE, leader sends at most one replication message
|
||||||
|
* per heartbeat interval. It also probes actual progress of the follower.
|
||||||
|
*
|
||||||
|
* When in PROGRESS_STATE_REPLICATE, leader optimistically increases next
|
||||||
|
* to the latest entry sent after sending replication message. This is
|
||||||
|
* an optimized state for fast replicating log entries to the follower.
|
||||||
|
*
|
||||||
|
* When in PROGRESS_STATE_SNAPSHOT, leader should have sent out snapshot
|
||||||
|
* before and stops sending any replication message.
|
||||||
|
*
|
||||||
|
* PROGRESS_STATE_PROBE is the initial state.
|
||||||
|
**/
|
||||||
|
typedef enum RaftProgressState {
|
||||||
|
/**
|
||||||
|
* StateProbe indicates a follower whose last index isn't known. Such a
|
||||||
|
* follower is "probed" (i.e. an append sent periodically) to narrow down
|
||||||
|
* its last index. In the ideal (and common) case, only one round of probing
|
||||||
|
* is necessary as the follower will react with a hint. Followers that are
|
||||||
|
* probed over extended periods of time are often offline.
|
||||||
|
**/
|
||||||
|
PROGRESS_STATE_PROBE = 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StateReplicate is the state steady in which a follower eagerly receives
|
||||||
|
* log entries to append to its log.
|
||||||
|
**/
|
||||||
|
PROGRESS_STATE_REPLICATE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StateSnapshot indicates a follower that needs log entries not available
|
||||||
|
* from the leader's Raft log. Such a follower needs a full snapshot to
|
||||||
|
* return to StateReplicate.
|
||||||
|
**/
|
||||||
|
PROGRESS_STATE_SNAPSHOT,
|
||||||
|
} RaftProgressState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Progress represents a follower’s progress in the view of the leader. Leader maintains
|
||||||
|
* progresses of all followers, and sends entries to the follower based on its progress.
|
||||||
|
**/
|
||||||
|
struct SSyncRaftProgress {
|
||||||
|
SyncNodeId id;
|
||||||
|
|
||||||
|
SyncIndex nextIndex;
|
||||||
|
|
||||||
|
SyncIndex matchIndex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* State defines how the leader should interact with the follower.
|
||||||
|
*
|
||||||
|
* When in StateProbe, leader sends at most one replication message
|
||||||
|
* per heartbeat interval. It also probes actual progress of the follower.
|
||||||
|
*
|
||||||
|
* When in StateReplicate, leader optimistically increases next
|
||||||
|
* to the latest entry sent after sending replication message. This is
|
||||||
|
* an optimized state for fast replicating log entries to the follower.
|
||||||
|
*
|
||||||
|
* When in StateSnapshot, leader should have sent out snapshot
|
||||||
|
* before and stops sending any replication message.
|
||||||
|
**/
|
||||||
|
RaftProgressState state;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pendingSnapshotIndex is used in PROGRESS_STATE_SNAPSHOT.
|
||||||
|
* If there is a pending snapshot, the pendingSnapshotIndex will be set to the
|
||||||
|
* index of the snapshot. If pendingSnapshotIndex is set, the replication process of
|
||||||
|
* this Progress will be paused. raft will not resend snapshot until the pending one
|
||||||
|
* is reported to be failed.
|
||||||
|
**/
|
||||||
|
SyncIndex pendingSnapshotIndex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* recentActive is true if the progress is recently active. Receiving any messages
|
||||||
|
* from the corresponding follower indicates the progress is active.
|
||||||
|
* RecentActive can be reset to false after an election timeout.
|
||||||
|
**/
|
||||||
|
bool recentActive;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* probeSent is used while this follower is in StateProbe. When probeSent is
|
||||||
|
* true, raft should pause sending replication message to this peer until
|
||||||
|
* probeSent is reset. See ProbeAcked() and IsPaused().
|
||||||
|
**/
|
||||||
|
bool probeSent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* inflights is a sliding window for the inflight messages.
|
||||||
|
* Each inflight message contains one or more log entries.
|
||||||
|
* The max number of entries per message is defined in raft config as MaxSizePerMsg.
|
||||||
|
* Thus inflight effectively limits both the number of inflight messages
|
||||||
|
* and the bandwidth each Progress can use.
|
||||||
|
* When inflights is Full, no more message should be sent.
|
||||||
|
* When a leader sends out a message, the index of the last
|
||||||
|
* entry should be added to inflights. The index MUST be added
|
||||||
|
* into inflights in order.
|
||||||
|
* When a leader receives a reply, the previous inflights should
|
||||||
|
* be freed by calling inflights.FreeLE with the index of the last
|
||||||
|
* received entry.
|
||||||
|
**/
|
||||||
|
SSyncRaftInflights* inflights;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IsLearner is true if this progress is tracked for a learner.
|
||||||
|
**/
|
||||||
|
bool isLearner;
|
||||||
|
};
|
||||||
|
|
||||||
|
void syncRaftInitProgress(int i, SSyncRaft* pRaft, SSyncRaftProgress* progress);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* syncRaftProgressBecomeProbe transitions into StateProbe. Next is reset to Match+1 or,
|
||||||
|
* optionally and if larger, the index of the pending snapshot.
|
||||||
|
**/
|
||||||
|
void syncRaftProgressBecomeProbe(SSyncRaftProgress* progress);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* syncRaftProgressBecomeReplicate transitions into StateReplicate, resetting Next to Match+1.
|
||||||
|
**/
|
||||||
|
void syncRaftProgressBecomeReplicate(SSyncRaftProgress* progress);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* syncRaftProgressMaybeUpdate is called when an MsgAppResp arrives from the follower, with the
|
||||||
|
* index acked by it. The method returns false if the given n index comes from
|
||||||
|
* an outdated message. Otherwise it updates the progress and returns true.
|
||||||
|
**/
|
||||||
|
bool syncRaftProgressMaybeUpdate(SSyncRaftProgress* progress, SyncIndex lastIndex);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* syncRaftProgressOptimisticNextIndex signals that appends all the way up to and including index n
|
||||||
|
* are in-flight. As a result, Next is increased to n+1.
|
||||||
|
**/
|
||||||
|
static FORCE_INLINE void syncRaftProgressOptimisticNextIndex(SSyncRaftProgress* progress, SyncIndex nextIndex) {
|
||||||
|
progress->nextIndex = nextIndex + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* syncRaftProgressMaybeDecrTo adjusts the Progress to the receipt of a MsgApp rejection. The
|
||||||
|
* arguments are the index of the append message rejected by the follower, and
|
||||||
|
* the hint that we want to decrease to.
|
||||||
|
*
|
||||||
|
* Rejections can happen spuriously as messages are sent out of order or
|
||||||
|
* duplicated. In such cases, the rejection pertains to an index that the
|
||||||
|
* Progress already knows were previously acknowledged, and false is returned
|
||||||
|
* without changing the Progress.
|
||||||
|
*
|
||||||
|
* If the rejection is genuine, Next is lowered sensibly, and the Progress is
|
||||||
|
* cleared for sending log entries.
|
||||||
|
**/
|
||||||
|
bool syncRaftProgressMaybeDecrTo(SSyncRaftProgress* progress,
|
||||||
|
SyncIndex rejected, SyncIndex matchHint);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* syncRaftProgressIsPaused returns whether sending log entries to this node has been throttled.
|
||||||
|
* This is done when a node has rejected recent MsgApps, is currently waiting
|
||||||
|
* for a snapshot, or has reached the MaxInflightMsgs limit. In normal
|
||||||
|
* operation, this is false. A throttled node will be contacted less frequently
|
||||||
|
* until it has reached a state in which it's able to accept a steady stream of
|
||||||
|
* log entries again.
|
||||||
|
**/
|
||||||
|
bool syncRaftProgressIsPaused(SSyncRaftProgress* progress);
|
||||||
|
|
||||||
|
static FORCE_INLINE SyncIndex syncRaftProgressNextIndex(SSyncRaftProgress* progress) {
|
||||||
|
return progress->nextIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCE_INLINE RaftProgressState syncRaftProgressInReplicate(SSyncRaftProgress* progress) {
|
||||||
|
return progress->state == PROGRESS_STATE_REPLICATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCE_INLINE RaftProgressState syncRaftProgressInSnapshot(SSyncRaftProgress* progress) {
|
||||||
|
return progress->state == PROGRESS_STATE_SNAPSHOT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCE_INLINE RaftProgressState syncRaftProgressInProbe(SSyncRaftProgress* progress) {
|
||||||
|
return progress->state == PROGRESS_STATE_PROBE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCE_INLINE bool syncRaftProgressRecentActive(SSyncRaftProgress* progress) {
|
||||||
|
return progress->recentActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return true if progress's log is up-todate
|
||||||
|
**/
|
||||||
|
bool syncRaftProgressIsUptodate(SSyncRaft* pRaft, SSyncRaftProgress* progress);
|
||||||
|
|
||||||
|
void syncRaftProgressBecomeSnapshot(SSyncRaftProgress* progress, SyncIndex snapshotIndex);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
void syncRaftProgressAbortSnapshot(SSyncRaft* pRaft, int i);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
SyncIndex syncRaftProgressMatchIndex(SSyncRaft* pRaft, int i);
|
||||||
|
|
||||||
|
void syncRaftProgressUpdateLastSend(SSyncRaft* pRaft, int i);
|
||||||
|
|
||||||
|
void syncRaftProgressUpdateSnapshotLastSend(SSyncRaft* pRaft, int i);
|
||||||
|
|
||||||
|
bool syncRaftProgressResetRecentRecv(SSyncRaft* pRaft, int i);
|
||||||
|
|
||||||
|
void syncRaftProgressMarkRecentRecv(SSyncRaft* pRaft, int i);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void syncRaftProgressAbortSnapshot(SSyncRaft* pRaft, int i);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* TD_SYNC_RAFT_PROGRESS_H */
|
|
@ -0,0 +1,113 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <cli@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_LIBS_SYNC_RAFT_PROGRESS_TRACKER_H
|
||||||
|
#define _TD_LIBS_SYNC_RAFT_PROGRESS_TRACKER_H
|
||||||
|
|
||||||
|
#include "sync_type.h"
|
||||||
|
#include "sync_raft_quorum_joint.h"
|
||||||
|
#include "sync_raft_progress.h"
|
||||||
|
|
||||||
|
struct SSyncRaftProgressTrackerConfig {
|
||||||
|
SSyncRaftQuorumJointConfig voters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* autoLeave is true if the configuration is joint and a transition to the
|
||||||
|
* incoming configuration should be carried out automatically by Raft when
|
||||||
|
* this is possible. If false, the configuration will be joint until the
|
||||||
|
* application initiates the transition manually.
|
||||||
|
**/
|
||||||
|
bool autoLeave;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Learners is a set of IDs corresponding to the learners active in the
|
||||||
|
* current configuration.
|
||||||
|
*
|
||||||
|
* Invariant: Learners and Voters does not intersect, i.e. if a peer is in
|
||||||
|
* either half of the joint config, it can't be a learner; if it is a
|
||||||
|
* learner it can't be in either half of the joint config. This invariant
|
||||||
|
* simplifies the implementation since it allows peers to have clarity about
|
||||||
|
* its current role without taking into account joint consensus.
|
||||||
|
**/
|
||||||
|
SyncNodeId learners[TSDB_MAX_REPLICA];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When we turn a voter into a learner during a joint consensus transition,
|
||||||
|
* we cannot add the learner directly when entering the joint state. This is
|
||||||
|
* because this would violate the invariant that the intersection of
|
||||||
|
* voters and learners is empty. For example, assume a Voter is removed and
|
||||||
|
* immediately re-added as a learner (or in other words, it is demoted):
|
||||||
|
*
|
||||||
|
* Initially, the configuration will be
|
||||||
|
*
|
||||||
|
* voters: {1 2 3}
|
||||||
|
* learners: {}
|
||||||
|
*
|
||||||
|
* and we want to demote 3. Entering the joint configuration, we naively get
|
||||||
|
*
|
||||||
|
* voters: {1 2} & {1 2 3}
|
||||||
|
* learners: {3}
|
||||||
|
*
|
||||||
|
* but this violates the invariant (3 is both voter and learner). Instead,
|
||||||
|
* we get
|
||||||
|
*
|
||||||
|
* voters: {1 2} & {1 2 3}
|
||||||
|
* learners: {}
|
||||||
|
* next_learners: {3}
|
||||||
|
*
|
||||||
|
* Where 3 is now still purely a voter, but we are remembering the intention
|
||||||
|
* to make it a learner upon transitioning into the final configuration:
|
||||||
|
*
|
||||||
|
* voters: {1 2}
|
||||||
|
* learners: {3}
|
||||||
|
* next_learners: {}
|
||||||
|
*
|
||||||
|
* Note that next_learners is not used while adding a learner that is not
|
||||||
|
* also a voter in the joint config. In this case, the learner is added
|
||||||
|
* right away when entering the joint configuration, so that it is caught up
|
||||||
|
* as soon as possible.
|
||||||
|
**/
|
||||||
|
SyncNodeId learnersNext[TSDB_MAX_REPLICA];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SSyncRaftProgressTracker {
|
||||||
|
SSyncRaftProgressTrackerConfig config;
|
||||||
|
|
||||||
|
SSyncRaftProgress progressMap[TSDB_MAX_REPLICA];
|
||||||
|
|
||||||
|
SyncRaftVoteResult votes[TSDB_MAX_REPLICA];
|
||||||
|
int maxInflight;
|
||||||
|
};
|
||||||
|
|
||||||
|
SSyncRaftProgressTracker* syncRaftOpenProgressTracker();
|
||||||
|
|
||||||
|
void syncRaftResetVotes(SSyncRaftProgressTracker*);
|
||||||
|
|
||||||
|
typedef void (*visitProgressFp)(int i, SSyncRaftProgress* progress, void* arg);
|
||||||
|
void syncRaftProgressVisit(SSyncRaftProgressTracker*, visitProgressFp visit, void* arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* syncRaftRecordVote records that the node with the given id voted for this Raft
|
||||||
|
* instance if v == true (and declined it otherwise).
|
||||||
|
**/
|
||||||
|
void syncRaftRecordVote(SSyncRaftProgressTracker* tracker, int i, bool grant);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* syncRaftTallyVotes returns the number of granted and rejected Votes, and whether the
|
||||||
|
* election outcome is known.
|
||||||
|
**/
|
||||||
|
SyncRaftVoteResult syncRaftTallyVotes(SSyncRaftProgressTracker* tracker, int* rejected, int *granted);
|
||||||
|
|
||||||
|
#endif /* _TD_LIBS_SYNC_RAFT_PROGRESS_TRACKER_H */
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <cli@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TD_SYNC_RAFT_QUORUM_H
|
||||||
|
#define TD_SYNC_RAFT_QUORUM_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SSyncRaftVoteResult indicates the outcome of a vote.
|
||||||
|
**/
|
||||||
|
typedef enum {
|
||||||
|
/**
|
||||||
|
* SYNC_RAFT_VOTE_PENDING indicates that the decision of the vote depends on future
|
||||||
|
* votes, i.e. neither "yes" or "no" has reached quorum yet.
|
||||||
|
**/
|
||||||
|
SYNC_RAFT_VOTE_PENDING = 1,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SYNC_RAFT_VOTE_LOST indicates that the quorum has voted "no".
|
||||||
|
**/
|
||||||
|
SYNC_RAFT_VOTE_LOST = 2,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SYNC_RAFT_VOTE_WON indicates that the quorum has voted "yes".
|
||||||
|
**/
|
||||||
|
SYNC_RAFT_VOTE_WON = 3,
|
||||||
|
} SSyncRaftVoteResult;
|
||||||
|
|
||||||
|
#endif /* TD_SYNC_RAFT_QUORUM_H */
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <cli@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_LIBS_SYNC_RAFT_QUORUM_JOINT_H
|
||||||
|
#define _TD_LIBS_SYNC_RAFT_QUORUM_JOINT_H
|
||||||
|
|
||||||
|
#include "taosdef.h"
|
||||||
|
#include "sync.h"
|
||||||
|
#include "sync_type.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SSyncRaftQuorumJointConfig is a configuration of two groups of (possibly overlapping)
|
||||||
|
* majority configurations. Decisions require the support of both majorities.
|
||||||
|
**/
|
||||||
|
typedef struct SSyncRaftQuorumJointConfig {
|
||||||
|
SSyncCluster majorityConfig[2];
|
||||||
|
}SSyncRaftQuorumJointConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* syncRaftVoteResult takes a mapping of voters to yes/no (true/false) votes and returns
|
||||||
|
* a result indicating whether the vote is pending, lost, or won. A joint quorum
|
||||||
|
* requires both majority quorums to vote in favor.
|
||||||
|
**/
|
||||||
|
SyncRaftVoteResult syncRaftVoteResult(SSyncRaftQuorumJointConfig* config, const SyncRaftVoteResult* votes);
|
||||||
|
|
||||||
|
#endif /* _TD_LIBS_SYNC_RAFT_QUORUM_JOINT_H */
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <cli@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_LIBS_SYNC_RAFT_QUORUM_MAJORITY_H
|
||||||
|
#define _TD_LIBS_SYNC_RAFT_QUORUM_MAJORITY_H
|
||||||
|
|
||||||
|
#include "sync.h"
|
||||||
|
#include "sync_type.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* syncRaftMajorityVoteResult takes a mapping of voters to yes/no (true/false) votes and returns
|
||||||
|
* a result indicating whether the vote is pending (i.e. neither a quorum of
|
||||||
|
* yes/no has been reached), won (a quorum of yes has been reached), or lost (a
|
||||||
|
* quorum of no has been reached).
|
||||||
|
**/
|
||||||
|
SyncRaftVoteResult syncRaftMajorityVoteResult(SSyncCluster* config, const SyncRaftVoteResult* votes);
|
||||||
|
|
||||||
|
#endif /* _TD_LIBS_SYNC_RAFT_QUORUM_MAJORITY_H */
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <cli@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TD_LIBS_SYNC_TYPE_H
|
||||||
|
#define _TD_LIBS_SYNC_TYPE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "osMath.h"
|
||||||
|
|
||||||
|
#define SYNC_NON_NODE_ID -1
|
||||||
|
#define SYNC_NON_TERM 0
|
||||||
|
|
||||||
|
typedef int32_t SyncTime;
|
||||||
|
typedef uint32_t SyncTick;
|
||||||
|
|
||||||
|
typedef struct SSyncRaft SSyncRaft;
|
||||||
|
|
||||||
|
typedef struct SSyncRaftProgress SSyncRaftProgress;
|
||||||
|
typedef struct SSyncRaftProgressTrackerConfig SSyncRaftProgressTrackerConfig;
|
||||||
|
|
||||||
|
typedef struct SSyncRaftProgressTracker SSyncRaftProgressTracker;
|
||||||
|
|
||||||
|
typedef struct SSyncRaftLog SSyncRaftLog;
|
||||||
|
|
||||||
|
typedef struct SSyncRaftEntry SSyncRaftEntry;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#ifndef MIN
|
||||||
|
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MAX
|
||||||
|
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SYNC_RAFT_CAMPAIGN_PRE_ELECTION = 0,
|
||||||
|
SYNC_RAFT_CAMPAIGN_ELECTION = 1,
|
||||||
|
SYNC_RAFT_CAMPAIGN_TRANSFER = 2,
|
||||||
|
} SyncRaftElectionType;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
// the init vote resp status
|
||||||
|
SYNC_RAFT_VOTE_RESP_UNKNOWN = 0,
|
||||||
|
|
||||||
|
// grant the vote request
|
||||||
|
SYNC_RAFT_VOTE_RESP_GRANT = 1,
|
||||||
|
|
||||||
|
//reject the vote request
|
||||||
|
SYNC_RAFT_VOTE_RESP_REJECT = 2,
|
||||||
|
} SyncRaftVoteResult;
|
||||||
|
|
||||||
|
#endif /* _TD_LIBS_SYNC_TYPE_H */
|
|
@ -0,0 +1,203 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <cli@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "raft.h"
|
||||||
|
#include "raft_configuration.h"
|
||||||
|
#include "raft_log.h"
|
||||||
|
#include "raft_replication.h"
|
||||||
|
#include "sync_raft_progress_tracker.h"
|
||||||
|
#include "syncInt.h"
|
||||||
|
|
||||||
|
#define RAFT_READ_LOG_MAX_NUM 100
|
||||||
|
|
||||||
|
static bool preHandleMessage(SSyncRaft* pRaft, const SSyncMessage* pMsg);
|
||||||
|
static bool preHandleNewTermMessage(SSyncRaft* pRaft, const SSyncMessage* pMsg);
|
||||||
|
static bool preHandleOldTermMessage(SSyncRaft* pRaft, const SSyncMessage* pMsg);
|
||||||
|
|
||||||
|
int32_t syncRaftStart(SSyncRaft* pRaft, const SSyncInfo* pInfo) {
|
||||||
|
SSyncNode* pNode = pRaft->pNode;
|
||||||
|
SSyncServerState serverState;
|
||||||
|
SStateManager* stateManager;
|
||||||
|
SSyncLogStore* logStore;
|
||||||
|
SSyncFSM* fsm;
|
||||||
|
SyncIndex initIndex = pInfo->snapshotIndex;
|
||||||
|
SSyncBuffer buffer[RAFT_READ_LOG_MAX_NUM];
|
||||||
|
int nBuf, limit, i;
|
||||||
|
|
||||||
|
memset(pRaft, 0, sizeof(SSyncRaft));
|
||||||
|
|
||||||
|
memcpy(&pRaft->fsm, &pInfo->fsm, sizeof(SSyncFSM));
|
||||||
|
memcpy(&pRaft->logStore, &pInfo->logStore, sizeof(SSyncLogStore));
|
||||||
|
memcpy(&pRaft->stateManager, &pInfo->stateManager, sizeof(SStateManager));
|
||||||
|
|
||||||
|
stateManager = &(pRaft->stateManager);
|
||||||
|
logStore = &(pRaft->logStore);
|
||||||
|
fsm = &(pRaft->fsm);
|
||||||
|
|
||||||
|
// init progress tracker
|
||||||
|
pRaft->tracker = syncRaftOpenProgressTracker();
|
||||||
|
if (pRaft->tracker == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// open raft log
|
||||||
|
if ((pRaft->log = syncRaftLogOpen()) == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// read server state
|
||||||
|
if (stateManager->readServerState(stateManager, &serverState) != 0) {
|
||||||
|
syncError("readServerState for vgid %d fail", pInfo->vgId);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
assert(initIndex <= serverState.commitIndex);
|
||||||
|
|
||||||
|
// restore fsm state from snapshot index + 1 until commitIndex
|
||||||
|
++initIndex;
|
||||||
|
while (initIndex <= serverState.commitIndex) {
|
||||||
|
limit = MIN(RAFT_READ_LOG_MAX_NUM, serverState.commitIndex - initIndex + 1);
|
||||||
|
|
||||||
|
if (logStore->logRead(logStore, initIndex, limit, buffer, &nBuf) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
assert(limit == nBuf);
|
||||||
|
|
||||||
|
for (i = 0; i < limit; ++i) {
|
||||||
|
fsm->applyLog(fsm, initIndex + i, &(buffer[i]), NULL);
|
||||||
|
free(buffer[i].data);
|
||||||
|
}
|
||||||
|
initIndex += nBuf;
|
||||||
|
}
|
||||||
|
assert(initIndex == serverState.commitIndex);
|
||||||
|
|
||||||
|
//pRaft->heartbeatTimeoutTick = 1;
|
||||||
|
|
||||||
|
syncRaftBecomeFollower(pRaft, pRaft->term, SYNC_NON_NODE_ID);
|
||||||
|
|
||||||
|
pRaft->selfIndex = pRaft->cluster.selfIndex;
|
||||||
|
|
||||||
|
syncInfo("[%d:%d] restore vgid %d state: snapshot index success",
|
||||||
|
pRaft->selfGroupId, pRaft->selfId, pInfo->vgId);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t syncRaftStep(SSyncRaft* pRaft, const SSyncMessage* pMsg) {
|
||||||
|
syncDebug("from %d, type:%d, term:%" PRId64 ", state:%d",
|
||||||
|
pMsg->from, pMsg->msgType, pMsg->term, pRaft->state);
|
||||||
|
|
||||||
|
if (preHandleMessage(pRaft, pMsg)) {
|
||||||
|
syncFreeMessage(pMsg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
RaftMessageType msgType = pMsg->msgType;
|
||||||
|
if (msgType == RAFT_MSG_INTERNAL_ELECTION) {
|
||||||
|
syncRaftHandleElectionMessage(pRaft, pMsg);
|
||||||
|
} else if (msgType == RAFT_MSG_VOTE) {
|
||||||
|
syncRaftHandleVoteMessage(pRaft, pMsg);
|
||||||
|
} else {
|
||||||
|
pRaft->stepFp(pRaft, pMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
syncFreeMessage(pMsg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t syncRaftTick(SSyncRaft* pRaft) {
|
||||||
|
pRaft->currentTick += 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pre-handle message, return true means no need to continue
|
||||||
|
* Handle the message term, which may result in our stepping down to a follower.
|
||||||
|
**/
|
||||||
|
static bool preHandleMessage(SSyncRaft* pRaft, const SSyncMessage* pMsg) {
|
||||||
|
// local message?
|
||||||
|
if (pMsg->term == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pMsg->term > pRaft->term) {
|
||||||
|
return preHandleNewTermMessage(pRaft, pMsg);
|
||||||
|
} else if (pMsg->term < pRaft->term) {
|
||||||
|
return preHandleOldTermMessage(pRaft, pMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool preHandleNewTermMessage(SSyncRaft* pRaft, const SSyncMessage* pMsg) {
|
||||||
|
SyncNodeId leaderId = pMsg->from;
|
||||||
|
RaftMessageType msgType = pMsg->msgType;
|
||||||
|
|
||||||
|
if (msgType == RAFT_MSG_VOTE) {
|
||||||
|
// TODO
|
||||||
|
leaderId = SYNC_NON_NODE_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (syncIsPreVoteMsg(pMsg)) {
|
||||||
|
// Never change our term in response to a PreVote
|
||||||
|
} else if (syncIsPreVoteRespMsg(pMsg) && !pMsg->voteResp.rejected) {
|
||||||
|
/**
|
||||||
|
* We send pre-vote requests with a term in our future. If the
|
||||||
|
* pre-vote is granted, we will increment our term when we get a
|
||||||
|
* quorum. If it is not, the term comes from the node that
|
||||||
|
* rejected our vote so we should become a follower at the new
|
||||||
|
* term.
|
||||||
|
**/
|
||||||
|
} else {
|
||||||
|
syncInfo("[%d:%d] [term:%" PRId64 "] received a %d message with higher term from %d [term:%" PRId64 "]",
|
||||||
|
pRaft->selfGroupId, pRaft->selfId, pRaft->term, msgType, pMsg->from, pMsg->term);
|
||||||
|
syncRaftBecomeFollower(pRaft, pMsg->term, leaderId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool preHandleOldTermMessage(SSyncRaft* pRaft, const SSyncMessage* pMsg) {
|
||||||
|
if (pRaft->checkQuorum && pMsg->msgType == RAFT_MSG_APPEND) {
|
||||||
|
/**
|
||||||
|
* We have received messages from a leader at a lower term. It is possible
|
||||||
|
* that these messages were simply delayed in the network, but this could
|
||||||
|
* also mean that this node has advanced its term number during a network
|
||||||
|
* partition, and it is now unable to either win an election or to rejoin
|
||||||
|
* the majority on the old term. If checkQuorum is false, this will be
|
||||||
|
* handled by incrementing term numbers in response to MsgVote with a
|
||||||
|
* higher term, but if checkQuorum is true we may not advance the term on
|
||||||
|
* MsgVote and must generate other messages to advance the term. The net
|
||||||
|
* result of these two features is to minimize the disruption caused by
|
||||||
|
* nodes that have been removed from the cluster's configuration: a
|
||||||
|
* removed node will send MsgVotes (or MsgPreVotes) which will be ignored,
|
||||||
|
* but it will not receive MsgApp or MsgHeartbeat, so it will not create
|
||||||
|
* disruptive term increases
|
||||||
|
**/
|
||||||
|
int peerIndex = syncRaftConfigurationIndexOfNode(pRaft, pMsg->from);
|
||||||
|
if (peerIndex < 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
SSyncMessage* msg = syncNewEmptyAppendRespMsg(pRaft->selfGroupId, pRaft->selfId, pRaft->term);
|
||||||
|
if (msg == NULL) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pRaft->io.send(msg, &(pRaft->cluster.nodeInfo[peerIndex]));
|
||||||
|
} else {
|
||||||
|
// ignore other cases
|
||||||
|
syncInfo("[%d:%d] [term:%" PRId64 "] ignored a %d message with lower term from %d [term:%" PRId64 "]",
|
||||||
|
pRaft->selfGroupId, pRaft->selfId, pRaft->term, pMsg->msgType, pMsg->from, pMsg->term);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <cli@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "raft_configuration.h"
|
||||||
|
#include "raft.h"
|
||||||
|
|
||||||
|
int syncRaftConfigurationIndexOfNode(SSyncRaft *pRaft, SyncNodeId id) {
|
||||||
|
return (int)(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
int syncRaftConfigurationVoterCount(SSyncRaft *pRaft) {
|
||||||
|
return pRaft->cluster.replica;
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <cli@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "syncInt.h"
|
||||||
|
#include "raft.h"
|
||||||
|
#include "raft_log.h"
|
||||||
|
#include "raft_message.h"
|
||||||
|
|
||||||
|
void syncRaftStartElection(SSyncRaft* pRaft, SyncRaftElectionType cType) {
|
||||||
|
SyncTerm term;
|
||||||
|
bool preVote;
|
||||||
|
RaftMessageType voteMsgType;
|
||||||
|
|
||||||
|
if (syncRaftIsPromotable(pRaft)) {
|
||||||
|
syncDebug("[%d:%d] is unpromotable; campaign() should have been called", pRaft->selfGroupId, pRaft->selfId);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cType == SYNC_RAFT_CAMPAIGN_PRE_ELECTION) {
|
||||||
|
syncRaftBecomePreCandidate(pRaft);
|
||||||
|
preVote = true;
|
||||||
|
// PreVote RPCs are sent for the next term before we've incremented r.Term.
|
||||||
|
term = pRaft->term + 1;
|
||||||
|
} else {
|
||||||
|
syncRaftBecomeCandidate(pRaft);
|
||||||
|
voteMsgType = RAFT_MSG_VOTE;
|
||||||
|
term = pRaft->term;
|
||||||
|
preVote = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int quorum = syncRaftQuorum(pRaft);
|
||||||
|
SSyncRaftVoteResult result = syncRaftPollVote(pRaft, pRaft->selfId, preVote, true, NULL, NULL);
|
||||||
|
if (result == SYNC_RAFT_VOTE_WON) {
|
||||||
|
/**
|
||||||
|
* We won the election after voting for ourselves (which must mean that
|
||||||
|
* this is a single-node cluster). Advance to the next state.
|
||||||
|
**/
|
||||||
|
if (cType == SYNC_RAFT_CAMPAIGN_PRE_ELECTION) {
|
||||||
|
syncRaftStartElection(pRaft, SYNC_RAFT_CAMPAIGN_ELECTION);
|
||||||
|
} else {
|
||||||
|
syncRaftBecomeLeader(pRaft);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// broadcast vote message to other peers
|
||||||
|
int i;
|
||||||
|
SyncIndex lastIndex = syncRaftLogLastIndex(pRaft->log);
|
||||||
|
SyncTerm lastTerm = syncRaftLogLastTerm(pRaft->log);
|
||||||
|
for (i = 0; i < pRaft->cluster.replica; ++i) {
|
||||||
|
if (i == pRaft->cluster.selfIndex) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SyncNodeId nodeId = pRaft->cluster.nodeInfo[i].nodeId;
|
||||||
|
|
||||||
|
SSyncMessage* pMsg = syncNewVoteMsg(pRaft->selfGroupId, pRaft->selfId,
|
||||||
|
term, cType, lastIndex, lastTerm);
|
||||||
|
if (pMsg == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
syncInfo("[%d:%d] [logterm: %" PRId64 ", index: %" PRId64 "] sent %d request to %d at term %" PRId64 "",
|
||||||
|
pRaft->selfGroupId, pRaft->selfId, lastTerm,
|
||||||
|
lastIndex, voteMsgType, nodeId, pRaft->term);
|
||||||
|
|
||||||
|
pRaft->io.send(pMsg, &(pRaft->cluster.nodeInfo[i]));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <cli@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "syncInt.h"
|
||||||
|
#include "raft.h"
|
||||||
|
#include "raft_log.h"
|
||||||
|
#include "raft_configuration.h"
|
||||||
|
#include "raft_message.h"
|
||||||
|
|
||||||
|
int syncRaftHandleAppendEntriesMessage(SSyncRaft* pRaft, const SSyncMessage* pMsg) {
|
||||||
|
const RaftMsg_Append_Entries *appendEntries = &(pMsg->appendEntries);
|
||||||
|
|
||||||
|
int peerIndex = syncRaftConfigurationIndexOfNode(pRaft, pMsg->from);
|
||||||
|
|
||||||
|
if (peerIndex < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SSyncMessage* pRespMsg = syncNewEmptyAppendRespMsg(pRaft->selfGroupId, pRaft->selfId, pRaft->term);
|
||||||
|
if (pRespMsg == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
RaftMsg_Append_Entries *appendResp = &(pRespMsg->appendResp);
|
||||||
|
// ignore committed logs
|
||||||
|
if (syncRaftLogIsCommitted(pRaft->log, appendEntries->index)) {
|
||||||
|
appendResp->index = pRaft->log->commitIndex;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
syncInfo("[%d:%d] recv append from %d index %" PRId64"",
|
||||||
|
pRaft->selfGroupId, pRaft->selfId, pMsg->from, appendEntries->index);
|
||||||
|
|
||||||
|
out:
|
||||||
|
pRaft->io.send(pRespMsg, &(pRaft->cluster.nodeInfo[peerIndex]));
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <cli@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "syncInt.h"
|
||||||
|
#include "raft.h"
|
||||||
|
#include "raft_log.h"
|
||||||
|
#include "raft_message.h"
|
||||||
|
|
||||||
|
int syncRaftHandleElectionMessage(SSyncRaft* pRaft, const SSyncMessage* pMsg) {
|
||||||
|
if (pRaft->state == TAOS_SYNC_STATE_LEADER) {
|
||||||
|
syncDebug("[%d:%d] ignoring RAFT_MSG_INTERNAL_ELECTION because already leader", pRaft->selfGroupId, pRaft->selfId);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!syncRaftIsPromotable(pRaft)) {
|
||||||
|
syncDebug("[%d:%d] is unpromotable and can not campaign", pRaft->selfGroupId, pRaft->selfId);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// if there is pending uncommitted config,cannot start election
|
||||||
|
if (syncRaftLogNumOfPendingConf(pRaft->log) > 0 && syncRaftHasUnappliedLog(pRaft->log)) {
|
||||||
|
syncWarn("[%d:%d] cannot syncRaftStartElection at term %" PRId64 " since there are still pending configuration changes to apply",
|
||||||
|
pRaft->selfGroupId, pRaft->selfId, pRaft->term);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
syncInfo("[%d:%d] is starting a new election at term %" PRId64 "", pRaft->selfGroupId, pRaft->selfId, pRaft->term);
|
||||||
|
|
||||||
|
if (pRaft->preVote) {
|
||||||
|
syncRaftStartElection(pRaft, SYNC_RAFT_CAMPAIGN_PRE_ELECTION);
|
||||||
|
} else {
|
||||||
|
syncRaftStartElection(pRaft, SYNC_RAFT_CAMPAIGN_ELECTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <cli@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "syncInt.h"
|
||||||
|
#include "raft.h"
|
||||||
|
#include "raft_configuration.h"
|
||||||
|
#include "raft_log.h"
|
||||||
|
#include "raft_message.h"
|
||||||
|
|
||||||
|
static bool canGrantVoteMessage(SSyncRaft* pRaft, const SSyncMessage* pMsg);
|
||||||
|
|
||||||
|
int syncRaftHandleVoteMessage(SSyncRaft* pRaft, const SSyncMessage* pMsg) {
|
||||||
|
SSyncMessage* pRespMsg;
|
||||||
|
int voteIndex = syncRaftConfigurationIndexOfNode(pRaft, pMsg->from);
|
||||||
|
if (voteIndex == -1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
bool grant;
|
||||||
|
SyncIndex lastIndex = syncRaftLogLastIndex(pRaft->log);
|
||||||
|
SyncTerm lastTerm = syncRaftLogLastTerm(pRaft->log);
|
||||||
|
|
||||||
|
grant = canGrantVoteMessage(pRaft, pMsg);
|
||||||
|
pRespMsg = syncNewVoteRespMsg(pRaft->selfGroupId, pRaft->selfId, pMsg->vote.cType, !grant);
|
||||||
|
if (pRespMsg == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
syncInfo("[%d:%d] [logterm: %" PRId64 ", index: %" PRId64 ", vote: %d] %s for %d"\
|
||||||
|
"[logterm: %" PRId64 ", index: %" PRId64 "] at term %" PRId64 "",
|
||||||
|
pRaft->selfGroupId, pRaft->selfId, lastTerm, lastIndex, pRaft->voteFor,
|
||||||
|
grant ? "grant" : "reject",
|
||||||
|
pMsg->from, pMsg->vote.lastTerm, pMsg->vote.lastIndex, pRaft->term);
|
||||||
|
|
||||||
|
pRaft->io.send(pRespMsg, &(pRaft->cluster.nodeInfo[voteIndex]));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool canGrantVoteMessage(SSyncRaft* pRaft, const SSyncMessage* pMsg) {
|
||||||
|
if (!(pRaft->voteFor == SYNC_NON_NODE_ID || pMsg->term > pRaft->term || pRaft->voteFor == pMsg->from)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!syncRaftLogIsUptodate(pRaft->log, pMsg->vote.lastIndex, pMsg->vote.lastTerm)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue