From d012c3eb8e121dd016ca4db7db342c0ff7889e20 Mon Sep 17 00:00:00 2001 From: slguan Date: Thu, 30 Jul 2020 18:44:29 +0800 Subject: [PATCH 01/56] [TD-992] cmake file for darwin --- CMakeLists.txt | 11 +- cmake/platform.inc | 14 +- src/common/src/tglobal.c | 2 +- src/os/inc/osDarwin64.h | 187 +------------- src/os/inc/osLinux32.h | 7 +- src/os/inc/osSpec.h | 27 +- src/os/src/darwin64/CMakeLists.txt | 15 +- src/os/src/darwin64/darwinCoredump.c | 19 ++ src/os/src/darwin64/darwinEnv.c | 8 +- src/os/src/darwin64/darwinFileOp.c | 67 +++++ src/os/src/darwin64/darwinPlatform.c | 370 --------------------------- src/os/src/darwin64/darwinSem.c | 47 ++++ src/os/src/darwin64/darwinSocket.c | 36 +++ src/os/src/darwin64/darwinSysInfo.c | 106 ++++++++ src/os/src/darwin64/darwinTimer.c | 43 ++++ src/os/src/darwin64/darwinUtil.c | 22 ++ src/os/src/detail/osDir.c | 2 +- src/os/src/detail/osFileOp.c | 42 +-- src/os/src/detail/osSocket.c | 12 +- src/os/src/detail/osSysinfo.c | 4 +- src/os/src/detail/osTimer.c | 59 +++-- src/os/src/linux64/CMakeLists.txt | 1 - src/query/src/qTsbuf.c | 6 +- src/util/inc/talgo.h | 5 + 24 files changed, 473 insertions(+), 639 deletions(-) create mode 100644 src/os/src/darwin64/darwinCoredump.c create mode 100644 src/os/src/darwin64/darwinFileOp.c delete mode 100644 src/os/src/darwin64/darwinPlatform.c create mode 100644 src/os/src/darwin64/darwinSem.c create mode 100644 src/os/src/darwin64/darwinSocket.c create mode 100644 src/os/src/darwin64/darwinSysInfo.c create mode 100644 src/os/src/darwin64/darwinTimer.c create mode 100644 src/os/src/darwin64/darwinUtil.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 8dd99f0b58..bc6a888f9d 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,14 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8) -PROJECT(TDengine) +IF (CMAKE_VERSION VERSION_LESS 3.0) + PROJECT(TDengine CXX) + SET(PROJECT_VERSION_MAJOR "${LIB_MAJOR_VERSION}") + SET(PROJECT_VERSION_MINOR "${LIB_MINOR_VERSION}") + SET(PROJECT_VERSION_PATCH"${LIB_PATCH_VERSION}") + SET(PROJECT_VERSION "${LIB_VERSION_STRING}") +ELSE () + CMAKE_POLICY(SET CMP0048 NEW) + PROJECT(TDengine VERSION "${LIB_VERSION_STRING}" LANGUAGES CXX) +ENDIF () SET(TD_ACCOUNT FALSE) SET(TD_ADMIN FALSE) diff --git a/cmake/platform.inc b/cmake/platform.inc index a0668de7b5..488786b178 100755 --- a/cmake/platform.inc +++ b/cmake/platform.inc @@ -52,14 +52,16 @@ ELSE () MESSAGE(STATUS "input cpuType unknown " ${CPUTYPE}) ENDIF () -# -# Get OS information and store in variable TD_OS_INFO. -# -execute_process(COMMAND chmod 777 ${TD_COMMUNITY_DIR}/packaging/tools/get_os.sh) -execute_process(COMMAND ${TD_COMMUNITY_DIR}/packaging/tools/get_os.sh "" OUTPUT_VARIABLE TD_OS_INFO) -MESSAGE(STATUS "The current os is " ${TD_OS_INFO}) + IF (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + # + # Get OS information and store in variable TD_OS_INFO. + # + execute_process(COMMAND chmod 777 ${TD_COMMUNITY_DIR}/packaging/tools/get_os.sh) + execute_process(COMMAND ${TD_COMMUNITY_DIR}/packaging/tools/get_os.sh "" OUTPUT_VARIABLE TD_OS_INFO) + MESSAGE(STATUS "The current os is " ${TD_OS_INFO}) + SET(TD_LINUX TRUE) IF (${CMAKE_SIZEOF_VOID_P} MATCHES 8) SET(TD_LINUX_64 TRUE) diff --git a/src/common/src/tglobal.c b/src/common/src/tglobal.c index 79ea2b2d46..1e407ec786 100644 --- a/src/common/src/tglobal.c +++ b/src/common/src/tglobal.c @@ -111,7 +111,7 @@ int32_t tsFsyncPeriod = TSDB_DEFAULT_FSYNC_PERIOD; int32_t tsReplications = TSDB_DEFAULT_DB_REPLICA_OPTION; int32_t tsQuorum = TSDB_DEFAULT_DB_QUORUM_OPTION; int32_t tsMaxVgroupsPerDb = 0; -int32_t tsMinTablePerVnode = 100; +int32_t tsMinTablePerVnode = TSDB_TABLES_STEP; int32_t tsMaxTablePerVnode = TSDB_DEFAULT_TABLES; int32_t tsTableIncStepPerVnode = TSDB_TABLES_STEP; diff --git a/src/os/inc/osDarwin64.h b/src/os/inc/osDarwin64.h index 3ceb7ea8f5..8e476c86ef 100644 --- a/src/os/inc/osDarwin64.h +++ b/src/os/inc/osDarwin64.h @@ -22,7 +22,6 @@ extern "C" { #include #include - #include #include #include @@ -72,168 +71,25 @@ extern "C" { #include #include -#define htobe64 htonll - -#define taosCloseSocket(x) \ - { \ - if (FD_VALID(x)) { \ - close(x); \ - x = FD_INITIALIZER; \ - } \ - } - -#define taosWriteSocket(fd, buf, len) write(fd, buf, len) -#define taosReadSocket(fd, buf, len) read(fd, buf, len) - -#define atomic_load_8(ptr) __atomic_load_n((ptr), __ATOMIC_SEQ_CST) -#define atomic_load_16(ptr) __atomic_load_n((ptr), __ATOMIC_SEQ_CST) -#define atomic_load_32(ptr) __atomic_load_n((ptr), __ATOMIC_SEQ_CST) -#define atomic_load_64(ptr) __atomic_load_n((ptr), __ATOMIC_SEQ_CST) -#define atomic_load_ptr(ptr) __atomic_load_n((ptr), __ATOMIC_SEQ_CST) - -#define atomic_store_8(ptr, val) __atomic_store_n((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_store_16(ptr, val) __atomic_store_n((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_store_32(ptr, val) __atomic_store_n((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_store_64(ptr, val) __atomic_store_n((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_store_ptr(ptr, val) __atomic_store_n((ptr), (val), __ATOMIC_SEQ_CST) - -#define atomic_exchange_8(ptr, val) __atomic_exchange_n((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_exchange_16(ptr, val) __atomic_exchange_n((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_exchange_32(ptr, val) __atomic_exchange_n((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_exchange_64(ptr, val) __atomic_exchange_n((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_exchange_ptr(ptr, val) __atomic_exchange_n((ptr), (val), __ATOMIC_SEQ_CST) - -#define atomic_val_compare_exchange_8 __sync_val_compare_and_swap -#define atomic_val_compare_exchange_16 __sync_val_compare_and_swap -#define atomic_val_compare_exchange_32 __sync_val_compare_and_swap -#define atomic_val_compare_exchange_64 __sync_val_compare_and_swap -#define atomic_val_compare_exchange_ptr __sync_val_compare_and_swap - -#define atomic_add_fetch_8(ptr, val) __atomic_add_fetch((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_add_fetch_16(ptr, val) __atomic_add_fetch((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_add_fetch_32(ptr, val) __atomic_add_fetch((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_add_fetch_64(ptr, val) __atomic_add_fetch((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_add_fetch_ptr(ptr, val) __atomic_add_fetch((ptr), (val), __ATOMIC_SEQ_CST) - -#define atomic_fetch_add_8(ptr, val) __atomic_fetch_add((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_fetch_add_16(ptr, val) __atomic_fetch_add((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_fetch_add_32(ptr, val) __atomic_fetch_add((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_fetch_add_64(ptr, val) __atomic_fetch_add((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_fetch_add_ptr(ptr, val) __atomic_fetch_add((ptr), (val), __ATOMIC_SEQ_CST) - -#define atomic_sub_fetch_8(ptr, val) __atomic_sub_fetch((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_sub_fetch_16(ptr, val) __atomic_sub_fetch((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_sub_fetch_32(ptr, val) __atomic_sub_fetch((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_sub_fetch_64(ptr, val) __atomic_sub_fetch((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_sub_fetch_ptr(ptr, val) __atomic_sub_fetch((ptr), (val), __ATOMIC_SEQ_CST) - -#define atomic_fetch_sub_8(ptr, val) __atomic_fetch_sub((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_fetch_sub_16(ptr, val) __atomic_fetch_sub((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_fetch_sub_32(ptr, val) __atomic_fetch_sub((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_fetch_sub_64(ptr, val) __atomic_fetch_sub((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_fetch_sub_ptr(ptr, val) __atomic_fetch_sub((ptr), (val), __ATOMIC_SEQ_CST) - -#define atomic_and_fetch_8(ptr, val) __atomic_and_fetch((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_and_fetch_16(ptr, val) __atomic_and_fetch((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_and_fetch_32(ptr, val) __atomic_and_fetch((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_and_fetch_64(ptr, val) __atomic_and_fetch((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_and_fetch_ptr(ptr, val) __atomic_and_fetch((ptr), (val), __ATOMIC_SEQ_CST) - -#define atomic_fetch_and_8(ptr, val) __atomic_fetch_and((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_fetch_and_16(ptr, val) __atomic_fetch_and((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_fetch_and_32(ptr, val) __atomic_fetch_and((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_fetch_and_64(ptr, val) __atomic_fetch_and((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_fetch_and_ptr(ptr, val) __atomic_fetch_and((ptr), (val), __ATOMIC_SEQ_CST) - -#define atomic_or_fetch_8(ptr, val) __atomic_or_fetch((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_or_fetch_16(ptr, val) __atomic_or_fetch((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_or_fetch_32(ptr, val) __atomic_or_fetch((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_or_fetch_64(ptr, val) __atomic_or_fetch((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_or_fetch_ptr(ptr, val) __atomic_or_fetch((ptr), (val), __ATOMIC_SEQ_CST) - -#define atomic_fetch_or_8(ptr, val) __atomic_fetch_or((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_fetch_or_16(ptr, val) __atomic_fetch_or((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_fetch_or_32(ptr, val) __atomic_fetch_or((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_fetch_or_64(ptr, val) __atomic_fetch_or((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_fetch_or_ptr(ptr, val) __atomic_fetch_or((ptr), (val), __ATOMIC_SEQ_CST) - -#define atomic_xor_fetch_8(ptr, val) __atomic_xor_fetch((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_xor_fetch_16(ptr, val) __atomic_xor_fetch((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_xor_fetch_32(ptr, val) __atomic_xor_fetch((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_xor_fetch_64(ptr, val) __atomic_xor_fetch((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_xor_fetch_ptr(ptr, val) __atomic_xor_fetch((ptr), (val), __ATOMIC_SEQ_CST) - -#define atomic_fetch_xor_8(ptr, val) __atomic_fetch_xor((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_fetch_xor_16(ptr, val) __atomic_fetch_xor((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_fetch_xor_32(ptr, val) __atomic_fetch_xor((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_fetch_xor_64(ptr, val) __atomic_fetch_xor((ptr), (val), __ATOMIC_SEQ_CST) -#define atomic_fetch_xor_ptr(ptr, val) __atomic_fetch_xor((ptr), (val), __ATOMIC_SEQ_CST) - -#define SWAP(a, b, c) \ - do { \ - typeof(a) __tmp = (a); \ - (a) = (b); \ - (b) = __tmp; \ - } while (0) - -#define MAX(a, b) \ - ({ \ - typeof(a) __a = (a); \ - typeof(b) __b = (b); \ - (__a > __b) ? __a : __b; \ - }) - -#define MIN(a, b) \ - ({ \ - typeof(a) __a = (a); \ - typeof(b) __b = (b); \ - (__a < __b) ? __a : __b; \ - }) - -#define MILLISECOND_PER_SECOND ((int64_t)1000L) +#define TAOS_OS_FUNC_CORE +#define TAOS_OS_FUNC_FILEOP +#define taosFSendFile(outfile, infile, offset, count) taosFSendFileImp(outfile, infile, offset, size) +#define taosTSendFile(dfd, sfd, offset, size) taosTSendFileImp(dfd, sfd, offset, size) +#define TAOS_OS_FUNC_SEMPHONE #define tsem_t dispatch_semaphore_t - int tsem_init(dispatch_semaphore_t *sem, int pshared, unsigned int value); int tsem_wait(dispatch_semaphore_t *sem); int tsem_post(dispatch_semaphore_t *sem); int tsem_destroy(dispatch_semaphore_t *sem); -void osInit(); - -ssize_t tread(int fd, void *buf, size_t count); - -ssize_t twrite(int fd, void *buf, size_t n); - - -bool taosCheckPthreadValid(pthread_t thread); - -void taosResetPthread(pthread_t *thread); - -int64_t taosGetPthreadId(); - -int taosSetNonblocking(int sock, int on); - -int taosSetSockOpt(int socketfd, int level, int optname, void *optval, int optlen); - -void taosPrintOsInfo(); - -void taosPrintOsInfo(); - -void taosGetSystemInfo(); - -void taosKillSystem(); - -bool taosSkipSocketCheck(); - -bool taosGetDisk(); - -int fsendfile(FILE* out_file, FILE* in_file, int64_t* offset, int32_t count); - -void taosSetCoreDump(); - -int tSystem(const char * cmd); +#define TAOS_OS_FUNC_SOCKET_SETSOCKETOPT +#define TAOS_OS_FUNC_SYSINFO +#define TAOS_OS_FUNC_TIMER +#define TAOS_OS_FUNC_UTIL +// specific +#define htobe64 htonll typedef int(*__compar_fn_t)(const void *, const void *); // for send function in tsocket.c @@ -246,27 +102,6 @@ typedef int(*__compar_fn_t)(const void *, const void *); #define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE #endif -#ifndef _TD_ARM_32_ -#define BUILDIN_CLZL(val) __builtin_clzl(val) -#define BUILDIN_CTZL(val) __builtin_ctzl(val) -#else -#define BUILDIN_CLZL(val) __builtin_clzll(val) -#define BUILDIN_CTZL(val) __builtin_ctzll(val) -#endif -#define BUILDIN_CLZ(val) __builtin_clz(val) -#define BUILDIN_CTZ(val) __builtin_ctz(val) - -#undef threadlocal -#ifdef _ISOC11_SOURCE - #define threadlocal _Thread_local -#elif defined(__APPLE__) - #define threadlocal -#elif defined(__GNUC__) && !defined(threadlocal) - #define threadlocal __thread -#else - #define threadlocal -#endif - #ifdef __cplusplus } #endif diff --git a/src/os/inc/osLinux32.h b/src/os/inc/osLinux32.h index 1778b0e315..b62b086d0f 100644 --- a/src/os/inc/osLinux32.h +++ b/src/os/inc/osLinux32.h @@ -22,7 +22,6 @@ extern "C" { #include #include - #include #include #include @@ -78,6 +77,12 @@ extern "C" { #include #include +#define TAOS_OS_FUNC_LZ4 +#define BUILDIN_CLZL(val) __builtin_clzll(val) +#define BUILDIN_CTZL(val) __builtin_ctzll(val) +#define BUILDIN_CLZ(val) __builtin_clz(val) +#define BUILDIN_CTZ(val) __builtin_ctz(val) + #ifdef __cplusplus } #endif diff --git a/src/os/inc/osSpec.h b/src/os/inc/osSpec.h index d93a647206..18dd8b75d8 100644 --- a/src/os/inc/osSpec.h +++ b/src/os/inc/osSpec.h @@ -232,12 +232,12 @@ extern "C" { ssize_t taosTReadImp(int fd, void *buf, size_t count); ssize_t taosTWriteImp(int fd, void *buf, size_t count); +// TAOS_OS_FUNC_FILEOP ssize_t taosTSendFileImp(int dfd, int sfd, off_t *offset, size_t size); -#ifndef TAOS_OS_FUNC_FILE_OP - #define taosTRead(fd, buf, count) taosTReadImp(fd, buf, count) - #define taosTWrite(fd, buf, count) taosTWriteImp(fd, buf, count) - #define taosLSeek(fd, offset, whence) lseek(fd, offset, whence) +int taosFSendFileImp(FILE* out_file, FILE* in_file, int64_t* offset, int32_t count); +#ifndef TAOS_OS_FUNC_FILEOP #define taosTSendFile(dfd, sfd, offset, size) taosTSendFileImp(dfd, sfd, offset, size) + #define taosFSendFile(outfile, infile, offset, count) taosTSendFileImp(fileno(outfile), fileno(infile), offset, size) #endif #ifndef TAOS_OS_FUNC_NETWORK @@ -284,14 +284,22 @@ int64_t taosGetPthreadId(); // TAOS_OS_FUNC_SOCKET int taosSetNonblocking(int sock, int on); -int taosSetSockOpt(int socketfd, int level, int optname, void *optval, int optlen); void taosBlockSIGPIPE(); +// TAOS_OS_FUNC_SOCKET_SETSOCKETOPT +int taosSetSockOpt(int socketfd, int level, int optname, void *optval, int optlen); + // TAOS_OS_FUNC_SYSINFO void taosGetSystemInfo(); +bool taosGetProcIO(float *readKB, float *writeKB); +bool taosGetBandSpeed(float *bandSpeedKb); +bool taosGetDisk(); +bool taosGetCpuUsage(float *sysCpuUsage, float *procCpuUsage) ; +bool taosGetProcMemory(float *memoryUsedMB) ; +bool taosGetSysMemory(float *memoryUsedMB); void taosPrintOsInfo(); +int taosSystem(const char * cmd) ; void taosKillSystem(); -int tSystem(const char * cmd) ; // TAOS_OS_FUNC_CORE void taosSetCoreDump(); @@ -344,12 +352,13 @@ void taosMvDir(char* destDir, char *srcDir); ssize_t taosReadFileRandomFail(int fd, void *buf, size_t count, const char *file, uint32_t line); ssize_t taosWriteFileRandomFail(int fd, void *buf, size_t count, const char *file, uint32_t line); off_t taosLSeekRandomFail(int fd, off_t offset, int whence, const char *file, uint32_t line); - #undef taosTRead - #undef taosTWrite - #undef taosLSeek #define taosTRead(fd, buf, count) taosReadFileRandomFail(fd, buf, count, __FILE__, __LINE__) #define taosTWrite(fd, buf, count) taosWriteFileRandomFail(fd, buf, count, __FILE__, __LINE__) #define taosLSeek(fd, offset, whence) taosLSeekRandomFail(fd, offset, whence, __FILE__, __LINE__) +#else + #define taosTRead(fd, buf, count) taosTReadImp(fd, buf, count) + #define taosTWrite(fd, buf, count) taosTWriteImp(fd, buf, count) + #define taosLSeek(fd, offset, whence) lseek(fd, offset, whence) #endif #ifdef TAOS_RANDOM_NETWORK_FAIL diff --git a/src/os/src/darwin64/CMakeLists.txt b/src/os/src/darwin64/CMakeLists.txt index 71029d9291..1568d16164 100644 --- a/src/os/src/darwin64/CMakeLists.txt +++ b/src/os/src/darwin64/CMakeLists.txt @@ -1,13 +1,10 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8) PROJECT(TDengine) -IF (TD_DARWIN_64) - INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/src/inc) - INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/src/os/inc) - INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/src/util/inc) - INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/src/common/inc) - INCLUDE_DIRECTORIES(inc) - AUX_SOURCE_DIRECTORY(src SRC) - ADD_LIBRARY(os ${SRC}) -ENDIF () +INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/src/inc) +INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/src/os/inc) +INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/src/util/inc) +INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/src/common/inc) +AUX_SOURCE_DIRECTORY(. SRC) +ADD_LIBRARY(os ${SRC}) diff --git a/src/os/src/darwin64/darwinCoredump.c b/src/os/src/darwin64/darwinCoredump.c new file mode 100644 index 0000000000..43f22b604d --- /dev/null +++ b/src/os/src/darwin64/darwinCoredump.c @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#define _DEFAULT_SOURCE +#include "os.h" + +void taosSetCoreDump() {} diff --git a/src/os/src/darwin64/darwinEnv.c b/src/os/src/darwin64/darwinEnv.c index 27d5a7c99b..71df78c923 100644 --- a/src/os/src/darwin64/darwinEnv.c +++ b/src/os/src/darwin64/darwinEnv.c @@ -19,12 +19,12 @@ #include "tulog.h" void osInit() { - strcpy(configDir, "/etc/taos"); + strcpy(configDir, "~/TDengine/cfg"); strcpy(tsVnodeDir, ""); strcpy(tsDnodeDir, ""); strcpy(tsMnodeDir, ""); - strcpy(tsDataDir, "/var/lib/taos"); - strcpy(tsLogDir, "~/TDengineLog"); - strcpy(tsScriptDir, "/etc/taos"); + strcpy(tsDataDir, "~/TDengine/data"); + strcpy(tsLogDir, "~/TDengine/log"); + strcpy(tsScriptDir, "~/TDengine/cfg"); strcpy(tsOsName, "Darwin"); } diff --git a/src/os/src/darwin64/darwinFileOp.c b/src/os/src/darwin64/darwinFileOp.c new file mode 100644 index 0000000000..7740f6d5cf --- /dev/null +++ b/src/os/src/darwin64/darwinFileOp.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#define _DEFAULT_SOURCE +#include "os.h" +#include "os.h" +#include "taosdef.h" +#include "tglobal.h" +#include "tconfig.h" +#include "ttimer.h" +#include "tulog.h" +#include "tutil.h" + +#define _SEND_FILE_STEP_ 1000 + +int taosFSendFileImp(FILE* out_file, FILE* in_file, int64_t* offset, int32_t count) { + fseek(in_file, (int32_t)(*offset), 0); + int writeLen = 0; + uint8_t buffer[_SEND_FILE_STEP_] = { 0 }; + + for (int len = 0; len < (count - _SEND_FILE_STEP_); len += _SEND_FILE_STEP_) { + size_t rlen = fread(buffer, 1, _SEND_FILE_STEP_, in_file); + if (rlen <= 0) { + return writeLen; + } + else if (rlen < _SEND_FILE_STEP_) { + fwrite(buffer, 1, rlen, out_file); + return (int)(writeLen + rlen); + } + else { + fwrite(buffer, 1, _SEND_FILE_STEP_, in_file); + writeLen += _SEND_FILE_STEP_; + } + } + + int remain = count - writeLen; + if (remain > 0) { + size_t rlen = fread(buffer, 1, remain, in_file); + if (rlen <= 0) { + return writeLen; + } + else { + fwrite(buffer, 1, remain, out_file); + writeLen += remain; + } + } + + return writeLen; +} + + +ssize_t taosTSendFileImp(int dfd, int sfd, off_t *offset, size_t size) { + uError("not implemented yet"); + return -1; +} \ No newline at end of file diff --git a/src/os/src/darwin64/darwinPlatform.c b/src/os/src/darwin64/darwinPlatform.c deleted file mode 100644 index 045e4a7099..0000000000 --- a/src/os/src/darwin64/darwinPlatform.c +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright (c) 2019 TAOS Data, Inc. - * - * This program is free software: you can use, redistribute, and/or modify - * it under the terms of the GNU Affero General Public License, version 3 - * or later ("AGPL"), as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#define _DEFAULT_SOURCE -#include "os.h" -#include "os.h" -#include "taosdef.h" -#include "tglobal.h" -#include "tconfig.h" -#include "ttimer.h" -#include "tulog.h" -#include "tutil.h" - -int64_t tsosStr2int64(char *str) { - char *endptr = NULL; - return strtoll(str, &endptr, 10); -} - -/* - to make taosMsleep work, - signal SIGALRM shall be blocked in the calling thread, - - sigset_t set; - sigemptyset(&set); - sigaddset(&set, SIGALRM); - pthread_sigmask(SIG_BLOCK, &set, NULL); -*/ -void taosMsleep(int mseconds) { - struct timeval timeout; - int seconds, useconds; - - seconds = mseconds / 1000; - useconds = (mseconds % 1000) * 1000; - timeout.tv_sec = seconds; - timeout.tv_usec = useconds; - - /* sigset_t set; */ - /* sigemptyset(&set); */ - /* sigaddset(&set, SIGALRM); */ - /* pthread_sigmask(SIG_BLOCK, &set, NULL); */ - - select(0, NULL, NULL, NULL, &timeout); - - /* pthread_sigmask(SIG_UNBLOCK, &set, NULL); */ -} - -bool taosCheckPthreadValid(pthread_t thread) { return thread != 0; } - -void taosResetPthread(pthread_t *thread) { *thread = 0; } - -int64_t taosGetPthreadId() { return (int64_t)pthread_self(); } - -/* -* Function to get the private ip address of current machine. If get IP -* successfully, return 0, else, return -1. The return values is ip. -* -* Use: -* if (taosGetPrivateIp(ip) != 0) { -* perror("Fail to get private IP address\n"); -* exit(EXIT_FAILURE); -* } -*/ -int taosGetPrivateIp(char *const ip) { - bool hasLoCard = false; - - struct ifaddrs *ifaddr, *ifa; - int family, s; - char host[NI_MAXHOST]; - - if (getifaddrs(&ifaddr) == -1) { - return -1; - } - - /* Walk through linked list, maintaining head pointer so we can free list later */ - int flag = 0; - for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { - if (ifa->ifa_addr == NULL) continue; - - family = ifa->ifa_addr->sa_family; - if (strcmp("lo", ifa->ifa_name) == 0) { - hasLoCard = true; - continue; - } - - if (family == AF_INET) { - /* printf("%-8s", ifa->ifa_name); */ - s = getnameinfo(ifa->ifa_addr, (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6), - host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); - if (s != 0) { - freeifaddrs(ifaddr); - return -1; - } - - strcpy(ip, host); - flag = 1; - break; - } - } - - freeifaddrs(ifaddr); - if (flag) { - return 0; - } else { - if (hasLoCard) { - uInfo("no net card was found, use lo:127.0.0.1 as default"); - strcpy(ip, "127.0.0.1"); - return 0; - } - return -1; - } -} - -int taosSetNonblocking(int sock, int on) { - int flags = 0; - if ((flags = fcntl(sock, F_GETFL, 0)) < 0) { - uError("fcntl(F_GETFL) error: %d (%s)\n", errno, strerror(errno)); - return 1; - } - - if (on) - flags |= O_NONBLOCK; - else - flags &= ~O_NONBLOCK; - - if ((flags = fcntl(sock, F_SETFL, flags)) < 0) { - uError("fcntl(F_SETFL) error: %d (%s)\n", errno, strerror(errno)); - return 1; - } - - return 0; -} - -int taosSetSockOpt(int socketfd, int level, int optname, void *optval, int optlen) { - if (level == SOL_SOCKET && optname == SO_SNDBUF) { - return 0; - } - - if (level == SOL_SOCKET && optname == SO_RCVBUF) { - return 0; - } - - return setsockopt(socketfd, level, optname, optval, (socklen_t)optlen); -} - -int taosInitTimer(void (*callback)(int), int ms) { - signal(SIGALRM, callback); - - struct itimerval tv; - tv.it_interval.tv_sec = 0; /* my timer resolution */ - tv.it_interval.tv_usec = 1000 * ms; // resolution is in msecond - tv.it_value = tv.it_interval; - - setitimer(ITIMER_REAL, &tv, NULL); - - return 0; -} - -void taosUninitTimer() { - struct itimerval tv = { 0 }; - setitimer(ITIMER_REAL, &tv, NULL); -} - -void taosGetSystemTimezone() { - // get and set default timezone - SGlobalCfg *cfg_timezone = taosGetConfigOption("timezone"); - if (cfg_timezone && cfg_timezone->cfgStatus < TAOS_CFG_CSTATUS_DEFAULT) { - char *tz = getenv("TZ"); - if (tz == NULL || strlen(tz) == 0) { - strcpy(tsTimezone, "not configured"); - } - else { - strcpy(tsTimezone, tz); - } - cfg_timezone->cfgStatus = TAOS_CFG_CSTATUS_DEFAULT; - uInfo("timezone not configured, use default"); - } -} - -void taosGetSystemLocale() { - // get and set default locale - SGlobalCfg *cfg_locale = taosGetConfigOption("locale"); - if (cfg_locale && cfg_locale->cfgStatus < TAOS_CFG_CSTATUS_DEFAULT) { - char *locale = setlocale(LC_CTYPE, "chs"); - if (locale != NULL) { - tstrncpy(tsLocale, locale, sizeof(tsLocale)); - cfg_locale->cfgStatus = TAOS_CFG_CSTATUS_DEFAULT; - uInfo("locale not configured, set to default:%s", tsLocale); - } - } - - SGlobalCfg *cfg_charset = taosGetConfigOption("charset"); - if (cfg_charset && cfg_charset->cfgStatus < TAOS_CFG_CSTATUS_DEFAULT) { - strcpy(tsCharset, "cp936"); - cfg_charset->cfgStatus = TAOS_CFG_CSTATUS_DEFAULT; - uInfo("charset not configured, set to default:%s", tsCharset); - } -} - - -void taosPrintOsInfo() {} - -void taosKillSystem() { - uError("function taosKillSystem, exit!"); - exit(0); -} - -bool taosGetDisk() { - return true; -} - -void taosGetSystemInfo() { - taosGetSystemTimezone(); - taosGetSystemLocale(); -} - -void *taosInitTcpClient(char *ip, uint16_t port, char *flabel, int num, void *fp, void *shandle) { - uError("function taosInitTcpClient is not implemented in darwin system, exit!"); - exit(0); -} - -void taosCloseTcpClientConnection(void *chandle) { - uError("function taosCloseTcpClientConnection is not implemented in darwin system, exit!"); - exit(0); -} - -void *taosOpenTcpClientConnection(void *shandle, void *thandle, char *ip, uint16_t port) { - uError("function taosOpenTcpClientConnection is not implemented in darwin system, exit!"); - exit(0); -} - -int taosSendTcpClientData(unsigned int ip, uint16_t port, char *data, int len, void *chandle) { - uError("function taosSendTcpClientData is not implemented in darwin system, exit!"); - exit(0); -} - -void taosCleanUpTcpClient(void *chandle) { - uError("function taosCleanUpTcpClient is not implemented in darwin system, exit!"); - exit(0); -} - -void taosCloseTcpServerConnection(void *chandle) { - uError("function taosCloseTcpServerConnection is not implemented in darwin system, exit!"); - exit(0); -} - -void taosCleanUpTcpServer(void *handle) { - uError("function taosCleanUpTcpServer is not implemented in darwin system, exit!"); - exit(0); -} - -void *taosInitTcpServer(char *ip, uint16_t port, char *label, int numOfThreads, void *fp, void *shandle) { - uError("function taosInitTcpServer is not implemented in darwin system, exit!"); - exit(0); -} - -int taosSendTcpServerData(unsigned int ip, uint16_t port, char *data, int len, void *chandle) { - uError("function taosSendTcpServerData is not implemented in darwin system, exit!"); - exit(0); -} - -void taosFreeMsgHdr(void *hdr) { - uError("function taosFreeMsgHdr is not implemented in darwin system, exit!"); - exit(0); -} - -int taosMsgHdrSize(void *hdr) { - uError("function taosMsgHdrSize is not implemented in darwin system, exit!"); - exit(0); -} - -void taosSendMsgHdr(void *hdr, int fd) { - uError("function taosSendMsgHdr is not implemented in darwin system, exit!"); - exit(0); -} - -void taosInitMsgHdr(void **hdr, void *dest, int maxPkts) { - uError("function taosInitMsgHdr is not implemented in darwin system, exit!"); - exit(0); -} - -void taosSetMsgHdrData(void *hdr, char *data, int dataLen) { - uError("function taosSetMsgHdrData is not implemented in darwin system, exit!"); - exit(0); -} - -bool taosSkipSocketCheck() { - return true; -} - -int tsem_init(dispatch_semaphore_t *sem, int pshared, unsigned int value) { - *sem = dispatch_semaphore_create(value); - if (*sem == NULL) { - return -1; - } else { - return 0; - } -} - -int tsem_wait(dispatch_semaphore_t *sem) { - dispatch_semaphore_wait(*sem, DISPATCH_TIME_FOREVER); - return 0; -} - -int tsem_post(dispatch_semaphore_t *sem) { - dispatch_semaphore_signal(*sem); - return 0; -} - -int tsem_destroy(dispatch_semaphore_t *sem) { - return 0; -} - -int32_t __sync_val_load_32(int32_t *ptr) { - return __atomic_load_n(ptr, __ATOMIC_ACQUIRE); -} - -void __sync_val_restore_32(int32_t *ptr, int32_t newval) { - __atomic_store_n(ptr, newval, __ATOMIC_RELEASE); -} - -#define _SEND_FILE_STEP_ 1000 - -int fsendfile(FILE* out_file, FILE* in_file, int64_t* offset, int32_t count) { - fseek(in_file, (int32_t)(*offset), 0); - int writeLen = 0; - uint8_t buffer[_SEND_FILE_STEP_] = { 0 }; - - for (int len = 0; len < (count - _SEND_FILE_STEP_); len += _SEND_FILE_STEP_) { - size_t rlen = fread(buffer, 1, _SEND_FILE_STEP_, in_file); - if (rlen <= 0) { - return writeLen; - } - else if (rlen < _SEND_FILE_STEP_) { - fwrite(buffer, 1, rlen, out_file); - return (int)(writeLen + rlen); - } - else { - fwrite(buffer, 1, _SEND_FILE_STEP_, in_file); - writeLen += _SEND_FILE_STEP_; - } - } - - int remain = count - writeLen; - if (remain > 0) { - size_t rlen = fread(buffer, 1, remain, in_file); - if (rlen <= 0) { - return writeLen; - } - else { - fwrite(buffer, 1, remain, out_file); - writeLen += remain; - } - } - - return writeLen; -} - -void taosSetCoreDump() {} diff --git a/src/os/src/darwin64/darwinSem.c b/src/os/src/darwin64/darwinSem.c new file mode 100644 index 0000000000..71571c8ba5 --- /dev/null +++ b/src/os/src/darwin64/darwinSem.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#define _DEFAULT_SOURCE +#include "os.h" +#include "os.h" +#include "taosdef.h" +#include "tglobal.h" +#include "tconfig.h" +#include "ttimer.h" +#include "tulog.h" +#include "tutil.h" + +int tsem_init(dispatch_semaphore_t *sem, int pshared, unsigned int value) { + *sem = dispatch_semaphore_create(value); + if (*sem == NULL) { + return -1; + } else { + return 0; + } +} + +int tsem_wait(dispatch_semaphore_t *sem) { + dispatch_semaphore_wait(*sem, DISPATCH_TIME_FOREVER); + return 0; +} + +int tsem_post(dispatch_semaphore_t *sem) { + dispatch_semaphore_signal(*sem); + return 0; +} + +int tsem_destroy(dispatch_semaphore_t *sem) { + return 0; +} diff --git a/src/os/src/darwin64/darwinSocket.c b/src/os/src/darwin64/darwinSocket.c new file mode 100644 index 0000000000..32832b9d63 --- /dev/null +++ b/src/os/src/darwin64/darwinSocket.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#define _DEFAULT_SOURCE +#include "os.h" +#include "os.h" +#include "taosdef.h" +#include "tglobal.h" +#include "tconfig.h" +#include "ttimer.h" +#include "tulog.h" +#include "tutil.h" + +int taosSetSockOpt(int socketfd, int level, int optname, void *optval, int optlen) { + if (level == SOL_SOCKET && optname == SO_SNDBUF) { + return 0; + } + + if (level == SOL_SOCKET && optname == SO_RCVBUF) { + return 0; + } + + return setsockopt(socketfd, level, optname, optval, (socklen_t)optlen); +} diff --git a/src/os/src/darwin64/darwinSysInfo.c b/src/os/src/darwin64/darwinSysInfo.c new file mode 100644 index 0000000000..ea29a0b96c --- /dev/null +++ b/src/os/src/darwin64/darwinSysInfo.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#define _DEFAULT_SOURCE +#include "os.h" +#include "os.h" +#include "taosdef.h" +#include "tglobal.h" +#include "tconfig.h" +#include "ttimer.h" +#include "tulog.h" +#include "tutil.h" + +static void taosGetSystemTimezone() { + // get and set default timezone + SGlobalCfg *cfg_timezone = taosGetConfigOption("timezone"); + if (cfg_timezone && cfg_timezone->cfgStatus < TAOS_CFG_CSTATUS_DEFAULT) { + char *tz = getenv("TZ"); + if (tz == NULL || strlen(tz) == 0) { + strcpy(tsTimezone, "not configured"); + } + else { + strcpy(tsTimezone, tz); + } + cfg_timezone->cfgStatus = TAOS_CFG_CSTATUS_DEFAULT; + uInfo("timezone not configured, use default"); + } +} + +static void taosGetSystemLocale() { + // get and set default locale + SGlobalCfg *cfg_locale = taosGetConfigOption("locale"); + if (cfg_locale && cfg_locale->cfgStatus < TAOS_CFG_CSTATUS_DEFAULT) { + char *locale = setlocale(LC_CTYPE, "chs"); + if (locale != NULL) { + strncpy(tsLocale, locale, TSDB_LOCALE_LEN - 1); + cfg_locale->cfgStatus = TAOS_CFG_CSTATUS_DEFAULT; + uInfo("locale not configured, set to default:%s", tsLocale); + } + } + + SGlobalCfg *cfg_charset = taosGetConfigOption("charset"); + if (cfg_charset && cfg_charset->cfgStatus < TAOS_CFG_CSTATUS_DEFAULT) { + strcpy(tsCharset, "cp936"); + cfg_charset->cfgStatus = TAOS_CFG_CSTATUS_DEFAULT; + uInfo("charset not configured, set to default:%s", tsCharset); + } +} + +void taosPrintOsInfo() {} + +void taosKillSystem() { + uError("function taosKillSystem, exit!"); + exit(0); +} + +void taosGetSystemInfo() { + taosGetSystemTimezone(); + taosGetSystemLocale(); +} + +bool taosGetDisk() { return true; } + +bool taosGetProcIO(float *readKB, float *writeKB) { + *readKB = 0; + *writeKB = 0; + return true; +} + +bool taosGetBandSpeed(float *bandSpeedKb) { + *bandSpeedKb = 0; + return true; +} + +bool taosGetCpuUsage(float *sysCpuUsage, float *procCpuUsage) { + *sysCpuUsage = 0; + *procCpuUsage = 0; + return true; +} + +bool taosGetProcMemory(float *memoryUsedMB) { + *memoryUsedMB = 0; + return true; +} + +bool taosGetSysMemory(float *memoryUsedMB) { + *memoryUsedMB = 0; + return true; +} + +int taosSystem(const char *cmd) { + uError("un support funtion"); + return -1; +} diff --git a/src/os/src/darwin64/darwinTimer.c b/src/os/src/darwin64/darwinTimer.c new file mode 100644 index 0000000000..93546088f3 --- /dev/null +++ b/src/os/src/darwin64/darwinTimer.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#define _DEFAULT_SOURCE +#include "os.h" +#include "os.h" +#include "taosdef.h" +#include "tglobal.h" +#include "tconfig.h" +#include "ttimer.h" +#include "tulog.h" +#include "tutil.h" + +int taosInitTimer(void (*callback)(int), int ms) { + signal(SIGALRM, callback); + + struct itimerval tv; + tv.it_interval.tv_sec = 0; /* my timer resolution */ + tv.it_interval.tv_usec = 1000 * ms; // resolution is in msecond + tv.it_value = tv.it_interval; + + setitimer(ITIMER_REAL, &tv, NULL); + + return 0; +} + +void taosUninitTimer() { + struct itimerval tv = { 0 }; + setitimer(ITIMER_REAL, &tv, NULL); +} + diff --git a/src/os/src/darwin64/darwinUtil.c b/src/os/src/darwin64/darwinUtil.c new file mode 100644 index 0000000000..3042e78666 --- /dev/null +++ b/src/os/src/darwin64/darwinUtil.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#define _DEFAULT_SOURCE +#include "os.h" + +int64_t tsosStr2int64(char *str) { + char *endptr = NULL; + return strtoll(str, &endptr, 10); +} diff --git a/src/os/src/detail/osDir.c b/src/os/src/detail/osDir.c index 27555938c2..b2a91d803a 100644 --- a/src/os/src/detail/osDir.c +++ b/src/os/src/detail/osDir.c @@ -60,7 +60,7 @@ void taosMvDir(char* destDir, char *srcDir) { //(void)snprintf(shellCmd, 1024, "cp -rf %s %s", srcDir, destDir); (void)snprintf(shellCmd, 1024, "mv %s %s", srcDir, destDir); - tSystem(shellCmd); + taosSystem(shellCmd); uInfo("shell cmd:%s is executed", shellCmd); } diff --git a/src/os/src/detail/osFileOp.c b/src/os/src/detail/osFileOp.c index 897b6c3f03..b6928049b6 100644 --- a/src/os/src/detail/osFileOp.c +++ b/src/os/src/detail/osFileOp.c @@ -40,6 +40,28 @@ ssize_t taosTReadImp(int fd, void *buf, size_t count) { return (ssize_t)count; } +ssize_t taosTWriteImp(int fd, void *buf, size_t n) { + size_t nleft = n; + ssize_t nwritten = 0; + char *tbuf = (char *)buf; + + while (nleft > 0) { + nwritten = write(fd, (void *)tbuf, nleft); + if (nwritten < 0) { + if (errno == EINTR) { + continue; + } + return -1; + } + nleft -= nwritten; + tbuf += nwritten; + } + + return n; +} + +#ifndef TAOS_OS_FUNC_FILEOP + ssize_t taosTSendFileImp(int dfd, int sfd, off_t *offset, size_t size) { size_t leftbytes = size; ssize_t sentbytes; @@ -67,22 +89,4 @@ ssize_t taosTSendFileImp(int dfd, int sfd, off_t *offset, size_t size) { return size; } -ssize_t taosTWriteImp(int fd, void *buf, size_t n) { - size_t nleft = n; - ssize_t nwritten = 0; - char *tbuf = (char *)buf; - - while (nleft > 0) { - nwritten = write(fd, (void *)tbuf, nleft); - if (nwritten < 0) { - if (errno == EINTR) { - continue; - } - return -1; - } - nleft -= nwritten; - tbuf += nwritten; - } - - return n; -} +#endif \ No newline at end of file diff --git a/src/os/src/detail/osSocket.c b/src/os/src/detail/osSocket.c index ea0b92de5f..7e4031eff9 100644 --- a/src/os/src/detail/osSocket.c +++ b/src/os/src/detail/osSocket.c @@ -39,10 +39,6 @@ int taosSetNonblocking(int sock, int on) { return 0; } -int taosSetSockOpt(int socketfd, int level, int optname, void *optval, int optlen) { - return setsockopt(socketfd, level, optname, optval, (socklen_t)optlen); -} - void taosBlockSIGPIPE() { sigset_t signal_mask; sigemptyset(&signal_mask); @@ -53,4 +49,12 @@ void taosBlockSIGPIPE() { } } +#endif + +#ifndef TAOS_OS_FUNC_SOCKET_SETSOCKETOPT + +int taosSetSockOpt(int socketfd, int level, int optname, void *optval, int optlen) { + return setsockopt(socketfd, level, optname, optval, (socklen_t)optlen); +} + #endif \ No newline at end of file diff --git a/src/os/src/detail/osSysinfo.c b/src/os/src/detail/osSysinfo.c index 7a395285af..89813d9864 100644 --- a/src/os/src/detail/osSysinfo.c +++ b/src/os/src/detail/osSysinfo.c @@ -543,12 +543,12 @@ void taosKillSystem() { kill(tsProcId, 2); } -int tSystem(const char *cmd) { +int taosSystem(const char *cmd) { FILE *fp; int res; char buf[1024]; if (cmd == NULL) { - uError("tSystem cmd is NULL!\n"); + uError("taosSystem cmd is NULL!\n"); return -1; } diff --git a/src/os/src/detail/osTimer.c b/src/os/src/detail/osTimer.c index e0a2e90314..7c6346205a 100644 --- a/src/os/src/detail/osTimer.c +++ b/src/os/src/detail/osTimer.c @@ -22,35 +22,6 @@ #ifndef TAOS_OS_FUNC_TIMER -/* - to make taosMsleep work, - signal SIGALRM shall be blocked in the calling thread, - - sigset_t set; - sigemptyset(&set); - sigaddset(&set, SIGALRM); - pthread_sigmask(SIG_BLOCK, &set, NULL); -*/ -void taosMsleep(int mseconds) { - struct timeval timeout; - int seconds, useconds; - - seconds = mseconds / 1000; - useconds = (mseconds % 1000) * 1000; - timeout.tv_sec = seconds; - timeout.tv_usec = useconds; - - /* sigset_t set; */ - /* sigemptyset(&set); */ - /* sigaddset(&set, SIGALRM); */ - /* pthread_sigmask(SIG_BLOCK, &set, NULL); */ - - select(0, NULL, NULL, NULL, &timeout); - - /* pthread_sigmask(SIG_UNBLOCK, &set, NULL); */ -} - - static void taosDeleteTimer(void *tharg) { timer_t *pTimer = tharg; timer_delete(*pTimer); @@ -129,4 +100,32 @@ void taosUninitTimer() { pthread_join(timerThread, NULL); } -#endif \ No newline at end of file +#endif + +/* + to make taosMsleep work, + signal SIGALRM shall be blocked in the calling thread, + + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGALRM); + pthread_sigmask(SIG_BLOCK, &set, NULL); +*/ +void taosMsleep(int mseconds) { + struct timeval timeout; + int seconds, useconds; + + seconds = mseconds / 1000; + useconds = (mseconds % 1000) * 1000; + timeout.tv_sec = seconds; + timeout.tv_usec = useconds; + + /* sigset_t set; */ + /* sigemptyset(&set); */ + /* sigaddset(&set, SIGALRM); */ + /* pthread_sigmask(SIG_BLOCK, &set, NULL); */ + + select(0, NULL, NULL, NULL, &timeout); + + /* pthread_sigmask(SIG_UNBLOCK, &set, NULL); */ +} \ No newline at end of file diff --git a/src/os/src/linux64/CMakeLists.txt b/src/os/src/linux64/CMakeLists.txt index 79cbf917e2..0c577374ed 100644 --- a/src/os/src/linux64/CMakeLists.txt +++ b/src/os/src/linux64/CMakeLists.txt @@ -9,4 +9,3 @@ AUX_SOURCE_DIRECTORY(. SRC) ADD_LIBRARY(os ${SRC}) TARGET_LINK_LIBRARIES(os m rt) - diff --git a/src/query/src/qTsbuf.c b/src/query/src/qTsbuf.c index 90cf394035..037e85c88c 100644 --- a/src/query/src/qTsbuf.c +++ b/src/query/src/qTsbuf.c @@ -739,11 +739,7 @@ int32_t tsBufMerge(STSBuf* pDestBuf, const STSBuf* pSrcBuf, int32_t vnodeId) { int64_t offset = getDataStartOffset(); int32_t size = pSrcBuf->fileSize - offset; -#ifdef LINUX - ssize_t rc = taosTSendFile(fileno(pDestBuf->f), fileno(pSrcBuf->f), &offset, size); -#else - ssize_t rc = fsendfile(pDestBuf->f, pSrcBuf->f, &offset, size); -#endif + ssize_t rc = taosFSendFile(pDestBuf->f, pSrcBuf->f, &offset, size); if (rc == -1) { // tscError("failed to merge tsBuf from:%s to %s, reason:%s\n", pSrcBuf->path, pDestBuf->path, strerror(errno)); diff --git a/src/util/inc/talgo.h b/src/util/inc/talgo.h index e71e340a21..9e3692225b 100644 --- a/src/util/inc/talgo.h +++ b/src/util/inc/talgo.h @@ -20,6 +20,11 @@ extern "C" { #endif +#ifndef __COMPAR_FN_T +# define __COMPAR_FN_T +typedef int (*__compar_fn_t) (const void *, const void *); +#endif + #define TD_EQ 0x1 #define TD_GT 0x2 #define TD_LT 0x4 From ffb2a5482aab6245502d802c85fb8e81b822348e Mon Sep 17 00:00:00 2001 From: Hongze Cheng Date: Fri, 31 Jul 2020 09:48:26 +0800 Subject: [PATCH 02/56] move load compIdx out --- src/tsdb/src/tsdbMain.c | 1 + src/tsdb/src/tsdbMemTable.c | 5 +++++ src/tsdb/src/tsdbRWHelper.c | 19 ++++++++----------- src/tsdb/src/tsdbRead.c | 9 +++++---- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/tsdb/src/tsdbMain.c b/src/tsdb/src/tsdbMain.c index b04b0be9ba..2b6dc66e2d 100644 --- a/src/tsdb/src/tsdbMain.c +++ b/src/tsdb/src/tsdbMain.c @@ -787,6 +787,7 @@ static int tsdbRestoreInfo(STsdbRepo *pRepo) { tsdbInitFileGroupIter(pFileH, &iter, TSDB_ORDER_DESC); while ((pFGroup = tsdbGetFileGroupNext(&iter)) != NULL) { if (tsdbSetAndOpenHelperFile(&rhelper, pFGroup) < 0) goto _err; + if (tsdbLoadCompIdx(&rhelper, NULL) < 0) goto _err; for (int i = 1; i < pMeta->maxTables; i++) { STable *pTable = pMeta->tables[i]; if (pTable == NULL) continue; diff --git a/src/tsdb/src/tsdbMemTable.c b/src/tsdb/src/tsdbMemTable.c index 506f3c11c1..0cb032a730 100644 --- a/src/tsdb/src/tsdbMemTable.c +++ b/src/tsdb/src/tsdbMemTable.c @@ -603,6 +603,11 @@ static int tsdbCommitToFile(STsdbRepo *pRepo, int fid, SCommitIter *iters, SRWHe goto _err; } + if (tsdbLoadCompIdx(pHelper, NULL) < 0) { + tsdbError("vgId:%d failed to load SCompIdx part since %s", REPO_ID(pRepo), tstrerror(terrno)); + goto _err; + } + // Loop to commit data in each table for (int tid = 1; tid < pMem->maxTables; tid++) { SCommitIter *pIter = iters + tid; diff --git a/src/tsdb/src/tsdbRWHelper.c b/src/tsdb/src/tsdbRWHelper.c index 8d3908666e..b25e5ac432 100644 --- a/src/tsdb/src/tsdbRWHelper.c +++ b/src/tsdb/src/tsdbRWHelper.c @@ -118,12 +118,12 @@ int tsdbSetAndOpenHelperFile(SRWHelper *pHelper, SFileGroup *pGroup) { // Open the files #ifdef TSDB_IDX - if (tsdbOpenFile(helperIdxF(pHelper), O_RDONLY) < 0) goto _err; + if (tsdbOpenFile(helperIdxF(pHelper), O_RDONLY) < 0) return -1; #endif - if (tsdbOpenFile(helperHeadF(pHelper), O_RDONLY) < 0) goto _err; + if (tsdbOpenFile(helperHeadF(pHelper), O_RDONLY) < 0) return -1; if (helperType(pHelper) == TSDB_WRITE_HELPER) { - if (tsdbOpenFile(helperDataF(pHelper), O_RDWR) < 0) goto _err; - if (tsdbOpenFile(helperLastF(pHelper), O_RDWR) < 0) goto _err; + if (tsdbOpenFile(helperDataF(pHelper), O_RDWR) < 0) return -1; + if (tsdbOpenFile(helperLastF(pHelper), O_RDWR) < 0) return -1; #ifdef TSDB_IDX // Create and open .i file @@ -144,23 +144,20 @@ int tsdbSetAndOpenHelperFile(SRWHelper *pHelper, SFileGroup *pGroup) { // Create and open .l file if should if (tsdbShouldCreateNewLast(pHelper)) { pFile = helperNewLastF(pHelper); - if (tsdbOpenFile(pFile, O_WRONLY | O_CREAT) < 0) goto _err; + if (tsdbOpenFile(pFile, O_WRONLY | O_CREAT) < 0) return -1; pFile->info.size = TSDB_FILE_HEAD_SIZE; pFile->info.magic = TSDB_FILE_INIT_MAGIC; pFile->info.len = 0; if (tsdbUpdateFileHeader(pFile, 0) < 0) return -1; } } else { - if (tsdbOpenFile(helperDataF(pHelper), O_RDONLY) < 0) goto _err; - if (tsdbOpenFile(helperLastF(pHelper), O_RDONLY) < 0) goto _err; + if (tsdbOpenFile(helperDataF(pHelper), O_RDONLY) < 0) return -1; + if (tsdbOpenFile(helperLastF(pHelper), O_RDONLY) < 0) return -1; } helperSetState(pHelper, TSDB_HELPER_FILE_SET_AND_OPEN); - return tsdbLoadCompIdx(pHelper, NULL); - -_err: - return -1; + return 0; } int tsdbCloseHelperFile(SRWHelper *pHelper, bool hasError) { diff --git a/src/tsdb/src/tsdbRead.c b/src/tsdb/src/tsdbRead.c index 0e3a657fde..3a89ead4a8 100644 --- a/src/tsdb/src/tsdbRead.c +++ b/src/tsdb/src/tsdbRead.c @@ -558,11 +558,12 @@ static int32_t getFileCompInfo(STsdbQueryHandle* pQueryHandle, int32_t* numOfBlo SFileGroup* fileGroup = pQueryHandle->pFileGroup; assert(fileGroup->files[TSDB_FILE_TYPE_HEAD].fname > 0); - int32_t code = tsdbSetAndOpenHelperFile(&pQueryHandle->rhelper, fileGroup); + if (tsdbSetAndOpenHelperFile(&pQueryHandle->rhelper, fileGroup) < 0) { + return terrno; + } - //open file failed, return error code to client - if (code != TSDB_CODE_SUCCESS) { - return code; + if (tsdbLoadCompIdx(&pQueryHandle->rhelper, NULL) < 0) { + return terrno; } // load all the comp offset value for all tables in this file From ee82eb602c6398f5fcd25f9b9c6ce428fac38bc7 Mon Sep 17 00:00:00 2001 From: slguan Date: Fri, 31 Jul 2020 10:17:15 +0800 Subject: [PATCH 03/56] TD-992 cmake file for w64 --- src/client/src/tscSubquery.c | 6 +- src/os/inc/osSpec.h | 2 +- src/os/inc/osWindows64.h | 567 ++++++++---------- src/os/src/detail/osFile.c | 6 +- src/os/src/detail/osTimer.c | 5 +- src/os/src/windows64/twindows.c | 410 ------------- src/os/src/windows64/twinsocket.c | 117 ---- src/os/src/windows64/twintcpclient.c | 39 -- src/os/src/windows64/w64Atomic.c | 172 ++++++ src/os/src/windows64/w64Coredump.c | 23 + src/os/src/windows64/{twinenv.c => w64Env.c} | 0 src/os/src/windows64/w64File.c | 2 +- src/os/src/windows64/w64FileOp.c | 59 ++ .../windows64/{twingetline.c => w64Getline.c} | 0 src/os/src/windows64/w64Godll.c | 34 ++ src/os/src/windows64/w64Lz4.c | 46 ++ .../windows64/{twinmsghdr.c => w64Msghdr.c} | 47 +- src/os/src/windows64/w64PThread.c | 34 ++ src/os/src/windows64/w64Socket.c | 64 ++ src/os/src/windows64/w64String.c | 92 +++ .../{twinstrptime.c => w64Strptime.c} | 0 src/os/src/windows64/w64Sysinfo.c | 116 ++++ .../src/windows64/{twintime.c => w64Time.c} | 0 .../src/windows64/{twintimer.c => w64Timer.c} | 7 +- src/os/src/windows64/w64Util.c | 117 ++++ .../{twintcpserver.c => w64Wordexp.c} | 27 +- src/query/src/qExtbuffer.c | 2 +- src/query/src/qResultbuf.c | 2 +- src/query/src/qTsbuf.c | 2 +- src/query/tests/unitTest.cpp | 2 +- 30 files changed, 1064 insertions(+), 936 deletions(-) delete mode 100644 src/os/src/windows64/twindows.c delete mode 100644 src/os/src/windows64/twinsocket.c delete mode 100644 src/os/src/windows64/twintcpclient.c create mode 100644 src/os/src/windows64/w64Atomic.c create mode 100644 src/os/src/windows64/w64Coredump.c rename src/os/src/windows64/{twinenv.c => w64Env.c} (100%) create mode 100644 src/os/src/windows64/w64FileOp.c rename src/os/src/windows64/{twingetline.c => w64Getline.c} (100%) create mode 100644 src/os/src/windows64/w64Godll.c create mode 100644 src/os/src/windows64/w64Lz4.c rename src/os/src/windows64/{twinmsghdr.c => w64Msghdr.c} (50%) create mode 100644 src/os/src/windows64/w64PThread.c create mode 100644 src/os/src/windows64/w64Socket.c create mode 100644 src/os/src/windows64/w64String.c rename src/os/src/windows64/{twinstrptime.c => w64Strptime.c} (100%) create mode 100644 src/os/src/windows64/w64Sysinfo.c rename src/os/src/windows64/{twintime.c => w64Time.c} (100%) rename src/os/src/windows64/{twintimer.c => w64Timer.c} (93%) create mode 100644 src/os/src/windows64/w64Util.c rename src/os/src/windows64/{twintcpserver.c => w64Wordexp.c} (55%) diff --git a/src/client/src/tscSubquery.c b/src/client/src/tscSubquery.c index 15e02799aa..79c45daa20 100644 --- a/src/client/src/tscSubquery.c +++ b/src/client/src/tscSubquery.c @@ -183,7 +183,7 @@ SJoinSupporter* tscCreateJoinSupporter(SSqlObj* pSql, SSubqueryState* pState, in pSupporter->uid = pTableMetaInfo->pTableMeta->id.uid; assert (pSupporter->uid != 0); - getTmpfilePath("join-", pSupporter->path); + taosGetTmpfilePath("join-", pSupporter->path); pSupporter->f = fopen(pSupporter->path, "w"); // todo handle error @@ -773,7 +773,7 @@ static void tsCompRetrieveCallback(void* param, TAOS_RES* tres, int32_t numOfRow // continue to retrieve ts-comp data from vnode if (!pRes->completed) { - getTmpfilePath("ts-join", pSupporter->path); + taosGetTmpfilePath("ts-join", pSupporter->path); pSupporter->f = fopen(pSupporter->path, "w"); pRes->row = pRes->numOfRows; @@ -797,7 +797,7 @@ static void tsCompRetrieveCallback(void* param, TAOS_RES* tres, int32_t numOfRow tscResetForNextRetrieve(&pSql->res); assert(pSupporter->f == NULL); - getTmpfilePath("ts-join", pSupporter->path); + taosGetTmpfilePath("ts-join", pSupporter->path); // TODO check for failure pSupporter->f = fopen(pSupporter->path, "w"); diff --git a/src/os/inc/osSpec.h b/src/os/inc/osSpec.h index 18dd8b75d8..f0223c3ac5 100644 --- a/src/os/inc/osSpec.h +++ b/src/os/inc/osSpec.h @@ -318,7 +318,7 @@ void taosRandStr(char* str, int32_t size); uint32_t trand(void); // TAOS_OS_FUNC_FILE -void getTmpfilePath(const char *fileNamePrefix, char *dstPath); +void taosGetTmpfilePath(const char *fileNamePrefix, char *dstPath); int32_t taosFileRename(char *fullPath, char *suffix, char delimiter, char **dstPath); // USE_LIBICONV diff --git a/src/os/inc/osWindows64.h b/src/os/inc/osWindows64.h index b4687afb82..75685744aa 100644 --- a/src/os/inc/osWindows64.h +++ b/src/os/inc/osWindows64.h @@ -49,6 +49,68 @@ extern "C" { #endif #define TAOS_OS_FUNC_WCHAR +#define TAOS_OS_FUNC_FILE +#define TAOS_OS_FUNC_SLEEP +#define TAOS_OS_FUNC_TIMER +#define TAOS_OS_FUNC_SOCKET +#define TAOS_OS_FUNC_PTHREAD + +#define TAOS_OS_FUNC_FILEOP + #define taosFSendFile(outfile, infile, offset, count) taosFSendFileImp(outfile, infile, offset, size) + #define taosTSendFile(dfd, sfd, offset, size) taosTSendFileImp(dfd, sfd, offset, size) + +#define TAOS_OS_FUNC_LZ4 + int32_t BUILDIN_CLZL(uint64_t val); + int32_t BUILDIN_CLZ(uint32_t val); + int32_t BUILDIN_CTZL(uint64_t val); + int32_t BUILDIN_CTZ(uint32_t val); + +#define TAOS_OS_FUNC_UTIL + #ifdef _TD_GO_DLL_ + int64_t tsosStr2int64(char *str); + uint64_t htonll(uint64_t val); + #else + #define tsosStr2int64 _atoi64 + #endif + +#define TAOS_OS_FUNC_MATH + #define SWAP(a, b, c) \ + do { \ + c __tmp = (c)(a); \ + (a) = (c)(b); \ + (b) = __tmp; \ + } while (0) + + #define MAX(a,b) (((a)>(b))?(a):(b)) + #define MIN(a,b) (((a)<(b))?(a):(b)) + +#define TAOS_OS_FUNC_NETWORK + #define taosSend(sockfd, buf, len, flags) send(sockfd, buf, len, flags) + #define taosSendto(sockfd, buf, len, flags, dest_addr, addrlen) sendto(sockfd, buf, len, flags, dest_addr, addrlen) + #define taosWriteSocket(fd, buf, len) send(fd, buf, len, 0) + #define taosReadSocket(fd, buf, len) recv(fd, buf, len, 0) + #define taosCloseSocket(fd) closesocket(fd) + +#define TAOS_OS_DEF_TIME + #ifdef _TD_GO_DLL_ + #define MILLISECOND_PER_SECOND (1000LL) + #else + #define MILLISECOND_PER_SECOND (1000i64) + #endif + +typedef int (*__compar_fn_t)(const void *, const void *); +int getline(char **lineptr, size_t *n, FILE *stream); +int gettimeofday(struct timeval *tv, struct timezone *tz); +struct tm *localtime_r(const time_t *timep, struct tm *result); +char * strptime(const char *buf, const char *fmt, struct tm *tm); +char * strsep(char **stringp, const char *delim); +char * getpass(const char *prefix); +int flock(int fd, int option); +int fsync(int filedes); +char * strndup(const char *s, size_t n); + +#define strdup _strdup +#define ssize_t int // for function open in stat.h #define S_IRWXU _S_IREAD @@ -79,12 +141,6 @@ extern "C" { #define strncasecmp _strnicmp #define wcsncasecmp _wcsnicmp #define strtok_r strtok_s -#ifdef _TD_GO_DLL_ - int64_t tsosStr2int64(char *str); - uint64_t htonll(uint64_t val); -#else - #define tsosStr2int64 _atoi64 -#endif #define snprintf _snprintf #define in_addr_t unsigned long @@ -96,327 +152,212 @@ extern "C" { #define PATH_MAX 256 #endif -#define taosCloseSocket(fd) closesocket(fd) -#define taosWriteSocket(fd, buf, len) send(fd, buf, len, 0) -#define taosReadSocket(fd, buf, len) recv(fd, buf, len, 0) - -#if defined(_M_ARM) || defined(_M_ARM64) - -/* the '__iso_volatile' functions does not use a memory fence, so these - * definitions are incorrect, comment out as we don't support Windows on - * ARM at present. - -#define atomic_load_8(ptr) __iso_volatile_load8((const volatile __int8*)(ptr)) -#define atomic_load_16(ptr) __iso_volatile_load16((const volatile __int16*)(ptr)) -#define atomic_load_32(ptr) __iso_volatile_load32((const volatile __int32*)(ptr)) -#define atomic_load_64(ptr) __iso_volatile_load64((const volatile __int64*)(ptr)) - -#define atomic_store_8(ptr, val) __iso_volatile_store8((volatile __int8*)(ptr), (__int8)(val)) -#define atomic_store_16(ptr, val) __iso_volatile_store16((volatile __int16*)(ptr), (__int16)(val)) -#define atomic_store_32(ptr, val) __iso_volatile_store32((volatile __int32*)(ptr), (__int32)(val)) -#define atomic_store_64(ptr, val) __iso_volatile_store64((volatile __int64*)(ptr), (__int64)(val)) - -#ifdef _M_ARM64 -#define atomic_load_ptr atomic_load_64 -#define atomic_store_ptr atomic_store_64 -#else -#define atomic_load_ptr atomic_load_32 -#define atomic_store_ptr atomic_store_32 -#endif -*/ -#else - -#define atomic_load_8(ptr) (*(char volatile*)(ptr)) -#define atomic_load_16(ptr) (*(short volatile*)(ptr)) -#define atomic_load_32(ptr) (*(long volatile*)(ptr)) -#define atomic_load_64(ptr) (*(__int64 volatile*)(ptr)) -#define atomic_load_ptr(ptr) (*(void* volatile*)(ptr)) - -#define atomic_store_8(ptr, val) ((*(char volatile*)(ptr)) = (char)(val)) -#define atomic_store_16(ptr, val) ((*(short volatile*)(ptr)) = (short)(val)) -#define atomic_store_32(ptr, val) ((*(long volatile*)(ptr)) = (long)(val)) -#define atomic_store_64(ptr, val) ((*(__int64 volatile*)(ptr)) = (__int64)(val)) -#define atomic_store_ptr(ptr, val) ((*(void* volatile*)(ptr)) = (void*)(val)) - -#endif - -#define atomic_exchange_8(ptr, val) _InterlockedExchange8((char volatile*)(ptr), (char)(val)) -#define atomic_exchange_16(ptr, val) _InterlockedExchange16((short volatile*)(ptr), (short)(val)) -#define atomic_exchange_32(ptr, val) _InterlockedExchange((long volatile*)(ptr), (long)(val)) -#define atomic_exchange_64(ptr, val) _InterlockedExchange64((__int64 volatile*)(ptr), (__int64)(val)) -#define atomic_exchange_ptr(ptr, val) _InterlockedExchangePointer((void* volatile*)(ptr), (void*)(val)) - -#ifdef _TD_GO_DLL_ - #define atomic_val_compare_exchange_8 __sync_val_compare_and_swap -#else - #define atomic_val_compare_exchange_8(ptr, oldval, newval) _InterlockedCompareExchange8((char volatile*)(ptr), (char)(newval), (char)(oldval)) -#endif - -#define atomic_val_compare_exchange_16(ptr, oldval, newval) _InterlockedCompareExchange16((short volatile*)(ptr), (short)(newval), (short)(oldval)) -#define atomic_val_compare_exchange_32(ptr, oldval, newval) _InterlockedCompareExchange((long volatile*)(ptr), (long)(newval), (long)(oldval)) -#define atomic_val_compare_exchange_64(ptr, oldval, newval) _InterlockedCompareExchange64((__int64 volatile*)(ptr), (__int64)(newval), (__int64)(oldval)) -#define atomic_val_compare_exchange_ptr(ptr, oldval, newval) _InterlockedCompareExchangePointer((void* volatile*)(ptr), (void*)(newval), (void*)(oldval)) - -char interlocked_add_fetch_8(char volatile *ptr, char val); -short interlocked_add_fetch_16(short volatile *ptr, short val); -long interlocked_add_fetch_32(long volatile *ptr, long val); -__int64 interlocked_add_fetch_64(__int64 volatile *ptr, __int64 val); - -#define atomic_add_fetch_8(ptr, val) interlocked_add_fetch_8((char volatile*)(ptr), (char)(val)) -#define atomic_add_fetch_16(ptr, val) interlocked_add_fetch_16((short volatile*)(ptr), (short)(val)) -#define atomic_add_fetch_32(ptr, val) interlocked_add_fetch_32((long volatile*)(ptr), (long)(val)) -#define atomic_add_fetch_64(ptr, val) interlocked_add_fetch_64((__int64 volatile*)(ptr), (__int64)(val)) -#ifdef _WIN64 - #define atomic_add_fetch_ptr atomic_add_fetch_64 -#else - #define atomic_add_fetch_ptr atomic_add_fetch_32 -#endif -#ifdef _TD_GO_DLL_ - #define atomic_fetch_add_8 __sync_fetch_and_ad - #define atomic_fetch_add_16 __sync_fetch_and_add -#else - #define atomic_fetch_add_8(ptr, val) _InterlockedExchangeAdd8((char volatile*)(ptr), (char)(val)) - #define atomic_fetch_add_16(ptr, val) _InterlockedExchangeAdd16((short volatile*)(ptr), (short)(val)) -#endif - -#define atomic_fetch_add_32(ptr, val) _InterlockedExchangeAdd((long volatile*)(ptr), (long)(val)) -#define atomic_fetch_add_64(ptr, val) _InterlockedExchangeAdd64((__int64 volatile*)(ptr), (__int64)(val)) -#ifdef _WIN64 - #define atomic_fetch_add_ptr atomic_fetch_add_64 -#else - #define atomic_fetch_add_ptr atomic_fetch_add_32 -#endif - -#define atomic_sub_fetch_8(ptr, val) interlocked_add_fetch_8((char volatile*)(ptr), -(char)(val)) -#define atomic_sub_fetch_16(ptr, val) interlocked_add_fetch_16((short volatile*)(ptr), -(short)(val)) -#define atomic_sub_fetch_32(ptr, val) interlocked_add_fetch_32((long volatile*)(ptr), -(long)(val)) -#define atomic_sub_fetch_64(ptr, val) interlocked_add_fetch_64((__int64 volatile*)(ptr), -(__int64)(val)) -#ifdef _WIN64 - #define atomic_sub_fetch_ptr atomic_sub_fetch_64 -#else - #define atomic_sub_fetch_ptr atomic_sub_fetch_32 -#endif - -#define atomic_fetch_sub_8(ptr, val) _InterlockedExchangeAdd8((char volatile*)(ptr), -(char)(val)) -#define atomic_fetch_sub_16(ptr, val) _InterlockedExchangeAdd16((short volatile*)(ptr), -(short)(val)) -#define atomic_fetch_sub_32(ptr, val) _InterlockedExchangeAdd((long volatile*)(ptr), -(long)(val)) -#define atomic_fetch_sub_64(ptr, val) _InterlockedExchangeAdd64((__int64 volatile*)(ptr), -(__int64)(val)) -#ifdef _WIN64 - #define atomic_fetch_sub_ptr atomic_fetch_sub_64 -#else - #define atomic_fetch_sub_ptr atomic_fetch_sub_32 -#endif -#ifndef _TD_GO_DLL_ - char interlocked_and_fetch_8(char volatile* ptr, char val); - short interlocked_and_fetch_16(short volatile* ptr, short val); -#endif -long interlocked_and_fetch_32(long volatile* ptr, long val); -__int64 interlocked_and_fetch_64(__int64 volatile* ptr, __int64 val); - -#ifndef _TD_GO_DLL_ - #define atomic_and_fetch_8(ptr, val) interlocked_and_fetch_8((char volatile*)(ptr), (char)(val)) - #define atomic_and_fetch_16(ptr, val) interlocked_and_fetch_16((short volatile*)(ptr), (short)(val)) -#endif -#define atomic_and_fetch_32(ptr, val) interlocked_and_fetch_32((long volatile*)(ptr), (long)(val)) -#define atomic_and_fetch_64(ptr, val) interlocked_and_fetch_64((__int64 volatile*)(ptr), (__int64)(val)) -#ifdef _WIN64 - #define atomic_and_fetch_ptr atomic_and_fetch_64 -#else - #define atomic_and_fetch_ptr atomic_and_fetch_32 -#endif -#ifndef _TD_GO_DLL_ - #define atomic_fetch_and_8(ptr, val) _InterlockedAnd8((char volatile*)(ptr), (char)(val)) - #define atomic_fetch_and_16(ptr, val) _InterlockedAnd16((short volatile*)(ptr), (short)(val)) -#endif -#define atomic_fetch_and_32(ptr, val) _InterlockedAnd((long volatile*)(ptr), (long)(val)) - -#ifdef _M_IX86 - __int64 interlocked_fetch_and_64(__int64 volatile* ptr, __int64 val); - #define atomic_fetch_and_64(ptr, val) interlocked_fetch_and_64((__int64 volatile*)(ptr), (__int64)(val)) -#else - #define atomic_fetch_and_64(ptr, val) _InterlockedAnd64((__int64 volatile*)(ptr), (__int64)(val)) -#endif - -#ifdef _WIN64 - #define atomic_fetch_and_ptr atomic_fetch_and_64 -#else - #define atomic_fetch_and_ptr atomic_fetch_and_32 -#endif -#ifndef _TD_GO_DLL_ - char interlocked_or_fetch_8(char volatile* ptr, char val); - short interlocked_or_fetch_16(short volatile* ptr, short val); -#endif -long interlocked_or_fetch_32(long volatile* ptr, long val); -__int64 interlocked_or_fetch_64(__int64 volatile* ptr, __int64 val); - -#ifndef _TD_GO_DLL_ - #define atomic_or_fetch_8(ptr, val) interlocked_or_fetch_8((char volatile*)(ptr), (char)(val)) - #define atomic_or_fetch_16(ptr, val) interlocked_or_fetch_16((short volatile*)(ptr), (short)(val)) -#endif -#define atomic_or_fetch_32(ptr, val) interlocked_or_fetch_32((long volatile*)(ptr), (long)(val)) -#define atomic_or_fetch_64(ptr, val) interlocked_or_fetch_64((__int64 volatile*)(ptr), (__int64)(val)) -#ifdef _WIN64 - #define atomic_or_fetch_ptr atomic_or_fetch_64 -#else - #define atomic_or_fetch_ptr atomic_or_fetch_32 -#endif -#ifndef _TD_GO_DLL_ - #define atomic_fetch_or_8(ptr, val) _InterlockedOr8((char volatile*)(ptr), (char)(val)) - #define atomic_fetch_or_16(ptr, val) _InterlockedOr16((short volatile*)(ptr), (short)(val)) -#endif -#define atomic_fetch_or_32(ptr, val) _InterlockedOr((long volatile*)(ptr), (long)(val)) - -#ifdef _M_IX86 - __int64 interlocked_fetch_or_64(__int64 volatile* ptr, __int64 val); - #define atomic_fetch_or_64(ptr, val) interlocked_fetch_or_64((__int64 volatile*)(ptr), (__int64)(val)) -#else - #define atomic_fetch_or_64(ptr, val) _InterlockedOr64((__int64 volatile*)(ptr), (__int64)(val)) -#endif - -#ifdef _WIN64 - #define atomic_fetch_or_ptr atomic_fetch_or_64 -#else - #define atomic_fetch_or_ptr atomic_fetch_or_32 -#endif - -#ifndef _TD_GO_DLL_ - char interlocked_xor_fetch_8(char volatile* ptr, char val); - short interlocked_xor_fetch_16(short volatile* ptr, short val); -#endif -long interlocked_xor_fetch_32(long volatile* ptr, long val); -__int64 interlocked_xor_fetch_64(__int64 volatile* ptr, __int64 val); - -#ifndef _TD_GO_DLL_ - #define atomic_xor_fetch_8(ptr, val) interlocked_xor_fetch_8((char volatile*)(ptr), (char)(val)) - #define atomic_xor_fetch_16(ptr, val) interlocked_xor_fetch_16((short volatile*)(ptr), (short)(val)) -#endif -#define atomic_xor_fetch_32(ptr, val) interlocked_xor_fetch_32((long volatile*)(ptr), (long)(val)) -#define atomic_xor_fetch_64(ptr, val) interlocked_xor_fetch_64((__int64 volatile*)(ptr), (__int64)(val)) -#ifdef _WIN64 - #define atomic_xor_fetch_ptr atomic_xor_fetch_64 -#else - #define atomic_xor_fetch_ptr atomic_xor_fetch_32 -#endif - -#ifndef _TD_GO_DLL_ - #define atomic_fetch_xor_8(ptr, val) _InterlockedXor8((char volatile*)(ptr), (char)(val)) - #define atomic_fetch_xor_16(ptr, val) _InterlockedXor16((short volatile*)(ptr), (short)(val)) -#endif -#define atomic_fetch_xor_32(ptr, val) _InterlockedXor((long volatile*)(ptr), (long)(val)) - -#ifdef _M_IX86 - __int64 interlocked_fetch_xor_64(__int64 volatile* ptr, __int64 val); - #define atomic_fetch_xor_64(ptr, val) interlocked_fetch_xor_64((__int64 volatile*)(ptr), (__int64)(val)) -#else - #define atomic_fetch_xor_64(ptr, val) _InterlockedXor64((__int64 volatile*)(ptr), (__int64)(val)) -#endif - -#ifdef _WIN64 - #define atomic_fetch_xor_ptr atomic_fetch_xor_64 -#else - #define atomic_fetch_xor_ptr atomic_fetch_xor_32 -#endif - -#define SWAP(a, b, c) \ - do { \ - c __tmp = (c)(a); \ - (a) = (c)(b); \ - (b) = __tmp; \ - } while (0) - -#define MAX(a,b) (((a)>(b))?(a):(b)) -#define MIN(a,b) (((a)<(b))?(a):(b)) - -#ifdef _TD_GO_DLL_ - #define MILLISECOND_PER_SECOND (1000LL) -#else - #define MILLISECOND_PER_SECOND (1000i64) -#endif - -#define tsem_t sem_t -#define tsem_init sem_init -#define tsem_wait sem_wait -#define tsem_post sem_post -#define tsem_destroy sem_destroy - -void osInit(); - -int getline(char **lineptr, size_t *n, FILE *stream); - -int taosWinSetTimer(int ms, void(*callback)(int)); - -int gettimeofday(struct timeval *tv, struct timezone *tz); - -struct tm *localtime_r(const time_t *timep, struct tm *result); - -char *strptime(const char *buf, const char *fmt, struct tm *tm); - -bool taosCheckPthreadValid(pthread_t thread); - -void taosResetPthread(pthread_t *thread); - -int64_t taosGetPthreadId(); - -int taosSetNonblocking(int sock, int on); - -int taosSetSockOpt(int socketfd, int level, int optname, void *optval, int optlen); - - -void taosPrintOsInfo(); - -void taosGetSystemInfo(); - -void taosKillSystem(); - -int32_t BUILDIN_CLZL(uint64_t val); -int32_t BUILDIN_CLZ(uint32_t val); -int32_t BUILDIN_CTZL(uint64_t val); -int32_t BUILDIN_CTZ(uint32_t val); - //for signal, not dispose #define SIGALRM 1234 typedef int sigset_t; - struct sigaction { void (*sa_handler)(int); }; - -typedef struct { - int we_wordc; - char **we_wordv; - int we_offs; - char wordPos[20]; -} wordexp_t; - -int wordexp(const char *words, wordexp_t *pwordexp, int flags); - -void wordfree(wordexp_t *pwordexp); - -int flock(int fd, int option); - -int fsync(int filedes); - -char *getpass(const char *prefix); - -char *strsep(char **stringp, const char *delim); - -typedef int(*__compar_fn_t)(const void *, const void *); - int sigaction(int, struct sigaction *, void *); -void sleep(int mseconds); +typedef struct { + int we_wordc; + char **we_wordv; + int we_offs; + char wordPos[20]; +} wordexp_t; +int wordexp(const char *words, wordexp_t *pwordexp, int flags); +void wordfree(wordexp_t *pwordexp); -bool taosSkipSocketCheck(); +#define TAOS_OS_FUNC_ATOMIC + #define atomic_load_8(ptr) (*(char volatile*)(ptr)) + #define atomic_load_16(ptr) (*(short volatile*)(ptr)) + #define atomic_load_32(ptr) (*(long volatile*)(ptr)) + #define atomic_load_64(ptr) (*(__int64 volatile*)(ptr)) + #define atomic_load_ptr(ptr) (*(void* volatile*)(ptr)) -int fsendfile(FILE* out_file, FILE* in_file, int64_t* offset, int32_t count); + #define atomic_store_8(ptr, val) ((*(char volatile*)(ptr)) = (char)(val)) + #define atomic_store_16(ptr, val) ((*(short volatile*)(ptr)) = (short)(val)) + #define atomic_store_32(ptr, val) ((*(long volatile*)(ptr)) = (long)(val)) + #define atomic_store_64(ptr, val) ((*(__int64 volatile*)(ptr)) = (__int64)(val)) + #define atomic_store_ptr(ptr, val) ((*(void* volatile*)(ptr)) = (void*)(val)) -#define ssize_t int + #define atomic_exchange_8(ptr, val) _InterlockedExchange8((char volatile*)(ptr), (char)(val)) + #define atomic_exchange_16(ptr, val) _InterlockedExchange16((short volatile*)(ptr), (short)(val)) + #define atomic_exchange_32(ptr, val) _InterlockedExchange((long volatile*)(ptr), (long)(val)) + #define atomic_exchange_64(ptr, val) _InterlockedExchange64((__int64 volatile*)(ptr), (__int64)(val)) + #define atomic_exchange_ptr(ptr, val) _InterlockedExchangePointer((void* volatile*)(ptr), (void*)(val)) -#define strdup _strdup + #ifdef _TD_GO_DLL_ + #define atomic_val_compare_exchange_8 __sync_val_compare_and_swap + #else + #define atomic_val_compare_exchange_8(ptr, oldval, newval) _InterlockedCompareExchange8((char volatile*)(ptr), (char)(newval), (char)(oldval)) + #endif + #define atomic_val_compare_exchange_16(ptr, oldval, newval) _InterlockedCompareExchange16((short volatile*)(ptr), (short)(newval), (short)(oldval)) + #define atomic_val_compare_exchange_32(ptr, oldval, newval) _InterlockedCompareExchange((long volatile*)(ptr), (long)(newval), (long)(oldval)) + #define atomic_val_compare_exchange_64(ptr, oldval, newval) _InterlockedCompareExchange64((__int64 volatile*)(ptr), (__int64)(newval), (__int64)(oldval)) + #define atomic_val_compare_exchange_ptr(ptr, oldval, newval) _InterlockedCompareExchangePointer((void* volatile*)(ptr), (void*)(newval), (void*)(oldval)) -char *strndup(const char *s, size_t n); + char interlocked_add_fetch_8(char volatile *ptr, char val); + short interlocked_add_fetch_16(short volatile *ptr, short val); + long interlocked_add_fetch_32(long volatile *ptr, long val); + __int64 interlocked_add_fetch_64(__int64 volatile *ptr, __int64 val); -void taosSetCoreDump(); + #define atomic_add_fetch_8(ptr, val) interlocked_add_fetch_8((char volatile*)(ptr), (char)(val)) + #define atomic_add_fetch_16(ptr, val) interlocked_add_fetch_16((short volatile*)(ptr), (short)(val)) + #define atomic_add_fetch_32(ptr, val) interlocked_add_fetch_32((long volatile*)(ptr), (long)(val)) + #define atomic_add_fetch_64(ptr, val) interlocked_add_fetch_64((__int64 volatile*)(ptr), (__int64)(val)) + #ifdef _WIN64 + #define atomic_add_fetch_ptr atomic_add_fetch_64 + #else + #define atomic_add_fetch_ptr atomic_add_fetch_32 + #endif + + #ifdef _TD_GO_DLL_ + #define atomic_fetch_add_8 __sync_fetch_and_ad + #define atomic_fetch_add_16 __sync_fetch_and_add + #else + #define atomic_fetch_add_8(ptr, val) _InterlockedExchangeAdd8((char volatile*)(ptr), (char)(val)) + #define atomic_fetch_add_16(ptr, val) _InterlockedExchangeAdd16((short volatile*)(ptr), (short)(val)) + #endif + #define atomic_fetch_add_32(ptr, val) _InterlockedExchangeAdd((long volatile*)(ptr), (long)(val)) + #define atomic_fetch_add_64(ptr, val) _InterlockedExchangeAdd64((__int64 volatile*)(ptr), (__int64)(val)) + #ifdef _WIN64 + #define atomic_fetch_add_ptr atomic_fetch_add_64 + #else + #define atomic_fetch_add_ptr atomic_fetch_add_32 + #endif + + #define atomic_sub_fetch_8(ptr, val) interlocked_add_fetch_8((char volatile*)(ptr), -(char)(val)) + #define atomic_sub_fetch_16(ptr, val) interlocked_add_fetch_16((short volatile*)(ptr), -(short)(val)) + #define atomic_sub_fetch_32(ptr, val) interlocked_add_fetch_32((long volatile*)(ptr), -(long)(val)) + #define atomic_sub_fetch_64(ptr, val) interlocked_add_fetch_64((__int64 volatile*)(ptr), -(__int64)(val)) + #ifdef _WIN64 + #define atomic_sub_fetch_ptr atomic_sub_fetch_64 + #else + #define atomic_sub_fetch_ptr atomic_sub_fetch_32 + #endif + + #define atomic_fetch_sub_8(ptr, val) _InterlockedExchangeAdd8((char volatile*)(ptr), -(char)(val)) + #define atomic_fetch_sub_16(ptr, val) _InterlockedExchangeAdd16((short volatile*)(ptr), -(short)(val)) + #define atomic_fetch_sub_32(ptr, val) _InterlockedExchangeAdd((long volatile*)(ptr), -(long)(val)) + #define atomic_fetch_sub_64(ptr, val) _InterlockedExchangeAdd64((__int64 volatile*)(ptr), -(__int64)(val)) + #ifdef _WIN64 + #define atomic_fetch_sub_ptr atomic_fetch_sub_64 + #else + #define atomic_fetch_sub_ptr atomic_fetch_sub_32 + #endif + + #ifndef _TD_GO_DLL_ + char interlocked_and_fetch_8(char volatile* ptr, char val); + short interlocked_and_fetch_16(short volatile* ptr, short val); + #endif + long interlocked_and_fetch_32(long volatile* ptr, long val); + __int64 interlocked_and_fetch_64(__int64 volatile* ptr, __int64 val); + + #ifndef _TD_GO_DLL_ + #define atomic_and_fetch_8(ptr, val) interlocked_and_fetch_8((char volatile*)(ptr), (char)(val)) + #define atomic_and_fetch_16(ptr, val) interlocked_and_fetch_16((short volatile*)(ptr), (short)(val)) + #endif + #define atomic_and_fetch_32(ptr, val) interlocked_and_fetch_32((long volatile*)(ptr), (long)(val)) + #define atomic_and_fetch_64(ptr, val) interlocked_and_fetch_64((__int64 volatile*)(ptr), (__int64)(val)) + #ifdef _WIN64 + #define atomic_and_fetch_ptr atomic_and_fetch_64 + #else + #define atomic_and_fetch_ptr atomic_and_fetch_32 + #endif + #ifndef _TD_GO_DLL_ + #define atomic_fetch_and_8(ptr, val) _InterlockedAnd8((char volatile*)(ptr), (char)(val)) + #define atomic_fetch_and_16(ptr, val) _InterlockedAnd16((short volatile*)(ptr), (short)(val)) + #endif + #define atomic_fetch_and_32(ptr, val) _InterlockedAnd((long volatile*)(ptr), (long)(val)) + + #ifdef _M_IX86 + __int64 interlocked_fetch_and_64(__int64 volatile* ptr, __int64 val); + #define atomic_fetch_and_64(ptr, val) interlocked_fetch_and_64((__int64 volatile*)(ptr), (__int64)(val)) + #else + #define atomic_fetch_and_64(ptr, val) _InterlockedAnd64((__int64 volatile*)(ptr), (__int64)(val)) + #endif + + #ifdef _WIN64 + #define atomic_fetch_and_ptr atomic_fetch_and_64 + #else + #define atomic_fetch_and_ptr atomic_fetch_and_32 + #endif + #ifndef _TD_GO_DLL_ + char interlocked_or_fetch_8(char volatile* ptr, char val); + short interlocked_or_fetch_16(short volatile* ptr, short val); + #endif + long interlocked_or_fetch_32(long volatile* ptr, long val); + __int64 interlocked_or_fetch_64(__int64 volatile* ptr, __int64 val); + + #ifndef _TD_GO_DLL_ + #define atomic_or_fetch_8(ptr, val) interlocked_or_fetch_8((char volatile*)(ptr), (char)(val)) + #define atomic_or_fetch_16(ptr, val) interlocked_or_fetch_16((short volatile*)(ptr), (short)(val)) + #endif + #define atomic_or_fetch_32(ptr, val) interlocked_or_fetch_32((long volatile*)(ptr), (long)(val)) + #define atomic_or_fetch_64(ptr, val) interlocked_or_fetch_64((__int64 volatile*)(ptr), (__int64)(val)) + #ifdef _WIN64 + #define atomic_or_fetch_ptr atomic_or_fetch_64 + #else + #define atomic_or_fetch_ptr atomic_or_fetch_32 + #endif + #ifndef _TD_GO_DLL_ + #define atomic_fetch_or_8(ptr, val) _InterlockedOr8((char volatile*)(ptr), (char)(val)) + #define atomic_fetch_or_16(ptr, val) _InterlockedOr16((short volatile*)(ptr), (short)(val)) + #endif + #define atomic_fetch_or_32(ptr, val) _InterlockedOr((long volatile*)(ptr), (long)(val)) + + #ifdef _M_IX86 + __int64 interlocked_fetch_or_64(__int64 volatile* ptr, __int64 val); + #define atomic_fetch_or_64(ptr, val) interlocked_fetch_or_64((__int64 volatile*)(ptr), (__int64)(val)) + #else + #define atomic_fetch_or_64(ptr, val) _InterlockedOr64((__int64 volatile*)(ptr), (__int64)(val)) + #endif + + #ifdef _WIN64 + #define atomic_fetch_or_ptr atomic_fetch_or_64 + #else + #define atomic_fetch_or_ptr atomic_fetch_or_32 + #endif + + #ifndef _TD_GO_DLL_ + char interlocked_xor_fetch_8(char volatile* ptr, char val); + short interlocked_xor_fetch_16(short volatile* ptr, short val); + #endif + long interlocked_xor_fetch_32(long volatile* ptr, long val); + __int64 interlocked_xor_fetch_64(__int64 volatile* ptr, __int64 val); + + #ifndef _TD_GO_DLL_ + #define atomic_xor_fetch_8(ptr, val) interlocked_xor_fetch_8((char volatile*)(ptr), (char)(val)) + #define atomic_xor_fetch_16(ptr, val) interlocked_xor_fetch_16((short volatile*)(ptr), (short)(val)) + #endif + #define atomic_xor_fetch_32(ptr, val) interlocked_xor_fetch_32((long volatile*)(ptr), (long)(val)) + #define atomic_xor_fetch_64(ptr, val) interlocked_xor_fetch_64((__int64 volatile*)(ptr), (__int64)(val)) + #ifdef _WIN64 + #define atomic_xor_fetch_ptr atomic_xor_fetch_64 + #else + #define atomic_xor_fetch_ptr atomic_xor_fetch_32 + #endif + + #ifndef _TD_GO_DLL_ + #define atomic_fetch_xor_8(ptr, val) _InterlockedXor8((char volatile*)(ptr), (char)(val)) + #define atomic_fetch_xor_16(ptr, val) _InterlockedXor16((short volatile*)(ptr), (short)(val)) + #endif + #define atomic_fetch_xor_32(ptr, val) _InterlockedXor((long volatile*)(ptr), (long)(val)) + + #ifdef _M_IX86 + __int64 interlocked_fetch_xor_64(__int64 volatile* ptr, __int64 val); + #define atomic_fetch_xor_64(ptr, val) interlocked_fetch_xor_64((__int64 volatile*)(ptr), (__int64)(val)) + #else + #define atomic_fetch_xor_64(ptr, val) _InterlockedXor64((__int64 volatile*)(ptr), (__int64)(val)) + #endif + + #ifdef _WIN64 + #define atomic_fetch_xor_ptr atomic_fetch_xor_64 + #else + #define atomic_fetch_xor_ptr atomic_fetch_xor_32 + #endif #ifdef __cplusplus } diff --git a/src/os/src/detail/osFile.c b/src/os/src/detail/osFile.c index 5502dfb4a6..7b5d5fbfcc 100644 --- a/src/os/src/detail/osFile.c +++ b/src/os/src/detail/osFile.c @@ -19,7 +19,7 @@ #ifndef TAOS_OS_FUNC_FILE -void getTmpfilePath(const char *fileNamePrefix, char *dstPath) { +void taosGetTmpfilePath(const char *fileNamePrefix, char *dstPath) { const char* tdengineTmpFileNamePrefix = "tdengine-"; char tmpPath[PATH_MAX]; @@ -37,6 +37,8 @@ void getTmpfilePath(const char *fileNamePrefix, char *dstPath) { snprintf(dstPath, PATH_MAX, tmpPath, getpid(), rand); } +#endif + // rename file name int32_t taosFileRename(char *fullPath, char *suffix, char delimiter, char **dstPath) { int32_t ts = taosGetTimestampSec(); @@ -64,5 +66,3 @@ int32_t taosFileRename(char *fullPath, char *suffix, char delimiter, char **dstP return rename(fullPath, *dstPath); } - -#endif \ No newline at end of file diff --git a/src/os/src/detail/osTimer.c b/src/os/src/detail/osTimer.c index 7c6346205a..bea5a718de 100644 --- a/src/os/src/detail/osTimer.c +++ b/src/os/src/detail/osTimer.c @@ -102,6 +102,7 @@ void taosUninitTimer() { #endif +#ifndef TAOS_OS_FUNC_SLEEP /* to make taosMsleep work, signal SIGALRM shall be blocked in the calling thread, @@ -128,4 +129,6 @@ void taosMsleep(int mseconds) { select(0, NULL, NULL, NULL, &timeout); /* pthread_sigmask(SIG_UNBLOCK, &set, NULL); */ -} \ No newline at end of file +} + +#endif \ No newline at end of file diff --git a/src/os/src/windows64/twindows.c b/src/os/src/windows64/twindows.c deleted file mode 100644 index 4284dcb14e..0000000000 --- a/src/os/src/windows64/twindows.c +++ /dev/null @@ -1,410 +0,0 @@ -/* - * Copyright (c) 2019 TAOS Data, Inc. - * - * This program is free software: you can use, redistribute, and/or modify - * it under the terms of the GNU Affero General Public License, version 3 - * or later ("AGPL"), as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#define _DEFAULT_SOURCE -#include "os.h" -#include "taosdef.h" -#include "tglobal.h" -#include "ttimer.h" -#include "tulog.h" -#include "tutil.h" - -bool taosCheckPthreadValid(pthread_t thread) { - return thread.p != NULL; -} - -void taosResetPthread(pthread_t *thread) { - thread->p = 0; -} - -int64_t taosGetPthreadId() { -#ifdef PTW32_VERSION - return pthread_getw32threadid_np(pthread_self()); -#else - return (int64_t)pthread_self(); -#endif -} - -int taosSetSockOpt(int socketfd, int level, int optname, void *optval, int optlen) { - if (level == SOL_SOCKET && optname == TCP_KEEPCNT) { - return 0; - } - - if (level == SOL_TCP && optname == TCP_KEEPIDLE) { - return 0; - } - - if (level == SOL_TCP && optname == TCP_KEEPINTVL) { - return 0; - } - - return setsockopt(socketfd, level, optname, optval, optlen); -} - -// add -char interlocked_add_fetch_8(char volatile* ptr, char val) { - #ifdef _TD_GO_DLL_ - return __sync_fetch_and_add(ptr, val) + val; - #else - return _InterlockedExchangeAdd8(ptr, val) + val; - #endif -} - -short interlocked_add_fetch_16(short volatile* ptr, short val) { - #ifdef _TD_GO_DLL_ - return __sync_fetch_and_add(ptr, val) + val; - #else - return _InterlockedExchangeAdd16(ptr, val) + val; - #endif -} - -long interlocked_add_fetch_32(long volatile* ptr, long val) { - return _InterlockedExchangeAdd(ptr, val) + val; -} - -__int64 interlocked_add_fetch_64(__int64 volatile* ptr, __int64 val) { - return _InterlockedExchangeAdd64(ptr, val) + val; -} - -// and -#ifndef _TD_GO_DLL_ -char interlocked_and_fetch_8(char volatile* ptr, char val) { - return _InterlockedAnd8(ptr, val) & val; -} - -short interlocked_and_fetch_16(short volatile* ptr, short val) { - return _InterlockedAnd16(ptr, val) & val; -} -#endif - -long interlocked_and_fetch_32(long volatile* ptr, long val) { - return _InterlockedAnd(ptr, val) & val; -} - -#ifndef _M_IX86 - -__int64 interlocked_and_fetch_64(__int64 volatile* ptr, __int64 val) { - return _InterlockedAnd64(ptr, val) & val; -} - -#else - -__int64 interlocked_and_fetch_64(__int64 volatile* ptr, __int64 val) { - __int64 old, res; - do { - old = *ptr; - res = old & val; - } while(_InterlockedCompareExchange64(ptr, res, old) != old); - return res; -} - -__int64 interlocked_fetch_and_64(__int64 volatile* ptr, __int64 val) { - __int64 old; - do { - old = *ptr; - } while(_InterlockedCompareExchange64(ptr, old & val, old) != old); - return old; -} - -#endif - -// or -#ifndef _TD_GO_DLL_ -char interlocked_or_fetch_8(char volatile* ptr, char val) { - return _InterlockedOr8(ptr, val) | val; -} - -short interlocked_or_fetch_16(short volatile* ptr, short val) { - return _InterlockedOr16(ptr, val) | val; -} -#endif -long interlocked_or_fetch_32(long volatile* ptr, long val) { - return _InterlockedOr(ptr, val) | val; -} - -#ifndef _M_IX86 - -__int64 interlocked_or_fetch_64(__int64 volatile* ptr, __int64 val) { - return _InterlockedOr64(ptr, val) & val; -} - -#else - -__int64 interlocked_or_fetch_64(__int64 volatile* ptr, __int64 val) { - __int64 old, res; - do { - old = *ptr; - res = old | val; - } while(_InterlockedCompareExchange64(ptr, res, old) != old); - return res; -} - -__int64 interlocked_fetch_or_64(__int64 volatile* ptr, __int64 val) { - __int64 old; - do { - old = *ptr; - } while(_InterlockedCompareExchange64(ptr, old | val, old) != old); - return old; -} - -#endif - -// xor -#ifndef _TD_GO_DLL_ -char interlocked_xor_fetch_8(char volatile* ptr, char val) { - return _InterlockedXor8(ptr, val) ^ val; -} - -short interlocked_xor_fetch_16(short volatile* ptr, short val) { - return _InterlockedXor16(ptr, val) ^ val; -} -#endif -long interlocked_xor_fetch_32(long volatile* ptr, long val) { - return _InterlockedXor(ptr, val) ^ val; -} - -#ifndef _M_IX86 - -__int64 interlocked_xor_fetch_64(__int64 volatile* ptr, __int64 val) { - return _InterlockedXor64(ptr, val) ^ val; -} - -#else - -__int64 interlocked_xor_fetch_64(__int64 volatile* ptr, __int64 val) { - __int64 old, res; - do { - old = *ptr; - res = old ^ val; - } while(_InterlockedCompareExchange64(ptr, res, old) != old); - return res; -} - -__int64 interlocked_fetch_xor_64(__int64 volatile* ptr, __int64 val) { - __int64 old; - do { - old = *ptr; - } while(_InterlockedCompareExchange64(ptr, old ^ val, old) != old); - return old; -} - -#endif - -void taosPrintOsInfo() {} - -void taosGetSystemTimezone() { - // get and set default timezone - SGlobalCfg *cfg_timezone = taosGetConfigOption("timezone"); - if (cfg_timezone && cfg_timezone->cfgStatus < TAOS_CFG_CSTATUS_DEFAULT) { - char *tz = getenv("TZ"); - if (tz == NULL || strlen(tz) == 0) { - strcpy(tsTimezone, "not configured"); - } - else { - strcpy(tsTimezone, tz); - } - cfg_timezone->cfgStatus = TAOS_CFG_CSTATUS_DEFAULT; - uInfo("timezone not configured, use default"); - } -} - -void taosGetSystemLocale() { - // get and set default locale - SGlobalCfg *cfg_locale = taosGetConfigOption("locale"); - if (cfg_locale && cfg_locale->cfgStatus < TAOS_CFG_CSTATUS_DEFAULT) { - char *locale = setlocale(LC_CTYPE, "chs"); - if (locale != NULL) { - tstrncpy(tsLocale, locale, sizeof(tsLocale)); - cfg_locale->cfgStatus = TAOS_CFG_CSTATUS_DEFAULT; - uInfo("locale not configured, set to default:%s", tsLocale); - } - } - - SGlobalCfg *cfg_charset = taosGetConfigOption("charset"); - if (cfg_charset && cfg_charset->cfgStatus < TAOS_CFG_CSTATUS_DEFAULT) { - strcpy(tsCharset, "cp936"); - cfg_charset->cfgStatus = TAOS_CFG_CSTATUS_DEFAULT; - uInfo("charset not configured, set to default:%s", tsCharset); - } -} - -void taosGetSystemInfo() { - taosGetSystemTimezone(); - taosGetSystemLocale(); -} - -void taosKillSystem() { - exit(0); -} - -/* - * Get next token from string *stringp, where tokens are possibly-empty - * strings separated by characters from delim. - * - * Writes NULs into the string at *stringp to end tokens. - * delim need not remain constant from call to call. - * On return, *stringp points past the last NUL written (if there might - * be further tokens), or is NULL (if there are definitely no moretokens). - * - * If *stringp is NULL, strsep returns NULL. - */ -char *strsep(char **stringp, const char *delim) { - char *s; - const char *spanp; - int c, sc; - char *tok; - if ((s = *stringp) == NULL) - return (NULL); - for (tok = s;;) { - c = *s++; - spanp = delim; - do { - if ((sc = *spanp++) == c) { - if (c == 0) - s = NULL; - else - s[-1] = 0; - *stringp = s; - return (tok); - } - } while (sc != 0); - } - /* NOTREACHED */ -} - -char *getpass(const char *prefix) { - static char passwd[TSDB_KEY_LEN] = {0}; - - printf("%s", prefix); - scanf("%s", passwd); - - char n = getchar(); - return passwd; -} - -int flock(int fd, int option) { - return 0; -} - -int fsync(int filedes) { - return 0; -} - -int sigaction(int sig, struct sigaction *d, void *p) { - return 0; -} - -int wordexp(const char *words, wordexp_t *pwordexp, int flags) { - pwordexp->we_offs = 0; - pwordexp->we_wordc = 1; - pwordexp->we_wordv = (char **)(pwordexp->wordPos); - pwordexp->we_wordv[0] = (char *)words; - return 0; -} - -void wordfree(wordexp_t *pwordexp) {} - -void taosGetDisk() {} - -bool taosSkipSocketCheck() { - return false; -} - -#define _SEND_FILE_STEP_ 1000 - -int fsendfile(FILE* out_file, FILE* in_file, int64_t* offset, int32_t count) { - fseek(in_file, (int32_t)(*offset), 0); - int writeLen = 0; - uint8_t buffer[_SEND_FILE_STEP_] = { 0 }; - - for (int len = 0; len < (count - _SEND_FILE_STEP_); len += _SEND_FILE_STEP_) { - size_t rlen = fread(buffer, 1, _SEND_FILE_STEP_, in_file); - if (rlen <= 0) { - return writeLen; - } - else if (rlen < _SEND_FILE_STEP_) { - fwrite(buffer, 1, rlen, out_file); - return (int)(writeLen + rlen); - } - else { - fwrite(buffer, 1, _SEND_FILE_STEP_, in_file); - writeLen += _SEND_FILE_STEP_; - } - } - - int remain = count - writeLen; - if (remain > 0) { - size_t rlen = fread(buffer, 1, remain, in_file); - if (rlen <= 0) { - return writeLen; - } - else { - fwrite(buffer, 1, remain, out_file); - writeLen += remain; - } - } - - return writeLen; -} - -int32_t BUILDIN_CLZL(uint64_t val) { - unsigned long r = 0; - _BitScanReverse64(&r, val); - return (int)(r >> 3); -} - -int32_t BUILDIN_CLZ(uint32_t val) { - unsigned long r = 0; - _BitScanReverse(&r, val); - return (int)(r >> 3); -} - -int32_t BUILDIN_CTZL(uint64_t val) { - unsigned long r = 0; - _BitScanForward64(&r, val); - return (int)(r >> 3); -} - -int32_t BUILDIN_CTZ(uint32_t val) { - unsigned long r = 0; - _BitScanForward(&r, val); - return (int)(r >> 3); -} - -char *strndup(const char *s, size_t n) { - int len = strlen(s); - if (len >= n) { - len = n; - } - - char *r = calloc(len + 1, 1); - memcpy(r, s, len); - r[len] = 0; - return r; -} - -void taosSetCoreDump() {} - -#ifdef _TD_GO_DLL_ -int64_t tsosStr2int64(char *str) { - char *endptr = NULL; - return strtoll(str, &endptr, 10); -} - -uint64_t htonll(uint64_t val) -{ - return (((uint64_t) htonl(val)) << 32) + htonl(val >> 32); -} -#endif \ No newline at end of file diff --git a/src/os/src/windows64/twinsocket.c b/src/os/src/windows64/twinsocket.c deleted file mode 100644 index 0690a4ceb1..0000000000 --- a/src/os/src/windows64/twinsocket.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2019 TAOS Data, Inc. - * - * This program is free software: you can use, redistribute, and/or modify - * it under the terms of the GNU Affero General Public License, version 3 - * or later ("AGPL"), as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include - -void taosWinSocketInit() { - static char flag = 0; - if (flag == 0) { - WORD wVersionRequested; - WSADATA wsaData; - wVersionRequested = MAKEWORD(1, 1); - if (WSAStartup(wVersionRequested, &wsaData) == 0) { - flag = 1; - } - } -} - -int taosSetNonblocking(SOCKET sock, int on) { - u_long mode; - if (on) { - mode = 1; - ioctlsocket(sock, FIONBIO, &mode); - } - else { - mode = 0; - ioctlsocket(sock, FIONBIO, &mode); - } - return 0; -} - -int taosGetPrivateIp(char *const ip) { - PIP_ADAPTER_ADDRESSES pAddresses = 0; - IP_ADAPTER_DNS_SERVER_ADDRESS *pDnServer = 0; - ULONG outBufLen = 0; - DWORD dwRetVal = 0; - char buff[100]; - DWORD bufflen = 100; - int i; - int flag = -1; - - taosWinSocketInit(); - GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAddresses, &outBufLen); - pAddresses = (IP_ADAPTER_ADDRESSES *)malloc(outBufLen); - if ((dwRetVal = GetAdaptersAddresses(AF_INET, GAA_FLAG_SKIP_ANYCAST, NULL, pAddresses, &outBufLen)) == NO_ERROR) { - while (pAddresses) { - if (wcsstr(pAddresses->FriendlyName, L"Loopback") != 0) { - pAddresses = pAddresses->Next; - continue; - } - if (pAddresses->OperStatus == IfOperStatusUp) { - //printf("%s, Status: active\n", pAddresses->FriendlyName); - } - else { - //printf("%s, Status: deactive\n", pAddresses->FriendlyName); - pAddresses = pAddresses->Next; - continue; - } - - PIP_ADAPTER_UNICAST_ADDRESS pUnicast = pAddresses->FirstUnicastAddress; - for (i = 0; pUnicast != NULL; i++) { - if (pUnicast->Address.lpSockaddr->sa_family == AF_INET) { - struct sockaddr_in *sa_in = (struct sockaddr_in *)pUnicast->Address.lpSockaddr; - strcpy(ip, inet_ntop(AF_INET, &(sa_in->sin_addr), buff, bufflen)); - flag = 0; - //printf("%s\n", ip); - } - else if (pUnicast->Address.lpSockaddr->sa_family == AF_INET6) { - struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)pUnicast->Address.lpSockaddr; - strcpy(ip, inet_ntop(AF_INET6, &(sa_in6->sin6_addr), buff, bufflen)); - flag = 0; - //printf("%s\n", ip); - } - else { - } - pUnicast = pUnicast->Next; - } - pAddresses = pAddresses->Next; - } - } - else { - LPVOID lpMsgBuf; - printf("Call to GetAdaptersAddresses failed.\n"); - if (FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - dwRetVal, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR) & lpMsgBuf, - 0, - NULL)) { - printf("\tError: %s", lpMsgBuf); - } - LocalFree(lpMsgBuf); - } - free(pAddresses); - return flag; -} diff --git a/src/os/src/windows64/twintcpclient.c b/src/os/src/windows64/twintcpclient.c deleted file mode 100644 index 4736042aba..0000000000 --- a/src/os/src/windows64/twintcpclient.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2019 TAOS Data, Inc. - * - * This program is free software: you can use, redistribute, and/or modify - * it under the terms of the GNU Affero General Public License, version 3 - * or later ("AGPL"), as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include "tulog.h" - -void *taosInitTcpClient(char *ip, uint16_t port, char *label, int num, void *fp, void *shandle) { - tError("InitTcpClient not support in windows"); - return 0; -} - -void taosCloseTcpClientConnection(void *chandle) { - tError("CloseTcpClientConnection not support in windows"); -} - -void *taosOpenTcpClientConnection(void *shandle, void *thandle, char *ip, uint16_t port) { - tError("OpenTcpClientConnection not support in windows"); - return 0; -} - -int taosSendTcpClientData(unsigned int ip, uint16_t port, char *data, int len, void *chandle) { - tError("SendTcpClientData not support in windows"); - return 0; -} - -void taosCleanUpTcpClient(void *chandle) { - tError("SendTcpClientData not support in windows"); -} diff --git a/src/os/src/windows64/w64Atomic.c b/src/os/src/windows64/w64Atomic.c new file mode 100644 index 0000000000..0425f4ed3f --- /dev/null +++ b/src/os/src/windows64/w64Atomic.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#define _DEFAULT_SOURCE +#include "os.h" +#include "taosdef.h" +#include "tglobal.h" +#include "ttimer.h" +#include "tulog.h" +#include "tutil.h" + +// add +char interlocked_add_fetch_8(char volatile* ptr, char val) { + #ifdef _TD_GO_DLL_ + return __sync_fetch_and_add(ptr, val) + val; + #else + return _InterlockedExchangeAdd8(ptr, val) + val; + #endif +} + +short interlocked_add_fetch_16(short volatile* ptr, short val) { + #ifdef _TD_GO_DLL_ + return __sync_fetch_and_add(ptr, val) + val; + #else + return _InterlockedExchangeAdd16(ptr, val) + val; + #endif +} + +long interlocked_add_fetch_32(long volatile* ptr, long val) { + return _InterlockedExchangeAdd(ptr, val) + val; +} + +__int64 interlocked_add_fetch_64(__int64 volatile* ptr, __int64 val) { + return _InterlockedExchangeAdd64(ptr, val) + val; +} + +// and +#ifndef _TD_GO_DLL_ +char interlocked_and_fetch_8(char volatile* ptr, char val) { + return _InterlockedAnd8(ptr, val) & val; +} + +short interlocked_and_fetch_16(short volatile* ptr, short val) { + return _InterlockedAnd16(ptr, val) & val; +} +#endif + +long interlocked_and_fetch_32(long volatile* ptr, long val) { + return _InterlockedAnd(ptr, val) & val; +} + +#ifndef _M_IX86 + +__int64 interlocked_and_fetch_64(__int64 volatile* ptr, __int64 val) { + return _InterlockedAnd64(ptr, val) & val; +} + +#else + +__int64 interlocked_and_fetch_64(__int64 volatile* ptr, __int64 val) { + __int64 old, res; + do { + old = *ptr; + res = old & val; + } while(_InterlockedCompareExchange64(ptr, res, old) != old); + return res; +} + +__int64 interlocked_fetch_and_64(__int64 volatile* ptr, __int64 val) { + __int64 old; + do { + old = *ptr; + } while(_InterlockedCompareExchange64(ptr, old & val, old) != old); + return old; +} + +#endif + +// or +#ifndef _TD_GO_DLL_ +char interlocked_or_fetch_8(char volatile* ptr, char val) { + return _InterlockedOr8(ptr, val) | val; +} + +short interlocked_or_fetch_16(short volatile* ptr, short val) { + return _InterlockedOr16(ptr, val) | val; +} +#endif +long interlocked_or_fetch_32(long volatile* ptr, long val) { + return _InterlockedOr(ptr, val) | val; +} + +#ifndef _M_IX86 + +__int64 interlocked_or_fetch_64(__int64 volatile* ptr, __int64 val) { + return _InterlockedOr64(ptr, val) & val; +} + +#else + +__int64 interlocked_or_fetch_64(__int64 volatile* ptr, __int64 val) { + __int64 old, res; + do { + old = *ptr; + res = old | val; + } while(_InterlockedCompareExchange64(ptr, res, old) != old); + return res; +} + +__int64 interlocked_fetch_or_64(__int64 volatile* ptr, __int64 val) { + __int64 old; + do { + old = *ptr; + } while(_InterlockedCompareExchange64(ptr, old | val, old) != old); + return old; +} + +#endif + +// xor +#ifndef _TD_GO_DLL_ +char interlocked_xor_fetch_8(char volatile* ptr, char val) { + return _InterlockedXor8(ptr, val) ^ val; +} + +short interlocked_xor_fetch_16(short volatile* ptr, short val) { + return _InterlockedXor16(ptr, val) ^ val; +} +#endif +long interlocked_xor_fetch_32(long volatile* ptr, long val) { + return _InterlockedXor(ptr, val) ^ val; +} + +#ifndef _M_IX86 + +__int64 interlocked_xor_fetch_64(__int64 volatile* ptr, __int64 val) { + return _InterlockedXor64(ptr, val) ^ val; +} + +#else + +__int64 interlocked_xor_fetch_64(__int64 volatile* ptr, __int64 val) { + __int64 old, res; + do { + old = *ptr; + res = old ^ val; + } while(_InterlockedCompareExchange64(ptr, res, old) != old); + return res; +} + +__int64 interlocked_fetch_xor_64(__int64 volatile* ptr, __int64 val) { + __int64 old; + do { + old = *ptr; + } while(_InterlockedCompareExchange64(ptr, old ^ val, old) != old); + return old; +} + +#endif + diff --git a/src/os/src/windows64/w64Coredump.c b/src/os/src/windows64/w64Coredump.c new file mode 100644 index 0000000000..95490e7ad0 --- /dev/null +++ b/src/os/src/windows64/w64Coredump.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#define _DEFAULT_SOURCE +#include "os.h" +#include "tconfig.h" +#include "tglobal.h" +#include "tulog.h" +#include "tsystem.h" + +void taosSetCoreDump() {} \ No newline at end of file diff --git a/src/os/src/windows64/twinenv.c b/src/os/src/windows64/w64Env.c similarity index 100% rename from src/os/src/windows64/twinenv.c rename to src/os/src/windows64/w64Env.c diff --git a/src/os/src/windows64/w64File.c b/src/os/src/windows64/w64File.c index 140277f990..5cfcc8f79c 100644 --- a/src/os/src/windows64/w64File.c +++ b/src/os/src/windows64/w64File.c @@ -16,7 +16,7 @@ #define _DEFAULT_SOURCE #include "os.h" -void getTmpfilePath(const char *fileNamePrefix, char *dstPath) { +void taosGetTmpfilePath(const char *fileNamePrefix, char *dstPath) { const char* tdengineTmpFileNamePrefix = "tdengine-"; char tmpPath[PATH_MAX]; diff --git a/src/os/src/windows64/w64FileOp.c b/src/os/src/windows64/w64FileOp.c new file mode 100644 index 0000000000..54f7938dde --- /dev/null +++ b/src/os/src/windows64/w64FileOp.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#define _DEFAULT_SOURCE +#include "os.h" +#include "taosdef.h" +#include "tglobal.h" +#include "ttimer.h" +#include "tulog.h" +#include "tutil.h" + +#define _SEND_FILE_STEP_ 1000 + +int taosTSendFileImp(FILE* out_file, FILE* in_file, int64_t* offset, int32_t count) { + fseek(in_file, (int32_t)(*offset), 0); + int writeLen = 0; + uint8_t buffer[_SEND_FILE_STEP_] = { 0 }; + + for (int len = 0; len < (count - _SEND_FILE_STEP_); len += _SEND_FILE_STEP_) { + size_t rlen = fread(buffer, 1, _SEND_FILE_STEP_, in_file); + if (rlen <= 0) { + return writeLen; + } + else if (rlen < _SEND_FILE_STEP_) { + fwrite(buffer, 1, rlen, out_file); + return (int)(writeLen + rlen); + } + else { + fwrite(buffer, 1, _SEND_FILE_STEP_, in_file); + writeLen += _SEND_FILE_STEP_; + } + } + + int remain = count - writeLen; + if (remain > 0) { + size_t rlen = fread(buffer, 1, remain, in_file); + if (rlen <= 0) { + return writeLen; + } + else { + fwrite(buffer, 1, remain, out_file); + writeLen += remain; + } + } + + return writeLen; +} diff --git a/src/os/src/windows64/twingetline.c b/src/os/src/windows64/w64Getline.c similarity index 100% rename from src/os/src/windows64/twingetline.c rename to src/os/src/windows64/w64Getline.c diff --git a/src/os/src/windows64/w64Godll.c b/src/os/src/windows64/w64Godll.c new file mode 100644 index 0000000000..b0267c4aac --- /dev/null +++ b/src/os/src/windows64/w64Godll.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#define _DEFAULT_SOURCE +#include "os.h" +#include "taosdef.h" +#include "tglobal.h" +#include "ttimer.h" +#include "tulog.h" +#include "tutil.h" + +#ifdef _TD_GO_DLL_ +int64_t tsosStr2int64(char *str) { + char *endptr = NULL; + return strtoll(str, &endptr, 10); +} + +uint64_t htonll(uint64_t val) +{ + return (((uint64_t) htonl(val)) << 32) + htonl(val >> 32); +} +#endif \ No newline at end of file diff --git a/src/os/src/windows64/w64Lz4.c b/src/os/src/windows64/w64Lz4.c new file mode 100644 index 0000000000..96556c1f1c --- /dev/null +++ b/src/os/src/windows64/w64Lz4.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#define _DEFAULT_SOURCE +#include "os.h" +#include "taosdef.h" +#include "tglobal.h" +#include "ttimer.h" +#include "tulog.h" +#include "tutil.h" + +int32_t BUILDIN_CLZL(uint64_t val) { + unsigned long r = 0; + _BitScanReverse64(&r, val); + return (int)(r >> 3); +} + +int32_t BUILDIN_CLZ(uint32_t val) { + unsigned long r = 0; + _BitScanReverse(&r, val); + return (int)(r >> 3); +} + +int32_t BUILDIN_CTZL(uint64_t val) { + unsigned long r = 0; + _BitScanForward64(&r, val); + return (int)(r >> 3); +} + +int32_t BUILDIN_CTZ(uint32_t val) { + unsigned long r = 0; + _BitScanForward(&r, val); + return (int)(r >> 3); +} diff --git a/src/os/src/windows64/twinmsghdr.c b/src/os/src/windows64/w64Msghdr.c similarity index 50% rename from src/os/src/windows64/twinmsghdr.c rename to src/os/src/windows64/w64Msghdr.c index 9f35d3ec62..9d1924f311 100644 --- a/src/os/src/windows64/twinmsghdr.c +++ b/src/os/src/windows64/w64Msghdr.c @@ -16,42 +16,41 @@ #include void taosFreeMsgHdr(void *hdr) { - WSAMSG *msgHdr = (WSAMSG *)hdr; - free(msgHdr->lpBuffers); + WSAMSG *msgHdr = (WSAMSG *)hdr; + free(msgHdr->lpBuffers); } int taosMsgHdrSize(void *hdr) { - WSAMSG *msgHdr = (WSAMSG *)hdr; - return msgHdr->dwBufferCount; + WSAMSG *msgHdr = (WSAMSG *)hdr; + return msgHdr->dwBufferCount; } void taosSendMsgHdr(void *hdr, int fd) { - WSAMSG *msgHdr = (WSAMSG *)hdr; - DWORD len; + WSAMSG *msgHdr = (WSAMSG *)hdr; + DWORD len; - WSASendMsg(fd, msgHdr, 0, &len, 0, 0); - msgHdr->dwBufferCount = 0; + WSASendMsg(fd, msgHdr, 0, &len, 0, 0); + msgHdr->dwBufferCount = 0; } void taosInitMsgHdr(void **hdr, void *dest, int maxPkts) { - WSAMSG *msgHdr = (WSAMSG *)malloc(sizeof(WSAMSG)); - memset(msgHdr, 0, sizeof(WSAMSG)); - *hdr = msgHdr; + WSAMSG *msgHdr = (WSAMSG *)malloc(sizeof(WSAMSG)); + memset(msgHdr, 0, sizeof(WSAMSG)); + *hdr = msgHdr; - // see ws2def.h - // the size of LPSOCKADDR and sockaddr_in * is same, so it's safe - msgHdr->name = (LPSOCKADDR)dest; - msgHdr->namelen = sizeof(struct sockaddr_in); - int size = sizeof(WSABUF) * maxPkts; - msgHdr->lpBuffers = (LPWSABUF)malloc(size); - memset(msgHdr->lpBuffers, 0, size); - msgHdr->dwBufferCount = 0; + // see ws2def.h + // the size of LPSOCKADDR and sockaddr_in * is same, so it's safe + msgHdr->name = (LPSOCKADDR)dest; + msgHdr->namelen = sizeof(struct sockaddr_in); + int size = sizeof(WSABUF) * maxPkts; + msgHdr->lpBuffers = (LPWSABUF)malloc(size); + memset(msgHdr->lpBuffers, 0, size); + msgHdr->dwBufferCount = 0; } void taosSetMsgHdrData(void *hdr, char *data, int dataLen) { - WSAMSG *msgHdr = (WSAMSG *)hdr; - msgHdr->lpBuffers[msgHdr->dwBufferCount].buf = data; - msgHdr->lpBuffers[msgHdr->dwBufferCount].len = dataLen; - msgHdr->dwBufferCount++; + WSAMSG *msgHdr = (WSAMSG *)hdr; + msgHdr->lpBuffers[msgHdr->dwBufferCount].buf = data; + msgHdr->lpBuffers[msgHdr->dwBufferCount].len = dataLen; + msgHdr->dwBufferCount++; } - diff --git a/src/os/src/windows64/w64PThread.c b/src/os/src/windows64/w64PThread.c new file mode 100644 index 0000000000..7ed6228228 --- /dev/null +++ b/src/os/src/windows64/w64PThread.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#define _DEFAULT_SOURCE +#include "os.h" +#include "taosdef.h" +#include "tglobal.h" +#include "ttimer.h" +#include "tulog.h" +#include "tutil.h" + +bool taosCheckPthreadValid(pthread_t thread) { return thread.p != NULL; } + +void taosResetPthread(pthread_t *thread) { thread->p = 0; } + +int64_t taosGetPthreadId() { +#ifdef PTW32_VERSION + return pthread_getw32threadid_np(pthread_self()); +#else + return (int64_t)pthread_self(); +#endif +} diff --git a/src/os/src/windows64/w64Socket.c b/src/os/src/windows64/w64Socket.c new file mode 100644 index 0000000000..cdf46825e8 --- /dev/null +++ b/src/os/src/windows64/w64Socket.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +void taosWinSocketInit() { + static char flag = 0; + if (flag == 0) { + WORD wVersionRequested; + WSADATA wsaData; + wVersionRequested = MAKEWORD(1, 1); + if (WSAStartup(wVersionRequested, &wsaData) == 0) { + flag = 1; + } + } +} + +int taosSetNonblocking(SOCKET sock, int on) { + u_long mode; + if (on) { + mode = 1; + ioctlsocket(sock, FIONBIO, &mode); + } else { + mode = 0; + ioctlsocket(sock, FIONBIO, &mode); + } + return 0; +} + +void taosBlockSIGPIPE() {} + +int taosSetSockOpt(int socketfd, int level, int optname, void *optval, int optlen) { + if (level == SOL_SOCKET && optname == TCP_KEEPCNT) { + return 0; + } + + if (level == SOL_TCP && optname == TCP_KEEPIDLE) { + return 0; + } + + if (level == SOL_TCP && optname == TCP_KEEPINTVL) { + return 0; + } + + return setsockopt(socketfd, level, optname, optval, optlen); +} \ No newline at end of file diff --git a/src/os/src/windows64/w64String.c b/src/os/src/windows64/w64String.c new file mode 100644 index 0000000000..0b392466fa --- /dev/null +++ b/src/os/src/windows64/w64String.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#define _DEFAULT_SOURCE +#include "os.h" +#include "taosdef.h" +#include "tglobal.h" +#include "ttimer.h" +#include "tulog.h" +#include "tutil.h" + + +/* + * Get next token from string *stringp, where tokens are possibly-empty + * strings separated by characters from delim. + * + * Writes NULs into the string at *stringp to end tokens. + * delim need not remain constant from call to call. + * On return, *stringp points past the last NUL written (if there might + * be further tokens), or is NULL (if there are definitely no moretokens). + * + * If *stringp is NULL, strsep returns NULL. + */ +char *strsep(char **stringp, const char *delim) { + char *s; + const char *spanp; + int c, sc; + char *tok; + if ((s = *stringp) == NULL) + return (NULL); + for (tok = s;;) { + c = *s++; + spanp = delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + *stringp = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} + +char *getpass(const char *prefix) { + static char passwd[TSDB_KEY_LEN] = {0}; + + printf("%s", prefix); + scanf("%s", passwd); + + char n = getchar(); + return passwd; +} + +char *strndup(const char *s, size_t n) { + int len = strlen(s); + if (len >= n) { + len = n; + } + + char *r = calloc(len + 1, 1); + memcpy(r, s, len); + r[len] = 0; + return r; +} + +#ifdef _TD_GO_DLL_ +int64_t tsosStr2int64(char *str) { + char *endptr = NULL; + return strtoll(str, &endptr, 10); +} + +uint64_t htonll(uint64_t val) +{ + return (((uint64_t) htonl(val)) << 32) + htonl(val >> 32); +} +#endif \ No newline at end of file diff --git a/src/os/src/windows64/twinstrptime.c b/src/os/src/windows64/w64Strptime.c similarity index 100% rename from src/os/src/windows64/twinstrptime.c rename to src/os/src/windows64/w64Strptime.c diff --git a/src/os/src/windows64/w64Sysinfo.c b/src/os/src/windows64/w64Sysinfo.c new file mode 100644 index 0000000000..950230e567 --- /dev/null +++ b/src/os/src/windows64/w64Sysinfo.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#define _DEFAULT_SOURCE +#include "os.h" +#include "taosdef.h" +#include "tglobal.h" +#include "tconfig.h" +#include "ttimer.h" +#include "tulog.h" +#include "tutil.h" + +static void taosGetSystemTimezone() { + // get and set default timezone + SGlobalCfg *cfg_timezone = taosGetConfigOption("timezone"); + if (cfg_timezone && cfg_timezone->cfgStatus < TAOS_CFG_CSTATUS_DEFAULT) { + char *tz = getenv("TZ"); + if (tz == NULL || strlen(tz) == 0) { + strcpy(tsTimezone, "not configured"); + } else { + strcpy(tsTimezone, tz); + } + cfg_timezone->cfgStatus = TAOS_CFG_CSTATUS_DEFAULT; + uInfo("timezone not configured, use default"); + } +} + +static void taosGetSystemLocale() { + // get and set default locale + SGlobalCfg *cfg_locale = taosGetConfigOption("locale"); + if (cfg_locale && cfg_locale->cfgStatus < TAOS_CFG_CSTATUS_DEFAULT) { + char *locale = setlocale(LC_CTYPE, "chs"); + if (locale != NULL) { + tstrncpy(tsLocale, locale, sizeof(tsLocale)); + cfg_locale->cfgStatus = TAOS_CFG_CSTATUS_DEFAULT; + uInfo("locale not configured, set to default:%s", tsLocale); + } + } + + SGlobalCfg *cfg_charset = taosGetConfigOption("charset"); + if (cfg_charset && cfg_charset->cfgStatus < TAOS_CFG_CSTATUS_DEFAULT) { + strcpy(tsCharset, "cp936"); + cfg_charset->cfgStatus = TAOS_CFG_CSTATUS_DEFAULT; + uInfo("charset not configured, set to default:%s", tsCharset); + } +} + +void taosPrintOsInfo() {} + +void taosKillSystem() { + uError("function taosKillSystem, exit!"); + exit(0); +} + +void taosGetSystemInfo() { + taosGetSystemTimezone(); + taosGetSystemLocale(); +} + +bool taosGetDisk() { return true; } + +bool taosGetProcIO(float *readKB, float *writeKB) { + *readKB = 0; + *writeKB = 0; + return true; +} + +bool taosGetBandSpeed(float *bandSpeedKb) { + *bandSpeedKb = 0; + return true; +} + +bool taosGetCpuUsage(float *sysCpuUsage, float *procCpuUsage) { + *sysCpuUsage = 0; + *procCpuUsage = 0; + return true; +} + +bool taosGetProcMemory(float *memoryUsedMB) { + *memoryUsedMB = 0; + return true; +} + +bool taosGetSysMemory(float *memoryUsedMB) { + *memoryUsedMB = 0; + return true; +} + +int taosSystem(const char *cmd) { + uError("taosSystem not support"); + return -1; +} + +int flock(int fd, int option) { + return 0; +} + +int fsync(int filedes) { + return 0; +} + +int sigaction(int sig, struct sigaction *d, void *p) { + return 0; +} \ No newline at end of file diff --git a/src/os/src/windows64/twintime.c b/src/os/src/windows64/w64Time.c similarity index 100% rename from src/os/src/windows64/twintime.c rename to src/os/src/windows64/w64Time.c diff --git a/src/os/src/windows64/twintimer.c b/src/os/src/windows64/w64Timer.c similarity index 93% rename from src/os/src/windows64/twintimer.c rename to src/os/src/windows64/w64Timer.c index 2bb8478f09..32e04746f1 100644 --- a/src/os/src/windows64/twintimer.c +++ b/src/os/src/windows64/w64Timer.c @@ -22,8 +22,7 @@ typedef void (*win_timer_f)(int signo); -void WINAPI taosWinOnTimer(UINT wTimerID, UINT msg, DWORD_PTR dwUser, DWORD_PTR dwl, DWORD_PTR dw2) -{ +void WINAPI taosWinOnTimer(UINT wTimerID, UINT msg, DWORD_PTR dwUser, DWORD_PTR dwl, DWORD_PTR dw2) { win_timer_f callback = *((win_timer_f *)&dwUser); if (callback != NULL) { callback(0); @@ -48,7 +47,3 @@ void taosUninitTimer() { void taosMsleep(int mseconds) { Sleep(mseconds); } - -void sleep(int mseconds) { - taosMsleep(mseconds); -} \ No newline at end of file diff --git a/src/os/src/windows64/w64Util.c b/src/os/src/windows64/w64Util.c new file mode 100644 index 0000000000..1a9f71b3c3 --- /dev/null +++ b/src/os/src/windows64/w64Util.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#define _DEFAULT_SOURCE +#include "os.h" +#include "taosdef.h" +#include "tglobal.h" +#include "ttimer.h" +#include "tulog.h" +#include "tutil.h" + + +/* + * Get next token from string *stringp, where tokens are possibly-empty + * strings separated by characters from delim. + * + * Writes NULs into the string at *stringp to end tokens. + * delim need not remain constant from call to call. + * On return, *stringp points past the last NUL written (if there might + * be further tokens), or is NULL (if there are definitely no moretokens). + * + * If *stringp is NULL, strsep returns NULL. + */ +char *strsep(char **stringp, const char *delim) { + char *s; + const char *spanp; + int c, sc; + char *tok; + if ((s = *stringp) == NULL) + return (NULL); + for (tok = s;;) { + c = *s++; + spanp = delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + *stringp = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} + +char *getpass(const char *prefix) { + static char passwd[TSDB_KEY_LEN] = {0}; + + printf("%s", prefix); + scanf("%s", passwd); + + char n = getchar(); + return passwd; +} + +int flock(int fd, int option) { + return 0; +} + +int fsync(int filedes) { + return 0; +} + +int sigaction(int sig, struct sigaction *d, void *p) { + return 0; +} + +int wordexp(const char *words, wordexp_t *pwordexp, int flags) { + pwordexp->we_offs = 0; + pwordexp->we_wordc = 1; + pwordexp->we_wordv = (char **)(pwordexp->wordPos); + pwordexp->we_wordv[0] = (char *)words; + return 0; +} + +void wordfree(wordexp_t *pwordexp) {} + + +char *strndup(const char *s, size_t n) { + int len = strlen(s); + if (len >= n) { + len = n; + } + + char *r = calloc(len + 1, 1); + memcpy(r, s, len); + r[len] = 0; + return r; +} + +void taosSetCoreDump() {} + +#ifdef _TD_GO_DLL_ +int64_t tsosStr2int64(char *str) { + char *endptr = NULL; + return strtoll(str, &endptr, 10); +} + +uint64_t htonll(uint64_t val) +{ + return (((uint64_t) htonl(val)) << 32) + htonl(val >> 32); +} +#endif \ No newline at end of file diff --git a/src/os/src/windows64/twintcpserver.c b/src/os/src/windows64/w64Wordexp.c similarity index 55% rename from src/os/src/windows64/twintcpserver.c rename to src/os/src/windows64/w64Wordexp.c index 10c0348bef..bb9acde25a 100644 --- a/src/os/src/windows64/twintcpserver.c +++ b/src/os/src/windows64/w64Wordexp.c @@ -13,22 +13,21 @@ * along with this program. If not, see . */ +#define _DEFAULT_SOURCE +#include "os.h" +#include "taosdef.h" +#include "tglobal.h" +#include "ttimer.h" #include "tulog.h" +#include "tutil.h" -void taosCloseTcpServerConnection(void *chandle) { - tError("CloseTcpServerConnection not support in windows"); -} - -void taosCleanUpTcpServer(void *handle) { - tError("CleanUpTcpServer not support in windows"); -} - -void *taosInitTcpServer(char *ip, uint16_t port, char *label, int numOfThreads, void *fp, void *shandle) { - tError("InitTcpServer not support in windows"); +int wordexp(const char *words, wordexp_t *pwordexp, int flags) { + pwordexp->we_offs = 0; + pwordexp->we_wordc = 1; + pwordexp->we_wordv = (char **)(pwordexp->wordPos); + pwordexp->we_wordv[0] = (char *)words; return 0; } -int taosSendTcpServerData(unsigned int ip, uint16_t port, char *data, int len, void *chandle) { - tError("SendTcpServerData not support in windows"); - return 0; -} +void wordfree(wordexp_t *pwordexp) {} + diff --git a/src/query/src/qExtbuffer.c b/src/query/src/qExtbuffer.c index fb57f71199..6f1c51a19e 100644 --- a/src/query/src/qExtbuffer.c +++ b/src/query/src/qExtbuffer.c @@ -38,7 +38,7 @@ tExtMemBuffer* createExtMemBuffer(int32_t inMemSize, int32_t elemSize, int32_t p pMemBuffer->numOfElemsPerPage = (pMemBuffer->pageSize - sizeof(tFilePage)) / pMemBuffer->nElemSize; char name[MAX_TMPFILE_PATH_LENGTH] = {0}; - getTmpfilePath("extbuf", name); + taosGetTmpfilePath("extbuf", name); pMemBuffer->path = strdup(name); uDebug("create tmp file:%s", pMemBuffer->path); diff --git a/src/query/src/qResultbuf.c b/src/query/src/qResultbuf.c index 93ccad8e27..363b590d80 100644 --- a/src/query/src/qResultbuf.c +++ b/src/query/src/qResultbuf.c @@ -39,7 +39,7 @@ int32_t createDiskbasedResultBuffer(SDiskbasedResultBuf** pResultBuf, int32_t ro pResBuf->all = taosHashInit(10, taosGetDefaultHashFunction(TSDB_DATA_TYPE_INT), false); char path[PATH_MAX] = {0}; - getTmpfilePath("qbuf", path); + taosGetTmpfilePath("qbuf", path); pResBuf->path = strdup(path); pResBuf->emptyDummyIdList = taosArrayInit(1, sizeof(int32_t)); diff --git a/src/query/src/qTsbuf.c b/src/query/src/qTsbuf.c index 037e85c88c..8ab45cc1a9 100644 --- a/src/query/src/qTsbuf.c +++ b/src/query/src/qTsbuf.c @@ -21,7 +21,7 @@ STSBuf* tsBufCreate(bool autoDelete, int32_t order) { return NULL; } - getTmpfilePath("join", pTSBuf->path); + taosGetTmpfilePath("join", pTSBuf->path); pTSBuf->f = fopen(pTSBuf->path, "w+"); if (pTSBuf->f == NULL) { free(pTSBuf); diff --git a/src/query/tests/unitTest.cpp b/src/query/tests/unitTest.cpp index 59fd326ef4..60c73b4fad 100644 --- a/src/query/tests/unitTest.cpp +++ b/src/query/tests/unitTest.cpp @@ -766,7 +766,7 @@ TEST(testCase, getTempFilePath_test) { char path[4096] = {0}; memset(path, 1, 4096); - getTmpfilePath("new_tmp", path); + taosGetTmpfilePath("new_tmp", path); printf("%s\n", path); } From 1619faa0c4de1d1ba87334d9a7369c61e0be836d Mon Sep 17 00:00:00 2001 From: Hongze Cheng Date: Fri, 31 Jul 2020 10:26:25 +0800 Subject: [PATCH 04/56] make update file group atomic --- src/tsdb/src/tsdbMemTable.c | 16 ++++++--- src/tsdb/src/tsdbRWHelper.c | 69 +++++++++++++++---------------------- 2 files changed, 39 insertions(+), 46 deletions(-) diff --git a/src/tsdb/src/tsdbMemTable.c b/src/tsdb/src/tsdbMemTable.c index 0cb032a730..d5e90bcd60 100644 --- a/src/tsdb/src/tsdbMemTable.c +++ b/src/tsdb/src/tsdbMemTable.c @@ -656,12 +656,20 @@ static int tsdbCommitToFile(STsdbRepo *pRepo, int fid, SCommitIter *iters, SRWHe tsdbCloseHelperFile(pHelper, 0); pthread_rwlock_wrlock(&(pFileH->fhlock)); + #ifdef TSDB_IDX - pGroup->files[TSDB_FILE_TYPE_IDX] = *(helperIdxF(pHelper)); + rename(helperNewIdxF(pHelper)->fname, helperIdxF(pHelper)->fname); + pGroup->files[TSDB_FILE_TYPE_IDX].info = helperNewIdxF(pHelper)->info; #endif - pGroup->files[TSDB_FILE_TYPE_HEAD] = *(helperHeadF(pHelper)); - pGroup->files[TSDB_FILE_TYPE_DATA] = *(helperDataF(pHelper)); - pGroup->files[TSDB_FILE_TYPE_LAST] = *(helperLastF(pHelper)); + + rename(helperNewHeadF(pHelper)->fname, helperHeadF(pHelper)->fname); + pGroup->files[TSDB_FILE_TYPE_HEAD].info = helperNewHeadF(pHelper)->info; + + rename(helperNewLastF(pHelper)->fname, helperLastF(pHelper)->fname); + pGroup->files[TSDB_FILE_TYPE_LAST].info = helperNewLastF(pHelper)->info; + + pGroup->files[TSDB_FILE_TYPE_DATA].info = helperDataF(pHelper)->info; + pthread_rwlock_unlock(&(pFileH->fhlock)); return 0; diff --git a/src/tsdb/src/tsdbRWHelper.c b/src/tsdb/src/tsdbRWHelper.c index b25e5ac432..b04d08f850 100644 --- a/src/tsdb/src/tsdbRWHelper.c +++ b/src/tsdb/src/tsdbRWHelper.c @@ -180,8 +180,12 @@ int tsdbCloseHelperFile(SRWHelper *pHelper, bool hasError) { pFile = helperDataF(pHelper); if (pFile->fd > 0) { if (helperType(pHelper) == TSDB_WRITE_HELPER) { - tsdbUpdateFileHeader(pFile, 0); - fsync(pFile->fd); + if (!hasError) { + tsdbUpdateFileHeader(pFile, 0); + fsync(pFile->fd); + } else { + // TODO: shrink back to origin + } } close(pFile->fd); pFile->fd = -1; @@ -190,7 +194,12 @@ int tsdbCloseHelperFile(SRWHelper *pHelper, bool hasError) { pFile = helperLastF(pHelper); if (pFile->fd > 0) { if (helperType(pHelper) == TSDB_WRITE_HELPER && !TSDB_NLAST_FILE_OPENED(pHelper)) { - fsync(pFile->fd); + if (!hasError) { + tsdbUpdateFileHeader(pFile, 0); + fsync(pFile->fd); + } else { + // TODO: shrink back to origin + } } close(pFile->fd); pFile->fd = -1; @@ -200,60 +209,36 @@ int tsdbCloseHelperFile(SRWHelper *pHelper, bool hasError) { #ifdef TSDB_IDX pFile = helperNewIdxF(pHelper); if (pFile->fd > 0) { - if (!hasError) tsdbUpdateFileHeader(pFile, 0); - fsync(pFile->fd); + if (!hasError) { + tsdbUpdateFileHeader(pFile, 0); + fsync(pFile->fd); + } close(pFile->fd); pFile->fd = -1; - if (hasError) { - (void)remove(pFile->fname); - } else { - if (rename(pFile->fname, helperIdxF(pHelper)->fname) < 0) { - tsdbError("failed to rename file from %s to %s since %s", pFile->fname, helperIdxF(pHelper)->fname, - strerror(errno)); - terrno = TAOS_SYSTEM_ERROR(errno); - return -1; - } - helperIdxF(pHelper)->info = pFile->info; - } + if (hasError) (void)remove(pFile->fname); } #endif pFile = helperNewHeadF(pHelper); if (pFile->fd > 0) { - if (!hasError) tsdbUpdateFileHeader(pFile, 0); - fsync(pFile->fd); + if (!hasError) { + tsdbUpdateFileHeader(pFile, 0); + fsync(pFile->fd); + } close(pFile->fd); pFile->fd = -1; - if (hasError) { - (void)remove(pFile->fname); - } else { - if (rename(pFile->fname, helperHeadF(pHelper)->fname) < 0) { - tsdbError("failed to rename file from %s to %s since %s", pFile->fname, helperHeadF(pHelper)->fname, - strerror(errno)); - terrno = TAOS_SYSTEM_ERROR(errno); - return -1; - } - helperHeadF(pHelper)->info = pFile->info; - } + if (hasError) (void)remove(pFile->fname); } pFile = helperNewLastF(pHelper); if (pFile->fd > 0) { - if (!hasError) tsdbUpdateFileHeader(pFile, 0); - fsync(pFile->fd); + if (!hasError) { + tsdbUpdateFileHeader(pFile, 0); + fsync(pFile->fd); + } close(pFile->fd); pFile->fd = -1; - if (hasError) { - (void)remove(pFile->fname); - } else { - if (rename(pFile->fname, helperLastF(pHelper)->fname) < 0) { - tsdbError("failed to rename file from %s to %s since %s", pFile->fname, helperLastF(pHelper)->fname, - strerror(errno)); - terrno = TAOS_SYSTEM_ERROR(errno); - return -1; - } - helperLastF(pHelper)->info = helperNewLastF(pHelper)->info; - } + if (hasError) (void)remove(pFile->fname); } } return 0; From 89c81042389b568186f0a5af28f406e26ae50c69 Mon Sep 17 00:00:00 2001 From: Hongze Cheng Date: Fri, 31 Jul 2020 10:59:57 +0800 Subject: [PATCH 05/56] add lock when read --- src/tsdb/src/tsdbRead.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/tsdb/src/tsdbRead.c b/src/tsdb/src/tsdbRead.c index 3a89ead4a8..4494b86209 100644 --- a/src/tsdb/src/tsdbRead.c +++ b/src/tsdb/src/tsdbRead.c @@ -555,17 +555,6 @@ static int32_t binarySearchForBlock(SCompBlock* pBlock, int32_t numOfBlocks, TSK } static int32_t getFileCompInfo(STsdbQueryHandle* pQueryHandle, int32_t* numOfBlocks) { - SFileGroup* fileGroup = pQueryHandle->pFileGroup; - assert(fileGroup->files[TSDB_FILE_TYPE_HEAD].fname > 0); - - if (tsdbSetAndOpenHelperFile(&pQueryHandle->rhelper, fileGroup) < 0) { - return terrno; - } - - if (tsdbLoadCompIdx(&pQueryHandle->rhelper, NULL) < 0) { - return terrno; - } - // load all the comp offset value for all tables in this file *numOfBlocks = 0; size_t numOfTables = taosArrayGetSize(pQueryHandle->pTableCheckInfo); @@ -1462,12 +1451,20 @@ static int32_t getDataBlocksInFilesImpl(STsdbQueryHandle* pQueryHandle, bool* ex STsdbCfg* pCfg = &pQueryHandle->pTsdb->config; STimeWindow win = TSWINDOW_INITIALIZER; - while ((pQueryHandle->pFileGroup = tsdbGetFileGroupNext(&pQueryHandle->fileIter)) != NULL) { + while (true) { + pthread_rwlock_rdlock(&pQueryHandle->pTsdb->tsdbFileH->fhlock); + + if ((pQueryHandle->pFileGroup = tsdbGetFileGroupNext(&pQueryHandle->fileIter)) == NULL) { + pthread_rwlock_unlock(&pQueryHandle->pTsdb->tsdbFileH->fhlock); + break; + } + tsdbGetFidKeyRange(pCfg->daysPerFile, pCfg->precision, pQueryHandle->pFileGroup->fileId, &win.skey, &win.ekey); // current file are not overlapped with query time window, ignore remain files if ((ASCENDING_TRAVERSE(pQueryHandle->order) && win.skey > pQueryHandle->window.ekey) || (!ASCENDING_TRAVERSE(pQueryHandle->order) && win.ekey < pQueryHandle->window.ekey)) { + pthread_rwlock_unlock(&pQueryHandle->pTsdb->tsdbFileH->fhlock); tsdbDebug("%p remain files are not qualified for qrange:%" PRId64 "-%" PRId64 ", ignore, %p", pQueryHandle, pQueryHandle->window.skey, pQueryHandle->window.ekey, pQueryHandle->qinfo); pQueryHandle->pFileGroup = NULL; @@ -1475,6 +1472,19 @@ static int32_t getDataBlocksInFilesImpl(STsdbQueryHandle* pQueryHandle, bool* ex break; } + if (tsdbSetAndOpenHelperFile(&pQueryHandle->rhelper, pQueryHandle->pFileGroup) < 0) { + pthread_rwlock_unlock(&pQueryHandle->pTsdb->tsdbFileH->fhlock); + code = terrno; + break; + } + + pthread_rwlock_unlock(&pQueryHandle->pTsdb->tsdbFileH->fhlock); + + if (tsdbLoadCompIdx(&pQueryHandle->rhelper, NULL) < 0) { + code = terrno; + break; + } + if ((code = getFileCompInfo(pQueryHandle, &numOfBlocks)) != TSDB_CODE_SUCCESS) { break; } From 0271f943944786bad3c96b7d494e8f0adef43221 Mon Sep 17 00:00:00 2001 From: Hongze Cheng Date: Fri, 31 Jul 2020 14:02:20 +0800 Subject: [PATCH 06/56] refact FGroup Iter make it multi-thread safe --- src/tsdb/inc/tsdbMain.h | 6 ++-- src/tsdb/src/tsdbFile.c | 72 ++++++++++++++++++++++++++--------------- src/tsdb/src/tsdbRead.c | 2 ++ 3 files changed, 51 insertions(+), 29 deletions(-) diff --git a/src/tsdb/inc/tsdbMain.h b/src/tsdb/inc/tsdbMain.h index 6a54cb2399..d6f73ee1be 100644 --- a/src/tsdb/inc/tsdbMain.h +++ b/src/tsdb/inc/tsdbMain.h @@ -183,10 +183,10 @@ typedef struct { } STsdbFileH; typedef struct { - int numOfFGroups; - SFileGroup *base; - SFileGroup *pFileGroup; int direction; + STsdbFileH* pFileH; + int fileId; + int index; } SFileGroupIter; // ------------------ tsdbMain.c diff --git a/src/tsdb/src/tsdbFile.c b/src/tsdb/src/tsdbFile.c index 6e7b39830e..7d8a68182b 100644 --- a/src/tsdb/src/tsdbFile.c +++ b/src/tsdb/src/tsdbFile.c @@ -156,8 +156,10 @@ SFileGroup *tsdbCreateFGroupIfNeed(STsdbRepo *pRepo, char *dataDir, int fid) { goto _err; } + pthread_rwlock_wrlock(&pFileH->fhlock); pFileH->pFGroup[pFileH->nFGroups++] = fGroup; qsort((void *)(pFileH->pFGroup), pFileH->nFGroups, sizeof(SFileGroup), compFGroup); + pthread_rwlock_unlock(&pFileH->fhlock); return tsdbSearchFGroup(pFileH, fid, TD_EQ); } @@ -168,54 +170,72 @@ _err: return NULL; } -void tsdbInitFileGroupIter(STsdbFileH *pFileH, SFileGroupIter *pIter, int direction) { // TODO +void tsdbInitFileGroupIter(STsdbFileH *pFileH, SFileGroupIter *pIter, int direction) { + pIter->pFileH = pFileH; pIter->direction = direction; - pIter->base = pFileH->pFGroup; - pIter->numOfFGroups = pFileH->nFGroups; + if (pFileH->nFGroups == 0) { - pIter->pFileGroup = NULL; + pIter->index = -1; + pIter->fileId = -1; } else { if (direction == TSDB_FGROUP_ITER_FORWARD) { - pIter->pFileGroup = pFileH->pFGroup; + pIter->index = 0; } else { - pIter->pFileGroup = pFileH->pFGroup + pFileH->nFGroups - 1; + pIter->index = pFileH->nFGroups - 1; } + pIter->fileId = pFileH->pFGroup[pIter->index].fileId; } } -void tsdbSeekFileGroupIter(SFileGroupIter *pIter, int fid) { // TODO - if (pIter->numOfFGroups == 0) { - assert(pIter->pFileGroup == NULL); +void tsdbSeekFileGroupIter(SFileGroupIter *pIter, int fid) { + STsdbFileH *pFileH = pIter->pFileH; + + if (pFileH->nFGroups == 0) { + pIter->index = -1; + pIter->fileId = -1; return; } int flags = (pIter->direction == TSDB_FGROUP_ITER_FORWARD) ? TD_GE : TD_LE; - void *ptr = taosbsearch(&fid, pIter->base, pIter->numOfFGroups, sizeof(SFileGroup), keyFGroupCompFunc, flags); + void *ptr = taosbsearch(&fid, (void *)pFileH->pFGroup, pFileH->nFGroups, sizeof(SFileGroup), keyFGroupCompFunc, flags); if (ptr == NULL) { - pIter->pFileGroup = NULL; + pIter->index = -1; + pIter->fileId = -1; } else { - pIter->pFileGroup = (SFileGroup *)ptr; + pIter->index = POINTER_DISTANCE(ptr, pFileH->pFGroup) / sizeof(SFileGroup); + pIter->fileId = ((SFileGroup *)ptr)->fileId; } } -SFileGroup *tsdbGetFileGroupNext(SFileGroupIter *pIter) {//TODO - SFileGroup *ret = pIter->pFileGroup; - if (ret == NULL) return NULL; +SFileGroup *tsdbGetFileGroupNext(SFileGroupIter *pIter) { + STsdbFileH *pFileH = pIter->pFileH; + SFileGroup *pFGroup = NULL; + + if (pIter->index < 0 || pIter->index >= pFileH->nFGroups || pIter->fileId < 0) return NULL; + + pFGroup = &pFileH->pFGroup[pIter->index]; + if (pFGroup->fileId != pIter->fileId) { + tsdbSeekFileGroupIter(pIter, pIter->fileId); + } + + if (pIter->index < 0) return NULL; + + pFGroup = &pFileH->pFGroup[pIter->index]; + ASSERT(pFGroup->fileId == pIter->fileId); if (pIter->direction == TSDB_FGROUP_ITER_FORWARD) { - if ((pIter->pFileGroup + 1) == (pIter->base + pIter->numOfFGroups)) { - pIter->pFileGroup = NULL; - } else { - pIter->pFileGroup += 1; - } + pIter->index++; } else { - if (pIter->pFileGroup == pIter->base) { - pIter->pFileGroup = NULL; - } else { - pIter->pFileGroup -= 1; - } + pIter->index--; } - return ret; + + if (pIter->index >= 0 && pIter->index < pFileH->nFGroups) { + pIter->fileId = pFileH->pFGroup[pIter->index].fileId; + } else { + pIter->fileId = -1; + } + + return pFGroup; } int tsdbOpenFile(SFile *pFile, int oflag) { diff --git a/src/tsdb/src/tsdbRead.c b/src/tsdb/src/tsdbRead.c index 4494b86209..8515fb52e3 100644 --- a/src/tsdb/src/tsdbRead.c +++ b/src/tsdb/src/tsdbRead.c @@ -1539,8 +1539,10 @@ static int32_t getDataBlocksInFiles(STsdbQueryHandle* pQueryHandle, bool* exists STsdbCfg* pCfg = &pQueryHandle->pTsdb->config; int32_t fid = getFileIdFromKey(pQueryHandle->window.skey, pCfg->daysPerFile, pCfg->precision); + pthread_rwlock_rdlock(&pQueryHandle->pTsdb->tsdbFileH->fhlock); tsdbInitFileGroupIter(pFileHandle, &pQueryHandle->fileIter, pQueryHandle->order); tsdbSeekFileGroupIter(&pQueryHandle->fileIter, fid); + pthread_rwlock_unlock(&pQueryHandle->pTsdb->tsdbFileH->fhlock); return getDataBlocksInFilesImpl(pQueryHandle, exists); } else { From 794e20c99f514f83eb387878e0f77b51a998856b Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Fri, 31 Jul 2020 06:18:23 +0000 Subject: [PATCH 07/56] [TD-992] --- src/balance/src/balance.c | 2 +- src/client/src/TSDBJNIConnector.c | 1 - src/client/src/tscFunctionImpl.c | 3 +- src/client/src/tscLocal.c | 4 +- src/client/src/tscLocalMerge.c | 64 +-- src/client/src/tscParseInsert.c | 9 +- src/client/src/tscPrepare.c | 2 +- src/client/src/tscProfile.c | 1 - src/client/src/tscSQLParser.c | 7 +- src/client/src/tscServer.c | 9 +- src/client/src/tscSql.c | 10 +- src/client/src/tscStream.c | 9 +- src/client/src/tscSub.c | 1 - src/client/src/tscSubquery.c | 34 +- src/client/src/tscSystem.c | 1 - src/client/src/tscUtil.c | 66 +-- src/client/tests/timeParseTest.cpp | 2 +- src/common/inc/tdataformat.h | 4 +- src/common/src/tdataformat.c | 10 +- src/common/src/tvariant.c | 2 +- src/cq/src/cqMain.c | 2 +- src/dnode/src/dnodeMPeer.c | 2 +- src/dnode/src/dnodeMWrite.c | 2 +- src/dnode/src/dnodeMgmt.c | 2 - src/kit/shell/src/shellDarwin.c | 4 +- src/kit/shell/src/shellEngine.c | 5 +- src/kit/shell/src/shellImport.c | 1 - src/kit/shell/src/shellLinux.c | 6 +- src/kit/taosdump/taosdump.c | 46 +- src/kit/taosmigrate/taosmigrateVnodeCfg.c | 2 +- src/mnode/src/mnodeAcct.c | 3 +- src/mnode/src/mnodeCluster.c | 3 +- src/mnode/src/mnodeDb.c | 7 +- src/mnode/src/mnodeDnode.c | 5 +- src/mnode/src/mnodeMnode.c | 5 +- src/mnode/src/mnodeProfile.c | 5 +- src/mnode/src/mnodeSdb.c | 2 +- src/mnode/src/mnodeShow.c | 2 +- src/mnode/src/mnodeTable.c | 15 +- src/mnode/src/mnodeUser.c | 5 +- src/mnode/src/mnodeVgroup.c | 3 +- src/os/inc/os.h | 18 +- src/os/inc/osAtomic.h | 113 +++++ src/os/inc/osDef.h | 104 +++++ src/os/inc/osDir.h | 32 ++ src/os/inc/osFile.h | 57 +++ src/os/inc/osLz4.h | 34 ++ src/os/inc/osMath.h | 52 +++ src/os/inc/osMemory.h | 78 ++++ src/os/inc/osPthread.h | 31 ++ src/os/inc/osRand.h | 32 ++ src/os/inc/osSemphone.h | 35 ++ src/os/inc/osSocket.h | 63 +++ src/os/inc/osSpec.h | 400 ------------------ src/os/inc/osString.h | 56 +++ src/os/inc/osSysinfo.h | 42 ++ src/{util/inc/ttime.h => os/inc/osTime.h} | 14 +- src/os/inc/osTimer.h | 32 ++ src/os/src/detail/osDir.c | 1 + src/os/src/detail/osFile.c | 88 +++- src/os/src/detail/osFileOp.c | 92 ---- src/os/src/detail/osMalloc.c | 66 --- src/os/src/detail/{osMem.c => osMemory.c} | 67 ++- src/os/src/detail/osSysinfo.c | 14 +- .../src/ttime.c => os/src/detail/osTime.c} | 1 - src/plugins/http/src/httpContext.c | 5 +- src/plugins/http/src/httpServer.c | 5 +- src/plugins/http/src/httpSession.c | 1 - src/plugins/http/src/httpSystem.c | 2 +- src/plugins/monitor/src/monitorMain.c | 1 - src/query/src/qExecutor.c | 91 ++-- src/query/src/qExtbuffer.c | 16 +- src/query/src/qFill.c | 16 +- src/query/src/qParserImpl.c | 9 +- src/query/src/qPercentile.c | 22 +- src/query/src/qResultbuf.c | 12 +- src/query/src/qTsbuf.c | 8 +- src/query/src/qUtil.c | 5 +- src/query/tests/tsBufTest.cpp | 3 +- src/query/tests/unitTest.cpp | 2 +- src/rpc/src/rpcCache.c | 7 +- src/rpc/src/rpcMain.c | 5 +- src/rpc/src/rpcTcp.c | 10 +- src/rpc/src/rpcUdp.c | 4 +- src/sync/src/syncMain.c | 17 +- src/sync/src/syncRestore.c | 6 +- src/sync/src/syncRetrieve.c | 10 +- src/sync/src/taosTcpPool.c | 8 +- src/sync/src/tarbitrator.c | 5 +- src/tsdb/src/tsdbBuffer.c | 2 +- src/tsdb/src/tsdbFile.c | 7 +- src/tsdb/src/tsdbMain.c | 15 +- src/tsdb/src/tsdbMemTable.c | 8 +- src/tsdb/src/tsdbMeta.c | 20 +- src/tsdb/src/tsdbRWHelper.c | 60 +-- src/tsdb/src/tsdbRead.c | 33 +- src/tsdb/tests/tsdbTests.cpp | 4 +- src/util/src/hash.c | 4 +- src/util/src/talgo.c | 2 +- src/util/src/tcache.c | 3 +- src/util/src/tconfig.c | 4 +- src/util/src/tdes.c | 7 +- src/util/src/tkvstore.c | 10 +- src/util/src/tlog.c | 12 +- src/util/src/tmempool.c | 6 +- src/util/src/tskiplist.c | 20 +- src/util/src/ttimer.c | 1 - src/util/src/tutil.c | 1 - src/util/tests/cacheTest.cpp | 2 +- src/util/tests/hashTest.cpp | 4 +- src/util/tests/skiplistTest.cpp | 12 +- src/vnode/src/vnodeMain.c | 7 +- src/wal/src/walMain.c | 2 +- tests/test/c/createTablePerformance.c | 1 - tests/test/c/hashPerformance.c | 1 - tests/tsim/src/simExe.c | 1 + tests/tsim/src/simParse.c | 5 +- tests/tsim/src/simSystem.c | 7 +- 118 files changed, 1359 insertions(+), 1062 deletions(-) create mode 100644 src/os/inc/osAtomic.h create mode 100644 src/os/inc/osDef.h create mode 100644 src/os/inc/osDir.h create mode 100644 src/os/inc/osFile.h create mode 100644 src/os/inc/osLz4.h create mode 100644 src/os/inc/osMath.h create mode 100644 src/os/inc/osMemory.h create mode 100644 src/os/inc/osPthread.h create mode 100644 src/os/inc/osRand.h create mode 100644 src/os/inc/osSemphone.h create mode 100644 src/os/inc/osSocket.h delete mode 100644 src/os/inc/osSpec.h create mode 100644 src/os/inc/osString.h create mode 100644 src/os/inc/osSysinfo.h rename src/{util/inc/ttime.h => os/inc/osTime.h} (79%) create mode 100644 src/os/inc/osTimer.h delete mode 100644 src/os/src/detail/osFileOp.c delete mode 100644 src/os/src/detail/osMalloc.c rename src/os/src/detail/{osMem.c => osMemory.c} (87%) rename src/{util/src/ttime.c => os/src/detail/osTime.c} (99%) diff --git a/src/balance/src/balance.c b/src/balance/src/balance.c index 7aed8c05ca..db5dd6a520 100644 --- a/src/balance/src/balance.c +++ b/src/balance/src/balance.c @@ -14,10 +14,10 @@ */ #define _DEFAULT_SOURCE +#include "os.h" #include "tutil.h" #include "tbalance.h" #include "tsync.h" -#include "ttime.h" #include "ttimer.h" #include "tglobal.h" #include "tdataformat.h" diff --git a/src/client/src/TSDBJNIConnector.c b/src/client/src/TSDBJNIConnector.c index 549a0e8d0d..eee255f55b 100644 --- a/src/client/src/TSDBJNIConnector.c +++ b/src/client/src/TSDBJNIConnector.c @@ -18,7 +18,6 @@ #include "tlog.h" #include "tscUtil.h" #include "tsclient.h" -#include "ttime.h" #include "com_taosdata_jdbc_TSDBJNIConnector.h" diff --git a/src/client/src/tscFunctionImpl.c b/src/client/src/tscFunctionImpl.c index 17f6c97ea1..c4f768f6ac 100644 --- a/src/client/src/tscFunctionImpl.c +++ b/src/client/src/tscFunctionImpl.c @@ -27,7 +27,6 @@ #include "tscSubquery.h" #include "tscompression.h" #include "tsqlfunction.h" -#include "ttime.h" #include "tutil.h" #define GET_INPUT_CHAR(x) (((char *)((x)->aInputElemBuf)) + ((x)->startOffset) * ((x)->inputBytes)) @@ -2108,7 +2107,7 @@ static void copyTopBotRes(SQLFunctionCtx *pCtx, int32_t type) { } } - tfree(pData); + taosTFree(pData); } /* diff --git a/src/client/src/tscLocal.c b/src/client/src/tscLocal.c index 7f336daa91..a8f287d499 100644 --- a/src/client/src/tscLocal.c +++ b/src/client/src/tscLocal.c @@ -326,7 +326,7 @@ static void tscProcessServerVer(SSqlObj *pSql) { STR_WITH_SIZE_TO_VARSTR(vx, v, t); tscSetLocalQueryResult(pSql, vx, pExpr->aliasName, pExpr->resType, pExpr->resBytes); - tfree(vx); + taosTFree(vx); } static void tscProcessClientVer(SSqlObj *pSql) { @@ -342,7 +342,7 @@ static void tscProcessClientVer(SSqlObj *pSql) { STR_WITH_SIZE_TO_VARSTR(v, version, t); tscSetLocalQueryResult(pSql, v, pExpr->aliasName, pExpr->resType, pExpr->resBytes); - tfree(v); + taosTFree(v); } static void tscProcessServStatus(SSqlObj *pSql) { diff --git a/src/client/src/tscLocalMerge.c b/src/client/src/tscLocalMerge.c index bf76b8cbe8..394b725781 100644 --- a/src/client/src/tscLocalMerge.c +++ b/src/client/src/tscLocalMerge.c @@ -230,7 +230,7 @@ void tscCreateLocalReducer(tExtMemBuffer **pMemBuffer, int32_t numOfBuffer, tOrd if (ds == NULL) { tscError("%p failed to create merge structure", pSql); pRes->code = TSDB_CODE_TSC_OUT_OF_MEMORY; - tfree(pReducer); + taosTFree(pReducer); return; } @@ -257,7 +257,7 @@ void tscCreateLocalReducer(tExtMemBuffer **pMemBuffer, int32_t numOfBuffer, tOrd if (ds->filePage.num == 0) { // no data in this flush, the index does not increase tscDebug("%p flush data is empty, ignore %d flush record", pSql, idx); - tfree(ds); + taosTFree(ds); continue; } @@ -267,7 +267,7 @@ void tscCreateLocalReducer(tExtMemBuffer **pMemBuffer, int32_t numOfBuffer, tOrd // no data actually, no need to merge result. if (idx == 0) { - tfree(pReducer); + taosTFree(pReducer); return; } @@ -275,7 +275,7 @@ void tscCreateLocalReducer(tExtMemBuffer **pMemBuffer, int32_t numOfBuffer, tOrd SCompareParam *param = malloc(sizeof(SCompareParam)); if (param == NULL) { - tfree(pReducer); + taosTFree(pReducer); return; } param->pLocalData = pReducer->pLocalDataSrc; @@ -288,8 +288,8 @@ void tscCreateLocalReducer(tExtMemBuffer **pMemBuffer, int32_t numOfBuffer, tOrd pRes->code = tLoserTreeCreate(&pReducer->pLoserTree, pReducer->numOfBuffer, param, treeComparator); if (pReducer->pLoserTree == NULL || pRes->code != 0) { - tfree(param); - tfree(pReducer); + taosTFree(param); + taosTFree(pReducer); return; } @@ -332,14 +332,14 @@ void tscCreateLocalReducer(tExtMemBuffer **pMemBuffer, int32_t numOfBuffer, tOrd if (pReducer->pTempBuffer == NULL || pReducer->discardData == NULL || pReducer->pResultBuf == NULL || /*pReducer->pBufForInterpo == NULL || */pReducer->pFinalRes == NULL || pReducer->prevRowOfInput == NULL) { - tfree(pReducer->pTempBuffer); - tfree(pReducer->discardData); - tfree(pReducer->pResultBuf); - tfree(pReducer->pFinalRes); - tfree(pReducer->prevRowOfInput); - tfree(pReducer->pLoserTree); - tfree(param); - tfree(pReducer); + taosTFree(pReducer->pTempBuffer); + taosTFree(pReducer->discardData); + taosTFree(pReducer->pResultBuf); + taosTFree(pReducer->pFinalRes); + taosTFree(pReducer->prevRowOfInput); + taosTFree(pReducer->pLoserTree); + taosTFree(param); + taosTFree(pReducer); pRes->code = TSDB_CODE_TSC_OUT_OF_MEMORY; return; } @@ -516,38 +516,38 @@ void tscDestroyLocalReducer(SSqlObj *pSql) { tVariantDestroy(&pCtx->tag); if (pCtx->tagInfo.pTagCtxList != NULL) { - tfree(pCtx->tagInfo.pTagCtxList); + taosTFree(pCtx->tagInfo.pTagCtxList); } } - tfree(pLocalReducer->pCtx); + taosTFree(pLocalReducer->pCtx); } - tfree(pLocalReducer->prevRowOfInput); + taosTFree(pLocalReducer->prevRowOfInput); - tfree(pLocalReducer->pTempBuffer); - tfree(pLocalReducer->pResultBuf); + taosTFree(pLocalReducer->pTempBuffer); + taosTFree(pLocalReducer->pResultBuf); if (pLocalReducer->pResInfo != NULL) { for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutput; ++i) { - tfree(pLocalReducer->pResInfo[i].interResultBuf); + taosTFree(pLocalReducer->pResInfo[i].interResultBuf); } - tfree(pLocalReducer->pResInfo); + taosTFree(pLocalReducer->pResInfo); } if (pLocalReducer->pLoserTree) { - tfree(pLocalReducer->pLoserTree->param); - tfree(pLocalReducer->pLoserTree); + taosTFree(pLocalReducer->pLoserTree->param); + taosTFree(pLocalReducer->pLoserTree); } - tfree(pLocalReducer->pFinalRes); - tfree(pLocalReducer->discardData); + taosTFree(pLocalReducer->pFinalRes); + taosTFree(pLocalReducer->discardData); tscLocalReducerEnvDestroy(pLocalReducer->pExtMemBuffer, pLocalReducer->pDesc, pLocalReducer->resColModel, pLocalReducer->numOfVnode); for (int32_t i = 0; i < pLocalReducer->numOfBuffer; ++i) { - tfree(pLocalReducer->pLocalDataSrc[i]); + taosTFree(pLocalReducer->pLocalDataSrc[i]); } pLocalReducer->numOfBuffer = 0; @@ -593,7 +593,7 @@ static int32_t createOrderDescriptor(tOrderDescriptor **pOrderDesc, SSqlCmd *pCm } *pOrderDesc = tOrderDesCreate(orderIdx, numOfGroupByCols, pModel, pQueryInfo->order.order); - tfree(orderIdx); + taosTFree(orderIdx); if (*pOrderDesc == NULL) { return TSDB_CODE_TSC_OUT_OF_MEMORY; @@ -705,7 +705,7 @@ int32_t tscLocalReducerEnvCreate(SSqlObj *pSql, tExtMemBuffer ***pMemBuffer, tOr if (createOrderDescriptor(pOrderDesc, pCmd, pModel) != TSDB_CODE_SUCCESS) { pRes->code = TSDB_CODE_TSC_OUT_OF_MEMORY; - tfree(pSchema); + taosTFree(pSchema); return pRes->code; } @@ -746,7 +746,7 @@ int32_t tscLocalReducerEnvCreate(SSqlObj *pSql, tExtMemBuffer ***pMemBuffer, tOr } *pFinalModel = createColumnModel(pSchema, size, capacity); - tfree(pSchema); + taosTFree(pSchema); return TSDB_CODE_SUCCESS; } @@ -765,7 +765,7 @@ void tscLocalReducerEnvDestroy(tExtMemBuffer **pMemBuffer, tOrderDescriptor *pDe pMemBuffer[i] = destoryExtMemBuffer(pMemBuffer[i]); } - tfree(pMemBuffer); + taosTFree(pMemBuffer); } /** @@ -1036,10 +1036,10 @@ static void doFillResult(SSqlObj *pSql, SLocalReducer *pLocalReducer, bool doneO pFinalDataPage->num = 0; for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutput; ++i) { - tfree(pResPages[i]); + taosTFree(pResPages[i]); } - tfree(pResPages); + taosTFree(pResPages); } static void savePreviousRow(SLocalReducer *pLocalReducer, tFilePage *tmpBuffer) { diff --git a/src/client/src/tscParseInsert.c b/src/client/src/tscParseInsert.c index ae2370cd56..2f245ee513 100644 --- a/src/client/src/tscParseInsert.c +++ b/src/client/src/tscParseInsert.c @@ -30,7 +30,6 @@ #include "tscLog.h" #include "tscSubquery.h" #include "tstoken.h" -#include "ttime.h" #include "tdataformat.h" @@ -1388,7 +1387,7 @@ static void parseFileSendDataBlock(void *param, TAOS_RES *tres, int code) { assert(taos_errno(pSql) == code); taos_free_result(pSql); - tfree(pSupporter); + taosTFree(pSupporter); fclose(fp); pParentSql->res.code = code; @@ -1453,7 +1452,7 @@ static void parseFileSendDataBlock(void *param, TAOS_RES *tres, int code) { } } - tfree(tokenBuf); + taosTFree(tokenBuf); free(line); if (count > 0) { @@ -1466,7 +1465,7 @@ static void parseFileSendDataBlock(void *param, TAOS_RES *tres, int code) { } else { taos_free_result(pSql); - tfree(pSupporter); + taosTFree(pSupporter); fclose(fp); pParentSql->fp = pParentSql->fetchFp; @@ -1496,7 +1495,7 @@ void tscProcessMultiVnodesImportFromFile(SSqlObj *pSql) { pSql->res.code = TAOS_SYSTEM_ERROR(errno); tscError("%p failed to open file %s to load data from file, code:%s", pSql, pCmd->payload, tstrerror(pSql->res.code)); - tfree(pSupporter) + taosTFree(pSupporter) tscQueueAsyncRes(pSql); return; diff --git a/src/client/src/tscPrepare.c b/src/client/src/tscPrepare.c index 0cf69dfd46..3ddfc1c341 100644 --- a/src/client/src/tscPrepare.c +++ b/src/client/src/tscPrepare.c @@ -613,7 +613,7 @@ int taos_stmt_execute(TAOS_STMT* stmt) { if (sql == NULL) { ret = TSDB_CODE_TSC_OUT_OF_MEMORY; } else { - tfree(pStmt->pSql->sqlstr); + taosTFree(pStmt->pSql->sqlstr); pStmt->pSql->sqlstr = sql; SSqlObj* pSql = taos_query((TAOS*)pStmt->taos, pStmt->pSql->sqlstr); ret = taos_errno(pSql); diff --git a/src/client/src/tscProfile.c b/src/client/src/tscProfile.c index 602b4654df..363243b1d7 100644 --- a/src/client/src/tscProfile.c +++ b/src/client/src/tscProfile.c @@ -16,7 +16,6 @@ #include "os.h" #include "tscLog.h" #include "tsclient.h" -#include "ttime.h" #include "ttimer.h" #include "tutil.h" #include "taosmsg.h" diff --git a/src/client/src/tscSQLParser.c b/src/client/src/tscSQLParser.c index 44236face0..4e0c238ac0 100644 --- a/src/client/src/tscSQLParser.c +++ b/src/client/src/tscSQLParser.c @@ -29,7 +29,6 @@ #include "tsclient.h" #include "tstoken.h" #include "tstrbuild.h" -#include "ttime.h" #include "ttokendef.h" #define DEFAULT_PRIMARY_TIMESTAMP_COL_NAME "_c0" @@ -737,7 +736,7 @@ int32_t tscSetTableFullName(STableMetaInfo* pTableMetaInfo, SSQLToken* pzTableNa assert(pTableMetaInfo->pTableMeta == NULL); } - tfree(oldName); + taosTFree(oldName); return TSDB_CODE_SUCCESS; } @@ -3648,7 +3647,7 @@ static int32_t setTableCondForSTableQuery(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, int32_t ret = setObjFullName(idBuf, account, &dbToken, &t, &xlen); if (ret != TSDB_CODE_SUCCESS) { taosStringBuilderDestroy(&sb1); - tfree(segments); + taosTFree(segments); invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg); return ret; @@ -3661,7 +3660,7 @@ static int32_t setTableCondForSTableQuery(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, pQueryInfo->tagCond.tbnameCond.cond = strdup(str); taosStringBuilderDestroy(&sb1); - tfree(segments); + taosTFree(segments); return TSDB_CODE_SUCCESS; } diff --git a/src/client/src/tscServer.c b/src/client/src/tscServer.c index 521280af87..3fd0aa79a6 100644 --- a/src/client/src/tscServer.c +++ b/src/client/src/tscServer.c @@ -23,7 +23,6 @@ #include "tscUtil.h" #include "tschemautil.h" #include "tsclient.h" -#include "ttime.h" #include "ttimer.h" #include "tutil.h" #include "tlockfree.h" @@ -196,7 +195,7 @@ void tscProcessActivityTimer(void *handle, void *tmrId) { pSql->cmd.command = TSDB_SQL_HB; if (TSDB_CODE_SUCCESS != tscAllocPayload(&(pSql->cmd), TSDB_DEFAULT_PAYLOAD_SIZE)) { - tfree(pSql); + taosTFree(pSql); return; } @@ -1538,7 +1537,7 @@ int tscBuildTableMetaMsg(SSqlObj *pSql, SSqlInfo *pInfo) { pCmd->payloadLen = pMsg - (char*)pInfoMsg; pCmd->msgType = TSDB_MSG_TYPE_CM_TABLE_META; - tfree(tmpData); + taosTFree(tmpData); assert(msgLen + minMsgSize() <= pCmd->allocSize); return TSDB_CODE_SUCCESS; @@ -1572,7 +1571,7 @@ int tscBuildMultiMeterMetaMsg(SSqlObj *pSql, SSqlInfo *pInfo) { memcpy(pInfoMsg->tableIds, tmpData, pCmd->payloadLen); } - tfree(tmpData); + taosTFree(tmpData); pCmd->payloadLen += sizeof(SMgmtHead) + sizeof(SCMMultiTableInfoMsg); pCmd->msgType = TSDB_MSG_TYPE_CM_TABLES_META; @@ -1962,7 +1961,7 @@ int tscProcessShowRsp(SSqlObj *pSql) { pCmd->numOfCols = pQueryInfo->fieldsInfo.numOfOutput; tscFieldInfoUpdateOffset(pQueryInfo); - tfree(pTableMeta); + taosTFree(pTableMeta); return 0; } diff --git a/src/client/src/tscSql.c b/src/client/src/tscSql.c index ff050dbbbf..10720874e2 100644 --- a/src/client/src/tscSql.c +++ b/src/client/src/tscSql.c @@ -474,7 +474,7 @@ int taos_fetch_block(TAOS_RES *res, TAOS_ROW *rows) { pRes->rspType = 0; pSql->numOfSubs = 0; - tfree(pSql->pSubs); + taosTFree(pSql->pSubs); assert(pSql->fp == NULL); @@ -753,7 +753,7 @@ int taos_validate_sql(TAOS *taos, const char *sql) { if (sqlLen > tsMaxSQLStringLen) { tscError("%p sql too long", pSql); pRes->code = TSDB_CODE_TSC_INVALID_SQL; - tfree(pSql); + taosTFree(pSql); return pRes->code; } @@ -762,7 +762,7 @@ int taos_validate_sql(TAOS *taos, const char *sql) { pRes->code = TSDB_CODE_TSC_OUT_OF_MEMORY; tscError("%p failed to malloc sql string buffer", pSql); tscDebug("%p Valid SQL result:%d, %s pObj:%p", pSql, pRes->code, taos_errstr(taos), pObj); - tfree(pSql); + taosTFree(pSql); return pRes->code; } @@ -896,7 +896,7 @@ int taos_load_table_info(TAOS *taos, const char *tableNameList) { if (tblListLen > MAX_TABLE_NAME_LENGTH) { tscError("%p tableNameList too long, length:%d, maximum allowed:%d", pSql, tblListLen, MAX_TABLE_NAME_LENGTH); pRes->code = TSDB_CODE_TSC_INVALID_SQL; - tfree(pSql); + taosTFree(pSql); return pRes->code; } @@ -904,7 +904,7 @@ int taos_load_table_info(TAOS *taos, const char *tableNameList) { if (str == NULL) { pRes->code = TSDB_CODE_TSC_OUT_OF_MEMORY; tscError("%p failed to malloc sql string buffer", pSql); - tfree(pSql); + taosTFree(pSql); return pRes->code; } diff --git a/src/client/src/tscStream.c b/src/client/src/tscStream.c index b07627c87b..20b5e86090 100644 --- a/src/client/src/tscStream.c +++ b/src/client/src/tscStream.c @@ -21,7 +21,6 @@ #include "tsched.h" #include "tcache.h" #include "tsclient.h" -#include "ttime.h" #include "ttimer.h" #include "tutil.h" @@ -156,7 +155,7 @@ static void tscProcessStreamQueryCallback(void *param, TAOS_RES *tres, int numOf STableMetaInfo* pTableMetaInfo = tscGetTableMetaInfoFromCmd(&pStream->pSql->cmd, 0, 0); taosCacheRelease(tscCacheHandle, (void**)&(pTableMetaInfo->pTableMeta), true); - tfree(pTableMetaInfo->vgroupList); + taosTFree(pTableMetaInfo->vgroupList); tscSetRetryTimer(pStream, pStream->pSql, retryDelay); return; @@ -260,9 +259,9 @@ static void tscProcessStreamRetrieveResult(void *param, TAOS_RES *res, int numOf taosCacheRelease(tscCacheHandle, (void**)&(pTableMetaInfo->pTableMeta), false); tscFreeSqlResult(pSql); - tfree(pSql->pSubs); + taosTFree(pSql->pSubs); pSql->numOfSubs = 0; - tfree(pTableMetaInfo->vgroupList); + taosTFree(pTableMetaInfo->vgroupList); tscSetNextLaunchTimer(pStream, pSql); } } @@ -592,6 +591,6 @@ void taos_close_stream(TAOS_STREAM *handle) { tscFreeSqlObj(pSql); pStream->pSql = NULL; - tfree(pStream); + taosTFree(pStream); } } diff --git a/src/client/src/tscSub.c b/src/client/src/tscSub.c index 6e572d94d1..9569987de0 100644 --- a/src/client/src/tscSub.c +++ b/src/client/src/tscSub.c @@ -18,7 +18,6 @@ #include "trpc.h" #include "tsclient.h" #include "tsocket.h" -#include "ttime.h" #include "ttimer.h" #include "tutil.h" #include "tscLog.h" diff --git a/src/client/src/tscSubquery.c b/src/client/src/tscSubquery.c index 79c45daa20..fed790b9af 100644 --- a/src/client/src/tscSubquery.c +++ b/src/client/src/tscSubquery.c @@ -215,7 +215,7 @@ static void tscDestroyJoinSupporter(SJoinSupporter* pSupporter) { pSupporter->f = NULL; } - tfree(pSupporter->pIdTagList); + taosTFree(pSupporter->pIdTagList); tscTagCondRelease(&pSupporter->tagCond); free(pSupporter); } @@ -407,7 +407,7 @@ void freeJoinSubqueryObj(SSqlObj* pSql) { } } - tfree(pState); + taosTFree(pState); pSql->numOfSubs = 0; } @@ -1317,12 +1317,12 @@ static void doCleanupSubqueries(SSqlObj *pSql, int32_t numOfSubs, SSubqueryState SRetrieveSupport* pSupport = pSub->param; - tfree(pSupport->localBuffer); + taosTFree(pSupport->localBuffer); pthread_mutex_unlock(&pSupport->queryMutex); pthread_mutex_destroy(&pSupport->queryMutex); - tfree(pSupport); + taosTFree(pSupport); tscFreeSqlObj(pSub); } @@ -1358,7 +1358,7 @@ int32_t tscHandleMasterSTableQuery(SSqlObj *pSql) { if (ret != 0) { pRes->code = TSDB_CODE_TSC_OUT_OF_MEMORY; tscQueueAsyncRes(pSql); - tfree(pMemoryBuf); + taosTFree(pMemoryBuf); return ret; } @@ -1386,7 +1386,7 @@ int32_t tscHandleMasterSTableQuery(SSqlObj *pSql) { trs->localBuffer = (tFilePage *)calloc(1, nBufferSize + sizeof(tFilePage)); if (trs->localBuffer == NULL) { tscError("%p failed to malloc buffer for local buffer, orderOfSub:%d, reason:%s", pSql, i, strerror(errno)); - tfree(trs); + taosTFree(trs); break; } @@ -1404,8 +1404,8 @@ int32_t tscHandleMasterSTableQuery(SSqlObj *pSql) { SSqlObj *pNew = tscCreateSqlObjForSubquery(pSql, trs, NULL); if (pNew == NULL) { tscError("%p failed to malloc buffer for subObj, orderOfSub:%d, reason:%s", pSql, i, strerror(errno)); - tfree(trs->localBuffer); - tfree(trs); + taosTFree(trs->localBuffer); + taosTFree(trs); break; } @@ -1450,12 +1450,12 @@ static void tscFreeSubSqlObj(SRetrieveSupport *trsupport, SSqlObj *pSql) { taos_free_result(pSql); - tfree(trsupport->localBuffer); + taosTFree(trsupport->localBuffer); pthread_mutex_unlock(&trsupport->queryMutex); pthread_mutex_destroy(&trsupport->queryMutex); - tfree(trsupport); + taosTFree(trsupport); } static void tscRetrieveFromDnodeCallBack(void *param, TAOS_RES *tres, int numOfRows); @@ -1572,7 +1572,7 @@ void tscHandleSubqueryError(SRetrieveSupport *trsupport, SSqlObj *pSql, int numO tscLocalReducerEnvDestroy(trsupport->pExtMemBuffer, trsupport->pOrderDescriptor, trsupport->pFinalColModel, pState->numOfTotal); - tfree(trsupport->pState); + taosTFree(trsupport->pState); tscFreeSubSqlObj(trsupport, pSql); // in case of second stage join subquery, invoke its callback function instead of regular QueueAsyncRes @@ -1651,7 +1651,7 @@ static void tscAllDataRetrievedFromDnode(SRetrieveSupport *trsupport, SSqlObj* p pParentSql->res.row = 0; // only free once - tfree(trsupport->pState); + taosTFree(trsupport->pState); tscFreeSubSqlObj(trsupport, pSql); // set the command flag must be after the semaphore been correctly set. @@ -1855,7 +1855,7 @@ static void multiVnodeInsertFinalize(void* param, TAOS_RES* tres, int numOfRows) } taos_free_result(tres); - tfree(pSupporter); + taosTFree(pSupporter); if (atomic_sub_fetch_32(&pState->numOfRemain, 1) > 0) { return; @@ -1864,7 +1864,7 @@ static void multiVnodeInsertFinalize(void* param, TAOS_RES* tres, int numOfRows) tscDebug("%p Async insertion completed, total inserted:%" PRId64, pParentObj, pParentObj->res.numOfRows); // release data block data - tfree(pState); + taosTFree(pState); // restore user defined fp pParentObj->fp = pParentObj->fetchFp; @@ -1968,11 +1968,11 @@ int32_t tscHandleMultivnodeInsert(SSqlObj *pSql) { _error: for(int32_t j = 0; j < numOfSub; ++j) { - tfree(pSql->pSubs[j]->param); + taosTFree(pSql->pSubs[j]->param); taos_free_result(pSql->pSubs[j]); } - tfree(pState); + taosTFree(pState); return TSDB_CODE_TSC_OUT_OF_MEMORY; } @@ -2143,7 +2143,7 @@ void **doSetResultRowData(SSqlObj *pSql, bool finalResult) { assert(pRes->row >= 0 && pRes->row <= pRes->numOfRows); if (pRes->row >= pRes->numOfRows) { // all the results has returned to invoker - tfree(pRes->tsrow); + taosTFree(pRes->tsrow); return pRes->tsrow; } diff --git a/src/client/src/tscSystem.c b/src/client/src/tscSystem.c index 42356108b1..a252beec33 100644 --- a/src/client/src/tscSystem.c +++ b/src/client/src/tscSystem.c @@ -18,7 +18,6 @@ #include "tcache.h" #include "trpc.h" #include "tsystem.h" -#include "ttime.h" #include "ttimer.h" #include "tutil.h" #include "tsched.h" diff --git a/src/client/src/tscUtil.c b/src/client/src/tscUtil.c index 73d6f0e592..9e0ff8a9bf 100644 --- a/src/client/src/tscUtil.c +++ b/src/client/src/tscUtil.c @@ -245,7 +245,7 @@ void tscClearInterpInfo(SQueryInfo* pQueryInfo) { } pQueryInfo->fillType = TSDB_FILL_NONE; - tfree(pQueryInfo->fillVal); + taosTFree(pQueryInfo->fillVal); } int32_t tscCreateResPointerInfo(SSqlRes* pRes, SQueryInfo* pQueryInfo) { @@ -259,9 +259,9 @@ int32_t tscCreateResPointerInfo(SSqlRes* pRes, SQueryInfo* pQueryInfo) { // not enough memory if (pRes->tsrow == NULL || (pRes->buffer == NULL && pRes->numOfCols > 0)) { - tfree(pRes->tsrow); - tfree(pRes->buffer); - tfree(pRes->length); + taosTFree(pRes->tsrow); + taosTFree(pRes->buffer); + taosTFree(pRes->length); pRes->code = TSDB_CODE_TSC_OUT_OF_MEMORY; return pRes->code; @@ -274,23 +274,23 @@ int32_t tscCreateResPointerInfo(SSqlRes* pRes, SQueryInfo* pQueryInfo) { void tscDestroyResPointerInfo(SSqlRes* pRes) { if (pRes->buffer != NULL) { // free all buffers containing the multibyte string for (int i = 0; i < pRes->numOfCols; i++) { - tfree(pRes->buffer[i]); + taosTFree(pRes->buffer[i]); } pRes->numOfCols = 0; } - tfree(pRes->pRsp); - tfree(pRes->tsrow); - tfree(pRes->length); + taosTFree(pRes->pRsp); + taosTFree(pRes->tsrow); + taosTFree(pRes->length); - tfree(pRes->pGroupRec); - tfree(pRes->pColumnIndex); - tfree(pRes->buffer); + taosTFree(pRes->pGroupRec); + taosTFree(pRes->pColumnIndex); + taosTFree(pRes->buffer); if (pRes->pArithSup != NULL) { - tfree(pRes->pArithSup->data); - tfree(pRes->pArithSup); + taosTFree(pRes->pArithSup->data); + taosTFree(pRes->pArithSup); } pRes->data = NULL; // pRes->data points to the buffer of pRsp, no need to free @@ -307,11 +307,11 @@ static void tscFreeQueryInfo(SSqlCmd* pCmd) { freeQueryInfoImpl(pQueryInfo); clearAllTableMetaInfo(pQueryInfo, (const char*)addr, false); - tfree(pQueryInfo); + taosTFree(pQueryInfo); } pCmd->numOfClause = 0; - tfree(pCmd->pQueryInfo); + taosTFree(pCmd->pQueryInfo); } void tscResetSqlCmdObj(SSqlCmd* pCmd) { @@ -357,13 +357,13 @@ void tscPartiallyFreeSqlObj(SSqlObj* pSql) { // pSql->sqlstr will be used by tscBuildQueryStreamDesc if (pObj->signature == pObj) { //pthread_mutex_lock(&pObj->mutex); - tfree(pSql->sqlstr); + taosTFree(pSql->sqlstr); //pthread_mutex_unlock(&pObj->mutex); } tscFreeSqlResult(pSql); - tfree(pSql->pSubs); + taosTFree(pSql->pSubs); pSql->numOfSubs = 0; tscResetSqlCmdObj(pCmd); @@ -383,10 +383,10 @@ void tscFreeSqlObj(SSqlObj* pSql) { SSqlCmd* pCmd = &pSql->cmd; memset(pCmd->payload, 0, (size_t)pCmd->allocSize); - tfree(pCmd->payload); + taosTFree(pCmd->payload); pCmd->allocSize = 0; - tfree(pSql->sqlstr); + taosTFree(pSql->sqlstr); sem_destroy(&pSql->rspSem); free(pSql); } @@ -396,12 +396,12 @@ void tscDestroyDataBlock(STableDataBlocks* pDataBlock) { return; } - tfree(pDataBlock->pData); - tfree(pDataBlock->params); + taosTFree(pDataBlock->pData); + taosTFree(pDataBlock->params); // free the refcount for metermeta taosCacheRelease(tscCacheHandle, (void**)&(pDataBlock->pTableMeta), false); - tfree(pDataBlock); + taosTFree(pDataBlock); } SParamInfo* tscAddParamToDataBlock(STableDataBlocks* pDataBlock, char type, uint8_t timePrec, short bytes, @@ -679,7 +679,7 @@ int32_t tscMergeTableDataBlocks(SSqlObj* pSql, SArray* pTableDataBlockList) { taosHashCleanup(pVnodeDataBlockHashList); tscDestroyBlockArrayList(pVnodeDataBlockList); - tfree(dataBuf->pData); + taosTFree(dataBuf->pData); return TSDB_CODE_TSC_OUT_OF_MEMORY; } @@ -735,7 +735,7 @@ void tscCloseTscObj(STscObj* pObj) { } tscDebug("%p DB connection is closed, dnodeConn:%p", pObj, pObj->pDnodeConn); - tfree(pObj); + taosTFree(pObj); } bool tscIsInsertData(char* sqlstr) { @@ -916,7 +916,7 @@ void tscFieldInfoClear(SFieldInfo* pFieldInfo) { if (pInfo->pArithExprInfo != NULL) { tExprTreeDestroy(&pInfo->pArithExprInfo->pExpr, NULL); - tfree(pInfo->pArithExprInfo); + taosTFree(pInfo->pArithExprInfo); } } @@ -1029,7 +1029,7 @@ void* sqlExprDestroy(SSqlExpr* pExpr) { tVariantDestroy(&pExpr->param[i]); } - tfree(pExpr); + taosTFree(pExpr); return NULL; } @@ -1116,11 +1116,11 @@ SColumn* tscColumnListInsert(SArray* pColumnList, SColumnIndex* pColIndex) { static void destroyFilterInfo(SColumnFilterInfo* pFilterInfo, int32_t numOfFilters) { for(int32_t i = 0; i < numOfFilters; ++i) { if (pFilterInfo[i].filterstr) { - tfree(pFilterInfo[i].pz); + taosTFree(pFilterInfo[i].pz); } } - tfree(pFilterInfo); + taosTFree(pFilterInfo); } SColumn* tscColumnClone(const SColumn* src) { @@ -1351,7 +1351,7 @@ void tscTagCondRelease(STagCond* pTagCond) { size_t s = taosArrayGetSize(pTagCond->pCond); for (int32_t i = 0; i < s; ++i) { SCond* p = taosArrayGet(pTagCond->pCond, i); - tfree(p->cond); + taosTFree(p->cond); } taosArrayDestroy(pTagCond->pCond); @@ -1546,7 +1546,7 @@ static void freeQueryInfoImpl(SQueryInfo* pQueryInfo) { pQueryInfo->tsBuf = tsBufDestroy(pQueryInfo->tsBuf); - tfree(pQueryInfo->fillVal); + taosTFree(pQueryInfo->fillVal); } void tscClearSubqueryInfo(SSqlCmd* pCmd) { @@ -1566,7 +1566,7 @@ void clearAllTableMetaInfo(SQueryInfo* pQueryInfo, const char* address, bool rem free(pTableMetaInfo); } - tfree(pQueryInfo->pTableMetaInfo); + taosTFree(pQueryInfo->pTableMetaInfo); } STableMetaInfo* tscAddTableMetaInfo(SQueryInfo* pQueryInfo, const char* name, STableMeta* pTableMeta, @@ -1613,7 +1613,7 @@ void tscClearTableMetaInfo(STableMetaInfo* pTableMetaInfo, bool removeFromCache) } taosCacheRelease(tscCacheHandle, (void**)&(pTableMetaInfo->pTableMeta), removeFromCache); - tfree(pTableMetaInfo->vgroupList); + taosTFree(pTableMetaInfo->vgroupList); tscColumnListDestroy(pTableMetaInfo->tagColList); pTableMetaInfo->tagColList = NULL; @@ -2084,7 +2084,7 @@ void tscTryQueryNextClause(SSqlObj* pSql, __async_cb_func_t fp) { pRes->numOfTotal = num; - tfree(pSql->pSubs); + taosTFree(pSql->pSubs); pSql->numOfSubs = 0; pSql->fp = fp; diff --git a/src/client/tests/timeParseTest.cpp b/src/client/tests/timeParseTest.cpp index b37be0485b..bee01b5cec 100644 --- a/src/client/tests/timeParseTest.cpp +++ b/src/client/tests/timeParseTest.cpp @@ -1,10 +1,10 @@ +#include "os.h" #include #include #include #include "taos.h" #include "tstoken.h" -#include "ttime.h" #include "tutil.h" int main(int argc, char** argv) { diff --git a/src/common/inc/tdataformat.h b/src/common/inc/tdataformat.h index 68875341ba..6c6e5e35d8 100644 --- a/src/common/inc/tdataformat.h +++ b/src/common/inc/tdataformat.h @@ -80,7 +80,7 @@ typedef struct { #define schemaFLen(s) ((s)->flen) #define schemaVLen(s) ((s)->vlen) #define schemaColAt(s, i) ((s)->columns + i) -#define tdFreeSchema(s) tfree((s)) +#define tdFreeSchema(s) taosTFree((s)) STSchema *tdDupSchema(STSchema *pSchema); int tdEncodeSchema(void **buf, STSchema *pSchema); @@ -284,7 +284,7 @@ typedef struct { #define kvRowCpy(dst, r) memcpy((dst), (r), kvRowLen(r)) #define kvRowColVal(r, colIdx) POINTER_SHIFT(kvRowValues(r), (colIdx)->offset) #define kvRowColIdxAt(r, i) (kvRowColIdx(r) + (i)) -#define kvRowFree(r) tfree(r) +#define kvRowFree(r) taosTFree(r) #define kvRowEnd(r) POINTER_SHIFT(r, kvRowLen(r)) SKVRow tdKVRowDup(SKVRow row); diff --git a/src/common/src/tdataformat.c b/src/common/src/tdataformat.c index adfce5580e..a185a9de7b 100644 --- a/src/common/src/tdataformat.c +++ b/src/common/src/tdataformat.c @@ -93,7 +93,7 @@ int tdInitTSchemaBuilder(STSchemaBuilder *pBuilder, int32_t version) { void tdDestroyTSchemaBuilder(STSchemaBuilder *pBuilder) { if (pBuilder) { - tfree(pBuilder->columns); + taosTFree(pBuilder->columns); } } @@ -361,8 +361,8 @@ int tdInitDataCols(SDataCols *pCols, STSchema *pSchema) { void tdFreeDataCols(SDataCols *pCols) { if (pCols) { - tfree(pCols->buf); - tfree(pCols->cols); + taosTFree(pCols->buf); + taosTFree(pCols->cols); free(pCols); } } @@ -685,8 +685,8 @@ int tdInitKVRowBuilder(SKVRowBuilder *pBuilder) { } void tdDestroyKVRowBuilder(SKVRowBuilder *pBuilder) { - tfree(pBuilder->pColIdx); - tfree(pBuilder->buf); + taosTFree(pBuilder->pColIdx); + taosTFree(pBuilder->buf); } void tdResetKVRowBuilder(SKVRowBuilder *pBuilder) { diff --git a/src/common/src/tvariant.c b/src/common/src/tvariant.c index 1b64a7aefa..2906b3f0ac 100644 --- a/src/common/src/tvariant.c +++ b/src/common/src/tvariant.c @@ -128,7 +128,7 @@ void tVariantDestroy(tVariant *pVar) { if (pVar == NULL) return; if (pVar->nType == TSDB_DATA_TYPE_BINARY || pVar->nType == TSDB_DATA_TYPE_NCHAR) { - tfree(pVar->pz); + taosTFree(pVar->pz); pVar->nLen = 0; } diff --git a/src/cq/src/cqMain.c b/src/cq/src/cqMain.c index e0f30166c4..758d620e57 100644 --- a/src/cq/src/cqMain.c +++ b/src/cq/src/cqMain.c @@ -114,7 +114,7 @@ void cqClose(void *handle) { SCqObj *pTemp = pObj; pObj = pObj->next; tdFreeSchema(pTemp->pSchema); - tfree(pTemp->sqlStr); + taosTFree(pTemp->sqlStr); free(pTemp); } diff --git a/src/dnode/src/dnodeMPeer.c b/src/dnode/src/dnodeMPeer.c index 85230c7da9..82ed7dd179 100644 --- a/src/dnode/src/dnodeMPeer.c +++ b/src/dnode/src/dnodeMPeer.c @@ -75,7 +75,7 @@ void dnodeCleanupMnodePeer() { } taosCloseQset(tsMPeerQset); - tfree(tsMPeerPool.peerWorker); + taosTFree(tsMPeerPool.peerWorker); dInfo("dnode mpeer is closed"); } diff --git a/src/dnode/src/dnodeMWrite.c b/src/dnode/src/dnodeMWrite.c index b53c66e00c..0a305b5598 100644 --- a/src/dnode/src/dnodeMWrite.c +++ b/src/dnode/src/dnodeMWrite.c @@ -77,7 +77,7 @@ void dnodeCleanupMnodeWrite() { } taosCloseQset(tsMWriteQset); - tfree(tsMWritePool.writeWorker); + taosTFree(tsMWritePool.writeWorker); dInfo("dnode mwrite is closed"); } diff --git a/src/dnode/src/dnodeMgmt.c b/src/dnode/src/dnodeMgmt.c index ec35475d73..745ffb3b84 100644 --- a/src/dnode/src/dnodeMgmt.c +++ b/src/dnode/src/dnodeMgmt.c @@ -18,13 +18,11 @@ #include "cJSON.h" #include "taoserror.h" #include "taosmsg.h" -#include "ttime.h" #include "ttimer.h" #include "tsdb.h" #include "twal.h" #include "tqueue.h" #include "tsync.h" -#include "ttime.h" #include "ttimer.h" #include "tbalance.h" #include "tglobal.h" diff --git a/src/kit/shell/src/shellDarwin.c b/src/kit/shell/src/shellDarwin.c index 1a75a2aa85..3cb324abe9 100644 --- a/src/kit/shell/src/shellDarwin.c +++ b/src/kit/shell/src/shellDarwin.c @@ -229,8 +229,8 @@ void shellReadCommand(TAOS *con, char *command) { printf("\n"); if (isReadyGo(&cmd)) { sprintf(command, "%s%s", cmd.buffer, cmd.command); - tfree(cmd.buffer); - tfree(cmd.command); + taosTFree(cmd.buffer); + taosTFree(cmd.command); return; } else { updateBuffer(&cmd); diff --git a/src/kit/shell/src/shellEngine.c b/src/kit/shell/src/shellEngine.c index 616a3bfd7f..5d877ba6f0 100644 --- a/src/kit/shell/src/shellEngine.c +++ b/src/kit/shell/src/shellEngine.c @@ -21,7 +21,6 @@ #include "os.h" #include "shell.h" #include "shellCommand.h" -#include "ttime.h" #include "tutil.h" #include "taosdef.h" #include "taoserror.h" @@ -176,7 +175,7 @@ int32_t shellRunCommand(TAOS* con, char* command) { history.hist[(history.hend + MAX_HISTORY_SIZE - 1) % MAX_HISTORY_SIZE] == NULL || strcmp(command, history.hist[(history.hend + MAX_HISTORY_SIZE - 1) % MAX_HISTORY_SIZE]) != 0) { if (history.hist[history.hend] != NULL) { - tfree(history.hist[history.hend]); + taosTFree(history.hist[history.hend]); } history.hist[history.hend] = strdup(command); @@ -770,7 +769,7 @@ void write_history() { for (int i = history.hstart; i != history.hend;) { if (history.hist[i] != NULL) { fprintf(f, "%s\n", history.hist[i]); - tfree(history.hist[i]); + taosTFree(history.hist[i]); } i = (i + 1) % MAX_HISTORY_SIZE; } diff --git a/src/kit/shell/src/shellImport.c b/src/kit/shell/src/shellImport.c index afd2d85dae..ee0a90757b 100644 --- a/src/kit/shell/src/shellImport.c +++ b/src/kit/shell/src/shellImport.c @@ -21,7 +21,6 @@ #include "shell.h" #include "shellCommand.h" #include "tglobal.h" -#include "ttime.h" #include "tutil.h" static char **shellSQLFiles = NULL; diff --git a/src/kit/shell/src/shellLinux.c b/src/kit/shell/src/shellLinux.c index 94f3901dd8..963afe346d 100644 --- a/src/kit/shell/src/shellLinux.c +++ b/src/kit/shell/src/shellLinux.c @@ -201,8 +201,8 @@ void shellReadCommand(TAOS *con, char *command) { printf("\n"); if (isReadyGo(&cmd)) { sprintf(command, "%s%s", cmd.buffer, cmd.command); - tfree(cmd.buffer); - tfree(cmd.command); + taosTFree(cmd.buffer); + taosTFree(cmd.command); return; } else { updateBuffer(&cmd); @@ -320,7 +320,7 @@ void *shellLoopQuery(void *arg) { reset_terminal_mode(); } while (shellRunCommand(con, command) == 0); - tfree(command); + taosTFree(command); exitShell(); pthread_cleanup_pop(1); diff --git a/src/kit/taosdump/taosdump.c b/src/kit/taosdump/taosdump.c index 7ae209bbdf..ee98c711e0 100644 --- a/src/kit/taosdump/taosdump.c +++ b/src/kit/taosdump/taosdump.c @@ -448,8 +448,8 @@ int main(int argc, char *argv[]) { void taosFreeDbInfos() { if (dbInfos == NULL) return; - for (int i = 0; i < 128; i++) tfree(dbInfos[i]); - tfree(dbInfos); + for (int i = 0; i < 128; i++) taosTFree(dbInfos[i]); + taosTFree(dbInfos); } // check table is normal table or super table @@ -606,11 +606,11 @@ int32_t taosSaveTableOfMetricToTempFile(TAOS *taosCon, char* metric, struct argu if (numOfTable >= arguments->table_batch) { numOfTable = 0; - tclose(fd); + taosClose(fd); fd = -1; } } - tclose(fd); + taosClose(fd); fd = -1; taos_free_result(result); @@ -780,14 +780,14 @@ int taosDumpOut(struct arguments *arguments) { if (retCode < 0) { if (-1 != normalTblFd){ - tclose(normalTblFd); + taosClose(normalTblFd); } goto _clean_tmp_file; } } if (-1 != normalTblFd){ - tclose(normalTblFd); + taosClose(normalTblFd); } // start multi threads to dumpout @@ -806,7 +806,7 @@ int taosDumpOut(struct arguments *arguments) { fclose(fp); taos_close(taos); taos_free_result(result); - tfree(command); + taosTFree(command); taosFreeDbInfos(); fprintf(stderr, "dump out rows: %" PRId64 "\n", totalDumpOutRows); return 0; @@ -815,7 +815,7 @@ _exit_failure: fclose(fp); taos_close(taos); taos_free_result(result); - tfree(command); + taosTFree(command); taosFreeDbInfos(); fprintf(stderr, "dump out rows: %" PRId64 "\n", totalDumpOutRows); return -1; @@ -1076,7 +1076,7 @@ void* taosDumpOutWorkThreadFp(void *arg) } taos_free_result(tmpResult); - tclose(fd); + taosClose(fd); fclose(fp); return NULL; @@ -1206,7 +1206,7 @@ int32_t taosDumpCreateSuperTableClause(TAOS* taosCon, char* dbName, FILE *fp) (void)taosDumpStable(tableRecord.name, fp, taosCon); } - tclose(fd); + taosClose(fd); remove(".stables.tmp"); free(tmpCommand); @@ -1288,11 +1288,11 @@ int taosDumpDb(SDbInfo *dbInfo, struct arguments *arguments, FILE *fp, TAOS *tao if (numOfTable >= arguments->table_batch) { numOfTable = 0; - tclose(fd); + taosClose(fd); fd = -1; } } - tclose(fd); + taosClose(fd); fd = -1; taos_free_result(tmpResult); @@ -1760,13 +1760,13 @@ void taosLoadFileCharset(FILE *fp, char *fcharset) { } strcpy(fcharset, line + 2); - tfree(line); + taosTFree(line); return; _exit_no_charset: fseek(fp, 0, SEEK_SET); *fcharset = '\0'; - tfree(line); + taosTFree(line); return; } @@ -1860,9 +1860,9 @@ static void taosMallocSQLFiles() static void taosFreeSQLFiles() { for (int i = 0; i < tsSqlFileNum; i++) { - tfree(tsDumpInSqlFiles[i]); + taosTFree(tsDumpInSqlFiles[i]); } - tfree(tsDumpInSqlFiles); + taosTFree(tsDumpInSqlFiles); } static void taosGetDirectoryFileList(char *inputDir) @@ -2063,17 +2063,17 @@ int taosDumpInOneFile_old(TAOS * taos, FILE* fp, char* fcharset, char* encod } if (cd != ((iconv_t)(-1))) iconv_close(cd); - tfree(line); - tfree(command); - tfree(lcommand); + taosTFree(line); + taosTFree(command); + taosTFree(lcommand); taos_close(taos); fclose(fp); return 0; _dumpin_exit_failure: if (cd != ((iconv_t)(-1))) iconv_close(cd); - tfree(command); - tfree(lcommand); + taosTFree(command); + taosTFree(lcommand); taos_close(taos); fclose(fp); return -1; @@ -2120,8 +2120,8 @@ int taosDumpInOneFile(TAOS * taos, FILE* fp, char* fcharset, char* encode, c cmd_len = 0; } - tfree(cmd); - tfree(line); + taosTFree(cmd); + taosTFree(line); fclose(fp); return 0; } diff --git a/src/kit/taosmigrate/taosmigrateVnodeCfg.c b/src/kit/taosmigrate/taosmigrateVnodeCfg.c index e80e687f02..472671c22c 100644 --- a/src/kit/taosmigrate/taosmigrateVnodeCfg.c +++ b/src/kit/taosmigrate/taosmigrateVnodeCfg.c @@ -289,7 +289,7 @@ static int32_t readVnodeCfg(SVnodeObj *pVnode, char* cfgFile) //} PARSE_OVER: - tfree(content); + taosTFree(content); cJSON_Delete(root); if (fp) fclose(fp); return ret; diff --git a/src/mnode/src/mnodeAcct.c b/src/mnode/src/mnodeAcct.c index c40a696ede..5244bc3e85 100644 --- a/src/mnode/src/mnodeAcct.c +++ b/src/mnode/src/mnodeAcct.c @@ -16,7 +16,6 @@ #define _DEFAULT_SOURCE #include "os.h" #include "taoserror.h" -#include "ttime.h" #include "dnode.h" #include "mnodeDef.h" #include "mnodeInt.h" @@ -34,7 +33,7 @@ static int32_t mnodeCreateRootAcct(); static int32_t mnodeAcctActionDestroy(SSdbOper *pOper) { SAcctObj *pAcct = pOper->pObj; pthread_mutex_destroy(&pAcct->mutex); - tfree(pOper->pObj); + taosTFree(pOper->pObj); return TSDB_CODE_SUCCESS; } diff --git a/src/mnode/src/mnodeCluster.c b/src/mnode/src/mnodeCluster.c index 41727712b5..5231b7bcd3 100644 --- a/src/mnode/src/mnodeCluster.c +++ b/src/mnode/src/mnodeCluster.c @@ -16,7 +16,6 @@ #define _DEFAULT_SOURCE #include "os.h" #include "taoserror.h" -#include "ttime.h" #include "dnode.h" #include "mnodeDef.h" #include "mnodeInt.h" @@ -34,7 +33,7 @@ static int32_t mnodeGetClusterMeta(STableMetaMsg *pMeta, SShowObj *pShow, void * static int32_t mnodeRetrieveClusters(SShowObj *pShow, char *data, int32_t rows, void *pConn); static int32_t mnodeClusterActionDestroy(SSdbOper *pOper) { - tfree(pOper->pObj); + taosTFree(pOper->pObj); return TSDB_CODE_SUCCESS; } diff --git a/src/mnode/src/mnodeDb.c b/src/mnode/src/mnodeDb.c index 82ac0868d1..c7e3085e69 100644 --- a/src/mnode/src/mnodeDb.c +++ b/src/mnode/src/mnodeDb.c @@ -19,7 +19,6 @@ #include "tutil.h" #include "tgrant.h" #include "tglobal.h" -#include "ttime.h" #include "tname.h" #include "tbalance.h" #include "tdataformat.h" @@ -53,8 +52,8 @@ static int32_t mnodeProcessDropDbMsg(SMnodeMsg *pMsg); static void mnodeDestroyDb(SDbObj *pDb) { pthread_mutex_destroy(&pDb->mutex); - tfree(pDb->vgList); - tfree(pDb); + taosTFree(pDb->vgList); + taosTFree(pDb); } static int32_t mnodeDbActionDestroy(SSdbOper *pOper) { @@ -386,7 +385,7 @@ static int32_t mnodeCreateDb(SAcctObj *pAcct, SCMCreateDbMsg *pCreate, void *pMs code = mnodeCheckDbCfg(&pDb->cfg); if (code != TSDB_CODE_SUCCESS) { - tfree(pDb); + taosTFree(pDb); return code; } diff --git a/src/mnode/src/mnodeDnode.c b/src/mnode/src/mnodeDnode.c index be15abe354..06c343a903 100644 --- a/src/mnode/src/mnodeDnode.c +++ b/src/mnode/src/mnodeDnode.c @@ -19,7 +19,6 @@ #include "tbalance.h" #include "tglobal.h" #include "tconfig.h" -#include "ttime.h" #include "tutil.h" #include "tsocket.h" #include "tbalance.h" @@ -62,7 +61,7 @@ static int32_t mnodeRetrieveDnodes(SShowObj *pShow, char *data, int32_t rows, vo static char* mnodeGetDnodeAlternativeRoleStr(int32_t alternativeRole); static int32_t mnodeDnodeActionDestroy(SSdbOper *pOper) { - tfree(pOper->pObj); + taosTFree(pOper->pObj); return TSDB_CODE_SUCCESS; } @@ -504,7 +503,7 @@ static int32_t mnodeCreateDnode(char *ep, SMnodeMsg *pMsg) { int32_t code = sdbInsertRow(&oper); if (code != TSDB_CODE_SUCCESS && code != TSDB_CODE_MND_ACTION_IN_PROGRESS) { int dnodeId = pDnode->dnodeId; - tfree(pDnode); + taosTFree(pDnode); mError("failed to create dnode:%d, reason:%s", dnodeId, tstrerror(code)); } else { mLInfo("dnode:%d is created", pDnode->dnodeId); diff --git a/src/mnode/src/mnodeMnode.c b/src/mnode/src/mnodeMnode.c index 5f82a9afad..c762403525 100644 --- a/src/mnode/src/mnodeMnode.c +++ b/src/mnode/src/mnodeMnode.c @@ -21,7 +21,6 @@ #include "tsync.h" #include "tbalance.h" #include "tutil.h" -#include "ttime.h" #include "tsocket.h" #include "tdataformat.h" #include "mnodeDef.h" @@ -57,7 +56,7 @@ static int32_t mnodeRetrieveMnodes(SShowObj *pShow, char *data, int32_t rows, vo #endif static int32_t mnodeMnodeActionDestroy(SSdbOper *pOper) { - tfree(pOper->pObj); + taosTFree(pOper->pObj); return TSDB_CODE_SUCCESS; } @@ -279,7 +278,7 @@ int32_t mnodeAddMnode(int32_t dnodeId) { int32_t code = sdbInsertRow(&oper); if (code != TSDB_CODE_SUCCESS && code != TSDB_CODE_MND_ACTION_IN_PROGRESS) { - tfree(pMnode); + taosTFree(pMnode); } mnodeUpdateMnodeEpSet(); diff --git a/src/mnode/src/mnodeProfile.c b/src/mnode/src/mnodeProfile.c index ff4ddf1b2a..353dd59671 100644 --- a/src/mnode/src/mnodeProfile.c +++ b/src/mnode/src/mnodeProfile.c @@ -18,7 +18,6 @@ #include "taosmsg.h" #include "taoserror.h" #include "tutil.h" -#include "ttime.h" #include "tcache.h" #include "tglobal.h" #include "tdataformat.h" @@ -133,8 +132,8 @@ SConnObj *mnodeAccquireConn(int32_t connId, char *user, uint32_t ip, uint16_t po static void mnodeFreeConn(void *data) { SConnObj *pConn = data; - tfree(pConn->pQueries); - tfree(pConn->pStreams); + taosTFree(pConn->pQueries); + taosTFree(pConn->pStreams); mDebug("connId:%d, is destroyed", pConn->connId); } diff --git a/src/mnode/src/mnodeSdb.c b/src/mnode/src/mnodeSdb.c index f3f6e33431..a4c2c60aa3 100644 --- a/src/mnode/src/mnodeSdb.c +++ b/src/mnode/src/mnodeSdb.c @@ -934,7 +934,7 @@ void sdbCleanupWriteWorker() { } sdbFreeWritequeue(); - tfree(tsSdbPool.writeWorker); + taosTFree(tsSdbPool.writeWorker); mInfo("sdb write is closed"); } diff --git a/src/mnode/src/mnodeShow.c b/src/mnode/src/mnodeShow.c index 733bd43c74..995bfbe840 100644 --- a/src/mnode/src/mnodeShow.c +++ b/src/mnode/src/mnodeShow.c @@ -403,7 +403,7 @@ static void mnodeFreeShowObj(void *data) { sdbFreeIter(pShow->pIter); mDebug("%p, show is destroyed, data:%p index:%d", pShow, data, pShow->index); - tfree(pShow); + taosTFree(pShow); } static void mnodeReleaseShowObj(SShowObj *pShow, bool forceRemove) { diff --git a/src/mnode/src/mnodeTable.c b/src/mnode/src/mnodeTable.c index 009633b43b..1c39ef3294 100644 --- a/src/mnode/src/mnodeTable.c +++ b/src/mnode/src/mnodeTable.c @@ -16,7 +16,6 @@ #define _DEFAULT_SOURCE #include "os.h" #include "taosmsg.h" -#include "ttime.h" #include "tutil.h" #include "taoserror.h" #include "taosmsg.h" @@ -90,10 +89,10 @@ static void mnodeProcessAlterTableRsp(SRpcMsg *rpcMsg); static int32_t mnodeFindSuperTableColumnIndex(SSuperTableObj *pStable, char *colName); static void mnodeDestroyChildTable(SChildTableObj *pTable) { - tfree(pTable->info.tableId); - tfree(pTable->schema); - tfree(pTable->sql); - tfree(pTable); + taosTFree(pTable->info.tableId); + taosTFree(pTable->schema); + taosTFree(pTable->sql); + taosTFree(pTable); } static int32_t mnodeChildTableActionDestroy(SSdbOper *pOper) { @@ -411,9 +410,9 @@ static void mnodeDestroySuperTable(SSuperTableObj *pStable) { taosHashCleanup(pStable->vgHash); pStable->vgHash = NULL; } - tfree(pStable->info.tableId); - tfree(pStable->schema); - tfree(pStable); + taosTFree(pStable->info.tableId); + taosTFree(pStable->schema); + taosTFree(pStable); } static int32_t mnodeSuperTableActionDestroy(SSdbOper *pOper) { diff --git a/src/mnode/src/mnodeUser.c b/src/mnode/src/mnodeUser.c index a875cff4a2..765661ac71 100644 --- a/src/mnode/src/mnodeUser.c +++ b/src/mnode/src/mnodeUser.c @@ -16,7 +16,6 @@ #define _DEFAULT_SOURCE #include "os.h" #include "trpc.h" -#include "ttime.h" #include "tutil.h" #include "tglobal.h" #include "tgrant.h" @@ -43,7 +42,7 @@ static int32_t mnodeProcessDropUserMsg(SMnodeMsg *pMsg); static int32_t mnodeProcessAuthMsg(SMnodeMsg *pMsg); static int32_t mnodeUserActionDestroy(SSdbOper *pOper) { - tfree(pOper->pObj); + taosTFree(pOper->pObj); return TSDB_CODE_SUCCESS; } @@ -239,7 +238,7 @@ int32_t mnodeCreateUser(SAcctObj *pAcct, char *name, char *pass, void *pMsg) { code = sdbInsertRow(&oper); if (code != TSDB_CODE_SUCCESS && code != TSDB_CODE_MND_ACTION_IN_PROGRESS) { mError("user:%s, failed to create by %s, reason:%s", pUser->user, mnodeGetUserFromMsg(pMsg), tstrerror(code)); - tfree(pUser); + taosTFree(pUser); } else { mLInfo("user:%s, is created by %s", pUser->user, mnodeGetUserFromMsg(pMsg)); } diff --git a/src/mnode/src/mnodeVgroup.c b/src/mnode/src/mnodeVgroup.c index 91aa3fdec2..e46da1d892 100644 --- a/src/mnode/src/mnodeVgroup.c +++ b/src/mnode/src/mnodeVgroup.c @@ -20,7 +20,6 @@ #include "tsocket.h" #include "tidpool.h" #include "tsync.h" -#include "ttime.h" #include "tbalance.h" #include "tglobal.h" #include "tdataformat.h" @@ -70,7 +69,7 @@ static void mnodeDestroyVgroup(SVgObj *pVgroup) { pVgroup->idPool = NULL; } - tfree(pVgroup); + taosTFree(pVgroup); } static int32_t mnodeVgroupActionDestroy(SSdbOper *pOper) { diff --git a/src/os/inc/os.h b/src/os/inc/os.h index 896f3afc7a..70f8487baa 100644 --- a/src/os/inc/os.h +++ b/src/os/inc/os.h @@ -44,7 +44,23 @@ extern "C" { #include "osWindows32.h" #endif -#include "osSpec.h" +#include "osAtomic.h" +#include "osDef.h" +#include "osDir.h" +#include "osFile.h" +#include "osLz4.h" +#include "osMath.h" +#include "osMemory.h" +#include "osPthread.h" +#include "osRand.h" +#include "osSemphone.h" +#include "osSocket.h" +#include "osString.h" +#include "osSysinfo.h" +#include "osTime.h" +#include "osTimer.h" + +void osInit(); #ifdef __cplusplus } diff --git a/src/os/inc/osAtomic.h b/src/os/inc/osAtomic.h new file mode 100644 index 0000000000..803c351400 --- /dev/null +++ b/src/os/inc/osAtomic.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef TDENGINE_OS_ATOMIC_H +#define TDENGINE_OS_ATOMIC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef TAOS_OS_FUNC_ATOMIC + #define atomic_load_8(ptr) __atomic_load_n((ptr), __ATOMIC_SEQ_CST) + #define atomic_load_16(ptr) __atomic_load_n((ptr), __ATOMIC_SEQ_CST) + #define atomic_load_32(ptr) __atomic_load_n((ptr), __ATOMIC_SEQ_CST) + #define atomic_load_64(ptr) __atomic_load_n((ptr), __ATOMIC_SEQ_CST) + #define atomic_load_ptr(ptr) __atomic_load_n((ptr), __ATOMIC_SEQ_CST) + + #define atomic_store_8(ptr, val) __atomic_store_n((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_store_16(ptr, val) __atomic_store_n((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_store_32(ptr, val) __atomic_store_n((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_store_64(ptr, val) __atomic_store_n((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_store_ptr(ptr, val) __atomic_store_n((ptr), (val), __ATOMIC_SEQ_CST) + + #define atomic_exchange_8(ptr, val) __atomic_exchange_n((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_exchange_16(ptr, val) __atomic_exchange_n((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_exchange_32(ptr, val) __atomic_exchange_n((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_exchange_64(ptr, val) __atomic_exchange_n((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_exchange_ptr(ptr, val) __atomic_exchange_n((ptr), (val), __ATOMIC_SEQ_CST) + + #define atomic_val_compare_exchange_8 __sync_val_compare_and_swap + #define atomic_val_compare_exchange_16 __sync_val_compare_and_swap + #define atomic_val_compare_exchange_32 __sync_val_compare_and_swap + #define atomic_val_compare_exchange_64 __sync_val_compare_and_swap + #define atomic_val_compare_exchange_ptr __sync_val_compare_and_swap + + #define atomic_add_fetch_8(ptr, val) __atomic_add_fetch((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_add_fetch_16(ptr, val) __atomic_add_fetch((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_add_fetch_32(ptr, val) __atomic_add_fetch((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_add_fetch_64(ptr, val) __atomic_add_fetch((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_add_fetch_ptr(ptr, val) __atomic_add_fetch((ptr), (val), __ATOMIC_SEQ_CST) + + #define atomic_fetch_add_8(ptr, val) __atomic_fetch_add((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_fetch_add_16(ptr, val) __atomic_fetch_add((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_fetch_add_32(ptr, val) __atomic_fetch_add((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_fetch_add_64(ptr, val) __atomic_fetch_add((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_fetch_add_ptr(ptr, val) __atomic_fetch_add((ptr), (val), __ATOMIC_SEQ_CST) + + #define atomic_sub_fetch_8(ptr, val) __atomic_sub_fetch((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_sub_fetch_16(ptr, val) __atomic_sub_fetch((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_sub_fetch_32(ptr, val) __atomic_sub_fetch((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_sub_fetch_64(ptr, val) __atomic_sub_fetch((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_sub_fetch_ptr(ptr, val) __atomic_sub_fetch((ptr), (val), __ATOMIC_SEQ_CST) + + #define atomic_fetch_sub_8(ptr, val) __atomic_fetch_sub((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_fetch_sub_16(ptr, val) __atomic_fetch_sub((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_fetch_sub_32(ptr, val) __atomic_fetch_sub((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_fetch_sub_64(ptr, val) __atomic_fetch_sub((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_fetch_sub_ptr(ptr, val) __atomic_fetch_sub((ptr), (val), __ATOMIC_SEQ_CST) + + #define atomic_and_fetch_8(ptr, val) __atomic_and_fetch((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_and_fetch_16(ptr, val) __atomic_and_fetch((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_and_fetch_32(ptr, val) __atomic_and_fetch((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_and_fetch_64(ptr, val) __atomic_and_fetch((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_and_fetch_ptr(ptr, val) __atomic_and_fetch((ptr), (val), __ATOMIC_SEQ_CST) + + #define atomic_fetch_and_8(ptr, val) __atomic_fetch_and((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_fetch_and_16(ptr, val) __atomic_fetch_and((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_fetch_and_32(ptr, val) __atomic_fetch_and((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_fetch_and_64(ptr, val) __atomic_fetch_and((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_fetch_and_ptr(ptr, val) __atomic_fetch_and((ptr), (val), __ATOMIC_SEQ_CST) + + #define atomic_or_fetch_8(ptr, val) __atomic_or_fetch((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_or_fetch_16(ptr, val) __atomic_or_fetch((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_or_fetch_32(ptr, val) __atomic_or_fetch((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_or_fetch_64(ptr, val) __atomic_or_fetch((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_or_fetch_ptr(ptr, val) __atomic_or_fetch((ptr), (val), __ATOMIC_SEQ_CST) + + #define atomic_fetch_or_8(ptr, val) __atomic_fetch_or((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_fetch_or_16(ptr, val) __atomic_fetch_or((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_fetch_or_32(ptr, val) __atomic_fetch_or((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_fetch_or_64(ptr, val) __atomic_fetch_or((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_fetch_or_ptr(ptr, val) __atomic_fetch_or((ptr), (val), __ATOMIC_SEQ_CST) + + #define atomic_xor_fetch_8(ptr, val) __atomic_xor_fetch((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_xor_fetch_16(ptr, val) __atomic_xor_fetch((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_xor_fetch_32(ptr, val) __atomic_xor_fetch((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_xor_fetch_64(ptr, val) __atomic_xor_fetch((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_xor_fetch_ptr(ptr, val) __atomic_xor_fetch((ptr), (val), __ATOMIC_SEQ_CST) + + #define atomic_fetch_xor_8(ptr, val) __atomic_fetch_xor((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_fetch_xor_16(ptr, val) __atomic_fetch_xor((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_fetch_xor_32(ptr, val) __atomic_fetch_xor((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_fetch_xor_64(ptr, val) __atomic_fetch_xor((ptr), (val), __ATOMIC_SEQ_CST) + #define atomic_fetch_xor_ptr(ptr, val) __atomic_fetch_xor((ptr), (val), __ATOMIC_SEQ_CST) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/os/inc/osDef.h b/src/os/inc/osDef.h new file mode 100644 index 0000000000..81c70a58fd --- /dev/null +++ b/src/os/inc/osDef.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef TDENGINE_OS_DEF_H +#define TDENGINE_OS_DEF_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef STDERR_FILENO +#define STDERR_FILENO (2) +#endif + +#define FD_VALID(x) ((x) > STDERR_FILENO) +#define FD_INITIALIZER ((int32_t)-1) + +#define WCHAR wchar_t + +#define POINTER_SHIFT(p, b) ((void *)((char *)(p) + (b))) +#define POINTER_DISTANCE(p1, p2) ((char *)(p1) - (char *)(p2)) + +#ifndef NDEBUG +#define ASSERT(x) assert(x) +#else +#define ASSERT(x) +#endif + +#ifdef UNUSED +#undefine UNUSED +#endif +#define UNUSED(x) ((void)(x)) + +#ifdef UNUSED_FUNC +#undefine UNUSED_FUNC +#endif + +#ifdef UNUSED_PARAM +#undef UNUSED_PARAM +#endif + +#if defined(__GNUC__) +#define UNUSED_PARAM(x) _UNUSED##x __attribute__((unused)) +#define UNUSED_FUNC __attribute__((unused)) +#else +#define UNUSED_PARAM(x) x +#define UNUSED_FUNC +#endif + +#ifdef tListLen +#undefine tListLen +#endif +#define tListLen(x) (sizeof(x) / sizeof((x)[0])) + +#if defined(__GNUC__) +#define FORCE_INLINE inline __attribute__((always_inline)) +#else +#define FORCE_INLINE +#endif + +#define DEFAULT_UNICODE_ENCODEC "UCS-4LE" + +#define DEFAULT_COMP(x, y) \ + do { \ + if ((x) == (y)) { \ + return 0; \ + } else { \ + return (x) < (y) ? -1 : 1; \ + } \ + } while (0) + +#define ALIGN_NUM(n, align) (((n) + ((align)-1)) & (~((align)-1))) + +// align to 8bytes +#define ALIGN8(n) ALIGN_NUM(n, 8) + +#undef threadlocal +#ifdef _ISOC11_SOURCE + #define threadlocal _Thread_local +#elif defined(__APPLE__) + #define threadlocal +#elif defined(__GNUC__) && !defined(threadlocal) + #define threadlocal __thread +#else + #define threadlocal +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/os/inc/osDir.h b/src/os/inc/osDir.h new file mode 100644 index 0000000000..73e4b216e6 --- /dev/null +++ b/src/os/inc/osDir.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef TDENGINE_OS_DIR_H +#define TDENGINE_OS_DIR_H + +#ifdef __cplusplus +extern "C" { +#endif + +// TAOS_OS_FUNC_DIR +void taosRemoveDir(char *rootDir); +int taosMkDir(const char *pathname, mode_t mode); +void taosMvDir(char* destDir, char *srcDir); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/os/inc/osFile.h b/src/os/inc/osFile.h new file mode 100644 index 0000000000..4f4d9e8aed --- /dev/null +++ b/src/os/inc/osFile.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef TDENGINE_OS_FILE_H +#define TDENGINE_OS_FILE_H + +#ifdef __cplusplus +extern "C" { +#endif + +ssize_t taosTReadImp(int fd, void *buf, size_t count); +ssize_t taosTWriteImp(int fd, void *buf, size_t count); + +// TAOS_OS_FUNC_FILE_TSENDIFLE +ssize_t taosTSendFileImp(int dfd, int sfd, off_t *offset, size_t size); +int taosFSendFileImp(FILE* out_file, FILE* in_file, int64_t* offset, int32_t count); + +#define taosTSendFile(dfd, sfd, offset, size) taosTSendFileImp(dfd, sfd, offset, size) +#define taosFSendFile(outfile, infile, offset, count) taosTSendFileImp(fileno(outfile), fileno(infile), offset, size) + +#ifndef TAOS_RANDOM_FILE_FAIL + #define taosTRead(fd, buf, count) taosTReadImp(fd, buf, count) + #define taosTWrite(fd, buf, count) taosTWriteImp(fd, buf, count) + #define taosLSeek(fd, offset, whence) lseek(fd, offset, whence) +#else + void taosSetRandomFileFailFactor(int factor); + void taosSetRandomFileFailOutput(const char *path); + ssize_t taosReadFileRandomFail(int fd, void *buf, size_t count, const char *file, uint32_t line); + ssize_t taosWriteFileRandomFail(int fd, void *buf, size_t count, const char *file, uint32_t line); + off_t taosLSeekRandomFail(int fd, off_t offset, int whence, const char *file, uint32_t line); + #define taosTRead(fd, buf, count) taosReadFileRandomFail(fd, buf, count, __FILE__, __LINE__) + #define taosTWrite(fd, buf, count) taosWriteFileRandomFail(fd, buf, count, __FILE__, __LINE__) + #define taosLSeek(fd, offset, whence) taosLSeekRandomFail(fd, offset, whence, __FILE__, __LINE__) +#endif + +// TAOS_OS_FUNC_FILE_GETTMPFILEPATH +void taosGetTmpfilePath(const char *fileNamePrefix, char *dstPath); + +int32_t taosFileRename(char *fullPath, char *suffix, char delimiter, char **dstPath); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/os/inc/osLz4.h b/src/os/inc/osLz4.h new file mode 100644 index 0000000000..a944892c48 --- /dev/null +++ b/src/os/inc/osLz4.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef TDENGINE_OS_LZ4_H +#define TDENGINE_OS_LZ4_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef TAOS_OS_FUNC_LZ4 + #define BUILDIN_CLZL(val) __builtin_clzl(val) + #define BUILDIN_CTZL(val) __builtin_ctzl(val) + #define BUILDIN_CLZ(val) __builtin_clz(val) + #define BUILDIN_CTZ(val) __builtin_ctz(val) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/os/inc/osMath.h b/src/os/inc/osMath.h new file mode 100644 index 0000000000..168f6607f0 --- /dev/null +++ b/src/os/inc/osMath.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef TDENGINE_OS_MATH_H +#define TDENGINE_OS_MATH_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define POW2(x) ((x) * (x)) + +#ifndef TAOS_OS_FUNC_MATH + #define SWAP(a, b, c) \ + do { \ + typeof(a) __tmp = (a); \ + (a) = (b); \ + (b) = __tmp; \ + } while (0) + + #define MAX(a, b) \ + ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + (__a > __b) ? __a : __b; \ + }) + + #define MIN(a, b) \ + ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + (__a < __b) ? __a : __b; \ + }) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/os/inc/osMemory.h b/src/os/inc/osMemory.h new file mode 100644 index 0000000000..eb2ff02f77 --- /dev/null +++ b/src/os/inc/osMemory.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef TDENGINE_OS_MEMORY_H +#define TDENGINE_OS_MEMORY_H + +#include "osString.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + TAOS_ALLOC_MODE_DEFAULT = 0, + TAOS_ALLOC_MODE_RANDOM_FAIL = 1, + TAOS_ALLOC_MODE_DETECT_LEAK = 2 +} ETaosMemoryAllocMode; + +void taosSetAllocMode(int mode, const char *path, bool autoDump); +void taosDumpMemoryLeak(); + +void * taosTMalloc(size_t size); +void * taosTCalloc(size_t nmemb, size_t size); +void * taosTRealloc(void *ptr, size_t size); +void taosTZfree(void *ptr); +size_t taosTSizeof(void *ptr); +void taosTMemset(void *ptr, int c); + +#define taosTFree(x) \ + do { \ + if (x) { \ + free((void *)(x)); \ + x = 0; \ + } \ + } while (0); + +#ifndef TAOS_MEM_CHECK + #define taosMalloc(size) malloc(size) + #define taosCalloc(num, size) calloc(num, size) + #define taosRealloc(ptr, size) realloc(ptr, size) + #define taosFree(ptr) free(ptr) + #define taosStrdup(str) taosStrdupImp(str) + #define taosStrndup(str, size) taosStrndupImp(str, size) + #define taosGetline(lineptr, n, stream) taosGetlineImp(lineptr, n, stream) +#else + void * taos_malloc(size_t size, const char *file, uint32_t line); + void * taos_calloc(size_t num, size_t size, const char *file, uint32_t line); + void * taos_realloc(void *ptr, size_t size, const char *file, uint32_t line); + void taos_free(void *ptr, const char *file, uint32_t line); + char * taos_strdup(const char *str, const char *file, uint32_t line); + char * taos_strndup(const char *str, size_t size, const char *file, uint32_t line); + ssize_t taos_getline(char **lineptr, size_t *n, FILE *stream, const char *file, uint32_t line); + #define taosMalloc(size) taos_malloc(size, __FILE__, __LINE__) + #define taosCalloc(num, size) taos_calloc(num, size, __FILE__, __LINE__) + #define taosRealloc(ptr, size) taos_realloc(ptr, size, __FILE__, __LINE__) + #define taosFree(ptr) taos_free(ptr, __FILE__, __LINE__) + #define taosStrdup(str) taos_strdup(str, __FILE__, __LINE__) + #define taosStrndup(str, size) taos_strndup(str, size, __FILE__, __LINE__) + #define taosGetline(lineptr, n, stream) taos_getline(lineptr, n, stream, __FILE__, __LINE__) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/os/inc/osPthread.h b/src/os/inc/osPthread.h new file mode 100644 index 0000000000..add5c9042d --- /dev/null +++ b/src/os/inc/osPthread.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef TDENGINE_OS_PTHREAD_H +#define TDENGINE_OS_PTHREAD_H + +#ifdef __cplusplus +extern "C" { +#endif + +// TAOS_OS_FUNC_PTHREAD +bool taosCheckPthreadValid(pthread_t thread); +int64_t taosGetPthreadId(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/os/inc/osRand.h b/src/os/inc/osRand.h new file mode 100644 index 0000000000..310340d420 --- /dev/null +++ b/src/os/inc/osRand.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef TDENGINE_OS_RAND_H +#define TDENGINE_OS_RAND_H + +#ifdef __cplusplus +extern "C" { +#endif + +// TAOS_OS_FUNC_RAND +uint32_t taosRand(void); +void taosRandStr(char* str, int32_t size); +uint32_t trand(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/os/inc/osSemphone.h b/src/os/inc/osSemphone.h new file mode 100644 index 0000000000..138a6f97ee --- /dev/null +++ b/src/os/inc/osSemphone.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef TDENGINE_OS_SEMPHONE_H +#define TDENGINE_OS_SEMPHONE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef TAOS_OS_FUNC_SEMPHONE + #define tsem_t sem_t + #define tsem_init sem_init + #define tsem_wait sem_wait + #define tsem_post sem_post + #define tsem_destroy sem_destroy +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/os/inc/osSocket.h b/src/os/inc/osSocket.h new file mode 100644 index 0000000000..f013ae4a3a --- /dev/null +++ b/src/os/inc/osSocket.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef TDENGINE_OS_SOCKET_H +#define TDENGINE_OS_SOCKET_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define taosSend(sockfd, buf, len, flags) send(sockfd, buf, len, flags) +#define taosSendto(sockfd, buf, len, flags, dest_addr, addrlen) sendto(sockfd, buf, len, flags, dest_addr, addrlen) +#define taosReadSocket(fd, buf, len) read(fd, buf, len) +#define taosWriteSocket(fd, buf, len) write(fd, buf, len) +#define taosCloseSocket(x) \ + { \ + if (FD_VALID(x)) { \ + close(x); \ + x = FD_INITIALIZER; \ + } \ + } + +#define taosClose(x) taosCloseSocket(x) + +#ifdef TAOS_RANDOM_NETWORK_FAIL + ssize_t taosSendRandomFail(int sockfd, const void *buf, size_t len, int flags); + ssize_t taosSendToRandomFail(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); + ssize_t taosReadSocketRandomFail(int fd, void *buf, size_t count); + ssize_t taosWriteSocketRandomFail(int fd, const void *buf, size_t count); + #undef taosSend + #undef taosSendto + #undef taosReadSocket + #undef taosWriteSocket + #define taosSend(sockfd, buf, len, flags) taosSendRandomFail(sockfd, buf, len, flags) + #define taosSendto(sockfd, buf, len, flags, dest_addr, addrlen) taosSendToRandomFail(sockfd, buf, len, flags, dest_addr, addrlen) + #define taosReadSocket(fd, buf, len) taosReadSocketRandomFail(fd, buf, len) + #define taosWriteSocket(fd, buf, len) taosWriteSocketRandomFail(fd, buf, len) +#endif + +// TAOS_OS_FUNC_SOCKET +int taosSetNonblocking(int sock, int on); +void taosBlockSIGPIPE(); + +// TAOS_OS_FUNC_SOCKET_SETSOCKETOPT +int taosSetSockOpt(int socketfd, int level, int optname, void *optval, int optlen); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/os/inc/osSpec.h b/src/os/inc/osSpec.h deleted file mode 100644 index f0223c3ac5..0000000000 --- a/src/os/inc/osSpec.h +++ /dev/null @@ -1,400 +0,0 @@ -/* - * Copyright (c) 2019 TAOS Data, Inc. - * - * This program is free software: you can use, redistribute, and/or modify - * it under the terms of the GNU Affero General Public License, version 3 - * or later ("AGPL"), as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#ifndef TDENGINE_OS_SPEC_H -#define TDENGINE_OS_SPEC_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define tclose(x) taosCloseSocket(x) -#define tfree(x) \ - do { \ - if (x) { \ - free((void *)(x)); \ - x = 0; \ - } \ - } while (0); - -#define tstrncpy(dst, src, size) \ - do { \ - strncpy((dst), (src), (size)); \ - (dst)[(size)-1] = 0; \ - } while (0); - -#ifndef STDERR_FILENO -#define STDERR_FILENO (2) -#endif - -#define FD_VALID(x) ((x) > STDERR_FILENO) -#define FD_INITIALIZER ((int32_t)-1) - -#define WCHAR wchar_t - -#define POINTER_SHIFT(p, b) ((void *)((char *)(p) + (b))) -#define POINTER_DISTANCE(p1, p2) ((char *)(p1) - (char *)(p2)) - -#ifndef NDEBUG -#define ASSERT(x) assert(x) -#else -#define ASSERT(x) -#endif - -#ifdef UNUSED -#undefine UNUSED -#endif -#define UNUSED(x) ((void)(x)) - -#ifdef UNUSED_FUNC -#undefine UNUSED_FUNC -#endif - -#ifdef UNUSED_PARAM -#undef UNUSED_PARAM -#endif - -#if defined(__GNUC__) -#define UNUSED_PARAM(x) _UNUSED##x __attribute__((unused)) -#define UNUSED_FUNC __attribute__((unused)) -#else -#define UNUSED_PARAM(x) x -#define UNUSED_FUNC -#endif - -#ifdef tListLen -#undefine tListLen -#endif -#define tListLen(x) (sizeof(x) / sizeof((x)[0])) - -#if defined(__GNUC__) -#define FORCE_INLINE inline __attribute__((always_inline)) -#else -#define FORCE_INLINE -#endif - -#define DEFAULT_UNICODE_ENCODEC "UCS-4LE" - -#define DEFAULT_COMP(x, y) \ - do { \ - if ((x) == (y)) { \ - return 0; \ - } else { \ - return (x) < (y) ? -1 : 1; \ - } \ - } while (0) - -#define ALIGN_NUM(n, align) (((n) + ((align)-1)) & (~((align)-1))) - -// align to 8bytes -#define ALIGN8(n) ALIGN_NUM(n, 8) - -#define POW2(x) ((x) * (x)) - -#ifndef TAOS_OS_FUNC_MATH - #define SWAP(a, b, c) \ - do { \ - typeof(a) __tmp = (a); \ - (a) = (b); \ - (b) = __tmp; \ - } while (0) - - #define MAX(a, b) \ - ({ \ - typeof(a) __a = (a); \ - typeof(b) __b = (b); \ - (__a > __b) ? __a : __b; \ - }) - - #define MIN(a, b) \ - ({ \ - typeof(a) __a = (a); \ - typeof(b) __b = (b); \ - (__a < __b) ? __a : __b; \ - }) -#endif - -#ifndef TAOS_OS_DEF_TIME - #define MILLISECOND_PER_SECOND ((int64_t)1000L) -#endif -#define MILLISECOND_PER_MINUTE (MILLISECOND_PER_SECOND * 60) -#define MILLISECOND_PER_HOUR (MILLISECOND_PER_MINUTE * 60) -#define MILLISECOND_PER_DAY (MILLISECOND_PER_HOUR * 24) -#define MILLISECOND_PER_WEEK (MILLISECOND_PER_DAY * 7) -#define MILLISECOND_PER_MONTH (MILLISECOND_PER_DAY * 30) -#define MILLISECOND_PER_YEAR (MILLISECOND_PER_DAY * 365) - -#ifndef TAOS_OS_FUNC_SEMPHONE - #define tsem_t sem_t - #define tsem_init sem_init - #define tsem_wait sem_wait - #define tsem_post sem_post - #define tsem_destroy sem_destroy -#endif - -#ifndef TAOS_OS_FUNC_ATOMIC - #define atomic_load_8(ptr) __atomic_load_n((ptr), __ATOMIC_SEQ_CST) - #define atomic_load_16(ptr) __atomic_load_n((ptr), __ATOMIC_SEQ_CST) - #define atomic_load_32(ptr) __atomic_load_n((ptr), __ATOMIC_SEQ_CST) - #define atomic_load_64(ptr) __atomic_load_n((ptr), __ATOMIC_SEQ_CST) - #define atomic_load_ptr(ptr) __atomic_load_n((ptr), __ATOMIC_SEQ_CST) - - #define atomic_store_8(ptr, val) __atomic_store_n((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_store_16(ptr, val) __atomic_store_n((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_store_32(ptr, val) __atomic_store_n((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_store_64(ptr, val) __atomic_store_n((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_store_ptr(ptr, val) __atomic_store_n((ptr), (val), __ATOMIC_SEQ_CST) - - #define atomic_exchange_8(ptr, val) __atomic_exchange_n((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_exchange_16(ptr, val) __atomic_exchange_n((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_exchange_32(ptr, val) __atomic_exchange_n((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_exchange_64(ptr, val) __atomic_exchange_n((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_exchange_ptr(ptr, val) __atomic_exchange_n((ptr), (val), __ATOMIC_SEQ_CST) - - #define atomic_val_compare_exchange_8 __sync_val_compare_and_swap - #define atomic_val_compare_exchange_16 __sync_val_compare_and_swap - #define atomic_val_compare_exchange_32 __sync_val_compare_and_swap - #define atomic_val_compare_exchange_64 __sync_val_compare_and_swap - #define atomic_val_compare_exchange_ptr __sync_val_compare_and_swap - - #define atomic_add_fetch_8(ptr, val) __atomic_add_fetch((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_add_fetch_16(ptr, val) __atomic_add_fetch((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_add_fetch_32(ptr, val) __atomic_add_fetch((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_add_fetch_64(ptr, val) __atomic_add_fetch((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_add_fetch_ptr(ptr, val) __atomic_add_fetch((ptr), (val), __ATOMIC_SEQ_CST) - - #define atomic_fetch_add_8(ptr, val) __atomic_fetch_add((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_fetch_add_16(ptr, val) __atomic_fetch_add((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_fetch_add_32(ptr, val) __atomic_fetch_add((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_fetch_add_64(ptr, val) __atomic_fetch_add((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_fetch_add_ptr(ptr, val) __atomic_fetch_add((ptr), (val), __ATOMIC_SEQ_CST) - - #define atomic_sub_fetch_8(ptr, val) __atomic_sub_fetch((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_sub_fetch_16(ptr, val) __atomic_sub_fetch((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_sub_fetch_32(ptr, val) __atomic_sub_fetch((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_sub_fetch_64(ptr, val) __atomic_sub_fetch((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_sub_fetch_ptr(ptr, val) __atomic_sub_fetch((ptr), (val), __ATOMIC_SEQ_CST) - - #define atomic_fetch_sub_8(ptr, val) __atomic_fetch_sub((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_fetch_sub_16(ptr, val) __atomic_fetch_sub((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_fetch_sub_32(ptr, val) __atomic_fetch_sub((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_fetch_sub_64(ptr, val) __atomic_fetch_sub((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_fetch_sub_ptr(ptr, val) __atomic_fetch_sub((ptr), (val), __ATOMIC_SEQ_CST) - - #define atomic_and_fetch_8(ptr, val) __atomic_and_fetch((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_and_fetch_16(ptr, val) __atomic_and_fetch((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_and_fetch_32(ptr, val) __atomic_and_fetch((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_and_fetch_64(ptr, val) __atomic_and_fetch((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_and_fetch_ptr(ptr, val) __atomic_and_fetch((ptr), (val), __ATOMIC_SEQ_CST) - - #define atomic_fetch_and_8(ptr, val) __atomic_fetch_and((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_fetch_and_16(ptr, val) __atomic_fetch_and((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_fetch_and_32(ptr, val) __atomic_fetch_and((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_fetch_and_64(ptr, val) __atomic_fetch_and((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_fetch_and_ptr(ptr, val) __atomic_fetch_and((ptr), (val), __ATOMIC_SEQ_CST) - - #define atomic_or_fetch_8(ptr, val) __atomic_or_fetch((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_or_fetch_16(ptr, val) __atomic_or_fetch((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_or_fetch_32(ptr, val) __atomic_or_fetch((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_or_fetch_64(ptr, val) __atomic_or_fetch((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_or_fetch_ptr(ptr, val) __atomic_or_fetch((ptr), (val), __ATOMIC_SEQ_CST) - - #define atomic_fetch_or_8(ptr, val) __atomic_fetch_or((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_fetch_or_16(ptr, val) __atomic_fetch_or((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_fetch_or_32(ptr, val) __atomic_fetch_or((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_fetch_or_64(ptr, val) __atomic_fetch_or((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_fetch_or_ptr(ptr, val) __atomic_fetch_or((ptr), (val), __ATOMIC_SEQ_CST) - - #define atomic_xor_fetch_8(ptr, val) __atomic_xor_fetch((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_xor_fetch_16(ptr, val) __atomic_xor_fetch((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_xor_fetch_32(ptr, val) __atomic_xor_fetch((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_xor_fetch_64(ptr, val) __atomic_xor_fetch((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_xor_fetch_ptr(ptr, val) __atomic_xor_fetch((ptr), (val), __ATOMIC_SEQ_CST) - - #define atomic_fetch_xor_8(ptr, val) __atomic_fetch_xor((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_fetch_xor_16(ptr, val) __atomic_fetch_xor((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_fetch_xor_32(ptr, val) __atomic_fetch_xor((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_fetch_xor_64(ptr, val) __atomic_fetch_xor((ptr), (val), __ATOMIC_SEQ_CST) - #define atomic_fetch_xor_ptr(ptr, val) __atomic_fetch_xor((ptr), (val), __ATOMIC_SEQ_CST) -#endif - -ssize_t taosTReadImp(int fd, void *buf, size_t count); -ssize_t taosTWriteImp(int fd, void *buf, size_t count); -// TAOS_OS_FUNC_FILEOP -ssize_t taosTSendFileImp(int dfd, int sfd, off_t *offset, size_t size); -int taosFSendFileImp(FILE* out_file, FILE* in_file, int64_t* offset, int32_t count); -#ifndef TAOS_OS_FUNC_FILEOP - #define taosTSendFile(dfd, sfd, offset, size) taosTSendFileImp(dfd, sfd, offset, size) - #define taosFSendFile(outfile, infile, offset, count) taosTSendFileImp(fileno(outfile), fileno(infile), offset, size) -#endif - -#ifndef TAOS_OS_FUNC_NETWORK - #define taosSend(sockfd, buf, len, flags) send(sockfd, buf, len, flags) - #define taosSendto(sockfd, buf, len, flags, dest_addr, addrlen) sendto(sockfd, buf, len, flags, dest_addr, addrlen) - #define taosReadSocket(fd, buf, len) read(fd, buf, len) - #define taosWriteSocket(fd, buf, len) write(fd, buf, len) - #define taosCloseSocket(x) \ - { \ - if (FD_VALID(x)) { \ - close(x); \ - x = FD_INITIALIZER; \ - } \ - } -#endif - -#ifndef TAOS_OS_FUNC_LZ4 - #define BUILDIN_CLZL(val) __builtin_clzl(val) - #define BUILDIN_CTZL(val) __builtin_ctzl(val) - #define BUILDIN_CLZ(val) __builtin_clz(val) - #define BUILDIN_CTZ(val) __builtin_ctz(val) -#endif - -#ifndef TAOS_OS_FUNC_WCHAR - #define twcslen wcslen -#endif - -#undef threadlocal -#ifdef _ISOC11_SOURCE - #define threadlocal _Thread_local -#elif defined(__APPLE__) - #define threadlocal -#elif defined(__GNUC__) && !defined(threadlocal) - #define threadlocal __thread -#else - #define threadlocal -#endif - -void osInit(); - -// TAOS_OS_FUNC_PTHREAD -bool taosCheckPthreadValid(pthread_t thread); -int64_t taosGetPthreadId(); - -// TAOS_OS_FUNC_SOCKET -int taosSetNonblocking(int sock, int on); -void taosBlockSIGPIPE(); - -// TAOS_OS_FUNC_SOCKET_SETSOCKETOPT -int taosSetSockOpt(int socketfd, int level, int optname, void *optval, int optlen); - -// TAOS_OS_FUNC_SYSINFO -void taosGetSystemInfo(); -bool taosGetProcIO(float *readKB, float *writeKB); -bool taosGetBandSpeed(float *bandSpeedKb); -bool taosGetDisk(); -bool taosGetCpuUsage(float *sysCpuUsage, float *procCpuUsage) ; -bool taosGetProcMemory(float *memoryUsedMB) ; -bool taosGetSysMemory(float *memoryUsedMB); -void taosPrintOsInfo(); -int taosSystem(const char * cmd) ; -void taosKillSystem(); - -// TAOS_OS_FUNC_CORE -void taosSetCoreDump(); - -// TAOS_OS_FUNC_UTIL -int64_t tsosStr2int64(char *str); - -// TAOS_OS_FUNC_TIMER -void taosMsleep(int mseconds); -int taosInitTimer(void (*callback)(int), int ms); -void taosUninitTimer(); - -// TAOS_OS_FUNC_RAND -uint32_t taosRand(void); -void taosRandStr(char* str, int32_t size); -uint32_t trand(void); - -// TAOS_OS_FUNC_FILE -void taosGetTmpfilePath(const char *fileNamePrefix, char *dstPath); -int32_t taosFileRename(char *fullPath, char *suffix, char delimiter, char **dstPath); - -// USE_LIBICONV -int32_t taosUcs4ToMbs(void *ucs4, int32_t ucs4_max_len, char *mbs); -bool taosMbsToUcs4(char *mbs, size_t mbs_len, char *ucs4, int32_t ucs4_max_len, size_t *len); -int tasoUcs4Compare(void *f1_ucs4, void *f2_ucs4, int bytes); -bool taosValidateEncodec(const char *encodec); -char * taosCharsetReplace(char *charsetstr); - -// TAOS_OS_FUNC_MALLOC -#define TAOS_ALLOC_MODE_DEFAULT 0 -#define TAOS_ALLOC_MODE_RANDOM_FAIL 1 -#define TAOS_ALLOC_MODE_DETECT_LEAK 2 -void taosSetAllocMode(int mode, const char *path, bool autoDump); -void taosDumpMemoryLeak(); -void * tmalloc(size_t size); -void * tcalloc(size_t nmemb, size_t size); -size_t tsizeof(void *ptr); -void tmemset(void *ptr, int c); -void * trealloc(void *ptr, size_t size); -void tzfree(void *ptr); - -// TAOS_OS_FUNC_DIR -void taosRemoveDir(char *rootDir); -int taosMkDir(const char *pathname, mode_t mode); -void taosMvDir(char* destDir, char *srcDir); - -#ifdef TAOS_RANDOM_FILE_FAIL - void taosSetRandomFileFailFactor(int factor); - void taosSetRandomFileFailOutput(const char *path); - ssize_t taosReadFileRandomFail(int fd, void *buf, size_t count, const char *file, uint32_t line); - ssize_t taosWriteFileRandomFail(int fd, void *buf, size_t count, const char *file, uint32_t line); - off_t taosLSeekRandomFail(int fd, off_t offset, int whence, const char *file, uint32_t line); - #define taosTRead(fd, buf, count) taosReadFileRandomFail(fd, buf, count, __FILE__, __LINE__) - #define taosTWrite(fd, buf, count) taosWriteFileRandomFail(fd, buf, count, __FILE__, __LINE__) - #define taosLSeek(fd, offset, whence) taosLSeekRandomFail(fd, offset, whence, __FILE__, __LINE__) -#else - #define taosTRead(fd, buf, count) taosTReadImp(fd, buf, count) - #define taosTWrite(fd, buf, count) taosTWriteImp(fd, buf, count) - #define taosLSeek(fd, offset, whence) lseek(fd, offset, whence) -#endif - -#ifdef TAOS_RANDOM_NETWORK_FAIL - ssize_t taosSendRandomFail(int sockfd, const void *buf, size_t len, int flags); - ssize_t taosSendToRandomFail(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); - ssize_t taosReadSocketRandomFail(int fd, void *buf, size_t count); - ssize_t taosWriteSocketRandomFail(int fd, const void *buf, size_t count); - #undef taosSend - #undef taosSendto - #undef taosReadSocket - #undef taosWriteSocket - #define taosSend(sockfd, buf, len, flags) taosSendRandomFail(sockfd, buf, len, flags) - #define taosSendto(sockfd, buf, len, flags, dest_addr, addrlen) taosSendToRandomFail(sockfd, buf, len, flags, dest_addr, addrlen) - #define taosReadSocket(fd, buf, len) taosReadSocketRandomFail(fd, buf, len) - #define taosWriteSocket(fd, buf, len) taosWriteSocketRandomFail(fd, buf, len) -#endif - -#ifdef TAOS_MEM_CHECK - void * taos_malloc(size_t size, const char *file, uint32_t line); - void * taos_calloc(size_t num, size_t size, const char *file, uint32_t line); - void * taos_realloc(void *ptr, size_t size, const char *file, uint32_t line); - void taos_free(void *ptr, const char *file, uint32_t line); - char * taos_strdup(const char *str, const char *file, uint32_t line); - char * taos_strndup(const char *str, size_t size, const char *file, uint32_t line); - ssize_t taos_getline(char **lineptr, size_t *n, FILE *stream, const char *file, uint32_t line); - #define malloc(size) taos_malloc(size, __FILE__, __LINE__) - #define calloc(num, size) taos_calloc(num, size, __FILE__, __LINE__) - #define realloc(ptr, size) taos_realloc(ptr, size, __FILE__, __LINE__) - #define free(ptr) taos_free(ptr, __FILE__, __LINE__) - #define strdup(str) taos_strdup(str, __FILE__, __LINE__) - #define strndup(str, size) taos_strndup(str, size, __FILE__, __LINE__) - #define getline(lineptr, n, stream) taos_getline(lineptr, n, stream, __FILE__, __LINE__) -#endif // TAOS_MEM_CHECK - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/os/inc/osString.h b/src/os/inc/osString.h new file mode 100644 index 0000000000..c91aef6d18 --- /dev/null +++ b/src/os/inc/osString.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef TDENGINE_OS_STRING_H +#define TDENGINE_OS_STRING_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef TAOS_OS_FUNC_STRING_STRDUP + #define taosStrdupImp(str) strdup(str) + #define taosStrndupImp(str, size) strndup(str, size) +#endif + +#ifndef TAOS_OS_FUNC_STRING_GETLINE + #define taosGetlineImp(lineptr, n, stream) getline(lineptr, n , stream) +#endif + +#ifndef TAOS_OS_FUNC_WCHAR + #define twcslen wcslen +#endif + +#define tstrncpy(dst, src, size) \ + do { \ + strncpy((dst), (src), (size)); \ + (dst)[(size)-1] = 0; \ + } while (0); + +// TAOS_OS_FUNC_UTIL +int64_t tsosStr2int64(char *str); + +// USE_LIBICONV +int32_t taosUcs4ToMbs(void *ucs4, int32_t ucs4_max_len, char *mbs); +bool taosMbsToUcs4(char *mbs, size_t mbs_len, char *ucs4, int32_t ucs4_max_len, size_t *len); +int tasoUcs4Compare(void *f1_ucs4, void *f2_ucs4, int bytes); +bool taosValidateEncodec(const char *encodec); +char * taosCharsetReplace(char *charsetstr); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/os/inc/osSysinfo.h b/src/os/inc/osSysinfo.h new file mode 100644 index 0000000000..ac91e73ab3 --- /dev/null +++ b/src/os/inc/osSysinfo.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef TDENGINE_OS_SYSINFO_H +#define TDENGINE_OS_SYSINFO_H + +#ifdef __cplusplus +extern "C" { +#endif + +// TAOS_OS_FUNC_SYSINFO +void taosGetSystemInfo(); +bool taosGetProcIO(float *readKB, float *writeKB); +bool taosGetBandSpeed(float *bandSpeedKb); +bool taosGetDisk(); +bool taosGetCpuUsage(float *sysCpuUsage, float *procCpuUsage) ; +bool taosGetProcMemory(float *memoryUsedMB) ; +bool taosGetSysMemory(float *memoryUsedMB); +void taosPrintOsInfo(); +int taosSystem(const char * cmd) ; +void taosKillSystem(); + +// TAOS_OS_FUNC_CORE +void taosSetCoreDump(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/util/inc/ttime.h b/src/os/inc/osTime.h similarity index 79% rename from src/util/inc/ttime.h rename to src/os/inc/osTime.h index 25d1bdb23e..e2d3e081a1 100644 --- a/src/util/inc/ttime.h +++ b/src/os/inc/osTime.h @@ -13,8 +13,8 @@ * along with this program. If not, see . */ -#ifndef TDENGINE_TTIME_H -#define TDENGINE_TTIME_H +#ifndef TDENGINE_OS_TIME_H +#define TDENGINE_OS_TIME_H #ifdef __cplusplus extern "C" { @@ -23,6 +23,16 @@ extern "C" { #include "os.h" #include "taosdef.h" +#ifndef TAOS_OS_DEF_TIME + #define MILLISECOND_PER_SECOND ((int64_t)1000L) +#endif +#define MILLISECOND_PER_MINUTE (MILLISECOND_PER_SECOND * 60) +#define MILLISECOND_PER_HOUR (MILLISECOND_PER_MINUTE * 60) +#define MILLISECOND_PER_DAY (MILLISECOND_PER_HOUR * 24) +#define MILLISECOND_PER_WEEK (MILLISECOND_PER_DAY * 7) +#define MILLISECOND_PER_MONTH (MILLISECOND_PER_DAY * 30) +#define MILLISECOND_PER_YEAR (MILLISECOND_PER_DAY * 365) + //@return timestamp in second int32_t taosGetTimestampSec(); diff --git a/src/os/inc/osTimer.h b/src/os/inc/osTimer.h new file mode 100644 index 0000000000..d6deae2a6d --- /dev/null +++ b/src/os/inc/osTimer.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef TDENGINE_OS_TIMER_H +#define TDENGINE_OS_TIMER_H + +#ifdef __cplusplus +extern "C" { +#endif + +// TAOS_OS_FUNC_TIMER +void taosMsleep(int mseconds); +int taosInitTimer(void (*callback)(int), int ms); +void taosUninitTimer(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/os/src/detail/osDir.c b/src/os/src/detail/osDir.c index b2a91d803a..c8d63f621e 100644 --- a/src/os/src/detail/osDir.c +++ b/src/os/src/detail/osDir.c @@ -17,6 +17,7 @@ #include "os.h" #include "tglobal.h" #include "tulog.h" +#include "osSysinfo.h" #ifndef TAOS_OS_FUNC_DIR diff --git a/src/os/src/detail/osFile.c b/src/os/src/detail/osFile.c index 7b5d5fbfcc..1cd7445658 100644 --- a/src/os/src/detail/osFile.c +++ b/src/os/src/detail/osFile.c @@ -15,28 +15,26 @@ #define _DEFAULT_SOURCE #include "os.h" -#include "ttime.h" - -#ifndef TAOS_OS_FUNC_FILE +#include "osRand.h" +#ifndef TAOS_OS_FUNC_FILE_GETTMPFILEPATH void taosGetTmpfilePath(const char *fileNamePrefix, char *dstPath) { - const char* tdengineTmpFileNamePrefix = "tdengine-"; - - char tmpPath[PATH_MAX]; + const char *tdengineTmpFileNamePrefix = "tdengine-"; + + char tmpPath[PATH_MAX]; char *tmpDir = "/tmp/"; - + strcpy(tmpPath, tmpDir); strcat(tmpPath, tdengineTmpFileNamePrefix); if (strlen(tmpPath) + strlen(fileNamePrefix) + strlen("-%d-%s") < PATH_MAX) { strcat(tmpPath, fileNamePrefix); strcat(tmpPath, "-%d-%s"); } - + char rand[8] = {0}; taosRandStr(rand, tListLen(rand) - 1); snprintf(dstPath, PATH_MAX, tmpPath, getpid(), rand); } - #endif // rename file name @@ -66,3 +64,75 @@ int32_t taosFileRename(char *fullPath, char *suffix, char delimiter, char **dstP return rename(fullPath, *dstPath); } + +ssize_t taosTReadImp(int fd, void *buf, size_t count) { + size_t leftbytes = count; + ssize_t readbytes; + char * tbuf = (char *)buf; + + while (leftbytes > 0) { + readbytes = read(fd, (void *)tbuf, leftbytes); + if (readbytes < 0) { + if (errno == EINTR) { + continue; + } else { + return -1; + } + } else if (readbytes == 0) { + return (ssize_t)(count - leftbytes); + } + + leftbytes -= readbytes; + tbuf += readbytes; + } + + return (ssize_t)count; +} + +ssize_t taosTWriteImp(int fd, void *buf, size_t n) { + size_t nleft = n; + ssize_t nwritten = 0; + char * tbuf = (char *)buf; + + while (nleft > 0) { + nwritten = write(fd, (void *)tbuf, nleft); + if (nwritten < 0) { + if (errno == EINTR) { + continue; + } + return -1; + } + nleft -= nwritten; + tbuf += nwritten; + } + + return n; +} + +#ifndef TAOS_OS_FUNC_FILE_TSENDIFLE +ssize_t taosTSendFileImp(int dfd, int sfd, off_t *offset, size_t size) { + size_t leftbytes = size; + ssize_t sentbytes; + + while (leftbytes > 0) { + /* + * TODO : Think to check if file is larger than 1GB + */ + // if (leftbytes > 1000000000) leftbytes = 1000000000; + sentbytes = sendfile(dfd, sfd, offset, leftbytes); + if (sentbytes == -1) { + if (errno == EINTR) { + continue; + } else { + return -1; + } + } else if (sentbytes == 0) { + return (ssize_t)(size - leftbytes); + } + + leftbytes -= sentbytes; + } + + return size; +} +#endif \ No newline at end of file diff --git a/src/os/src/detail/osFileOp.c b/src/os/src/detail/osFileOp.c deleted file mode 100644 index b6928049b6..0000000000 --- a/src/os/src/detail/osFileOp.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2019 TAOS Data, Inc. - * - * This program is free software: you can use, redistribute, and/or modify - * it under the terms of the GNU Affero General Public License, version 3 - * or later ("AGPL"), as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#define _DEFAULT_SOURCE -#include "os.h" - -ssize_t taosTReadImp(int fd, void *buf, size_t count) { - size_t leftbytes = count; - ssize_t readbytes; - char * tbuf = (char *)buf; - - while (leftbytes > 0) { - readbytes = read(fd, (void *)tbuf, leftbytes); - if (readbytes < 0) { - if (errno == EINTR) { - continue; - } else { - return -1; - } - } else if (readbytes == 0) { - return (ssize_t)(count - leftbytes); - } - - leftbytes -= readbytes; - tbuf += readbytes; - } - - return (ssize_t)count; -} - -ssize_t taosTWriteImp(int fd, void *buf, size_t n) { - size_t nleft = n; - ssize_t nwritten = 0; - char *tbuf = (char *)buf; - - while (nleft > 0) { - nwritten = write(fd, (void *)tbuf, nleft); - if (nwritten < 0) { - if (errno == EINTR) { - continue; - } - return -1; - } - nleft -= nwritten; - tbuf += nwritten; - } - - return n; -} - -#ifndef TAOS_OS_FUNC_FILEOP - -ssize_t taosTSendFileImp(int dfd, int sfd, off_t *offset, size_t size) { - size_t leftbytes = size; - ssize_t sentbytes; - - while (leftbytes > 0) { - /* - * TODO : Think to check if file is larger than 1GB - */ - //if (leftbytes > 1000000000) leftbytes = 1000000000; - sentbytes = sendfile(dfd, sfd, offset, leftbytes); - if (sentbytes == -1) { - if (errno == EINTR) { - continue; - } - else { - return -1; - } - } else if (sentbytes == 0) { - return (ssize_t)(size - leftbytes); - } - - leftbytes -= sentbytes; - } - - return size; -} - -#endif \ No newline at end of file diff --git a/src/os/src/detail/osMalloc.c b/src/os/src/detail/osMalloc.c deleted file mode 100644 index 66377827da..0000000000 --- a/src/os/src/detail/osMalloc.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2019 TAOS Data, Inc. - * - * This program is free software: you can use, redistribute, and/or modify - * it under the terms of the GNU Affero General Public License, version 3 - * or later ("AGPL"), as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#define _DEFAULT_SOURCE -#include "os.h" - -#ifndef TAOS_OS_FUNC_MALLOC - -void *tmalloc(size_t size) { - if (size <= 0) return NULL; - - void *ret = malloc(size + sizeof(size_t)); - if (ret == NULL) return NULL; - - *(size_t *)ret = size; - - return (void *)((char *)ret + sizeof(size_t)); -} - -void *tcalloc(size_t nmemb, size_t size) { - size_t tsize = nmemb * size; - void * ret = tmalloc(tsize); - if (ret == NULL) return NULL; - - tmemset(ret, 0); - return ret; -} - -size_t tsizeof(void *ptr) { return (ptr) ? (*(size_t *)((char *)ptr - sizeof(size_t))) : 0; } - -void tmemset(void *ptr, int c) { memset(ptr, c, tsizeof(ptr)); } - -void * trealloc(void *ptr, size_t size) { - if (ptr == NULL) return tmalloc(size); - - if (size <= tsizeof(ptr)) return ptr; - - void * tptr = (void *)((char *)ptr - sizeof(size_t)); - size_t tsize = size + sizeof(size_t); - tptr = realloc(tptr, tsize); - if (tptr == NULL) return NULL; - - *(size_t *)tptr = size; - - return (void *)((char *)tptr + sizeof(size_t)); -} - -void tzfree(void *ptr) { - if (ptr) { - free((void *)((char *)ptr - sizeof(size_t))); - } -} - -#endif \ No newline at end of file diff --git a/src/os/src/detail/osMem.c b/src/os/src/detail/osMemory.c similarity index 87% rename from src/os/src/detail/osMem.c rename to src/os/src/detail/osMemory.c index 93943c6543..3bbe806369 100644 --- a/src/os/src/detail/osMem.c +++ b/src/os/src/detail/osMemory.c @@ -19,7 +19,7 @@ #ifdef TAOS_MEM_CHECK -static int allocMode = TAOS_ALLOC_MODE_DEFAULT; +static ETaosMemoryAllocMode allocMode = TAOS_ALLOC_MODE_DEFAULT; static FILE* fpAllocLog = NULL; //////////////////////////////////////////////////////////////////////////////// @@ -62,7 +62,7 @@ static void* realloc_random(void* ptr, size_t size, const char* file, uint32_t l static char* strdup_random(const char* str, const char* file, uint32_t line) { size_t len = strlen(str); - return random_alloc_fail(len + 1, file, line) ? NULL : strdup(str); + return random_alloc_fail(len + 1, file, line) ? NULL : taosStrdupImp(str); } static char* strndup_random(const char* str, size_t size, const char* file, uint32_t line) { @@ -70,11 +70,11 @@ static char* strndup_random(const char* str, size_t size, const char* file, uint if (len > size) { len = size; } - return random_alloc_fail(len + 1, file, line) ? NULL : strndup(str, len); + return random_alloc_fail(len + 1, file, line) ? NULL : taosStrndupImp(str, len); } static ssize_t getline_random(char **lineptr, size_t *n, FILE *stream, const char* file, uint32_t line) { - return random_alloc_fail(*n, file, line) ? -1 : getline(lineptr, n, stream); + return random_alloc_fail(*n, file, line) ? -1 : taosGetlineImp(lineptr, n, stream); } //////////////////////////////////////////////////////////////////////////////// @@ -242,7 +242,7 @@ static char* strndup_detect_leak(const char* str, size_t size, const char* file, static ssize_t getline_detect_leak(char **lineptr, size_t *n, FILE *stream, const char* file, uint32_t line) { char* buf = NULL; size_t bufSize = 0; - ssize_t size = getline(&buf, &bufSize, stream); + ssize_t size = taosGetlineImp(&buf, &bufSize, stream); if (size != -1) { if (*n < size + 1) { void* p = realloc_detect_leak(*lineptr, size + 1, file, line); @@ -372,7 +372,7 @@ void taos_free(void* ptr, const char* file, uint32_t line) { char* taos_strdup(const char* str, const char* file, uint32_t line) { switch (allocMode) { case TAOS_ALLOC_MODE_DEFAULT: - return strdup(str); + return taosStrdupImp(str); case TAOS_ALLOC_MODE_RANDOM_FAIL: return strdup_random(str, file, line); @@ -380,13 +380,13 @@ char* taos_strdup(const char* str, const char* file, uint32_t line) { case TAOS_ALLOC_MODE_DETECT_LEAK: return strdup_detect_leak(str, file, line); } - return strdup(str); + return taosStrdupImp(str); } char* taos_strndup(const char* str, size_t size, const char* file, uint32_t line) { switch (allocMode) { case TAOS_ALLOC_MODE_DEFAULT: - return strndup(str, size); + return taosStrndupImp(str, size); case TAOS_ALLOC_MODE_RANDOM_FAIL: return strndup_random(str, size, file, line); @@ -394,13 +394,13 @@ char* taos_strndup(const char* str, size_t size, const char* file, uint32_t line case TAOS_ALLOC_MODE_DETECT_LEAK: return strndup_detect_leak(str, size, file, line); } - return strndup(str, size); + return taosStrndupImp(str, size); } ssize_t taos_getline(char **lineptr, size_t *n, FILE *stream, const char* file, uint32_t line) { switch (allocMode) { case TAOS_ALLOC_MODE_DEFAULT: - return getline(lineptr, n, stream); + return taosGetlineImp(lineptr, n, stream); case TAOS_ALLOC_MODE_RANDOM_FAIL: return getline_random(lineptr, n, stream, file, line); @@ -408,7 +408,7 @@ ssize_t taos_getline(char **lineptr, size_t *n, FILE *stream, const char* file, case TAOS_ALLOC_MODE_DETECT_LEAK: return getline_detect_leak(lineptr, n, stream, file, line); } - return getline(lineptr, n, stream); + return taosGetlineImp(lineptr, n, stream); } static void close_alloc_log() { @@ -472,3 +472,48 @@ void taosDumpMemoryLeak() { } #endif // TAOS_MEM_CHECK + +void *taosTMalloc(size_t size) { + if (size <= 0) return NULL; + + void *ret = malloc(size + sizeof(size_t)); + if (ret == NULL) return NULL; + + *(size_t *)ret = size; + + return (void *)((char *)ret + sizeof(size_t)); +} + +void *taosTCalloc(size_t nmemb, size_t size) { + size_t tsize = nmemb * size; + void * ret = taosTMalloc(tsize); + if (ret == NULL) return NULL; + + taosTMemset(ret, 0); + return ret; +} + +size_t taosTSizeof(void *ptr) { return (ptr) ? (*(size_t *)((char *)ptr - sizeof(size_t))) : 0; } + +void taosTMemset(void *ptr, int c) { memset(ptr, c, taosTSizeof(ptr)); } + +void * taosTRealloc(void *ptr, size_t size) { + if (ptr == NULL) return taosTMalloc(size); + + if (size <= taosTSizeof(ptr)) return ptr; + + void * tptr = (void *)((char *)ptr - sizeof(size_t)); + size_t tsize = size + sizeof(size_t); + tptr = realloc(tptr, tsize); + if (tptr == NULL) return NULL; + + *(size_t *)tptr = size; + + return (void *)((char *)tptr + sizeof(size_t)); +} + +void taosTZfree(void *ptr) { + if (ptr) { + free((void *)((char *)ptr - sizeof(size_t))); + } +} \ No newline at end of file diff --git a/src/os/src/detail/osSysinfo.c b/src/os/src/detail/osSysinfo.c index 89813d9864..f753566134 100644 --- a/src/os/src/detail/osSysinfo.c +++ b/src/os/src/detail/osSysinfo.c @@ -63,7 +63,7 @@ bool taosGetProcMemory(float *memoryUsedMB) { size_t len; char * line = NULL; while (!feof(fp)) { - tfree(line); + taosTFree(line); len = 0; getline(&line, &len, fp); if (line == NULL) { @@ -85,7 +85,7 @@ bool taosGetProcMemory(float *memoryUsedMB) { sscanf(line, "%s %" PRId64, tmp, &memKB); *memoryUsedMB = (float)((double)memKB / 1024); - tfree(line); + taosTFree(line); fclose(fp); return true; } @@ -109,7 +109,7 @@ static bool taosGetSysCpuInfo(SysCpuInfo *cpuInfo) { char cpu[10] = {0}; sscanf(line, "%s %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64, cpu, &cpuInfo->user, &cpuInfo->nice, &cpuInfo->system, &cpuInfo->idle); - tfree(line); + taosTFree(line); fclose(fp); return true; } @@ -138,7 +138,7 @@ static bool taosGetProcCpuInfo(ProcCpuInfo *cpuInfo) { } } - tfree(line); + taosTFree(line); fclose(fp); return true; } @@ -378,7 +378,7 @@ static bool taosGetCardInfo(int64_t *bytes) { *bytes += (rbytes + tbytes); } - tfree(line); + taosTFree(line); fclose(fp); return true; @@ -433,7 +433,7 @@ static bool taosReadProcIO(int64_t *readbyte, int64_t *writebyte) { int readIndex = 0; while (!feof(fp)) { - tfree(line); + taosTFree(line); len = 0; getline(&line, &len, fp); if (line == NULL) { @@ -451,7 +451,7 @@ static bool taosReadProcIO(int64_t *readbyte, int64_t *writebyte) { if (readIndex >= 2) break; } - tfree(line); + taosTFree(line); fclose(fp); if (readIndex < 2) { diff --git a/src/util/src/ttime.c b/src/os/src/detail/osTime.c similarity index 99% rename from src/util/src/ttime.c rename to src/os/src/detail/osTime.c index 018c0d640b..28c13165fa 100644 --- a/src/util/src/ttime.c +++ b/src/os/src/detail/osTime.c @@ -22,7 +22,6 @@ #include #include "taosdef.h" -#include "ttime.h" #include "tutil.h" /* * mktime64 - Converts date to seconds. diff --git a/src/plugins/http/src/httpContext.c b/src/plugins/http/src/httpContext.c index f46d3fb427..ad72ac8823 100644 --- a/src/plugins/http/src/httpContext.c +++ b/src/plugins/http/src/httpContext.c @@ -18,7 +18,6 @@ #include "taosmsg.h" #include "tsocket.h" #include "tutil.h" -#include "ttime.h" #include "ttimer.h" #include "tglobal.h" #include "tcache.h" @@ -39,7 +38,7 @@ static void httpRemoveContextFromEpoll(HttpContext *pContext) { static void httpDestroyContext(void *data) { HttpContext *pContext = *(HttpContext **)data; - if (pContext->fd > 0) tclose(pContext->fd); + if (pContext->fd > 0) taosClose(pContext->fd); HttpThread *pThread = pContext->pThread; httpRemoveContextFromEpoll(pContext); @@ -55,7 +54,7 @@ static void httpDestroyContext(void *data) { httpFreeJsonBuf(pContext); httpFreeMultiCmds(pContext); - tfree(pContext); + taosTFree(pContext); } bool httpInitContexts() { diff --git a/src/plugins/http/src/httpServer.c b/src/plugins/http/src/httpServer.c index ec3d2c0d44..5c910a3311 100644 --- a/src/plugins/http/src/httpServer.c +++ b/src/plugins/http/src/httpServer.c @@ -18,7 +18,6 @@ #include "taosmsg.h" #include "tsocket.h" #include "tutil.h" -#include "ttime.h" #include "ttimer.h" #include "tglobal.h" #include "httpInt.h" @@ -203,7 +202,7 @@ static void httpProcessHttpData(void *param) { if (pContext == NULL) { httpError("context:%p, is already released, close connect", events[i].data.ptr); //epoll_ctl(pThread->pollFd, EPOLL_CTL_DEL, events[i].data.fd, NULL); - //tclose(events[i].data.fd); + //taosClose(events[i].data.fd); continue; } @@ -331,7 +330,7 @@ static void *httpAcceptHttpConnection(void *arg) { if (epoll_ctl(pThread->pollFd, EPOLL_CTL_ADD, connFd, &event) < 0) { httpError("context:%p, fd:%d, ip:%s, thread:%s, failed to add http fd for epoll, error:%s", pContext, connFd, pContext->ipstr, pThread->label, strerror(errno)); - tclose(pContext->fd); + taosClose(pContext->fd); httpReleaseContext(pContext); continue; } diff --git a/src/plugins/http/src/httpSession.c b/src/plugins/http/src/httpSession.c index 256b0c9549..fce85df45e 100644 --- a/src/plugins/http/src/httpSession.c +++ b/src/plugins/http/src/httpSession.c @@ -16,7 +16,6 @@ #define _DEFAULT_SOURCE #include "os.h" #include "taos.h" -#include "ttime.h" #include "tglobal.h" #include "tcache.h" #include "httpInt.h" diff --git a/src/plugins/http/src/httpSystem.c b/src/plugins/http/src/httpSystem.c index 3a0998f2e8..38bd8624b2 100644 --- a/src/plugins/http/src/httpSystem.c +++ b/src/plugins/http/src/httpSystem.c @@ -99,7 +99,7 @@ void httpCleanUpSystem() { httpCleanupContexts(); httpCleanUpSessions(); pthread_mutex_destroy(&tsHttpServer.serverMutex); - tfree(tsHttpServer.pThreads); + taosTFree(tsHttpServer.pThreads); tsHttpServer.pThreads = NULL; tsHttpServer.status = HTTP_SERVER_CLOSED; diff --git a/src/plugins/monitor/src/monitorMain.c b/src/plugins/monitor/src/monitorMain.c index 0cc28bb82c..b31fc368af 100644 --- a/src/plugins/monitor/src/monitorMain.c +++ b/src/plugins/monitor/src/monitorMain.c @@ -18,7 +18,6 @@ #include "taosdef.h" #include "taoserror.h" #include "tlog.h" -#include "ttime.h" #include "ttimer.h" #include "tutil.h" #include "tsystem.h" diff --git a/src/query/src/qExecutor.c b/src/query/src/qExecutor.c index 6efc8a827e..1277e7bfbb 100644 --- a/src/query/src/qExecutor.c +++ b/src/query/src/qExecutor.c @@ -28,7 +28,6 @@ #include "queryLog.h" #include "tlosertree.h" #include "tscompression.h" -#include "ttime.h" /** * check if the primary column is load by default, otherwise, the program will @@ -930,7 +929,7 @@ static void blockwiseApplyFunctions(SQueryRuntimeEnv *pRuntimeEnv, SDataStatis * STimeWindow win = getActiveTimeWindow(pWindowResInfo, ts, pQuery); if (setWindowOutputBufByKey(pRuntimeEnv, pWindowResInfo, pDataBlockInfo->tid, &win, masterScan, &hasTimeWindow) != TSDB_CODE_SUCCESS) { - tfree(sasArray); + taosTFree(sasArray); return; } @@ -993,10 +992,10 @@ static void blockwiseApplyFunctions(SQueryRuntimeEnv *pRuntimeEnv, SDataStatis * continue; } - tfree(sasArray[i].data); + taosTFree(sasArray[i].data); } - tfree(sasArray); + taosTFree(sasArray); } static int32_t setGroupResultOutputBuf(SQueryRuntimeEnv *pRuntimeEnv, char *pData, int16_t type, int16_t bytes) { @@ -1301,7 +1300,7 @@ static void rowwiseApplyFunctions(SQueryRuntimeEnv *pRuntimeEnv, SDataStatis *pS continue; } - tfree(sasArray[i].data); + taosTFree(sasArray[i].data); } free(sasArray); @@ -1468,7 +1467,7 @@ static void setCtxTagColumnInfo(SQueryRuntimeEnv *pRuntimeEnv, SQLFunctionCtx *p p->tagInfo.numOfTagCols = num; p->tagInfo.tagsLen = tagLen; } else { - tfree(pTagCtx); + taosTFree(pTagCtx); } } } @@ -1576,8 +1575,8 @@ static int32_t setupQueryRuntimeEnv(SQueryRuntimeEnv *pRuntimeEnv, int16_t order return TSDB_CODE_SUCCESS; _clean: - tfree(pRuntimeEnv->resultInfo); - tfree(pRuntimeEnv->pCtx); + taosTFree(pRuntimeEnv->resultInfo); + taosTFree(pRuntimeEnv->pCtx); return TSDB_CODE_QRY_OUT_OF_MEMORY; } @@ -1602,11 +1601,11 @@ static void teardownQueryRuntimeEnv(SQueryRuntimeEnv *pRuntimeEnv) { } tVariantDestroy(&pCtx->tag); - tfree(pCtx->tagInfo.pTagCtxList); + taosTFree(pCtx->tagInfo.pTagCtxList); } - tfree(pRuntimeEnv->resultInfo); - tfree(pRuntimeEnv->pCtx); + taosTFree(pRuntimeEnv->resultInfo); + taosTFree(pRuntimeEnv->pCtx); } pRuntimeEnv->pFillInfo = taosDestoryFillInfo(pRuntimeEnv->pFillInfo); @@ -2739,8 +2738,8 @@ int32_t mergeIntoGroupResultImpl(SQInfo *pQInfo, SArray *pGroup) { STableQueryInfo **pTableList = malloc(POINTER_BYTES * size); if (pTableList == NULL || posList == NULL) { - tfree(posList); - tfree(pTableList); + taosTFree(posList); + taosTFree(pTableList); qError("QInfo:%p failed alloc memory", pQInfo); longjmp(pRuntimeEnv->env, TSDB_CODE_QRY_OUT_OF_MEMORY); @@ -2759,8 +2758,8 @@ int32_t mergeIntoGroupResultImpl(SQInfo *pQInfo, SArray *pGroup) { } if (numOfTables == 0) { - tfree(posList); - tfree(pTableList); + taosTFree(posList); + taosTFree(pTableList); assert(pQInfo->numOfGroupResultPages == 0); return 0; @@ -2843,10 +2842,10 @@ int32_t mergeIntoGroupResultImpl(SQInfo *pQInfo, SArray *pGroup) { if (flushFromResultBuf(pQInfo) != TSDB_CODE_SUCCESS) { qError("QInfo:%p failed to flush data into temp file, abort query", pQInfo); - tfree(pTree); - tfree(pTableList); - tfree(posList); - tfree(pResultInfo); + taosTFree(pTree); + taosTFree(pTableList); + taosTFree(posList); + taosTFree(pResultInfo); return -1; } @@ -2860,14 +2859,14 @@ int32_t mergeIntoGroupResultImpl(SQInfo *pQInfo, SArray *pGroup) { qDebug("QInfo:%p result merge completed for group:%d, elapsed time:%" PRId64 " ms", pQInfo, pQInfo->groupIndex, endt - startt); - tfree(pTableList); - tfree(posList); - tfree(pTree); + taosTFree(pTableList); + taosTFree(posList); + taosTFree(pTree); pQInfo->offset = 0; - tfree(pResultInfo); - tfree(buf); + taosTFree(pResultInfo); + taosTFree(buf); return pQInfo->numOfGroupResultPages; } @@ -5454,13 +5453,13 @@ static int32_t convertQueryMsg(SQueryTableMsg *pQueryMsg, SArray **pTableIdList, return TSDB_CODE_SUCCESS; _cleanup: - tfree(*pExpr); + taosTFree(*pExpr); taosArrayDestroy(*pTableIdList); *pTableIdList = NULL; - tfree(*tbnameCond); - tfree(*groupbyCols); - tfree(*tagCols); - tfree(*tagCond); + taosTFree(*tbnameCond); + taosTFree(*groupbyCols); + taosTFree(*tagCols); + taosTFree(*tagCond); return code; } @@ -5511,7 +5510,7 @@ static int32_t createQFunctionExprFromMsg(SQueryTableMsg *pQueryMsg, SExprInfo * code = buildAirthmeticExprFromMsg(&pExprs[i], pQueryMsg); if (code != TSDB_CODE_SUCCESS) { - tfree(pExprs); + taosTFree(pExprs); return code; } @@ -5540,7 +5539,7 @@ static int32_t createQFunctionExprFromMsg(SQueryTableMsg *pQueryMsg, SExprInfo * int32_t param = pExprs[i].base.arg[0].argValue.i64; if (getResultDataInfo(type, bytes, pExprs[i].base.functionId, param, &pExprs[i].type, &pExprs[i].bytes, &pExprs[i].interBytes, 0, isSuperTable) != TSDB_CODE_SUCCESS) { - tfree(pExprs); + taosTFree(pExprs); return TSDB_CODE_QRY_INVALID_MSG; } @@ -5905,14 +5904,14 @@ _cleanup_query: taosArrayDestroy(pGroupbyExpr->columnInfo); free(pGroupbyExpr); } - tfree(pTagCols); + taosTFree(pTagCols); for (int32_t i = 0; i < numOfOutput; ++i) { SExprInfo* pExprInfo = &pExprs[i]; if (pExprInfo->pExpr != NULL) { tExprTreeDestroy(&pExprInfo->pExpr, NULL); } } - tfree(pExprs); + taosTFree(pExprs); _cleanup: freeQInfo(pQInfo); @@ -5997,7 +5996,7 @@ static void freeQInfo(SQInfo *pQInfo) { qDebug("QInfo:%p start to free QInfo", pQInfo); for (int32_t col = 0; col < pQuery->numOfOutput; ++col) { - tfree(pQuery->sdata[col]); + taosTFree(pQuery->sdata[col]); } teardownQueryRuntimeEnv(&pQInfo->runtimeEnv); @@ -6005,7 +6004,7 @@ static void freeQInfo(SQInfo *pQInfo) { for (int32_t i = 0; i < pQuery->numOfFilterCols; ++i) { SSingleColumnFilterInfo *pColFilter = &pQuery->pFilterInfo[i]; if (pColFilter->numOfFilters > 0) { - tfree(pColFilter->pFilters); + taosTFree(pColFilter->pFilters); } } @@ -6018,11 +6017,11 @@ static void freeQInfo(SQInfo *pQInfo) { } } - tfree(pQuery->pSelectExpr); + taosTFree(pQuery->pSelectExpr); } if (pQuery->fillVal != NULL) { - tfree(pQuery->fillVal); + taosTFree(pQuery->fillVal); } // todo refactor, extract method to destroytableDataInfo @@ -6041,7 +6040,7 @@ static void freeQInfo(SQInfo *pQInfo) { } } - tfree(pQInfo->pBuf); + taosTFree(pQInfo->pBuf); taosArrayDestroy(pQInfo->tableqinfoGroupInfo.pGroupList); taosHashCleanup(pQInfo->tableqinfoGroupInfo.map); tsdbDestroyTableGroup(&pQInfo->tableGroupInfo); @@ -6049,27 +6048,27 @@ static void freeQInfo(SQInfo *pQInfo) { if (pQuery->pGroupbyExpr != NULL) { taosArrayDestroy(pQuery->pGroupbyExpr->columnInfo); - tfree(pQuery->pGroupbyExpr); + taosTFree(pQuery->pGroupbyExpr); } - tfree(pQuery->tagColList); - tfree(pQuery->pFilterInfo); + taosTFree(pQuery->tagColList); + taosTFree(pQuery->pFilterInfo); if (pQuery->colList != NULL) { for (int32_t i = 0; i < pQuery->numOfCols; i++) { SColumnInfo* column = pQuery->colList + i; freeColumnFilterInfo(column->filters, column->numOfFilters); } - tfree(pQuery->colList); + taosTFree(pQuery->colList); } - tfree(pQuery->sdata); - tfree(pQuery); + taosTFree(pQuery->sdata); + taosTFree(pQuery); pQInfo->signature = 0; qDebug("QInfo:%p QInfo is freed", pQInfo); - tfree(pQInfo); + taosTFree(pQInfo); } static size_t getResultSize(SQInfo *pQInfo, int64_t *numOfRows) { @@ -6692,7 +6691,7 @@ void qCleanupQueryMgmt(void* pQMgmt) { taosCacheCleanup(pqinfoPool); pthread_mutex_destroy(&pQueryMgmt->lock); - tfree(pQueryMgmt); + taosTFree(pQueryMgmt); qDebug("vgId:%d queryMgmt cleanup completed", vgId); } diff --git a/src/query/src/qExtbuffer.c b/src/query/src/qExtbuffer.c index 6f1c51a19e..21b5361acb 100644 --- a/src/query/src/qExtbuffer.c +++ b/src/query/src/qExtbuffer.c @@ -65,7 +65,7 @@ void* destoryExtMemBuffer(tExtMemBuffer *pMemBuffer) { // release flush out info link SExtFileInfo *pFileMeta = &pMemBuffer->fileMeta; if (pFileMeta->flushoutData.nAllocSize != 0 && pFileMeta->flushoutData.pFlushoutInfo != NULL) { - tfree(pFileMeta->flushoutData.pFlushoutInfo); + taosTFree(pFileMeta->flushoutData.pFlushoutInfo); } // release all in-memory buffer pages @@ -73,7 +73,7 @@ void* destoryExtMemBuffer(tExtMemBuffer *pMemBuffer) { while (pFilePages != NULL) { tFilePagesItem *pTmp = pFilePages; pFilePages = pFilePages->pNext; - tfree(pTmp); + taosTFree(pTmp); } // close temp file @@ -88,8 +88,8 @@ void* destoryExtMemBuffer(tExtMemBuffer *pMemBuffer) { destroyColumnModel(pMemBuffer->pColumnModel); - tfree(pMemBuffer->path); - tfree(pMemBuffer); + taosTFree(pMemBuffer->path); + taosTFree(pMemBuffer); return NULL; } @@ -276,7 +276,7 @@ int32_t tExtMemBufferFlush(tExtMemBuffer *pMemBuffer) { tFilePagesItem *ptmp = first; first = first->pNext; - tfree(ptmp); // release all data in memory buffer + taosTFree(ptmp); // release all data in memory buffer } fflush(pMemBuffer->file); // flush to disk @@ -301,7 +301,7 @@ void tExtMemBufferClear(tExtMemBuffer *pMemBuffer) { while (first != NULL) { tFilePagesItem *ptmp = first; first = first->pNext; - tfree(ptmp); + taosTFree(ptmp); } pMemBuffer->fileMeta.numOfElemsInFile = 0; @@ -788,7 +788,7 @@ void destroyColumnModel(SColumnModel *pModel) { return; } - tfree(pModel); + taosTFree(pModel); } static void printBinaryData(char *data, int32_t len) { @@ -1073,5 +1073,5 @@ void tOrderDescDestroy(tOrderDescriptor *pDesc) { } destroyColumnModel(pDesc->pColumnModel); - tfree(pDesc); + taosTFree(pDesc); } diff --git a/src/query/src/qFill.c b/src/query/src/qFill.c index 9dec2598bc..e65d793dc9 100644 --- a/src/query/src/qFill.c +++ b/src/query/src/qFill.c @@ -74,18 +74,18 @@ void* taosDestoryFillInfo(SFillInfo* pFillInfo) { return NULL; } - tfree(pFillInfo->prevValues); - tfree(pFillInfo->nextValues); - tfree(pFillInfo->pTags); + taosTFree(pFillInfo->prevValues); + taosTFree(pFillInfo->nextValues); + taosTFree(pFillInfo->pTags); for(int32_t i = 0; i < pFillInfo->numOfCols; ++i) { - tfree(pFillInfo->pData[i]); + taosTFree(pFillInfo->pData[i]); } - tfree(pFillInfo->pData); - tfree(pFillInfo->pFillCol); + taosTFree(pFillInfo->pData); + taosTFree(pFillInfo->pFillCol); - tfree(pFillInfo); + taosTFree(pFillInfo); return NULL; } @@ -454,7 +454,7 @@ int32_t generateDataBlockImpl(SFillInfo* pFillInfo, tFilePage** data, int32_t nu pFillInfo->numOfRows = 0; /* the raw data block is exhausted, next value does not exists */ - tfree(*nextValues); + taosTFree(*nextValues); } pFillInfo->numOfTotal += pFillInfo->numOfCurrent; diff --git a/src/query/src/qParserImpl.c b/src/query/src/qParserImpl.c index 7cf995193b..f556e2dd53 100644 --- a/src/query/src/qParserImpl.c +++ b/src/query/src/qParserImpl.c @@ -22,7 +22,6 @@ #include "tglobal.h" #include "tstoken.h" #include "tstrbuild.h" -#include "ttime.h" #include "ttokendef.h" #include "tutil.h" @@ -609,7 +608,7 @@ void destroyAllSelectClause(SSubclauseInfo *pClause) { doDestroyQuerySql(pQuerySql); } - tfree(pClause->pClause); + taosTFree(pClause->pClause); } SCreateTableSQL *tSetCreateSQLElems(tFieldList *pCols, tFieldList *pTags, SSQLToken *pStableName, @@ -679,12 +678,12 @@ void SQLInfoDestroy(SSqlInfo *pInfo) { tFieldListDestroy(pCreateTableInfo->colInfo.pTagColumns); tVariantListDestroy(pCreateTableInfo->usingInfo.pTagVals); - tfree(pInfo->pCreateTableInfo); + taosTFree(pInfo->pCreateTableInfo); } else if (pInfo->type == TSDB_SQL_ALTER_TABLE) { tVariantListDestroy(pInfo->pAlterInfo->varList); tFieldListDestroy(pInfo->pAlterInfo->pAddColumns); - tfree(pInfo->pAlterInfo); + taosTFree(pInfo->pAlterInfo); } else { if (pInfo->pDCLInfo != NULL && pInfo->pDCLInfo->nAlloc > 0) { free(pInfo->pDCLInfo->a); @@ -694,7 +693,7 @@ void SQLInfoDestroy(SSqlInfo *pInfo) { tVariantListDestroy(pInfo->pDCLInfo->dbOpt.keep); } - tfree(pInfo->pDCLInfo); + taosTFree(pInfo->pDCLInfo); } } diff --git a/src/query/src/qPercentile.c b/src/query/src/qPercentile.c index 85e45e46b3..7f5fa08cf1 100644 --- a/src/query/src/qPercentile.c +++ b/src/query/src/qPercentile.c @@ -70,7 +70,7 @@ static tFilePage *loadIntoBucketFromDisk(tMemBucket *pMemBucket, int32_t segIdx, printf("id: %d count: %" PRIu64 "\n", j, buffer->num); } } - tfree(pPage); + taosTFree(pPage); assert(buffer->num == pMemBuffer->fileMeta.numOfElemsInFile); } @@ -284,7 +284,7 @@ tMemBucket *tMemBucketCreate(int32_t totalSlots, int32_t nBufferSize, int16_t nE }; default: { uError("MemBucket:%p,not support data type %d,failed", pBucket, pBucket->dataType); - tfree(pBucket); + taosTFree(pBucket); return NULL; } } @@ -292,14 +292,14 @@ tMemBucket *tMemBucketCreate(int32_t totalSlots, int32_t nBufferSize, int16_t nE int32_t numOfCols = pDesc->pColumnModel->numOfCols; if (numOfCols != 1) { uError("MemBucket:%p,only consecutive data is allowed,invalid numOfCols:%d", pBucket, numOfCols); - tfree(pBucket); + taosTFree(pBucket); return NULL; } SSchema* pSchema = getColumnModelSchema(pDesc->pColumnModel, 0); if (pSchema->type != dataType) { uError("MemBucket:%p,data type is not consistent,%d in schema, %d in param", pBucket, pSchema->type, dataType); - tfree(pBucket); + taosTFree(pBucket); return NULL; } @@ -329,7 +329,7 @@ void tMemBucketDestroy(tMemBucket *pBucket) { if (pBucket->pSegs) { for (int32_t i = 0; i < pBucket->numOfSegs; ++i) { tMemBucketSegment *pSeg = &(pBucket->pSegs[i]); - tfree(pSeg->pBoundingEntries); + taosTFree(pSeg->pBoundingEntries); if (pSeg->pBuffer == NULL || pSeg->numOfSlots == 0) { continue; @@ -340,12 +340,12 @@ void tMemBucketDestroy(tMemBucket *pBucket) { pSeg->pBuffer[j] = destoryExtMemBuffer(pSeg->pBuffer[j]); } } - tfree(pSeg->pBuffer); + taosTFree(pSeg->pBuffer); } } - tfree(pBucket->pSegs); - tfree(pBucket); + taosTFree(pBucket->pSegs); + taosTFree(pBucket); } /* @@ -789,7 +789,7 @@ double getPercentileImpl(tMemBucket *pMemBucket, int32_t count, double fraction) } } double val = (1 - fraction) * td + fraction * nd; - tfree(buffer); + taosTFree(buffer); return val; } else { // incur a second round bucket split @@ -891,8 +891,8 @@ double getPercentileImpl(tMemBucket *pMemBucket, int32_t count, double fraction) if (unlink(pMemBuffer->path) != 0) { uError("MemBucket:%p, remove tmp file %s failed", pMemBucket, pMemBuffer->path); } - tfree(pMemBuffer); - tfree(pPage); + taosTFree(pMemBuffer); + taosTFree(pPage); return getPercentileImpl(pMemBucket, count - num, fraction); } diff --git a/src/query/src/qResultbuf.c b/src/query/src/qResultbuf.c index 363b590d80..b73a7cc887 100644 --- a/src/query/src/qResultbuf.c +++ b/src/query/src/qResultbuf.c @@ -258,7 +258,7 @@ static char* evicOneDataPage(SDiskbasedResultBuf* pResultBuf) { assert(d->pn == pn); d->pn = NULL; - tfree(pn); + taosTFree(pn); bufPage = flushPageToDisk(pResultBuf, d); } @@ -406,7 +406,7 @@ void destroyResultBuf(SDiskbasedResultBuf* pResultBuf) { } unlink(pResultBuf->path); - tfree(pResultBuf->path); + taosTFree(pResultBuf->path); SHashMutableIterator* iter = taosHashCreateIter(pResultBuf->groupSet); while(taosHashIterNext(iter)) { @@ -414,8 +414,8 @@ void destroyResultBuf(SDiskbasedResultBuf* pResultBuf) { size_t n = taosArrayGetSize(*p); for(int32_t i = 0; i < n; ++i) { SPageInfo* pi = taosArrayGetP(*p, i); - tfree(pi->pData); - tfree(pi); + taosTFree(pi->pData); + taosTFree(pi); } taosArrayDestroy(*p); @@ -428,8 +428,8 @@ void destroyResultBuf(SDiskbasedResultBuf* pResultBuf) { taosHashCleanup(pResultBuf->groupSet); taosHashCleanup(pResultBuf->all); - tfree(pResultBuf->assistBuf); - tfree(pResultBuf); + taosTFree(pResultBuf->assistBuf); + taosTFree(pResultBuf); } SPageInfo* getLastPageInfo(SIDList pList) { diff --git a/src/query/src/qTsbuf.c b/src/query/src/qTsbuf.c index 8ab45cc1a9..fe39fe4e4a 100644 --- a/src/query/src/qTsbuf.c +++ b/src/query/src/qTsbuf.c @@ -142,11 +142,11 @@ void* tsBufDestroy(STSBuf* pTSBuf) { return NULL; } - tfree(pTSBuf->assistBuf); - tfree(pTSBuf->tsData.rawBuf); + taosTFree(pTSBuf->assistBuf); + taosTFree(pTSBuf->tsData.rawBuf); - tfree(pTSBuf->pData); - tfree(pTSBuf->block.payload); + taosTFree(pTSBuf->pData); + taosTFree(pTSBuf->block.payload); fclose(pTSBuf->f); diff --git a/src/query/src/qUtil.c b/src/query/src/qUtil.c index c9143b3a53..7175262270 100644 --- a/src/query/src/qUtil.c +++ b/src/query/src/qUtil.c @@ -14,11 +14,8 @@ */ #include "os.h" - #include "hash.h" #include "taosmsg.h" -#include "ttime.h" - #include "qExecutor.h" #include "qUtil.h" @@ -89,7 +86,7 @@ void cleanupTimeWindowInfo(SWindowResInfo *pWindowResInfo) { } taosHashCleanup(pWindowResInfo->hashList); - tfree(pWindowResInfo->pResult); + taosTFree(pWindowResInfo->pResult); } void resetTimeWindowInfo(SQueryRuntimeEnv *pRuntimeEnv, SWindowResInfo *pWindowResInfo) { diff --git a/src/query/tests/tsBufTest.cpp b/src/query/tests/tsBufTest.cpp index e9827518e1..28b1d9cefe 100644 --- a/src/query/tests/tsBufTest.cpp +++ b/src/query/tests/tsBufTest.cpp @@ -1,13 +1,12 @@ +#include "os.h" #include #include #include #include "taos.h" #include "tsdb.h" - #include "qTsbuf.h" #include "tstoken.h" -#include "ttime.h" #include "tutil.h" namespace { diff --git a/src/query/tests/unitTest.cpp b/src/query/tests/unitTest.cpp index 60c73b4fad..b59e0783a2 100644 --- a/src/query/tests/unitTest.cpp +++ b/src/query/tests/unitTest.cpp @@ -1,3 +1,4 @@ +#include "os.h" #include #include #include @@ -6,7 +7,6 @@ #include "tsdb.h" #include "../../client/inc/tscUtil.h" -#include "ttime.h" #include "tutil.h" #include "tvariant.h" #include "ttokendef.h" diff --git a/src/rpc/src/rpcCache.c b/src/rpc/src/rpcCache.c index 6f89969305..3f76b202c9 100644 --- a/src/rpc/src/rpcCache.c +++ b/src/rpc/src/rpcCache.c @@ -16,7 +16,6 @@ #include "os.h" #include "tglobal.h" #include "tmempool.h" -#include "ttime.h" #include "ttimer.h" #include "tutil.h" #include "rpcLog.h" @@ -102,9 +101,9 @@ void rpcCloseConnCache(void *handle) { if (pCache->connHashMemPool) taosMemPoolCleanUp(pCache->connHashMemPool); - tfree(pCache->connHashList); - tfree(pCache->count); - tfree(pCache->lockedBy); + taosTFree(pCache->connHashList); + taosTFree(pCache->count); + taosTFree(pCache->lockedBy); pthread_mutex_unlock(&pCache->mutex); diff --git a/src/rpc/src/rpcMain.c b/src/rpc/src/rpcMain.c index 7425558535..be609c4ee8 100644 --- a/src/rpc/src/rpcMain.c +++ b/src/rpc/src/rpcMain.c @@ -17,7 +17,6 @@ #include "tidpool.h" #include "tmd5.h" #include "tmempool.h" -#include "ttime.h" #include "ttimer.h" #include "tutil.h" #include "lz4.h" @@ -1563,10 +1562,10 @@ static void rpcDecRef(SRpcInfo *pRpc) taosTmrCleanUp(pRpc->tmrCtrl); taosIdPoolCleanUp(pRpc->idPool); - tfree(pRpc->connList); + taosTFree(pRpc->connList); pthread_mutex_destroy(&pRpc->mutex); tDebug("%s rpc resources are released", pRpc->label); - tfree(pRpc); + taosTFree(pRpc); } } diff --git a/src/rpc/src/rpcTcp.c b/src/rpc/src/rpcTcp.c index 5cb45a6d26..7fa05af9b0 100644 --- a/src/rpc/src/rpcTcp.c +++ b/src/rpc/src/rpcTcp.c @@ -213,8 +213,8 @@ void taosCleanUpTcpServer(void *handle) { tDebug("%s TCP server is cleaned up", pServerObj->label); - tfree(pServerObj->pThreadObj); - tfree(pServerObj); + taosTFree(pServerObj->pThreadObj); + taosTFree(pServerObj); } static void *taosAcceptTcpConnection(void *arg) { @@ -324,7 +324,7 @@ void taosCleanUpTcpClient(void *chandle) { taosStopTcpThread(pThreadObj); tDebug ("%s TCP client is cleaned up", pThreadObj->label); - tfree(pThreadObj); + taosTFree(pThreadObj); } void *taosOpenTcpClientConnection(void *shandle, void *thandle, uint32_t ip, uint16_t port) { @@ -518,7 +518,7 @@ static SFdObj *taosMallocFdObj(SThreadObj *pThreadObj, int fd) { event.events = EPOLLIN | EPOLLRDHUP; event.data.ptr = pFdObj; if (epoll_ctl(pThreadObj->pollFd, EPOLL_CTL_ADD, fd, &event) < 0) { - tfree(pFdObj); + taosTFree(pFdObj); terrno = TAOS_SYSTEM_ERROR(errno); return NULL; } @@ -571,5 +571,5 @@ static void taosFreeFdObj(SFdObj *pFdObj) { tDebug("%s %p TCP connection is closed, FD:%p numOfFds:%d", pThreadObj->label, pFdObj->thandle, pFdObj, pThreadObj->numOfFds); - tfree(pFdObj); + taosTFree(pFdObj); } diff --git a/src/rpc/src/rpcUdp.c b/src/rpc/src/rpcUdp.c index bdaae4c597..f75375e2fe 100644 --- a/src/rpc/src/rpcUdp.c +++ b/src/rpc/src/rpcUdp.c @@ -145,7 +145,7 @@ void taosStopUdpConnection(void *handle) { for (int i = 0; i < pSet->threads; ++i) { pConn = pSet->udpConn + i; if (pConn->thread) pthread_join(pConn->thread, NULL); - tfree(pConn->buffer); + taosTFree(pConn->buffer); // tTrace("%s UDP thread is closed, index:%d", pConn->label, i); } @@ -164,7 +164,7 @@ void taosCleanUpUdpConnection(void *handle) { } tDebug("%s UDP is cleaned up", pSet->label); - tfree(pSet); + taosTFree(pSet); } void *taosOpenUdpConnection(void *shandle, void *thandle, uint32_t ip, uint16_t port) { diff --git a/src/sync/src/syncMain.c b/src/sync/src/syncMain.c index 5195e70364..2cc026484b 100644 --- a/src/sync/src/syncMain.c +++ b/src/sync/src/syncMain.c @@ -20,7 +20,6 @@ #include "tlog.h" #include "tutil.h" #include "ttimer.h" -#include "ttime.h" #include "tsocket.h" #include "tglobal.h" #include "taoserror.h" @@ -438,9 +437,9 @@ static void syncDecNodeRef(SSyncNode *pNode) { if (atomic_sub_fetch_8(&pNode->refCount, 1) == 0) { pthread_mutex_destroy(&pNode->mutex); - tfree(pNode->pRecv); - tfree(pNode->pSyncFwds); - tfree(pNode); + taosTFree(pNode->pRecv); + taosTFree(pNode->pSyncFwds); + taosTFree(pNode); if (atomic_sub_fetch_32(&tsNodeNum, 1) == 0) { if (tsTcpPool) taosCloseTcpThreadPool(tsTcpPool); @@ -466,8 +465,8 @@ int syncDecPeerRef(SSyncPeer *pPeer) syncDecNodeRef(pPeer->pSyncNode); sDebug("%s, resource is freed", pPeer->id); - tfree(pPeer->watchFd); - tfree(pPeer); + taosTFree(pPeer->watchFd); + taosTFree(pPeer); return 0; } @@ -477,7 +476,7 @@ int syncDecPeerRef(SSyncPeer *pPeer) static void syncClosePeerConn(SSyncPeer *pPeer) { taosTmrStopA(&pPeer->timer); - tclose(pPeer->syncFd); + taosClose(pPeer->syncFd); if (pPeer->peerFd >=0) { pPeer->peerFd = -1; taosFreeTcpConn(pPeer->pConn); @@ -756,7 +755,7 @@ static void syncProcessSyncRequest(char *msg, SSyncPeer *pPeer) if (nodeRole != TAOS_SYNC_ROLE_MASTER) { sError("%s, I am not master anymore", pPeer->id); - tclose(pPeer->syncFd); + taosClose(pPeer->syncFd); return; } @@ -1053,7 +1052,7 @@ static void syncCreateRestoreDataThread(SSyncPeer *pPeer) if (ret < 0) { sError("%s, failed to create sync thread", pPeer->id); - tclose(pPeer->syncFd); + taosClose(pPeer->syncFd); syncDecPeerRef(pPeer); } else { sInfo("%s, sync connection is up", pPeer->id); diff --git a/src/sync/src/syncRestore.c b/src/sync/src/syncRestore.c index 07d99b916e..505882b209 100644 --- a/src/sync/src/syncRestore.c +++ b/src/sync/src/syncRestore.c @@ -225,10 +225,10 @@ int syncSaveIntoBuffer(SSyncPeer *pPeer, SWalHead *pHead) static void syncCloseRecvBuffer(SSyncNode *pNode) { if (pNode->pRecv) { - tfree(pNode->pRecv->buffer); + taosTFree(pNode->pRecv->buffer); } - tfree(pNode->pRecv); + taosTFree(pNode->pRecv); } static int syncOpenRecvBuffer(SSyncNode *pNode) @@ -319,7 +319,7 @@ void *syncRestoreData(void *param) (*pNode->notifyRole)(pNode->ahandle, nodeRole); nodeSStatus = TAOS_SYNC_STATUS_INIT; - tclose(pPeer->syncFd) + taosClose(pPeer->syncFd) syncCloseRecvBuffer(pNode); __sync_fetch_and_sub(&tsSyncNum, 1); syncDecPeerRef(pPeer); diff --git a/src/sync/src/syncRetrieve.c b/src/sync/src/syncRetrieve.c index 8aa7d101e7..f881b680f5 100644 --- a/src/sync/src/syncRetrieve.c +++ b/src/sync/src/syncRetrieve.c @@ -190,7 +190,7 @@ static int syncReadOneWalRecord(int sfd, SWalHead *pHead, uint32_t *pEvent) static int syncMonitorLastWal(SSyncPeer *pPeer, char *name) { pPeer->watchNum = 0; - tclose(pPeer->notifyFd); + taosClose(pPeer->notifyFd); pPeer->notifyFd = inotify_init1(IN_NONBLOCK); if (pPeer->notifyFd < 0) { sError("%s, failed to init inotify(%s)", pPeer->id, strerror(errno)); @@ -271,7 +271,7 @@ static int syncRetrieveLastWal(SSyncPeer *pPeer, char *name, uint64_t fversion, } free(pHead); - tclose(sfd); + taosClose(sfd); if (code == 0) return bytes; return -1; @@ -352,7 +352,7 @@ static int syncProcessLastWal(SSyncPeer *pPeer, char *wname, uint32_t index) sDebug("%s, last wal is closed, try new one", pPeer->id); } - tclose(pPeer->notifyFd); + taosClose(pPeer->notifyFd); return code; } @@ -486,8 +486,8 @@ void *syncRetrieveData(void *param) } pPeer->fileChanged = 0; - tclose(pPeer->notifyFd); - tclose(pPeer->syncFd); + taosClose(pPeer->notifyFd); + taosClose(pPeer->syncFd); syncDecPeerRef(pPeer); return NULL; diff --git a/src/sync/src/taosTcpPool.c b/src/sync/src/taosTcpPool.c index fa94caeed7..88c2c53be4 100644 --- a/src/sync/src/taosTcpPool.c +++ b/src/sync/src/taosTcpPool.c @@ -102,7 +102,7 @@ void taosCloseTcpThreadPool(void *param) if (pThread) taosStopPoolThread(pThread); } - tfree(pPool->pThread); + taosTFree(pPool->pThread); free(pPool); uDebug("%p TCP pool is closed", pPool); } @@ -166,7 +166,7 @@ static void taosProcessBrokenLink(SConnObj *pConn) { pThread->numOfFds--; epoll_ctl(pThread->pollFd, EPOLL_CTL_DEL, pConn->fd, NULL); uDebug("%p fd:%d is removed from epoll thread, num:%d", pThread, pConn->fd, pThread->numOfFds); - tclose(pConn->fd); + taosClose(pConn->fd); free(pConn); } @@ -255,7 +255,7 @@ static void *taosAcceptPeerTcpConnection(void *argv) { (*pInfo->processIncomingConn)(connFd, clientAddr.sin_addr.s_addr); } - tclose(pPool->acceptFd); + taosClose(pPool->acceptFd); return NULL; } @@ -320,6 +320,6 @@ static void taosStopPoolThread(SThreadObj* pThread) { } pthread_join(thread, NULL); - tclose(fd); + taosClose(fd); } diff --git a/src/sync/src/tarbitrator.c b/src/sync/src/tarbitrator.c index c308c2a454..3c6db88a9c 100644 --- a/src/sync/src/tarbitrator.c +++ b/src/sync/src/tarbitrator.c @@ -19,7 +19,6 @@ #include "tlog.h" #include "tutil.h" #include "ttimer.h" -#include "ttime.h" #include "tsocket.h" #include "tglobal.h" #include "taoserror.h" @@ -133,7 +132,7 @@ static void arbProcessIncommingConnection(int connFd, uint32_t sourceIp) snprintf(pNode->id, sizeof(pNode->id), "vgId:%d peer:%s:%d", firstPkt.sourceId, firstPkt.fqdn, firstPkt.port); if (firstPkt.syncHead.vgId) { sDebug("%s, vgId in head is not zero, close the connection", pNode->id); - tfree(pNode); + taosTFree(pNode); taosCloseSocket(connFd); return; } @@ -149,7 +148,7 @@ static void arbProcessBrokenLink(void *param) { SNodeConn *pNode = param; sDebug("%s, TCP link is broken(%s), close connection", pNode->id, strerror(errno)); - tfree(pNode); + taosTFree(pNode); } static int arbProcessPeerMsg(void *param, void *buffer) diff --git a/src/tsdb/src/tsdbBuffer.c b/src/tsdb/src/tsdbBuffer.c index dcc9d4ca1b..2e097c6ff7 100644 --- a/src/tsdb/src/tsdbBuffer.c +++ b/src/tsdb/src/tsdbBuffer.c @@ -157,4 +157,4 @@ _err: return NULL; } -static void tsdbFreeBufBlock(STsdbBufBlock *pBufBlock) { tfree(pBufBlock); } \ No newline at end of file +static void tsdbFreeBufBlock(STsdbBufBlock *pBufBlock) { taosTFree(pBufBlock); } \ No newline at end of file diff --git a/src/tsdb/src/tsdbFile.c b/src/tsdb/src/tsdbFile.c index 6e7b39830e..299802f9b4 100644 --- a/src/tsdb/src/tsdbFile.c +++ b/src/tsdb/src/tsdbFile.c @@ -19,7 +19,6 @@ #include "tchecksum.h" #include "tsdbMain.h" #include "tutil.h" -#include "ttime.h" #ifdef TSDB_IDX const char *tsdbFileSuffix[] = {".idx", ".head", ".data", ".last", "", ".i", ".h", ".l"}; @@ -65,7 +64,7 @@ _err: void tsdbFreeFileH(STsdbFileH *pFileH) { if (pFileH) { pthread_rwlock_destroy(&pFileH->fhlock); - tfree(pFileH->pFGroup); + taosTFree(pFileH->pFGroup); free(pFileH); } } @@ -116,14 +115,14 @@ int tsdbOpenFileH(STsdbRepo *pRepo) { qsort((void *)(pFileH->pFGroup), pFileH->nFGroups, sizeof(SFileGroup), compFGroup); } - tfree(tDataDir); + taosTFree(tDataDir); closedir(dir); return 0; _err: for (int type = 0; type < TSDB_FILE_TYPE_MAX; type++) tsdbDestroyFile(&fileGroup.files[type]); - tfree(tDataDir); + taosTFree(tDataDir); if (dir != NULL) closedir(dir); tsdbCloseFileH(pRepo); return -1; diff --git a/src/tsdb/src/tsdbMain.c b/src/tsdb/src/tsdbMain.c index b04b0be9ba..e23228cc0e 100644 --- a/src/tsdb/src/tsdbMain.c +++ b/src/tsdb/src/tsdbMain.c @@ -23,7 +23,6 @@ #include "tchecksum.h" #include "tscompression.h" #include "tsdb.h" -#include "ttime.h" #include "tulog.h" @@ -214,7 +213,7 @@ uint32_t tsdbGetFileInfo(TSDB_REPO_T *repo, char *name, uint32_t *index, uint32_ char *sdup = strdup(pRepo->rootDir); char *prefix = dirname(sdup); int prefixLen = strlen(prefix); - tfree(sdup); + taosTFree(sdup); if (name[0] == 0) { // get the file from index or after, but not larger than eindex int fid = (*index) / TSDB_FILE_TYPE_MAX; @@ -262,14 +261,14 @@ uint32_t tsdbGetFileInfo(TSDB_REPO_T *repo, char *name, uint32_t *index, uint32_ } if (stat(fname, &fState) < 0) { - tfree(fname); + taosTFree(fname); return 0; } *size = fState.st_size; // magic = *size; - tfree(fname); + taosTFree(fname); return magic; } @@ -565,7 +564,7 @@ static int32_t tsdbSaveConfig(char *rootDir, STsdbCfg *pCfg) { return 0; _err: - tfree(fname); + taosTFree(fname); if (fd >= 0) close(fd); return -1; } @@ -602,13 +601,13 @@ static int tsdbLoadConfig(char *rootDir, STsdbCfg *pCfg) { tsdbDecodeCfg(buf, pCfg); - tfree(fname); + taosTFree(fname); close(fd); return 0; _err: - tfree(fname); + taosTFree(fname); if (fd >= 0) close(fd); return -1; } @@ -681,7 +680,7 @@ static void tsdbFreeRepo(STsdbRepo *pRepo) { tsdbFreeMeta(pRepo->tsdbMeta); // tsdbFreeMemTable(pRepo->mem); // tsdbFreeMemTable(pRepo->imem); - tfree(pRepo->rootDir); + taosTFree(pRepo->rootDir); pthread_mutex_destroy(&pRepo->mutex); free(pRepo); } diff --git a/src/tsdb/src/tsdbMemTable.c b/src/tsdb/src/tsdbMemTable.c index 506f3c11c1..803b07515c 100644 --- a/src/tsdb/src/tsdbMemTable.c +++ b/src/tsdb/src/tsdbMemTable.c @@ -398,7 +398,7 @@ static void tsdbFreeMemTable(SMemTable* pMemTable) { tdListFree(pMemTable->bufBlockList); tdListFree(pMemTable->actList); - tfree(pMemTable->tData); + taosTFree(pMemTable->tData); free(pMemTable); } } @@ -647,7 +647,7 @@ static int tsdbCommitToFile(STsdbRepo *pRepo, int fid, SCommitIter *iters, SRWHe goto _err; } - tfree(dataDir); + taosTFree(dataDir); tsdbCloseHelperFile(pHelper, 0); pthread_rwlock_wrlock(&(pFileH->fhlock)); @@ -662,7 +662,7 @@ static int tsdbCommitToFile(STsdbRepo *pRepo, int fid, SCommitIter *iters, SRWHe return 0; _err: - tfree(dataDir); + taosTFree(dataDir); tsdbCloseHelperFile(pHelper, 1); return -1; } @@ -737,7 +737,7 @@ static int tsdbAdjustMemMaxTables(SMemTable *pMemTable, int maxTables) { pMemTable->tData = pTableData; taosWUnLockLatch(&(pMemTable->latch)); - tfree(tData); + taosTFree(tData); return 0; } \ No newline at end of file diff --git a/src/tsdb/src/tsdbMeta.c b/src/tsdb/src/tsdbMeta.c index d389a96fee..8db6a4a32a 100644 --- a/src/tsdb/src/tsdbMeta.c +++ b/src/tsdb/src/tsdbMeta.c @@ -185,7 +185,7 @@ int tsdbDropTable(TSDB_REPO_T *repo, STableId tableId) { return 0; _err: - tfree(tbname); + taosTFree(tbname); return -1; } @@ -453,7 +453,7 @@ void tsdbFreeMeta(STsdbMeta *pMeta) { if (pMeta) { taosHashCleanup(pMeta->uidMap); tdListFree(pMeta->superList); - tfree(pMeta->tables); + taosTFree(pMeta->tables); pthread_rwlock_destroy(&pMeta->rwLock); free(pMeta); } @@ -477,11 +477,11 @@ int tsdbOpenMeta(STsdbRepo *pRepo) { } tsdbDebug("vgId:%d open TSDB meta succeed", REPO_ID(pRepo)); - tfree(fname); + taosTFree(fname); return 0; _err: - tfree(fname); + taosTFree(fname); return -1; } @@ -745,7 +745,7 @@ static void tsdbFreeTable(STable *pTable) { if (pTable->name != NULL) tsdbTrace("table %s tid %d uid %" PRIu64 " is freed", TABLE_CHAR_NAME(pTable), TABLE_TID(pTable), TABLE_UID(pTable)); - tfree(TABLE_NAME(pTable)); + taosTFree(TABLE_NAME(pTable)); if (TABLE_TYPE(pTable) != TSDB_CHILD_TABLE) { for (int i = 0; i < TSDB_MAX_TABLE_SCHEMAS; i++) { tdFreeSchema(pTable->schema[i]); @@ -759,7 +759,7 @@ static void tsdbFreeTable(STable *pTable) { kvRowFree(pTable->tagVal); tSkipListDestroy(pTable->pIndex); - tfree(pTable->sql); + taosTFree(pTable->sql); free(pTable); } } @@ -1065,9 +1065,9 @@ void tsdbClearTableCfg(STableCfg *config) { if (config->schema) tdFreeSchema(config->schema); if (config->tagSchema) tdFreeSchema(config->tagSchema); if (config->tagValues) kvRowFree(config->tagValues); - tfree(config->name); - tfree(config->sname); - tfree(config->sql); + taosTFree(config->name); + taosTFree(config->sname); + taosTFree(config->sql); free(config); } } @@ -1291,7 +1291,7 @@ static int tsdbAdjustMetaTables(STsdbRepo *pRepo, int tid) { STable **tTables = pMeta->tables; pMeta->tables = tables; - tfree(tTables); + taosTFree(tTables); tsdbDebug("vgId:%d tsdb meta maxTables is adjusted as %d", REPO_ID(pRepo), maxTables); return 0; diff --git a/src/tsdb/src/tsdbRWHelper.c b/src/tsdb/src/tsdbRWHelper.c index 8d3908666e..9a96ec62e2 100644 --- a/src/tsdb/src/tsdbRWHelper.c +++ b/src/tsdb/src/tsdbRWHelper.c @@ -72,8 +72,8 @@ int tsdbInitWriteHelper(SRWHelper *pHelper, STsdbRepo *pRepo) { void tsdbDestroyHelper(SRWHelper *pHelper) { if (pHelper) { - tzfree(pHelper->pBuffer); - tzfree(pHelper->compBuffer); + taosTZfree(pHelper->pBuffer); + taosTZfree(pHelper->compBuffer); tsdbDestroyHelperFile(pHelper); tsdbDestroyHelperTable(pHelper); tsdbDestroyHelperBlock(pHelper); @@ -444,8 +444,8 @@ int tsdbWriteCompInfo(SRWHelper *pHelper) { pFile = helperNewIdxF(pHelper); #endif - if (tsizeof(pHelper->pWIdx) < pFile->info.len + sizeof(SCompIdx) + 12) { - pHelper->pWIdx = trealloc(pHelper->pWIdx, tsizeof(pHelper->pWIdx) == 0 ? 1024 : tsizeof(pHelper->pWIdx) * 2); + if (taosTSizeof(pHelper->pWIdx) < pFile->info.len + sizeof(SCompIdx) + 12) { + pHelper->pWIdx = taosTRealloc(pHelper->pWIdx, taosTSizeof(pHelper->pWIdx) == 0 ? 1024 : taosTSizeof(pHelper->pWIdx) * 2); if (pHelper->pWIdx == NULL) { terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; return -1; @@ -470,8 +470,8 @@ int tsdbWriteCompIdx(SRWHelper *pHelper) { #endif pFile->info.len += sizeof(TSCKSUM); - if (tsizeof(pHelper->pWIdx) < pFile->info.len) { - pHelper->pWIdx = trealloc(pHelper->pWIdx, pFile->info.len); + if (taosTSizeof(pHelper->pWIdx) < pFile->info.len) { + pHelper->pWIdx = taosTRealloc(pHelper->pWIdx, pFile->info.len); if (pHelper->pWIdx == NULL) { terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; return -1; @@ -512,7 +512,7 @@ int tsdbLoadCompIdx(SRWHelper *pHelper, void *target) { if (!helperHasState(pHelper, TSDB_HELPER_IDX_LOAD)) { // If not load from file, just load it in object if (pFile->info.len > 0) { - if ((pHelper->pBuffer = trealloc(pHelper->pBuffer, pFile->info.len)) == NULL) { + if ((pHelper->pBuffer = taosTRealloc(pHelper->pBuffer, pFile->info.len)) == NULL) { terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; return -1; } @@ -541,11 +541,11 @@ int tsdbLoadCompIdx(SRWHelper *pHelper, void *target) { pHelper->idxH.numOfIdx = 0; void *ptr = pHelper->pBuffer; while (POINTER_DISTANCE(ptr, pHelper->pBuffer) < (pFile->info.len - sizeof(TSCKSUM))) { - size_t tlen = tsizeof(pHelper->idxH.pIdxArray); + size_t tlen = taosTSizeof(pHelper->idxH.pIdxArray); pHelper->idxH.numOfIdx++; if (tlen < pHelper->idxH.numOfIdx * sizeof(SCompIdx)) { - pHelper->idxH.pIdxArray = (SCompIdx *)trealloc(pHelper->idxH.pIdxArray, (tlen == 0) ? 1024 : tlen * 2); + pHelper->idxH.pIdxArray = (SCompIdx *)taosTRealloc(pHelper->idxH.pIdxArray, (tlen == 0) ? 1024 : tlen * 2); if (pHelper->idxH.pIdxArray == NULL) { terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; return -1; @@ -593,7 +593,7 @@ int tsdbLoadCompInfo(SRWHelper *pHelper, void *target) { return -1; } - pHelper->pCompInfo = trealloc((void *)pHelper->pCompInfo, pIdx->len); + pHelper->pCompInfo = taosTRealloc((void *)pHelper->pCompInfo, pIdx->len); if (taosTRead(fd, (void *)(pHelper->pCompInfo), pIdx->len) < pIdx->len) { tsdbError("vgId:%d failed to read %d bytes from file %s since %s", REPO_ID(pHelper->pRepo), pIdx->len, helperHeadF(pHelper)->fname, strerror(errno)); @@ -629,7 +629,7 @@ int tsdbLoadCompData(SRWHelper *pHelper, SCompBlock *pCompBlock, void *target) { } size_t tsize = TSDB_GET_COMPCOL_LEN(pCompBlock->numOfCols); - pHelper->pCompData = trealloc((void *)pHelper->pCompData, tsize); + pHelper->pCompData = taosTRealloc((void *)pHelper->pCompData, tsize); if (pHelper->pCompData == NULL) { terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; return -1; @@ -807,7 +807,7 @@ static int tsdbWriteBlockToFile(SRWHelper *pHelper, SFile *pFile, SDataCols *pDa if (pCfg->compression) { if (pCfg->compression == TWO_STAGE_COMP) { - pHelper->compBuffer = trealloc(pHelper->compBuffer, tlen + COMP_OVERFLOW_BYTES); + pHelper->compBuffer = taosTRealloc(pHelper->compBuffer, tlen + COMP_OVERFLOW_BYTES); if (pHelper->compBuffer == NULL) { terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; goto _err; @@ -815,8 +815,8 @@ static int tsdbWriteBlockToFile(SRWHelper *pHelper, SFile *pFile, SDataCols *pDa } flen = (*(tDataTypeDesc[pDataCol->type].compFunc))((char *)pDataCol->pData, tlen, rowsToWrite, tptr, - tsizeof(pHelper->pBuffer) - lsize, pCfg->compression, - pHelper->compBuffer, tsizeof(pHelper->compBuffer)); + taosTSizeof(pHelper->pBuffer) - lsize, pCfg->compression, + pHelper->compBuffer, taosTSizeof(pHelper->compBuffer)); } else { flen = tlen; memcpy(tptr, pDataCol->pData, flen); @@ -895,9 +895,9 @@ static int compareKeyBlock(const void *arg1, const void *arg2) { } static int tsdbAdjustInfoSizeIfNeeded(SRWHelper *pHelper, size_t esize) { - if (tsizeof((void *)pHelper->pCompInfo) <= esize) { + if (taosTSizeof((void *)pHelper->pCompInfo) <= esize) { size_t tsize = esize + sizeof(SCompBlock) * 16; - pHelper->pCompInfo = (SCompInfo *)trealloc(pHelper->pCompInfo, tsize); + pHelper->pCompInfo = (SCompInfo *)taosTRealloc(pHelper->pCompInfo, tsize); if (pHelper->pCompInfo == NULL) return -1; } @@ -923,8 +923,8 @@ static int tsdbInsertSuperBlock(SRWHelper *pHelper, SCompBlock *pCompBlock, int // Memmove if needed int tsize = pIdx->len - (sizeof(SCompInfo) + sizeof(SCompBlock) * blkIdx); if (tsize > 0) { - ASSERT(sizeof(SCompInfo) + sizeof(SCompBlock) * (blkIdx + 1) < tsizeof(pHelper->pCompInfo)); - ASSERT(sizeof(SCompInfo) + sizeof(SCompBlock) * (blkIdx + 1) + tsize <= tsizeof(pHelper->pCompInfo)); + ASSERT(sizeof(SCompInfo) + sizeof(SCompBlock) * (blkIdx + 1) < taosTSizeof(pHelper->pCompInfo)); + ASSERT(sizeof(SCompInfo) + sizeof(SCompBlock) * (blkIdx + 1) + tsize <= taosTSizeof(pHelper->pCompInfo)); memmove(POINTER_SHIFT(pHelper->pCompInfo, sizeof(SCompInfo) + sizeof(SCompBlock) * (blkIdx + 1)), POINTER_SHIFT(pHelper->pCompInfo, sizeof(SCompInfo) + sizeof(SCompBlock) * blkIdx), tsize); } @@ -932,7 +932,7 @@ static int tsdbInsertSuperBlock(SRWHelper *pHelper, SCompBlock *pCompBlock, int pIdx->numOfBlocks++; pIdx->len += sizeof(SCompBlock); - ASSERT(pIdx->len <= tsizeof(pHelper->pCompInfo)); + ASSERT(pIdx->len <= taosTSizeof(pHelper->pCompInfo)); pIdx->maxKey = blockAtIdx(pHelper, pIdx->numOfBlocks - 1)->keyLast; pIdx->hasLast = blockAtIdx(pHelper, pIdx->numOfBlocks - 1)->last; @@ -1094,8 +1094,8 @@ static int tsdbInitHelperFile(SRWHelper *pHelper) { static void tsdbDestroyHelperFile(SRWHelper *pHelper) { tsdbCloseHelperFile(pHelper, false); tsdbResetHelperFileImpl(pHelper); - tzfree(pHelper->idxH.pIdxArray); - tzfree(pHelper->pWIdx); + taosTZfree(pHelper->idxH.pIdxArray); + taosTZfree(pHelper->pWIdx); } // ---------- Operations on Helper Table part @@ -1112,7 +1112,7 @@ static void tsdbResetHelperTable(SRWHelper *pHelper) { static void tsdbInitHelperTable(SRWHelper *pHelper) { tsdbResetHelperTableImpl(pHelper); } -static void tsdbDestroyHelperTable(SRWHelper *pHelper) { tzfree((void *)pHelper->pCompInfo); } +static void tsdbDestroyHelperTable(SRWHelper *pHelper) { taosTZfree((void *)pHelper->pCompInfo); } // ---------- Operations on Helper Block part static void tsdbResetHelperBlockImpl(SRWHelper *pHelper) { @@ -1142,7 +1142,7 @@ static int tsdbInitHelperBlock(SRWHelper *pHelper) { } static void tsdbDestroyHelperBlock(SRWHelper *pHelper) { - tzfree(pHelper->pCompData); + taosTZfree(pHelper->pCompData); tdFreeDataCols(pHelper->pDataCols[0]); tdFreeDataCols(pHelper->pDataCols[1]); } @@ -1167,7 +1167,7 @@ static int tsdbInitHelper(SRWHelper *pHelper, STsdbRepo *pRepo, tsdb_rw_helper_t // TODO: pMeta->maxRowBytes and pMeta->maxCols may change here causing invalid write pHelper->pBuffer = - tmalloc(sizeof(SCompData) + (sizeof(SCompCol) + sizeof(TSCKSUM) + COMP_OVERFLOW_BYTES) * pMeta->maxCols + + taosTMalloc(sizeof(SCompData) + (sizeof(SCompCol) + sizeof(TSCKSUM) + COMP_OVERFLOW_BYTES) * pMeta->maxCols + pMeta->maxRowBytes * pCfg->maxRowsPerFileBlock + sizeof(TSCKSUM)); if (pHelper->pBuffer == NULL) { terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; @@ -1212,13 +1212,13 @@ static int tsdbLoadColData(SRWHelper *pHelper, SFile *pFile, SCompBlock *pCompBl SDataCol *pDataCol) { ASSERT(pDataCol->colId == pCompCol->colId); int tsize = pDataCol->bytes * pCompBlock->numOfRows + COMP_OVERFLOW_BYTES; - pHelper->pBuffer = trealloc(pHelper->pBuffer, pCompCol->len); + pHelper->pBuffer = taosTRealloc(pHelper->pBuffer, pCompCol->len); if (pHelper->pBuffer == NULL) { terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; return -1; } - pHelper->compBuffer = trealloc(pHelper->compBuffer, tsize); + pHelper->compBuffer = taosTRealloc(pHelper->compBuffer, tsize); if (pHelper->compBuffer == NULL) { terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; return -1; @@ -1240,7 +1240,7 @@ static int tsdbLoadColData(SRWHelper *pHelper, SFile *pFile, SCompBlock *pCompBl if (tsdbCheckAndDecodeColumnData(pDataCol, pHelper->pBuffer, pCompCol->len, pCompBlock->algorithm, pCompBlock->numOfRows, pHelper->pRepo->config.maxRowsPerFileBlock, - pHelper->compBuffer, tsizeof(pHelper->compBuffer)) < 0) { + pHelper->compBuffer, taosTSizeof(pHelper->compBuffer)) < 0) { tsdbError("vgId:%d file %s is broken at column %d offset %" PRId64, REPO_ID(pHelper->pRepo), pFile->fname, pCompCol->colId, offset); return -1; @@ -1331,7 +1331,7 @@ static int tsdbLoadBlockDataImpl(SRWHelper *pHelper, SCompBlock *pCompBlock, SDa SFile *pFile = (pCompBlock->last) ? helperLastF(pHelper) : helperDataF(pHelper); - pHelper->pBuffer = trealloc(pHelper->pBuffer, pCompBlock->len); + pHelper->pBuffer = taosTRealloc(pHelper->pBuffer, pCompBlock->len); if (pHelper->pBuffer == NULL) { terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; goto _err; @@ -1395,7 +1395,7 @@ static int tsdbLoadBlockDataImpl(SRWHelper *pHelper, SCompBlock *pCompBlock, SDa if (pDataCol->type == TSDB_DATA_TYPE_BINARY || pDataCol->type == TSDB_DATA_TYPE_NCHAR) { zsize += (sizeof(VarDataLenT) * pCompBlock->numOfRows); } - pHelper->compBuffer = trealloc(pHelper->compBuffer, zsize); + pHelper->compBuffer = taosTRealloc(pHelper->compBuffer, zsize); if (pHelper->compBuffer == NULL) { terrno = TSDB_CODE_TDB_OUT_OF_MEMORY; goto _err; @@ -1403,7 +1403,7 @@ static int tsdbLoadBlockDataImpl(SRWHelper *pHelper, SCompBlock *pCompBlock, SDa } if (tsdbCheckAndDecodeColumnData(pDataCol, (char *)pCompData + tsize + toffset, tlen, pCompBlock->algorithm, pCompBlock->numOfRows, pDataCols->maxPoints, pHelper->compBuffer, - tsizeof(pHelper->compBuffer)) < 0) { + taosTSizeof(pHelper->compBuffer)) < 0) { tsdbError("vgId:%d file %s is broken at column %d block offset %" PRId64 " column offset %d", REPO_ID(pHelper->pRepo), pFile->fname, tcolId, (int64_t)pCompBlock->offset, toffset); goto _err; diff --git a/src/tsdb/src/tsdbRead.c b/src/tsdb/src/tsdbRead.c index 0e3a657fde..c3aeed519c 100644 --- a/src/tsdb/src/tsdbRead.c +++ b/src/tsdb/src/tsdbRead.c @@ -17,7 +17,6 @@ #include "tulog.h" #include "talgo.h" #include "tutil.h" -#include "ttime.h" #include "tcompare.h" #include "exception.h" @@ -1291,15 +1290,15 @@ int32_t binarySearchForKey(char* pValue, int num, TSKEY key, int order) { } static void cleanBlockOrderSupporter(SBlockOrderSupporter* pSupporter, int32_t numOfTables) { - tfree(pSupporter->numOfBlocksPerTable); - tfree(pSupporter->blockIndexArray); + taosTFree(pSupporter->numOfBlocksPerTable); + taosTFree(pSupporter->blockIndexArray); for (int32_t i = 0; i < numOfTables; ++i) { STableBlockInfo* pBlockInfo = pSupporter->pDataBlockInfo[i]; - tfree(pBlockInfo); + taosTFree(pBlockInfo); } - tfree(pSupporter->pDataBlockInfo); + taosTFree(pSupporter->pDataBlockInfo); } static int32_t dataBlockOrderCompar(const void* pLeft, const void* pRight, void* param) { @@ -1770,11 +1769,11 @@ void changeQueryHandleForLastrowQuery(TsdbQueryHandleT pqHandle) { tSkipListDestroyIter(pTableCheckInfo->iter); if (pTableCheckInfo->pDataCols != NULL) { - tfree(pTableCheckInfo->pDataCols->buf); + taosTFree(pTableCheckInfo->pDataCols->buf); } - tfree(pTableCheckInfo->pDataCols); - tfree(pTableCheckInfo->pCompInfo); + taosTFree(pTableCheckInfo->pDataCols); + taosTFree(pTableCheckInfo->pCompInfo); } STableCheckInfo info = *(STableCheckInfo*) taosArrayGet(pQueryHandle->pTableCheckInfo, index); @@ -2033,7 +2032,7 @@ static void destroyHelper(void* param) { tQueryInfo* pInfo = (tQueryInfo*)param; if (pInfo->optr != TSDB_RELATION_IN) { - tfree(pInfo->q); + taosTFree(pInfo->q); } // tVariantDestroy(&(pInfo->q)); @@ -2185,7 +2184,7 @@ SArray* createTableGroup(SArray* pTableList, STSchema* pTagSchema, SColIndex* pC taosqsort(pTableList->pData, size, POINTER_BYTES, pSupp, tableGroupComparFn); createTableGroupImpl(pTableGroup, pTableList, size, pSupp, tableGroupComparFn); - tfree(pSupp); + taosTFree(pSupp); } return pTableGroup; @@ -2431,11 +2430,11 @@ void tsdbCleanupQueryHandle(TsdbQueryHandleT queryHandle) { destroyTableMemIterator(pTableCheckInfo); if (pTableCheckInfo->pDataCols != NULL) { - tfree(pTableCheckInfo->pDataCols->buf); + taosTFree(pTableCheckInfo->pDataCols->buf); } - tfree(pTableCheckInfo->pDataCols); - tfree(pTableCheckInfo->pCompInfo); + taosTFree(pTableCheckInfo->pDataCols); + taosTFree(pTableCheckInfo->pCompInfo); } taosArrayDestroy(pQueryHandle->pTableCheckInfo); } @@ -2444,14 +2443,14 @@ void tsdbCleanupQueryHandle(TsdbQueryHandleT queryHandle) { size_t cols = taosArrayGetSize(pQueryHandle->pColumns); for (int32_t i = 0; i < cols; ++i) { SColumnInfoData* pColInfo = taosArrayGet(pQueryHandle->pColumns, i); - tfree(pColInfo->pData); + taosTFree(pColInfo->pData); } taosArrayDestroy(pQueryHandle->pColumns); } taosArrayDestroy(pQueryHandle->defaultLoadColumn); - tfree(pQueryHandle->pDataBlockInfo); - tfree(pQueryHandle->statis); + taosTFree(pQueryHandle->pDataBlockInfo); + taosTFree(pQueryHandle->statis); // todo check error tsdbUnTakeMemSnapShot(pQueryHandle->pTsdb, pQueryHandle->mem, pQueryHandle->imem); @@ -2462,7 +2461,7 @@ void tsdbCleanupQueryHandle(TsdbQueryHandleT queryHandle) { tsdbDebug("%p :io-cost summary: statis-info:%"PRId64"us, datablock:%" PRId64"us, check data:%"PRId64"us, %p", pQueryHandle, pCost->statisInfoLoadTime, pCost->blockLoadTime, pCost->checkForNextTime, pQueryHandle->qinfo); - tfree(pQueryHandle); + taosTFree(pQueryHandle); } void tsdbDestroyTableGroup(STableGroupInfo *pGroupList) { diff --git a/src/tsdb/tests/tsdbTests.cpp b/src/tsdb/tests/tsdbTests.cpp index 5e678a8ee5..e504109cec 100644 --- a/src/tsdb/tests/tsdbTests.cpp +++ b/src/tsdb/tests/tsdbTests.cpp @@ -80,7 +80,7 @@ static int insertData(SInsertInfo *pInfo) { pMsg->numOfBlocks = htonl(pMsg->numOfBlocks); if (tsdbInsertData(pInfo->pRepo, pMsg, NULL) < 0) { - tfree(pMsg); + taosTFree(pMsg); return -1; } } @@ -88,7 +88,7 @@ static int insertData(SInsertInfo *pInfo) { double etime = getCurTime(); printf("Spent %f seconds to write %d records\n", etime - stime, pInfo->totalRows); - tfree(pMsg); + taosTFree(pMsg); return 0; } diff --git a/src/util/src/hash.c b/src/util/src/hash.c index 695529d02f..88f02aff7e 100644 --- a/src/util/src/hash.c +++ b/src/util/src/hash.c @@ -303,7 +303,7 @@ void taosHashRemove(SHashObj *pHashObj, const void *key, size_t keyLen) { pNode->next = NULL; pNode->prev = NULL; - tfree(pNode); + taosTFree(pNode); __unlock(pHashObj->lock); } @@ -335,7 +335,7 @@ void taosHashCleanup(SHashObj *pHashObj) { __unlock(pHashObj->lock); __lock_destroy(pHashObj->lock); - tfree(pHashObj->lock); + taosTFree(pHashObj->lock); memset(pHashObj, 0, sizeof(SHashObj)); free(pHashObj); } diff --git a/src/util/src/talgo.c b/src/util/src/talgo.c index 3a594faeb9..6879461953 100644 --- a/src/util/src/talgo.c +++ b/src/util/src/talgo.c @@ -153,7 +153,7 @@ static void tqsortImpl(void *src, int32_t start, int32_t end, size_t size, const void taosqsort(void *src, size_t numOfElem, size_t size, const void* param, __ext_compar_fn_t comparFn) { char *buf = calloc(1, size); // prepare the swap buffer tqsortImpl(src, 0, numOfElem - 1, size, param, comparFn, buf); - tfree(buf); + taosTFree(buf); } void * taosbsearch(const void *key, const void *base, size_t nmemb, size_t size, __compar_fn_t compar, int flags) { diff --git a/src/util/src/tcache.c b/src/util/src/tcache.c index dc9128d4a9..4a30a66871 100644 --- a/src/util/src/tcache.c +++ b/src/util/src/tcache.c @@ -16,7 +16,6 @@ #define _DEFAULT_SOURCE #include "os.h" #include "tulog.h" -#include "ttime.h" #include "ttimer.h" #include "tutil.h" #include "tcache.h" @@ -634,7 +633,7 @@ void doCleanupDataCache(SCacheObj *pCacheObj) { taosTrashCanEmpty(pCacheObj, true); __cache_lock_destroy(pCacheObj); - tfree(pCacheObj->name); + taosTFree(pCacheObj->name); memset(pCacheObj, 0, sizeof(SCacheObj)); free(pCacheObj); } diff --git a/src/util/src/tconfig.c b/src/util/src/tconfig.c index 59bc09e877..9fc9386b42 100644 --- a/src/util/src/tconfig.c +++ b/src/util/src/tconfig.c @@ -297,7 +297,7 @@ void taosReadGlobalLogCfg() { taosReadLogOption(option, value); } - tfree(line); + taosTFree(line); fclose(fp); } @@ -349,7 +349,7 @@ bool taosReadGlobalCfg() { fclose(fp); - tfree(line); + taosTFree(line); return true; } diff --git a/src/util/src/tdes.c b/src/util/src/tdes.c index c76938d3aa..871ae15a8a 100644 --- a/src/util/src/tdes.c +++ b/src/util/src/tdes.c @@ -1,8 +1,5 @@ -#include -#include -#include -#include -#include + +#include "os.h" #include "tkey.h" #define ENCRYPTION_MODE 1 diff --git a/src/util/src/tkvstore.c b/src/util/src/tkvstore.c index d7bf9d7857..2cea295c82 100644 --- a/src/util/src/tkvstore.c +++ b/src/util/src/tkvstore.c @@ -434,9 +434,9 @@ _err: static void tdFreeKVStore(SKVStore *pStore) { if (pStore) { - tfree(pStore->fname); - tfree(pStore->fsnap); - tfree(pStore->fnew); + taosTFree(pStore->fname); + taosTFree(pStore->fsnap); + taosTFree(pStore->fnew); taosHashCleanup(pStore->map); free(pStore); } @@ -575,11 +575,11 @@ static int tdRestoreKVStore(SKVStore *pStore) { if (pStore->aFunc) (*pStore->aFunc)(pStore->appH); taosHashDestroyIter(pIter); - tfree(buf); + taosTFree(buf); return 0; _err: taosHashDestroyIter(pIter); - tfree(buf); + taosTFree(buf); return -1; } diff --git a/src/util/src/tlog.c b/src/util/src/tlog.c index 96ae417297..6bba8885b1 100644 --- a/src/util/src/tlog.c +++ b/src/util/src/tlog.c @@ -210,10 +210,10 @@ static bool taosCheckFileIsOpen(char *logFileName) { if (taosLockFile(fd)) { taosUnLockFile(fd); - tclose(fd); + taosClose(fd); return false; } else { - tclose(fd); + taosClose(fd); return true; } } @@ -457,7 +457,7 @@ void taosCloseLog() { static void taosCloseLogByFd(int32_t fd) { if (fd >= 0) { taosUnLockFile(fd); - tclose(fd); + taosClose(fd); } } @@ -482,8 +482,8 @@ static SLogBuff *taosLogBuffNew(int32_t bufSize) { return tLogBuff; _err: - tfree(LOG_BUF_BUFFER(tLogBuff)); - tfree(tLogBuff); + taosTFree(LOG_BUF_BUFFER(tLogBuff)); + taosTFree(tLogBuff); return NULL; } @@ -492,7 +492,7 @@ static void taosLogBuffDestroy(SLogBuff *tLogBuff) { tsem_destroy(&(tLogBuff->buffNotEmpty)); pthread_mutex_destroy(&(tLogBuff->buffMutex)); free(tLogBuff->buffer); - tfree(tLogBuff); + taosTFree(tLogBuff); } #endif diff --git a/src/util/src/tmempool.c b/src/util/src/tmempool.c index f5329800f3..4a899ebb48 100644 --- a/src/util/src/tmempool.c +++ b/src/util/src/tmempool.c @@ -56,9 +56,9 @@ mpool_h taosMemPoolInit(int numOfBlock, int blockSize) { if (pool_p->pool == NULL || pool_p->freeList == NULL) { uError("failed to allocate memory\n"); - tfree(pool_p->freeList); - tfree(pool_p->pool); - tfree(pool_p); + taosTFree(pool_p->freeList); + taosTFree(pool_p->pool); + taosTFree(pool_p); return NULL; } diff --git a/src/util/src/tskiplist.c b/src/util/src/tskiplist.c index aacc4a5487..14029fbd81 100644 --- a/src/util/src/tskiplist.c +++ b/src/util/src/tskiplist.c @@ -162,7 +162,7 @@ SSkipList *tSkipListCreate(uint8_t maxLevel, uint8_t keyType, uint8_t keyLen, ui pSkipList->level = 1; if (!initForwardBackwardPtr(pSkipList)) { - tfree(pSkipList); + taosTFree(pSkipList); return NULL; } @@ -170,8 +170,8 @@ SSkipList *tSkipListCreate(uint8_t maxLevel, uint8_t keyType, uint8_t keyLen, ui pSkipList->lock = calloc(1, sizeof(pthread_rwlock_t)); if (pthread_rwlock_init(pSkipList->lock, NULL) != 0) { - tfree(pSkipList->pHead); - tfree(pSkipList); + taosTFree(pSkipList->pHead); + taosTFree(pSkipList); return NULL; } @@ -201,7 +201,7 @@ void *tSkipListDestroy(SSkipList *pSkipList) { while (pNode != pSkipList->pTail) { SSkipListNode *pTemp = pNode; pNode = SL_GET_FORWARD_POINTER(pNode, 0); - tfree(pTemp); + taosTFree(pTemp); } } @@ -209,11 +209,11 @@ void *tSkipListDestroy(SSkipList *pSkipList) { pthread_rwlock_unlock(pSkipList->lock); pthread_rwlock_destroy(pSkipList->lock); - tfree(pSkipList->lock); + taosTFree(pSkipList->lock); } - tfree(pSkipList->pHead); - tfree(pSkipList); + taosTFree(pSkipList->pHead); + taosTFree(pSkipList); return NULL; } @@ -470,7 +470,7 @@ uint32_t tSkipListRemove(SSkipList *pSkipList, SSkipListKey key) { } if (pSkipList->keyInfo.freeNode) { - tfree(p); + taosTFree(p); } ++count; @@ -509,7 +509,7 @@ void tSkipListRemoveNode(SSkipList *pSkipList, SSkipListNode *pNode) { } if (pSkipList->keyInfo.freeNode) { - tfree(pNode); + taosTFree(pNode); } atomic_sub_fetch_32(&pSkipList->size, 1); @@ -592,7 +592,7 @@ void* tSkipListDestroyIter(SSkipListIterator* iter) { return NULL; } - tfree(iter); + taosTFree(iter); return NULL; } diff --git a/src/util/src/ttimer.c b/src/util/src/ttimer.c index 5cdc6ff918..b2982d353f 100644 --- a/src/util/src/ttimer.c +++ b/src/util/src/ttimer.c @@ -16,7 +16,6 @@ #include "os.h" #include "tlog.h" #include "tsched.h" -#include "ttime.h" #include "ttimer.h" #include "tutil.h" diff --git a/src/util/src/tutil.c b/src/util/src/tutil.c index eaa60d739b..f4b6ae629d 100644 --- a/src/util/src/tutil.c +++ b/src/util/src/tutil.c @@ -16,7 +16,6 @@ #include "os.h" #include "tcrc32c.h" #include "tglobal.h" -#include "ttime.h" #include "taosdef.h" #include "tutil.h" #include "tulog.h" diff --git a/src/util/tests/cacheTest.cpp b/src/util/tests/cacheTest.cpp index 9100b7e7f6..e0debd53f4 100644 --- a/src/util/tests/cacheTest.cpp +++ b/src/util/tests/cacheTest.cpp @@ -1,3 +1,4 @@ +#include "os.h" #include #include #include @@ -10,7 +11,6 @@ #include "tutil.h" #include "tcache.h" #include "ttimer.h" -#include "ttime.h" namespace { int32_t tsMaxMgmtConnections = 10000; diff --git a/src/util/tests/hashTest.cpp b/src/util/tests/hashTest.cpp index 93a1989741..6ffce61e61 100644 --- a/src/util/tests/hashTest.cpp +++ b/src/util/tests/hashTest.cpp @@ -1,11 +1,11 @@ +#include "os.h" #include #include #include #include #include "hash.h" -#include "taos.h" -#include "ttime.h" +#include "taos.h"" namespace { // the simple test code for basic operations diff --git a/src/util/tests/skiplistTest.cpp b/src/util/tests/skiplistTest.cpp index 70445a3d65..77174f69fd 100644 --- a/src/util/tests/skiplistTest.cpp +++ b/src/util/tests/skiplistTest.cpp @@ -3,9 +3,9 @@ #include #include +#include "os.h" #include "taosmsg.h" #include "tskiplist.h" -#include "ttime.h" #include "tutil.h" namespace { @@ -59,7 +59,7 @@ void doubleSkipListTest() { } if (size > 0) { - tfree(pNodes); + taosTFree(pNodes); } } @@ -196,7 +196,7 @@ void stringKeySkiplistTest() { tSkipListRemoveNode(pSkipList, pres[0]); if (num > 0) { - tfree(pres); + taosTFree(pres); } } @@ -276,7 +276,7 @@ void skiplistPerformanceTest() { assert(tSkipListGetSize(pSkipList) == size); tSkipListDestroy(pSkipList); - tfree(total); + taosTFree(total); } // todo not support duplicated key yet @@ -357,7 +357,7 @@ TEST(testCase, skiplist_test) { printf("-----%lf\n", pNodes[i]->key.dKey); } printf("the range query result size is: %d\n", size); - tfree(pNodes); + taosTFree(pNodes); SSkipListKey *pKeys = malloc(sizeof(SSkipListKey) * 20); for (int32_t i = 0; i < 8; i += 2) { @@ -371,7 +371,7 @@ TEST(testCase, skiplist_test) { for (int32_t i = 0; i < r; ++i) { // printf("%lf ", pNodes[i]->key.dKey); } - tfree(pNodes); + taosTFree(pNodes); free(pKeys);*/ } diff --git a/src/vnode/src/vnodeMain.c b/src/vnode/src/vnodeMain.c index 8a56a2c500..6abd255dc4 100644 --- a/src/vnode/src/vnodeMain.c +++ b/src/vnode/src/vnodeMain.c @@ -25,7 +25,6 @@ #include "tglobal.h" #include "trpc.h" #include "tsdb.h" -#include "ttime.h" #include "ttimer.h" #include "tutil.h" #include "vnode.h" @@ -348,7 +347,7 @@ void vnodeRelease(void *pVnodeRaw) { dnodeFreeVnodeRqueue(pVnode->rqueue); pVnode->rqueue = NULL; - tfree(pVnode->rootDir); + taosTFree(pVnode->rootDir); if (pVnode->dropped) { char rootDir[TSDB_FILENAME_LEN] = {0}; @@ -870,7 +869,7 @@ static int32_t vnodeReadCfg(SVnodeObj *pVnode) { } PARSE_OVER: - tfree(content); + taosTFree(content); cJSON_Delete(root); if (fp) fclose(fp); return terrno; @@ -945,7 +944,7 @@ static int32_t vnodeReadVersion(SVnodeObj *pVnode) { vInfo("vgId:%d, read vnode version successfully, version:%" PRId64, pVnode->vgId, pVnode->version); PARSE_OVER: - tfree(content); + taosTFree(content); cJSON_Delete(root); if(fp) fclose(fp); return terrno; diff --git a/src/wal/src/walMain.c b/src/wal/src/walMain.c index bf3b0f63ea..a8f88c7be9 100644 --- a/src/wal/src/walMain.c +++ b/src/wal/src/walMain.c @@ -128,7 +128,7 @@ void walClose(void *handle) { if (handle == NULL) return; SWal *pWal = handle; - tclose(pWal->fd); + taosClose(pWal->fd); if (pWal->timer) taosTmrStopA(&pWal->timer); if (pWal->keep == 0) { diff --git a/tests/test/c/createTablePerformance.c b/tests/test/c/createTablePerformance.c index 69022bdecf..eae104291a 100644 --- a/tests/test/c/createTablePerformance.c +++ b/tests/test/c/createTablePerformance.c @@ -18,7 +18,6 @@ #include "taoserror.h" #include "taos.h" #include "tulog.h" -#include "ttime.h" #include "tutil.h" #include "tglobal.h" #include "hash.h" diff --git a/tests/test/c/hashPerformance.c b/tests/test/c/hashPerformance.c index fa3612d6e8..db3be0e950 100644 --- a/tests/test/c/hashPerformance.c +++ b/tests/test/c/hashPerformance.c @@ -17,7 +17,6 @@ #include "os.h" #include "taos.h" #include "tulog.h" -#include "ttime.h" #include "tutil.h" #include "hash.h" diff --git a/tests/tsim/src/simExe.c b/tests/tsim/src/simExe.c index 3469180607..fdec38b4c7 100644 --- a/tests/tsim/src/simExe.c +++ b/tests/tsim/src/simExe.c @@ -20,6 +20,7 @@ #include "tglobal.h" #include "tutil.h" #include "cJSON.h" +#undef TAOS_MEM_CHECK void simLogSql(char *sql, bool useSharp) { static FILE *fp = NULL; diff --git a/tests/tsim/src/simParse.c b/tests/tsim/src/simParse.c index 9fea1f115b..2528fde9f5 100644 --- a/tests/tsim/src/simParse.c +++ b/tests/tsim/src/simParse.c @@ -57,12 +57,11 @@ * */ +#include "os.h" #include "sim.h" -#include -#include -#include #include "simParse.h" #include "tutil.h" +#undef TAOS_MEM_CHECK static SCommand *cmdHashList[MAX_NUM_CMD]; static SCmdLine cmdLine[MAX_CMD_LINES]; diff --git a/tests/tsim/src/simSystem.c b/tests/tsim/src/simSystem.c index b50c853ea8..17df7f306a 100644 --- a/tests/tsim/src/simSystem.c +++ b/tests/tsim/src/simSystem.c @@ -20,6 +20,7 @@ #include "ttimer.h" #include "tutil.h" #include "tsocket.h" +#undef TAOS_MEM_CHECK SScript *simScriptList[MAX_MAIN_SCRIPT_NUM]; SCommand simCmdList[SIM_CMD_END]; @@ -94,9 +95,9 @@ void simFreeScript(SScript *script) { } taos_close(script->taos); - tfree(script->lines); - tfree(script->optionBuffer); - tfree(script); + taosTFree(script->lines); + taosTFree(script->optionBuffer); + taosTFree(script); } SScript *simProcessCallOver(SScript *script) { From b628b891e4effe8c1929aa689ac73755feb0623e Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Fri, 31 Jul 2020 14:44:31 +0800 Subject: [PATCH 08/56] [TD-992] --- src/os/inc/osFile.h | 27 ++++++++++-------- src/os/inc/osMemory.h | 55 +++++++++++++++++++++---------------- src/os/inc/osSocket.h | 26 ++++++++++-------- src/tsdb/src/tsdbFile.c | 2 +- src/tsdb/src/tsdbMain.c | 3 -- src/tsdb/src/tsdbRWHelper.c | 1 + src/util/src/tkvstore.c | 1 + src/util/src/tlog.c | 3 -- src/util/src/tnote.c | 4 +-- src/wal/src/walMain.c | 1 + 10 files changed, 67 insertions(+), 56 deletions(-) diff --git a/src/os/inc/osFile.h b/src/os/inc/osFile.h index 4f4d9e8aed..c43428ab82 100644 --- a/src/os/inc/osFile.h +++ b/src/os/inc/osFile.h @@ -30,19 +30,24 @@ int taosFSendFileImp(FILE* out_file, FILE* in_file, int64_t* offset, int32_t #define taosTSendFile(dfd, sfd, offset, size) taosTSendFileImp(dfd, sfd, offset, size) #define taosFSendFile(outfile, infile, offset, count) taosTSendFileImp(fileno(outfile), fileno(infile), offset, size) -#ifndef TAOS_RANDOM_FILE_FAIL - #define taosTRead(fd, buf, count) taosTReadImp(fd, buf, count) - #define taosTWrite(fd, buf, count) taosTWriteImp(fd, buf, count) - #define taosLSeek(fd, offset, whence) lseek(fd, offset, whence) -#else +#define taosTRead(fd, buf, count) taosTReadImp(fd, buf, count) +#define taosTWrite(fd, buf, count) taosTWriteImp(fd, buf, count) +#define taosLSeek(fd, offset, whence) lseek(fd, offset, whence) + +#ifdef TAOS_RANDOM_FILE_FAIL void taosSetRandomFileFailFactor(int factor); void taosSetRandomFileFailOutput(const char *path); - ssize_t taosReadFileRandomFail(int fd, void *buf, size_t count, const char *file, uint32_t line); - ssize_t taosWriteFileRandomFail(int fd, void *buf, size_t count, const char *file, uint32_t line); - off_t taosLSeekRandomFail(int fd, off_t offset, int whence, const char *file, uint32_t line); - #define taosTRead(fd, buf, count) taosReadFileRandomFail(fd, buf, count, __FILE__, __LINE__) - #define taosTWrite(fd, buf, count) taosWriteFileRandomFail(fd, buf, count, __FILE__, __LINE__) - #define taosLSeek(fd, offset, whence) taosLSeekRandomFail(fd, offset, whence, __FILE__, __LINE__) + #ifdef TAOS_RANDOM_FILE_FAIL_TEST + ssize_t taosReadFileRandomFail(int fd, void *buf, size_t count, const char *file, uint32_t line); + ssize_t taosWriteFileRandomFail(int fd, void *buf, size_t count, const char *file, uint32_t line); + off_t taosLSeekRandomFail(int fd, off_t offset, int whence, const char *file, uint32_t line); + #undef taosTRead + #undef taosTWrite + #undef taosLSeek + #define taosTRead(fd, buf, count) taosReadFileRandomFail(fd, buf, count, __FILE__, __LINE__) + #define taosTWrite(fd, buf, count) taosWriteFileRandomFail(fd, buf, count, __FILE__, __LINE__) + #define taosLSeek(fd, offset, whence) taosLSeekRandomFail(fd, offset, whence, __FILE__, __LINE__) + #endif #endif // TAOS_OS_FUNC_FILE_GETTMPFILEPATH diff --git a/src/os/inc/osMemory.h b/src/os/inc/osMemory.h index eb2ff02f77..aaac8c68e3 100644 --- a/src/os/inc/osMemory.h +++ b/src/os/inc/osMemory.h @@ -46,29 +46,38 @@ void taosTMemset(void *ptr, int c); } \ } while (0); -#ifndef TAOS_MEM_CHECK - #define taosMalloc(size) malloc(size) - #define taosCalloc(num, size) calloc(num, size) - #define taosRealloc(ptr, size) realloc(ptr, size) - #define taosFree(ptr) free(ptr) - #define taosStrdup(str) taosStrdupImp(str) - #define taosStrndup(str, size) taosStrndupImp(str, size) - #define taosGetline(lineptr, n, stream) taosGetlineImp(lineptr, n, stream) -#else - void * taos_malloc(size_t size, const char *file, uint32_t line); - void * taos_calloc(size_t num, size_t size, const char *file, uint32_t line); - void * taos_realloc(void *ptr, size_t size, const char *file, uint32_t line); - void taos_free(void *ptr, const char *file, uint32_t line); - char * taos_strdup(const char *str, const char *file, uint32_t line); - char * taos_strndup(const char *str, size_t size, const char *file, uint32_t line); - ssize_t taos_getline(char **lineptr, size_t *n, FILE *stream, const char *file, uint32_t line); - #define taosMalloc(size) taos_malloc(size, __FILE__, __LINE__) - #define taosCalloc(num, size) taos_calloc(num, size, __FILE__, __LINE__) - #define taosRealloc(ptr, size) taos_realloc(ptr, size, __FILE__, __LINE__) - #define taosFree(ptr) taos_free(ptr, __FILE__, __LINE__) - #define taosStrdup(str) taos_strdup(str, __FILE__, __LINE__) - #define taosStrndup(str, size) taos_strndup(str, size, __FILE__, __LINE__) - #define taosGetline(lineptr, n, stream) taos_getline(lineptr, n, stream, __FILE__, __LINE__) +#define taosMalloc(size) malloc(size) +#define taosCalloc(num, size) calloc(num, size) +#define taosRealloc(ptr, size) realloc(ptr, size) +#define taosFree(ptr) free(ptr) +#define taosStrdup(str) taosStrdupImp(str) +#define taosStrndup(str, size) taosStrndupImp(str, size) +#define taosGetline(lineptr, n, stream) taosGetlineImp(lineptr, n, stream) + +#ifdef TAOS_MEM_CHECK + #ifdef TAOS_MEM_CHECK_TEST + void * taos_malloc(size_t size, const char *file, uint32_t line); + void * taos_calloc(size_t num, size_t size, const char *file, uint32_t line); + void * taos_realloc(void *ptr, size_t size, const char *file, uint32_t line); + void taos_free(void *ptr, const char *file, uint32_t line); + char * taos_strdup(const char *str, const char *file, uint32_t line); + char * taos_strndup(const char *str, size_t size, const char *file, uint32_t line); + ssize_t taos_getline(char **lineptr, size_t *n, FILE *stream, const char *file, uint32_t line); + #undef taosMalloc + #undef taosCalloc + #undef taosRealloc + #undef taosFree + #undef taosStrdup + #undef taosStrndup + #undef taosGetline + #define taosMalloc(size) taos_malloc(size, __FILE__, __LINE__) + #define taosCalloc(num, size) taos_calloc(num, size, __FILE__, __LINE__) + #define taosRealloc(ptr, size) taos_realloc(ptr, size, __FILE__, __LINE__) + #define taosFree(ptr) taos_free(ptr, __FILE__, __LINE__) + #define taosStrdup(str) taos_strdup(str, __FILE__, __LINE__) + #define taosStrndup(str, size) taos_strndup(str, size, __FILE__, __LINE__) + #define taosGetline(lineptr, n, stream) taos_getline(lineptr, n, stream, __FILE__, __LINE__) + #endif #endif #ifdef __cplusplus diff --git a/src/os/inc/osSocket.h b/src/os/inc/osSocket.h index f013ae4a3a..749d3906f5 100644 --- a/src/os/inc/osSocket.h +++ b/src/os/inc/osSocket.h @@ -35,18 +35,20 @@ extern "C" { #define taosClose(x) taosCloseSocket(x) #ifdef TAOS_RANDOM_NETWORK_FAIL - ssize_t taosSendRandomFail(int sockfd, const void *buf, size_t len, int flags); - ssize_t taosSendToRandomFail(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); - ssize_t taosReadSocketRandomFail(int fd, void *buf, size_t count); - ssize_t taosWriteSocketRandomFail(int fd, const void *buf, size_t count); - #undef taosSend - #undef taosSendto - #undef taosReadSocket - #undef taosWriteSocket - #define taosSend(sockfd, buf, len, flags) taosSendRandomFail(sockfd, buf, len, flags) - #define taosSendto(sockfd, buf, len, flags, dest_addr, addrlen) taosSendToRandomFail(sockfd, buf, len, flags, dest_addr, addrlen) - #define taosReadSocket(fd, buf, len) taosReadSocketRandomFail(fd, buf, len) - #define taosWriteSocket(fd, buf, len) taosWriteSocketRandomFail(fd, buf, len) + #ifdef TAOS_RANDOM_NETWORK_FAIL_TEST + ssize_t taosSendRandomFail(int sockfd, const void *buf, size_t len, int flags); + ssize_t taosSendToRandomFail(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); + ssize_t taosReadSocketRandomFail(int fd, void *buf, size_t count); + ssize_t taosWriteSocketRandomFail(int fd, const void *buf, size_t count); + #undef taosSend + #undef taosSendto + #undef taosReadSocket + #undef taosWriteSocket + #define taosSend(sockfd, buf, len, flags) taosSendRandomFail(sockfd, buf, len, flags) + #define taosSendto(sockfd, buf, len, flags, dest_addr, addrlen) taosSendToRandomFail(sockfd, buf, len, flags, dest_addr, addrlen) + #define taosReadSocket(fd, buf, len) taosReadSocketRandomFail(fd, buf, len) + #define taosWriteSocket(fd, buf, len) taosWriteSocketRandomFail(fd, buf, len) + #endif #endif // TAOS_OS_FUNC_SOCKET diff --git a/src/tsdb/src/tsdbFile.c b/src/tsdb/src/tsdbFile.c index 299802f9b4..e3800f8117 100644 --- a/src/tsdb/src/tsdbFile.c +++ b/src/tsdb/src/tsdbFile.c @@ -14,11 +14,11 @@ */ #define _DEFAULT_SOURCE #include "os.h" - #include "talgo.h" #include "tchecksum.h" #include "tsdbMain.h" #include "tutil.h" +#define TAOS_RANDOM_FILE_FAIL_TEST #ifdef TSDB_IDX const char *tsdbFileSuffix[] = {".idx", ".head", ".data", ".last", "", ".i", ".h", ".l"}; diff --git a/src/tsdb/src/tsdbMain.c b/src/tsdb/src/tsdbMain.c index e23228cc0e..0d7a2866b7 100644 --- a/src/tsdb/src/tsdbMain.c +++ b/src/tsdb/src/tsdbMain.c @@ -14,8 +14,6 @@ */ // no test file errors here -#undef TAOS_RANDOM_FILE_FAIL - #include "tsdbMain.h" #include "os.h" #include "talgo.h" @@ -25,7 +23,6 @@ #include "tsdb.h" #include "tulog.h" - #define TSDB_CFG_FILE_NAME "config" #define TSDB_DATA_DIR_NAME "data" #define TSDB_META_FILE_NAME "meta" diff --git a/src/tsdb/src/tsdbRWHelper.c b/src/tsdb/src/tsdbRWHelper.c index 9a96ec62e2..6e14a86bd7 100644 --- a/src/tsdb/src/tsdbRWHelper.c +++ b/src/tsdb/src/tsdbRWHelper.c @@ -20,6 +20,7 @@ #include "tcoding.h" #include "tscompression.h" #include "tsdbMain.h" +#define TAOS_RANDOM_FILE_FAIL_TEST #define TSDB_GET_COMPCOL_LEN(nCols) (sizeof(SCompData) + sizeof(SCompCol) * (nCols) + sizeof(TSCKSUM)) #define TSDB_KEY_COL_OFFSET 0 diff --git a/src/util/src/tkvstore.c b/src/util/src/tkvstore.c index 2cea295c82..edcf9d45f2 100644 --- a/src/util/src/tkvstore.c +++ b/src/util/src/tkvstore.c @@ -21,6 +21,7 @@ #include "tcoding.h" #include "tkvstore.h" #include "tulog.h" +#define TAOS_RANDOM_FILE_FAIL_TEST #define TD_KVSTORE_HEADER_SIZE 512 #define TD_KVSTORE_MAJOR_VERSION 1 diff --git a/src/util/src/tlog.c b/src/util/src/tlog.c index 6bba8885b1..913989bf52 100644 --- a/src/util/src/tlog.c +++ b/src/util/src/tlog.c @@ -14,9 +14,6 @@ */ #define _DEFAULT_SOURCE -// no test file errors here -#undef TAOS_RANDOM_FILE_FAIL - #include "os.h" #include "tulog.h" #include "tlog.h" diff --git a/src/util/src/tnote.c b/src/util/src/tnote.c index 91916c92d7..ea09709449 100644 --- a/src/util/src/tnote.c +++ b/src/util/src/tnote.c @@ -13,9 +13,7 @@ * along with this program. If not, see . */ -// no test file errors here -#undef TAOS_RANDOM_FILE_FAIL - +#include "os.h" #include "tnote.h" taosNoteInfo m_HttpNote; diff --git a/src/wal/src/walMain.c b/src/wal/src/walMain.c index a8f88c7be9..4ac8a096c6 100644 --- a/src/wal/src/walMain.c +++ b/src/wal/src/walMain.c @@ -22,6 +22,7 @@ #include "taoserror.h" #include "twal.h" #include "tqueue.h" +#define TAOS_RANDOM_FILE_FAIL_TEST #define walPrefix "wal" From 22c9d652a8a82b382380c541dc3696b6afdc4ad0 Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Fri, 31 Jul 2020 06:51:02 +0000 Subject: [PATCH 09/56] [TD-992] --- src/os/inc/osRand.h | 2 +- src/os/src/detail/osRand.c | 2 +- tests/tsim/src/simMain.c | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/os/inc/osRand.h b/src/os/inc/osRand.h index 310340d420..803c0688bb 100644 --- a/src/os/inc/osRand.h +++ b/src/os/inc/osRand.h @@ -23,7 +23,7 @@ extern "C" { // TAOS_OS_FUNC_RAND uint32_t taosRand(void); void taosRandStr(char* str, int32_t size); -uint32_t trand(void); +uint32_t taosSafeRand(void); #ifdef __cplusplus } diff --git a/src/os/src/detail/osRand.c b/src/os/src/detail/osRand.c index 7e5f585634..edb8642bd6 100644 --- a/src/os/src/detail/osRand.c +++ b/src/os/src/detail/osRand.c @@ -20,7 +20,7 @@ uint32_t taosRand(void) { return rand(); } -uint32_t trand(void) { +uint32_t taosSafeRand(void) { int fd; int seed; diff --git a/tests/tsim/src/simMain.c b/tests/tsim/src/simMain.c index 5b2fc87307..ef1a488f60 100644 --- a/tests/tsim/src/simMain.c +++ b/tests/tsim/src/simMain.c @@ -16,6 +16,7 @@ #include "os.h" #include "tglobal.h" #include "sim.h" +#undef TAOS_MEM_CHECK bool simAsyncQuery = false; From 86fd70c2fd7be40ef0552d55c3a4c25fcb2211aa Mon Sep 17 00:00:00 2001 From: slguan Date: Fri, 31 Jul 2020 14:59:52 +0800 Subject: [PATCH 10/56] [TD-992] --- src/os/inc/osDarwin64.h | 3 +- src/os/inc/osFile.h | 7 +-- src/os/src/detail/osCoredump.c | 97 ---------------------------------- src/os/src/detail/osSysinfo.c | 71 +++++++++++++++++++++++++ 4 files changed, 76 insertions(+), 102 deletions(-) delete mode 100644 src/os/src/detail/osCoredump.c diff --git a/src/os/inc/osDarwin64.h b/src/os/inc/osDarwin64.h index 8e476c86ef..8f0978da53 100644 --- a/src/os/inc/osDarwin64.h +++ b/src/os/inc/osDarwin64.h @@ -71,8 +71,7 @@ extern "C" { #include #include -#define TAOS_OS_FUNC_CORE -#define TAOS_OS_FUNC_FILEOP +#define TAOS_OS_FUNC_FILE_TSENDIFLE #define taosFSendFile(outfile, infile, offset, count) taosFSendFileImp(outfile, infile, offset, size) #define taosTSendFile(dfd, sfd, offset, size) taosTSendFileImp(dfd, sfd, offset, size) diff --git a/src/os/inc/osFile.h b/src/os/inc/osFile.h index c43428ab82..f5513cc709 100644 --- a/src/os/inc/osFile.h +++ b/src/os/inc/osFile.h @@ -23,12 +23,13 @@ extern "C" { ssize_t taosTReadImp(int fd, void *buf, size_t count); ssize_t taosTWriteImp(int fd, void *buf, size_t count); -// TAOS_OS_FUNC_FILE_TSENDIFLE ssize_t taosTSendFileImp(int dfd, int sfd, off_t *offset, size_t size); int taosFSendFileImp(FILE* out_file, FILE* in_file, int64_t* offset, int32_t count); -#define taosTSendFile(dfd, sfd, offset, size) taosTSendFileImp(dfd, sfd, offset, size) -#define taosFSendFile(outfile, infile, offset, count) taosTSendFileImp(fileno(outfile), fileno(infile), offset, size) +#ifndef TAOS_OS_FUNC_FILE_TSENDIFLE + #define taosTSendFile(dfd, sfd, offset, size) taosTSendFileImp(dfd, sfd, offset, size) + #define taosFSendFile(outfile, infile, offset, count) taosTSendFileImp(fileno(outfile), fileno(infile), offset, size) +#endif #define taosTRead(fd, buf, count) taosTReadImp(fd, buf, count) #define taosTWrite(fd, buf, count) taosTWriteImp(fd, buf, count) diff --git a/src/os/src/detail/osCoredump.c b/src/os/src/detail/osCoredump.c deleted file mode 100644 index 1ead88ab9e..0000000000 --- a/src/os/src/detail/osCoredump.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2019 TAOS Data, Inc. - * - * This program is free software: you can use, redistribute, and/or modify - * it under the terms of the GNU Affero General Public License, version 3 - * or later ("AGPL"), as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#define _DEFAULT_SOURCE -#include "os.h" -#include "tconfig.h" -#include "tglobal.h" -#include "tulog.h" -#include "tsystem.h" - -#ifndef TAOS_OS_FUNC_CORE - -int _sysctl(struct __sysctl_args *args ); - -void taosSetCoreDump() { - if (0 == tsEnableCoreFile) { - return; - } - - // 1. set ulimit -c unlimited - struct rlimit rlim; - struct rlimit rlim_new; - if (getrlimit(RLIMIT_CORE, &rlim) == 0) { - uInfo("the old unlimited para: rlim_cur=%" PRIu64 ", rlim_max=%" PRIu64, rlim.rlim_cur, rlim.rlim_max); - rlim_new.rlim_cur = RLIM_INFINITY; - rlim_new.rlim_max = RLIM_INFINITY; - if (setrlimit(RLIMIT_CORE, &rlim_new) != 0) { - uInfo("set unlimited fail, error: %s", strerror(errno)); - rlim_new.rlim_cur = rlim.rlim_max; - rlim_new.rlim_max = rlim.rlim_max; - (void)setrlimit(RLIMIT_CORE, &rlim_new); - } - } - - if (getrlimit(RLIMIT_CORE, &rlim) == 0) { - uInfo("the new unlimited para: rlim_cur=%" PRIu64 ", rlim_max=%" PRIu64, rlim.rlim_cur, rlim.rlim_max); - } - -#ifndef _TD_ARM_ - // 2. set the path for saving core file - struct __sysctl_args args; - int old_usespid = 0; - size_t old_len = 0; - int new_usespid = 1; - size_t new_len = sizeof(new_usespid); - - int name[] = {CTL_KERN, KERN_CORE_USES_PID}; - - memset(&args, 0, sizeof(struct __sysctl_args)); - args.name = name; - args.nlen = sizeof(name)/sizeof(name[0]); - args.oldval = &old_usespid; - args.oldlenp = &old_len; - args.newval = &new_usespid; - args.newlen = new_len; - - old_len = sizeof(old_usespid); - - if (syscall(SYS__sysctl, &args) == -1) { - uInfo("_sysctl(kern_core_uses_pid) set fail: %s", strerror(errno)); - } - - uInfo("The old core_uses_pid[%" PRIu64 "]: %d", old_len, old_usespid); - - - old_usespid = 0; - old_len = 0; - memset(&args, 0, sizeof(struct __sysctl_args)); - args.name = name; - args.nlen = sizeof(name)/sizeof(name[0]); - args.oldval = &old_usespid; - args.oldlenp = &old_len; - - old_len = sizeof(old_usespid); - - if (syscall(SYS__sysctl, &args) == -1) { - uInfo("_sysctl(kern_core_uses_pid) get fail: %s", strerror(errno)); - } - - uInfo("The new core_uses_pid[%" PRIu64 "]: %d", old_len, old_usespid); -#endif - -} - -#endif \ No newline at end of file diff --git a/src/os/src/detail/osSysinfo.c b/src/os/src/detail/osSysinfo.c index f753566134..06000be81e 100644 --- a/src/os/src/detail/osSysinfo.c +++ b/src/os/src/detail/osSysinfo.c @@ -570,4 +570,75 @@ int taosSystem(const char *cmd) { } } +int _sysctl(struct __sysctl_args *args ); +void taosSetCoreDump() { + if (0 == tsEnableCoreFile) { + return; + } + + // 1. set ulimit -c unlimited + struct rlimit rlim; + struct rlimit rlim_new; + if (getrlimit(RLIMIT_CORE, &rlim) == 0) { + uInfo("the old unlimited para: rlim_cur=%" PRIu64 ", rlim_max=%" PRIu64, rlim.rlim_cur, rlim.rlim_max); + rlim_new.rlim_cur = RLIM_INFINITY; + rlim_new.rlim_max = RLIM_INFINITY; + if (setrlimit(RLIMIT_CORE, &rlim_new) != 0) { + uInfo("set unlimited fail, error: %s", strerror(errno)); + rlim_new.rlim_cur = rlim.rlim_max; + rlim_new.rlim_max = rlim.rlim_max; + (void)setrlimit(RLIMIT_CORE, &rlim_new); + } + } + + if (getrlimit(RLIMIT_CORE, &rlim) == 0) { + uInfo("the new unlimited para: rlim_cur=%" PRIu64 ", rlim_max=%" PRIu64, rlim.rlim_cur, rlim.rlim_max); + } + +#ifndef _TD_ARM_ + // 2. set the path for saving core file + struct __sysctl_args args; + int old_usespid = 0; + size_t old_len = 0; + int new_usespid = 1; + size_t new_len = sizeof(new_usespid); + + int name[] = {CTL_KERN, KERN_CORE_USES_PID}; + + memset(&args, 0, sizeof(struct __sysctl_args)); + args.name = name; + args.nlen = sizeof(name)/sizeof(name[0]); + args.oldval = &old_usespid; + args.oldlenp = &old_len; + args.newval = &new_usespid; + args.newlen = new_len; + + old_len = sizeof(old_usespid); + + if (syscall(SYS__sysctl, &args) == -1) { + uInfo("_sysctl(kern_core_uses_pid) set fail: %s", strerror(errno)); + } + + uInfo("The old core_uses_pid[%" PRIu64 "]: %d", old_len, old_usespid); + + + old_usespid = 0; + old_len = 0; + memset(&args, 0, sizeof(struct __sysctl_args)); + args.name = name; + args.nlen = sizeof(name)/sizeof(name[0]); + args.oldval = &old_usespid; + args.oldlenp = &old_len; + + old_len = sizeof(old_usespid); + + if (syscall(SYS__sysctl, &args) == -1) { + uInfo("_sysctl(kern_core_uses_pid) get fail: %s", strerror(errno)); + } + + uInfo("The new core_uses_pid[%" PRIu64 "]: %d", old_len, old_usespid); +#endif + +} + #endif \ No newline at end of file From caf933403f1be7d2a457d36822789877da6d3d79 Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Fri, 31 Jul 2020 07:23:05 +0000 Subject: [PATCH 11/56] [TD-992] --- src/os/inc/os.h | 1 - src/os/inc/osDarwin64.h | 2 +- src/os/inc/osFile.h | 4 +-- src/os/inc/osPthread.h | 31 ------------------- src/os/inc/osSemphone.h | 4 +++ src/os/inc/osString.h | 4 +-- src/os/inc/osSysinfo.h | 2 +- src/os/inc/osWindows64.h | 4 +-- .../src/detail/{osPThread.c => osSemphone.c} | 0 src/os/src/detail/{osWchar.c => osString.c} | 13 ++++++-- src/os/src/detail/osUtil.c | 26 ---------------- 11 files changed, 23 insertions(+), 68 deletions(-) delete mode 100644 src/os/inc/osPthread.h rename src/os/src/detail/{osPThread.c => osSemphone.c} (100%) rename src/os/src/detail/{osWchar.c => osString.c} (94%) delete mode 100644 src/os/src/detail/osUtil.c diff --git a/src/os/inc/os.h b/src/os/inc/os.h index 70f8487baa..9996f7d92a 100644 --- a/src/os/inc/os.h +++ b/src/os/inc/os.h @@ -51,7 +51,6 @@ extern "C" { #include "osLz4.h" #include "osMath.h" #include "osMemory.h" -#include "osPthread.h" #include "osRand.h" #include "osSemphone.h" #include "osSocket.h" diff --git a/src/os/inc/osDarwin64.h b/src/os/inc/osDarwin64.h index 8f0978da53..cda987f6d5 100644 --- a/src/os/inc/osDarwin64.h +++ b/src/os/inc/osDarwin64.h @@ -85,7 +85,7 @@ int tsem_destroy(dispatch_semaphore_t *sem); #define TAOS_OS_FUNC_SOCKET_SETSOCKETOPT #define TAOS_OS_FUNC_SYSINFO #define TAOS_OS_FUNC_TIMER -#define TAOS_OS_FUNC_UTIL +#define TAOS_OS_FUNC_STRING_STR2INT64 // specific #define htobe64 htonll diff --git a/src/os/inc/osFile.h b/src/os/inc/osFile.h index f5513cc709..8ff0089392 100644 --- a/src/os/inc/osFile.h +++ b/src/os/inc/osFile.h @@ -51,11 +51,11 @@ int taosFSendFileImp(FILE* out_file, FILE* in_file, int64_t* offset, int32_t #endif #endif +int32_t taosFileRename(char *fullPath, char *suffix, char delimiter, char **dstPath); + // TAOS_OS_FUNC_FILE_GETTMPFILEPATH void taosGetTmpfilePath(const char *fileNamePrefix, char *dstPath); -int32_t taosFileRename(char *fullPath, char *suffix, char delimiter, char **dstPath); - #ifdef __cplusplus } #endif diff --git a/src/os/inc/osPthread.h b/src/os/inc/osPthread.h deleted file mode 100644 index add5c9042d..0000000000 --- a/src/os/inc/osPthread.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2019 TAOS Data, Inc. - * - * This program is free software: you can use, redistribute, and/or modify - * it under the terms of the GNU Affero General Public License, version 3 - * or later ("AGPL"), as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#ifndef TDENGINE_OS_PTHREAD_H -#define TDENGINE_OS_PTHREAD_H - -#ifdef __cplusplus -extern "C" { -#endif - -// TAOS_OS_FUNC_PTHREAD -bool taosCheckPthreadValid(pthread_t thread); -int64_t taosGetPthreadId(); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/os/inc/osSemphone.h b/src/os/inc/osSemphone.h index 138a6f97ee..c001f95d89 100644 --- a/src/os/inc/osSemphone.h +++ b/src/os/inc/osSemphone.h @@ -28,6 +28,10 @@ extern "C" { #define tsem_destroy sem_destroy #endif +// TAOS_OS_FUNC_PTHREAD +bool taosCheckPthreadValid(pthread_t thread); +int64_t taosGetPthreadId(); + #ifdef __cplusplus } #endif diff --git a/src/os/inc/osString.h b/src/os/inc/osString.h index c91aef6d18..9d0a7b3352 100644 --- a/src/os/inc/osString.h +++ b/src/os/inc/osString.h @@ -29,7 +29,7 @@ extern "C" { #define taosGetlineImp(lineptr, n, stream) getline(lineptr, n , stream) #endif -#ifndef TAOS_OS_FUNC_WCHAR +#ifndef TAOS_OS_FUNC_STRING_WCHAR #define twcslen wcslen #endif @@ -39,7 +39,7 @@ extern "C" { (dst)[(size)-1] = 0; \ } while (0); -// TAOS_OS_FUNC_UTIL +// TAOS_OS_FUNC_STRING_STR2INT64 int64_t tsosStr2int64(char *str); // USE_LIBICONV diff --git a/src/os/inc/osSysinfo.h b/src/os/inc/osSysinfo.h index ac91e73ab3..c3db406a17 100644 --- a/src/os/inc/osSysinfo.h +++ b/src/os/inc/osSysinfo.h @@ -32,7 +32,7 @@ void taosPrintOsInfo(); int taosSystem(const char * cmd) ; void taosKillSystem(); -// TAOS_OS_FUNC_CORE +// TAOS_OS_FUNC_SYSINFO_CORE void taosSetCoreDump(); #ifdef __cplusplus diff --git a/src/os/inc/osWindows64.h b/src/os/inc/osWindows64.h index 75685744aa..3a42978ff2 100644 --- a/src/os/inc/osWindows64.h +++ b/src/os/inc/osWindows64.h @@ -48,7 +48,7 @@ extern "C" { #endif -#define TAOS_OS_FUNC_WCHAR +#define TAOS_OS_FUNC_STRING_WCHAR #define TAOS_OS_FUNC_FILE #define TAOS_OS_FUNC_SLEEP #define TAOS_OS_FUNC_TIMER @@ -65,7 +65,7 @@ extern "C" { int32_t BUILDIN_CTZL(uint64_t val); int32_t BUILDIN_CTZ(uint32_t val); -#define TAOS_OS_FUNC_UTIL +#define TAOS_OS_FUNC_STRING_STR2INT64 #ifdef _TD_GO_DLL_ int64_t tsosStr2int64(char *str); uint64_t htonll(uint64_t val); diff --git a/src/os/src/detail/osPThread.c b/src/os/src/detail/osSemphone.c similarity index 100% rename from src/os/src/detail/osPThread.c rename to src/os/src/detail/osSemphone.c diff --git a/src/os/src/detail/osWchar.c b/src/os/src/detail/osString.c similarity index 94% rename from src/os/src/detail/osWchar.c rename to src/os/src/detail/osString.c index 4e02973e50..6a613e89fc 100644 --- a/src/os/src/detail/osWchar.c +++ b/src/os/src/detail/osString.c @@ -18,7 +18,16 @@ #include "tglobal.h" #include "taosdef.h" -#ifndef TAOS_OS_FUNC_WCHAR +#ifndef TAOS_OS_FUNC_STRING_STR2INT64 + +int64_t tsosStr2int64(char *str) { + char *endptr = NULL; + return strtoll(str, &endptr, 10); +} + +#endif + +#ifndef TAOS_OS_FUNC_STRING_WCHAR int tasoUcs4Compare(void* f1_ucs4, void *f2_ucs4, int bytes) { return wcsncmp((wchar_t *)f1_ucs4, (wchar_t *)f2_ucs4, bytes / TSDB_NCHAR_SIZE); @@ -120,4 +129,4 @@ char *taosCharsetReplace(char *charsetstr) { } return strdup(charsetstr); -} \ No newline at end of file +} diff --git a/src/os/src/detail/osUtil.c b/src/os/src/detail/osUtil.c deleted file mode 100644 index 10576c9a0a..0000000000 --- a/src/os/src/detail/osUtil.c +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2019 TAOS Data, Inc. - * - * This program is free software: you can use, redistribute, and/or modify - * it under the terms of the GNU Affero General Public License, version 3 - * or later ("AGPL"), as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#define _DEFAULT_SOURCE -#include "os.h" - -#ifndef TAOS_OS_FUNC_UTIL - -int64_t tsosStr2int64(char *str) { - char *endptr = NULL; - return strtoll(str, &endptr, 10); -} - -#endif \ No newline at end of file From de38e2cf4fe128439dc6cab148996e3bd95c332c Mon Sep 17 00:00:00 2001 From: slguan Date: Fri, 31 Jul 2020 15:29:11 +0800 Subject: [PATCH 12/56] [TD-992] --- src/os/src/darwin64/darwinCoredump.c | 19 ------------------- .../darwin64/{darwinFileOp.c => darwinFile.c} | 1 - .../{darwinSem.c => darwinSemphone.c} | 0 .../darwin64/{darwinUtil.c => darwinString.c} | 0 src/os/src/darwin64/darwinSysInfo.c | 2 ++ 5 files changed, 2 insertions(+), 20 deletions(-) delete mode 100644 src/os/src/darwin64/darwinCoredump.c rename src/os/src/darwin64/{darwinFileOp.c => darwinFile.c} (99%) rename src/os/src/darwin64/{darwinSem.c => darwinSemphone.c} (100%) rename src/os/src/darwin64/{darwinUtil.c => darwinString.c} (100%) diff --git a/src/os/src/darwin64/darwinCoredump.c b/src/os/src/darwin64/darwinCoredump.c deleted file mode 100644 index 43f22b604d..0000000000 --- a/src/os/src/darwin64/darwinCoredump.c +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2019 TAOS Data, Inc. - * - * This program is free software: you can use, redistribute, and/or modify - * it under the terms of the GNU Affero General Public License, version 3 - * or later ("AGPL"), as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#define _DEFAULT_SOURCE -#include "os.h" - -void taosSetCoreDump() {} diff --git a/src/os/src/darwin64/darwinFileOp.c b/src/os/src/darwin64/darwinFile.c similarity index 99% rename from src/os/src/darwin64/darwinFileOp.c rename to src/os/src/darwin64/darwinFile.c index 7740f6d5cf..113ea7f1fa 100644 --- a/src/os/src/darwin64/darwinFileOp.c +++ b/src/os/src/darwin64/darwinFile.c @@ -60,7 +60,6 @@ int taosFSendFileImp(FILE* out_file, FILE* in_file, int64_t* offset, int32_t cou return writeLen; } - ssize_t taosTSendFileImp(int dfd, int sfd, off_t *offset, size_t size) { uError("not implemented yet"); return -1; diff --git a/src/os/src/darwin64/darwinSem.c b/src/os/src/darwin64/darwinSemphone.c similarity index 100% rename from src/os/src/darwin64/darwinSem.c rename to src/os/src/darwin64/darwinSemphone.c diff --git a/src/os/src/darwin64/darwinUtil.c b/src/os/src/darwin64/darwinString.c similarity index 100% rename from src/os/src/darwin64/darwinUtil.c rename to src/os/src/darwin64/darwinString.c diff --git a/src/os/src/darwin64/darwinSysInfo.c b/src/os/src/darwin64/darwinSysInfo.c index ea29a0b96c..ee2f82b307 100644 --- a/src/os/src/darwin64/darwinSysInfo.c +++ b/src/os/src/darwin64/darwinSysInfo.c @@ -104,3 +104,5 @@ int taosSystem(const char *cmd) { uError("un support funtion"); return -1; } + +void taosSetCoreDump() {} \ No newline at end of file From 8089a23c27d52d2827a5c6782a064c447b8405af Mon Sep 17 00:00:00 2001 From: slguan Date: Fri, 31 Jul 2020 16:09:38 +0800 Subject: [PATCH 13/56] [TD-992] --- src/os/inc/os.h | 10 +- src/os/inc/{osDarwin64.h => osDarwin.h} | 18 +-- src/os/inc/osFile.h | 2 +- src/os/inc/osSemphone.h | 2 +- src/os/inc/osSocket.h | 24 +-- src/os/inc/osString.h | 2 + src/os/inc/{osWindows64.h => osWindows.h} | 83 +++++----- src/os/inc/osWindows32.h | 54 ------- .../src/{darwin64 => darwin}/CMakeLists.txt | 0 src/os/src/{darwin64 => darwin}/darwinEnv.c | 0 src/os/src/{darwin64 => darwin}/darwinFile.c | 0 .../src/{darwin64 => darwin}/darwinSemphone.c | 0 .../src/{darwin64 => darwin}/darwinSocket.c | 0 .../src/{darwin64 => darwin}/darwinString.c | 0 .../src/{darwin64 => darwin}/darwinSysInfo.c | 0 src/os/src/{darwin64 => darwin}/darwinTimer.c | 0 src/os/src/detail/osFile.c | 2 +- src/os/src/detail/osSemphone.c | 2 +- src/os/src/detail/osString.c | 6 +- src/os/src/detail/osTimer.c | 2 +- .../src/{windows64 => windows}/CMakeLists.txt | 0 src/os/src/{windows64 => windows}/w64Atomic.c | 0 src/os/src/{windows64 => windows}/w64Env.c | 0 .../w64FileOp.c => windows/w64File.c} | 27 +++- src/os/src/windows/w64Getline.c | 124 +++++++++++++++ src/os/src/{windows64 => windows}/w64Godll.c | 7 +- src/os/src/{windows64 => windows}/w64Lz4.c | 0 .../w64PThread.c => windows/w64Semphone.c} | 0 src/os/src/{windows64 => windows}/w64Socket.c | 0 .../w64Util.c => windows/w64String.c} | 80 ++++++---- .../src/{windows64 => windows}/w64Strptime.c | 0 .../src/{windows64 => windows}/w64Sysinfo.c | 4 +- src/os/src/{windows64 => windows}/w64Time.c | 0 src/os/src/{windows64 => windows}/w64Timer.c | 0 .../src/{windows64 => windows}/w64Wordexp.c | 0 src/os/src/windows64/w64Coredump.c | 23 --- src/os/src/windows64/w64File.c | 38 ----- src/os/src/windows64/w64Getline.c | 145 ------------------ src/os/src/windows64/w64Msghdr.c | 56 ------- src/os/src/windows64/w64String.c | 92 ----------- src/os/src/windows64/w64Wchar.c | 71 --------- 41 files changed, 278 insertions(+), 596 deletions(-) rename src/os/inc/{osDarwin64.h => osDarwin.h} (83%) rename src/os/inc/{osWindows64.h => osWindows.h} (96%) delete mode 100644 src/os/inc/osWindows32.h rename src/os/src/{darwin64 => darwin}/CMakeLists.txt (100%) rename src/os/src/{darwin64 => darwin}/darwinEnv.c (100%) rename src/os/src/{darwin64 => darwin}/darwinFile.c (100%) rename src/os/src/{darwin64 => darwin}/darwinSemphone.c (100%) rename src/os/src/{darwin64 => darwin}/darwinSocket.c (100%) rename src/os/src/{darwin64 => darwin}/darwinString.c (100%) rename src/os/src/{darwin64 => darwin}/darwinSysInfo.c (100%) rename src/os/src/{darwin64 => darwin}/darwinTimer.c (100%) rename src/os/src/{windows64 => windows}/CMakeLists.txt (100%) rename src/os/src/{windows64 => windows}/w64Atomic.c (100%) rename src/os/src/{windows64 => windows}/w64Env.c (100%) rename src/os/src/{windows64/w64FileOp.c => windows/w64File.c} (73%) create mode 100644 src/os/src/windows/w64Getline.c rename src/os/src/{windows64 => windows}/w64Godll.c (89%) rename src/os/src/{windows64 => windows}/w64Lz4.c (100%) rename src/os/src/{windows64/w64PThread.c => windows/w64Semphone.c} (100%) rename src/os/src/{windows64 => windows}/w64Socket.c (100%) rename src/os/src/{windows64/w64Util.c => windows/w64String.c} (67%) rename src/os/src/{windows64 => windows}/w64Strptime.c (100%) rename src/os/src/{windows64 => windows}/w64Sysinfo.c (99%) rename src/os/src/{windows64 => windows}/w64Time.c (100%) rename src/os/src/{windows64 => windows}/w64Timer.c (100%) rename src/os/src/{windows64 => windows}/w64Wordexp.c (100%) delete mode 100644 src/os/src/windows64/w64Coredump.c delete mode 100644 src/os/src/windows64/w64File.c delete mode 100644 src/os/src/windows64/w64Getline.c delete mode 100644 src/os/src/windows64/w64Msghdr.c delete mode 100644 src/os/src/windows64/w64String.c delete mode 100644 src/os/src/windows64/w64Wchar.c diff --git a/src/os/inc/os.h b/src/os/inc/os.h index 9996f7d92a..700b29ce98 100644 --- a/src/os/inc/os.h +++ b/src/os/inc/os.h @@ -21,7 +21,7 @@ extern "C" { #endif #ifdef _TD_DARWIN_64 -#include "osDarwin64.h" +#include "osDarwin.h" #endif #ifdef _TD_LINUX_64 @@ -36,12 +36,8 @@ extern "C" { #include "osAlpine.h" #endif -#ifdef _TD_WINDOWS_64 -#include "osWindows64.h" -#endif - -#ifdef _TD_WINDOWS_32 -#include "osWindows32.h" +#if defined(_TD_WINDOWS_64) || defined(_TD_WINDOWS_32) +#include "osWindows.h" #endif #include "osAtomic.h" diff --git a/src/os/inc/osDarwin64.h b/src/os/inc/osDarwin.h similarity index 83% rename from src/os/inc/osDarwin64.h rename to src/os/inc/osDarwin.h index cda987f6d5..8628a0f3ac 100644 --- a/src/os/inc/osDarwin64.h +++ b/src/os/inc/osDarwin.h @@ -71,21 +71,21 @@ extern "C" { #include #include -#define TAOS_OS_FUNC_FILE_TSENDIFLE -#define taosFSendFile(outfile, infile, offset, count) taosFSendFileImp(outfile, infile, offset, size) -#define taosTSendFile(dfd, sfd, offset, size) taosTSendFileImp(dfd, sfd, offset, size) +#define TAOS_OS_FUNC_FILE_SENDIFLE + #define taosFSendFile(outfile, infile, offset, count) taosFSendFileImp(outfile, infile, offset, size) + #define taosTSendFile(dfd, sfd, offset, size) taosTSendFileImp(dfd, sfd, offset, size) #define TAOS_OS_FUNC_SEMPHONE -#define tsem_t dispatch_semaphore_t -int tsem_init(dispatch_semaphore_t *sem, int pshared, unsigned int value); -int tsem_wait(dispatch_semaphore_t *sem); -int tsem_post(dispatch_semaphore_t *sem); -int tsem_destroy(dispatch_semaphore_t *sem); + #define tsem_t dispatch_semaphore_t + int tsem_init(dispatch_semaphore_t *sem, int pshared, unsigned int value); + int tsem_wait(dispatch_semaphore_t *sem); + int tsem_post(dispatch_semaphore_t *sem); + int tsem_destroy(dispatch_semaphore_t *sem); #define TAOS_OS_FUNC_SOCKET_SETSOCKETOPT +#define TAOS_OS_FUNC_STRING_STR2INT64 #define TAOS_OS_FUNC_SYSINFO #define TAOS_OS_FUNC_TIMER -#define TAOS_OS_FUNC_STRING_STR2INT64 // specific #define htobe64 htonll diff --git a/src/os/inc/osFile.h b/src/os/inc/osFile.h index 8ff0089392..6e48e80ca4 100644 --- a/src/os/inc/osFile.h +++ b/src/os/inc/osFile.h @@ -26,7 +26,7 @@ ssize_t taosTWriteImp(int fd, void *buf, size_t count); ssize_t taosTSendFileImp(int dfd, int sfd, off_t *offset, size_t size); int taosFSendFileImp(FILE* out_file, FILE* in_file, int64_t* offset, int32_t count); -#ifndef TAOS_OS_FUNC_FILE_TSENDIFLE +#ifndef TAOS_OS_FUNC_FILE_SENDIFLE #define taosTSendFile(dfd, sfd, offset, size) taosTSendFileImp(dfd, sfd, offset, size) #define taosFSendFile(outfile, infile, offset, count) taosTSendFileImp(fileno(outfile), fileno(infile), offset, size) #endif diff --git a/src/os/inc/osSemphone.h b/src/os/inc/osSemphone.h index c001f95d89..300f1e8ef1 100644 --- a/src/os/inc/osSemphone.h +++ b/src/os/inc/osSemphone.h @@ -28,7 +28,7 @@ extern "C" { #define tsem_destroy sem_destroy #endif -// TAOS_OS_FUNC_PTHREAD +// TAOS_OS_FUNC_SEMPHONE_PTHREAD bool taosCheckPthreadValid(pthread_t thread); int64_t taosGetPthreadId(); diff --git a/src/os/inc/osSocket.h b/src/os/inc/osSocket.h index 749d3906f5..10fed022bb 100644 --- a/src/os/inc/osSocket.h +++ b/src/os/inc/osSocket.h @@ -20,17 +20,19 @@ extern "C" { #endif -#define taosSend(sockfd, buf, len, flags) send(sockfd, buf, len, flags) -#define taosSendto(sockfd, buf, len, flags, dest_addr, addrlen) sendto(sockfd, buf, len, flags, dest_addr, addrlen) -#define taosReadSocket(fd, buf, len) read(fd, buf, len) -#define taosWriteSocket(fd, buf, len) write(fd, buf, len) -#define taosCloseSocket(x) \ - { \ - if (FD_VALID(x)) { \ - close(x); \ - x = FD_INITIALIZER; \ - } \ - } +#ifndef TAOS_OS_FUNC_SOCKET_OP + #define taosSend(sockfd, buf, len, flags) send(sockfd, buf, len, flags) + #define taosSendto(sockfd, buf, len, flags, dest_addr, addrlen) sendto(sockfd, buf, len, flags, dest_addr, addrlen) + #define taosReadSocket(fd, buf, len) read(fd, buf, len) + #define taosWriteSocket(fd, buf, len) write(fd, buf, len) + #define taosCloseSocket(x) \ + { \ + if (FD_VALID(x)) { \ + close(x); \ + x = FD_INITIALIZER; \ + } \ + } +#endif #define taosClose(x) taosCloseSocket(x) diff --git a/src/os/inc/osString.h b/src/os/inc/osString.h index 9d0a7b3352..1e1953c81d 100644 --- a/src/os/inc/osString.h +++ b/src/os/inc/osString.h @@ -27,6 +27,8 @@ extern "C" { #ifndef TAOS_OS_FUNC_STRING_GETLINE #define taosGetlineImp(lineptr, n, stream) getline(lineptr, n , stream) +#else + int taosGetlineImp(char **lineptr, size_t *n, FILE *stream); #endif #ifndef TAOS_OS_FUNC_STRING_WCHAR diff --git a/src/os/inc/osWindows64.h b/src/os/inc/osWindows.h similarity index 96% rename from src/os/inc/osWindows64.h rename to src/os/inc/osWindows.h index 3a42978ff2..b44a41832e 100644 --- a/src/os/inc/osWindows64.h +++ b/src/os/inc/osWindows.h @@ -48,16 +48,7 @@ extern "C" { #endif -#define TAOS_OS_FUNC_STRING_WCHAR -#define TAOS_OS_FUNC_FILE -#define TAOS_OS_FUNC_SLEEP -#define TAOS_OS_FUNC_TIMER -#define TAOS_OS_FUNC_SOCKET -#define TAOS_OS_FUNC_PTHREAD - -#define TAOS_OS_FUNC_FILEOP - #define taosFSendFile(outfile, infile, offset, count) taosFSendFileImp(outfile, infile, offset, size) - #define taosTSendFile(dfd, sfd, offset, size) taosTSendFileImp(dfd, sfd, offset, size) +#define TAOS_OS_FUNC_ATOMIC #define TAOS_OS_FUNC_LZ4 int32_t BUILDIN_CLZL(uint64_t val); @@ -65,13 +56,13 @@ extern "C" { int32_t BUILDIN_CTZL(uint64_t val); int32_t BUILDIN_CTZ(uint32_t val); -#define TAOS_OS_FUNC_STRING_STR2INT64 - #ifdef _TD_GO_DLL_ - int64_t tsosStr2int64(char *str); - uint64_t htonll(uint64_t val); - #else - #define tsosStr2int64 _atoi64 - #endif +#define TAOS_OS_FUNC_DIR + +#define TAOS_OS_FUNC_FILE +#define TAOS_OS_FUNC_FILE_SENDIFLE + #define taosFSendFile(outfile, infile, offset, count) taosFSendFileImp(outfile, infile, offset, size) + #define taosTSendFile(dfd, sfd, offset, size) taosTSendFileImp(dfd, sfd, offset, size) +#define TAOS_OS_FUNC_FILE_GETTMPFILEPATH #define TAOS_OS_FUNC_MATH #define SWAP(a, b, c) \ @@ -80,26 +71,60 @@ extern "C" { (a) = (c)(b); \ (b) = __tmp; \ } while (0) - #define MAX(a,b) (((a)>(b))?(a):(b)) #define MIN(a,b) (((a)<(b))?(a):(b)) -#define TAOS_OS_FUNC_NETWORK +#define TAOS_OS_FUNC_SEMPHONE_PTHREAD + +#define TAOS_OS_FUNC_SOCKET +#define TAOS_OS_FUNC_SOCKET_SETSOCKETOPT +#define TAOS_OS_FUNC_SOCKET_OP #define taosSend(sockfd, buf, len, flags) send(sockfd, buf, len, flags) #define taosSendto(sockfd, buf, len, flags, dest_addr, addrlen) sendto(sockfd, buf, len, flags, dest_addr, addrlen) #define taosWriteSocket(fd, buf, len) send(fd, buf, len, 0) #define taosReadSocket(fd, buf, len) recv(fd, buf, len, 0) #define taosCloseSocket(fd) closesocket(fd) -#define TAOS_OS_DEF_TIME +#define TAOS_OS_FUNC_STRING_WCHAR +#define TAOS_OS_FUNC_STRING_GETLINE +#define TAOS_OS_FUNC_STRING_STR2INT64 + #ifdef _TD_GO_DLL_ + int64_t tsosStr2int64(char *str); + uint64_t htonll(uint64_t val); + #else + #define tsosStr2int64 _atoi64 + #endif +#define TAOS_OS_FUNC_STRING_STRDUP + #define taosStrdupImp(str) _strdup(str) + #define taosStrndupImp(str, size) _strndup(str, size) + +#define TAOS_OS_FUNC_SYSINFO + +#define TAOS_OS_FUNC_TIME_DEF #ifdef _TD_GO_DLL_ #define MILLISECOND_PER_SECOND (1000LL) #else #define MILLISECOND_PER_SECOND (1000i64) #endif +#define TAOS_OS_FUNC_TIMER_SLEEP +#define TAOS_OS_FUNC_TIMER + +// specific typedef int (*__compar_fn_t)(const void *, const void *); -int getline(char **lineptr, size_t *n, FILE *stream); +#define ssize_t int +#define bzero(ptr, size) memset((ptr), 0, (size)) +#define mkdir(pathname, mode) _mkdir(pathname) +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#define wcsncasecmp _wcsnicmp +#define strtok_r strtok_s +#define snprintf _snprintf +#define in_addr_t unsigned long +#define socklen_t int +#define htobe64 htonll +#define twrite write + int gettimeofday(struct timeval *tv, struct timezone *tz); struct tm *localtime_r(const time_t *timep, struct tm *result); char * strptime(const char *buf, const char *fmt, struct tm *tm); @@ -109,9 +134,6 @@ int flock(int fd, int option); int fsync(int filedes); char * strndup(const char *s, size_t n); -#define strdup _strdup -#define ssize_t int - // for function open in stat.h #define S_IRWXU _S_IREAD #define S_IRWXG _S_IWRITE @@ -135,19 +157,6 @@ char * strndup(const char *s, size_t n); #define LOCK_NB 2 #define LOCK_UN 3 -#define bzero(ptr, size) memset((ptr), 0, (size)) -#define mkdir(pathname, mode) _mkdir(pathname) -#define strcasecmp _stricmp -#define strncasecmp _strnicmp -#define wcsncasecmp _wcsnicmp -#define strtok_r strtok_s - -#define snprintf _snprintf -#define in_addr_t unsigned long -#define socklen_t int -#define htobe64 htonll -#define twrite write - #ifndef PATH_MAX #define PATH_MAX 256 #endif diff --git a/src/os/inc/osWindows32.h b/src/os/inc/osWindows32.h deleted file mode 100644 index 4744d4beb5..0000000000 --- a/src/os/inc/osWindows32.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -* Copyright (c) 2019 TAOS Data, Inc. -* -* This program is free software: you can use, redistribute, and/or modify -* it under the terms of the GNU Affero General Public License, version 3 -* or later ("AGPL"), as published by the Free Software Foundation. -* -* This program is distributed in the hope that it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see . -*/ - -#ifndef TDENGINE_PLATFORM_WINDOWS32_H -#define TDENGINE_PLATFORM_WINDOWS32_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "winsock2.h" -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef __cplusplus -} -#endif -#endif \ No newline at end of file diff --git a/src/os/src/darwin64/CMakeLists.txt b/src/os/src/darwin/CMakeLists.txt similarity index 100% rename from src/os/src/darwin64/CMakeLists.txt rename to src/os/src/darwin/CMakeLists.txt diff --git a/src/os/src/darwin64/darwinEnv.c b/src/os/src/darwin/darwinEnv.c similarity index 100% rename from src/os/src/darwin64/darwinEnv.c rename to src/os/src/darwin/darwinEnv.c diff --git a/src/os/src/darwin64/darwinFile.c b/src/os/src/darwin/darwinFile.c similarity index 100% rename from src/os/src/darwin64/darwinFile.c rename to src/os/src/darwin/darwinFile.c diff --git a/src/os/src/darwin64/darwinSemphone.c b/src/os/src/darwin/darwinSemphone.c similarity index 100% rename from src/os/src/darwin64/darwinSemphone.c rename to src/os/src/darwin/darwinSemphone.c diff --git a/src/os/src/darwin64/darwinSocket.c b/src/os/src/darwin/darwinSocket.c similarity index 100% rename from src/os/src/darwin64/darwinSocket.c rename to src/os/src/darwin/darwinSocket.c diff --git a/src/os/src/darwin64/darwinString.c b/src/os/src/darwin/darwinString.c similarity index 100% rename from src/os/src/darwin64/darwinString.c rename to src/os/src/darwin/darwinString.c diff --git a/src/os/src/darwin64/darwinSysInfo.c b/src/os/src/darwin/darwinSysInfo.c similarity index 100% rename from src/os/src/darwin64/darwinSysInfo.c rename to src/os/src/darwin/darwinSysInfo.c diff --git a/src/os/src/darwin64/darwinTimer.c b/src/os/src/darwin/darwinTimer.c similarity index 100% rename from src/os/src/darwin64/darwinTimer.c rename to src/os/src/darwin/darwinTimer.c diff --git a/src/os/src/detail/osFile.c b/src/os/src/detail/osFile.c index 1cd7445658..ad6be83e41 100644 --- a/src/os/src/detail/osFile.c +++ b/src/os/src/detail/osFile.c @@ -109,7 +109,7 @@ ssize_t taosTWriteImp(int fd, void *buf, size_t n) { return n; } -#ifndef TAOS_OS_FUNC_FILE_TSENDIFLE +#ifndef TAOS_OS_FUNC_FILE_SENDIFLE ssize_t taosTSendFileImp(int dfd, int sfd, off_t *offset, size_t size) { size_t leftbytes = size; ssize_t sentbytes; diff --git a/src/os/src/detail/osSemphone.c b/src/os/src/detail/osSemphone.c index 18207dc12e..82b916b4d7 100644 --- a/src/os/src/detail/osSemphone.c +++ b/src/os/src/detail/osSemphone.c @@ -16,7 +16,7 @@ #define _DEFAULT_SOURCE #include "os.h" -#ifndef TAOS_OS_FUNC_PTHREAD +#ifndef TAOS_OS_FUNC_SEMPHONE_PTHREAD bool taosCheckPthreadValid(pthread_t thread) { return thread != 0; } int64_t taosGetPthreadId() { return (int64_t)pthread_self(); } diff --git a/src/os/src/detail/osString.c b/src/os/src/detail/osString.c index 6a613e89fc..b4b8c9a294 100644 --- a/src/os/src/detail/osString.c +++ b/src/os/src/detail/osString.c @@ -19,20 +19,16 @@ #include "taosdef.h" #ifndef TAOS_OS_FUNC_STRING_STR2INT64 - int64_t tsosStr2int64(char *str) { char *endptr = NULL; return strtoll(str, &endptr, 10); } - #endif #ifndef TAOS_OS_FUNC_STRING_WCHAR - -int tasoUcs4Compare(void* f1_ucs4, void *f2_ucs4, int bytes) { +int tasoUcs4Compare(void *f1_ucs4, void *f2_ucs4, int bytes) { return wcsncmp((wchar_t *)f1_ucs4, (wchar_t *)f2_ucs4, bytes / TSDB_NCHAR_SIZE); } - #endif #ifdef USE_LIBICONV diff --git a/src/os/src/detail/osTimer.c b/src/os/src/detail/osTimer.c index bea5a718de..c425d1732e 100644 --- a/src/os/src/detail/osTimer.c +++ b/src/os/src/detail/osTimer.c @@ -102,7 +102,7 @@ void taosUninitTimer() { #endif -#ifndef TAOS_OS_FUNC_SLEEP +#ifndef TAOS_OS_FUNC_TIMER_SLEEP /* to make taosMsleep work, signal SIGALRM shall be blocked in the calling thread, diff --git a/src/os/src/windows64/CMakeLists.txt b/src/os/src/windows/CMakeLists.txt similarity index 100% rename from src/os/src/windows64/CMakeLists.txt rename to src/os/src/windows/CMakeLists.txt diff --git a/src/os/src/windows64/w64Atomic.c b/src/os/src/windows/w64Atomic.c similarity index 100% rename from src/os/src/windows64/w64Atomic.c rename to src/os/src/windows/w64Atomic.c diff --git a/src/os/src/windows64/w64Env.c b/src/os/src/windows/w64Env.c similarity index 100% rename from src/os/src/windows64/w64Env.c rename to src/os/src/windows/w64Env.c diff --git a/src/os/src/windows64/w64FileOp.c b/src/os/src/windows/w64File.c similarity index 73% rename from src/os/src/windows64/w64FileOp.c rename to src/os/src/windows/w64File.c index 54f7938dde..54a95297ac 100644 --- a/src/os/src/windows64/w64FileOp.c +++ b/src/os/src/windows/w64File.c @@ -15,11 +15,28 @@ #define _DEFAULT_SOURCE #include "os.h" -#include "taosdef.h" -#include "tglobal.h" -#include "ttimer.h" -#include "tulog.h" -#include "tutil.h" + +void taosGetTmpfilePath(const char *fileNamePrefix, char *dstPath) { + const char* tdengineTmpFileNamePrefix = "tdengine-"; + char tmpPath[PATH_MAX]; + + char *tmpDir = getenv("tmp"); + if (tmpDir == NULL) { + tmpDir = ""; + } + + strcpy(tmpPath, tmpDir); + strcat(tmpPath, tdengineTmpFileNamePrefix); + if (strlen(tmpPath) + strlen(fileNamePrefix) + strlen("-%d-%s") < PATH_MAX) { + strcat(tmpPath, fileNamePrefix); + strcat(tmpPath, "-%d-%s"); + } + + char rand[8] = {0}; + taosRandStr(rand, tListLen(rand) - 1); + snprintf(dstPath, PATH_MAX, tmpPath, getpid(), rand); +} + #define _SEND_FILE_STEP_ 1000 diff --git a/src/os/src/windows/w64Getline.c b/src/os/src/windows/w64Getline.c new file mode 100644 index 0000000000..3e8701e19b --- /dev/null +++ b/src/os/src/windows/w64Getline.c @@ -0,0 +1,124 @@ +/* getline.c -- Replacement for GNU C library function getline + +Copyright (C) 1993 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +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. See the GNU +General Public License for more details. */ + +/* Written by Jan Brittenson, bson@gnu.ai.mit.edu. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#if STDC_HEADERS +#include +#else +char *malloc(), *realloc(); +#endif + +/* Always add at least this many bytes when extending the buffer. */ +#define MIN_CHUNK 64 + +/* Read up to (and including) a TERMINATOR from STREAM into *LINEPTR ++ OFFSET (and null-terminate it). *LINEPTR is a pointer returned from +malloc (or NULL), pointing to *N characters of space. It is realloc'd +as necessary. Return the number of characters read (not including the +null terminator), or -1 on error or EOF. On a -1 return, the caller +should check feof(), if not then errno has been set to indicate +the error. */ + +int getstr(char **lineptr, size_t *n, FILE *stream, char terminator, int offset) { + int nchars_avail; /* Allocated but unused chars in *LINEPTR. */ + char *read_pos; /* Where we're reading into *LINEPTR. */ + int ret; + + if (!lineptr || !n || !stream) { + errno = EINVAL; + return -1; + } + + if (!*lineptr) { + *n = MIN_CHUNK; + *lineptr = malloc(*n); + if (!*lineptr) { + errno = ENOMEM; + return -1; + } + } + + nchars_avail = (int)(*n - offset); + read_pos = *lineptr + offset; + + for (;;) { + int save_errno; + register int c = getc(stream); + + save_errno = errno; + + /* We always want at least one char left in the buffer, since we + always (unless we get an error while reading the first char) + NUL-terminate the line buffer. */ + + assert((*lineptr + *n) == (read_pos + nchars_avail)); + if (nchars_avail < 2) { + if (*n > MIN_CHUNK) + *n *= 2; + else + *n += MIN_CHUNK; + + nchars_avail = (int)(*n + *lineptr - read_pos); + *lineptr = realloc(*lineptr, *n); + if (!*lineptr) { + errno = ENOMEM; + return -1; + } + read_pos = *n - nchars_avail + *lineptr; + assert((*lineptr + *n) == (read_pos + nchars_avail)); + } + + if (ferror(stream)) { + /* Might like to return partial line, but there is no + place for us to store errno. And we don't want to just + lose errno. */ + errno = save_errno; + return -1; + } + + if (c == EOF) { + /* Return partial line, if any. */ + if (read_pos == *lineptr) + return -1; + else + break; + } + + *read_pos++ = c; + nchars_avail--; + + if (c == terminator) /* Return the line. */ + break; + } + + /* Done - NUL terminate and return the number of chars read. */ + *read_pos = '\0'; + + ret = (int)(read_pos - (*lineptr + offset)); + return ret; +} + +int taosGetlineImp(char **lineptr, size_t *n, FILE *stream) { + return getstr(lineptr, n, stream, '\n', 0); +} \ No newline at end of file diff --git a/src/os/src/windows64/w64Godll.c b/src/os/src/windows/w64Godll.c similarity index 89% rename from src/os/src/windows64/w64Godll.c rename to src/os/src/windows/w64Godll.c index b0267c4aac..b270dab2f4 100644 --- a/src/os/src/windows64/w64Godll.c +++ b/src/os/src/windows/w64Godll.c @@ -27,8 +27,7 @@ int64_t tsosStr2int64(char *str) { return strtoll(str, &endptr, 10); } -uint64_t htonll(uint64_t val) -{ - return (((uint64_t) htonl(val)) << 32) + htonl(val >> 32); +uint64_t htonll(uint64_t val) { + return (((uint64_t) htonl(val)) << 32) + htonl(val >> 32); } -#endif \ No newline at end of file +#endif diff --git a/src/os/src/windows64/w64Lz4.c b/src/os/src/windows/w64Lz4.c similarity index 100% rename from src/os/src/windows64/w64Lz4.c rename to src/os/src/windows/w64Lz4.c diff --git a/src/os/src/windows64/w64PThread.c b/src/os/src/windows/w64Semphone.c similarity index 100% rename from src/os/src/windows64/w64PThread.c rename to src/os/src/windows/w64Semphone.c diff --git a/src/os/src/windows64/w64Socket.c b/src/os/src/windows/w64Socket.c similarity index 100% rename from src/os/src/windows64/w64Socket.c rename to src/os/src/windows/w64Socket.c diff --git a/src/os/src/windows64/w64Util.c b/src/os/src/windows/w64String.c similarity index 67% rename from src/os/src/windows64/w64Util.c rename to src/os/src/windows/w64String.c index 1a9f71b3c3..8057c89a55 100644 --- a/src/os/src/windows64/w64Util.c +++ b/src/os/src/windows/w64String.c @@ -21,7 +21,6 @@ #include "tulog.h" #include "tutil.h" - /* * Get next token from string *stringp, where tokens are possibly-empty * strings separated by characters from delim. @@ -67,29 +66,6 @@ char *getpass(const char *prefix) { return passwd; } -int flock(int fd, int option) { - return 0; -} - -int fsync(int filedes) { - return 0; -} - -int sigaction(int sig, struct sigaction *d, void *p) { - return 0; -} - -int wordexp(const char *words, wordexp_t *pwordexp, int flags) { - pwordexp->we_offs = 0; - pwordexp->we_wordc = 1; - pwordexp->we_wordv = (char **)(pwordexp->wordPos); - pwordexp->we_wordv[0] = (char *)words; - return 0; -} - -void wordfree(wordexp_t *pwordexp) {} - - char *strndup(const char *s, size_t n) { int len = strlen(s); if (len >= n) { @@ -102,16 +78,54 @@ char *strndup(const char *s, size_t n) { return r; } -void taosSetCoreDump() {} +size_t twcslen(const wchar_t *wcs) { + int *wstr = (int *)wcs; + if (NULL == wstr) { + return 0; + } -#ifdef _TD_GO_DLL_ -int64_t tsosStr2int64(char *str) { - char *endptr = NULL; - return strtoll(str, &endptr, 10); + size_t n = 0; + while (1) { + if (0 == *wstr++) { + break; + } + n++; + } + + return n; } -uint64_t htonll(uint64_t val) -{ - return (((uint64_t) htonl(val)) << 32) + htonl(val >> 32); +int tasoUcs4Compare(void *f1_ucs4, void *f2_ucs4, int bytes) { + for (int i = 0; i < bytes; ++i) { + int32_t f1 = *(int32_t *)((char *)f1_ucs4 + i * 4); + int32_t f2 = *(int32_t *)((char *)f2_ucs4 + i * 4); + + if ((f1 == 0 && f2 != 0) || (f1 != 0 && f2 == 0)) { + return f1 - f2; + } else if (f1 == 0 && f2 == 0) { + return 0; + } + + if (f1 != f2) { + return f1 - f2; + } + } + + return 0; + +#if 0 + int32_t ucs4_max_len = bytes + 4; + char *f1_mbs = calloc(bytes, 1); + char *f2_mbs = calloc(bytes, 1); + if (taosUcs4ToMbs(f1_ucs4, ucs4_max_len, f1_mbs) < 0) { + return -1; + } + if (taosUcs4ToMbs(f2_ucs4, ucs4_max_len, f2_mbs) < 0) { + return -1; + } + int32_t ret = strcmp(f1_mbs, f2_mbs); + free(f1_mbs); + free(f2_mbs); + return ret; +#endif } -#endif \ No newline at end of file diff --git a/src/os/src/windows64/w64Strptime.c b/src/os/src/windows/w64Strptime.c similarity index 100% rename from src/os/src/windows64/w64Strptime.c rename to src/os/src/windows/w64Strptime.c diff --git a/src/os/src/windows64/w64Sysinfo.c b/src/os/src/windows/w64Sysinfo.c similarity index 99% rename from src/os/src/windows64/w64Sysinfo.c rename to src/os/src/windows/w64Sysinfo.c index 950230e567..0a680ac0b7 100644 --- a/src/os/src/windows64/w64Sysinfo.c +++ b/src/os/src/windows/w64Sysinfo.c @@ -113,4 +113,6 @@ int fsync(int filedes) { int sigaction(int sig, struct sigaction *d, void *p) { return 0; -} \ No newline at end of file +} + +void taosSetCoreDump() {} \ No newline at end of file diff --git a/src/os/src/windows64/w64Time.c b/src/os/src/windows/w64Time.c similarity index 100% rename from src/os/src/windows64/w64Time.c rename to src/os/src/windows/w64Time.c diff --git a/src/os/src/windows64/w64Timer.c b/src/os/src/windows/w64Timer.c similarity index 100% rename from src/os/src/windows64/w64Timer.c rename to src/os/src/windows/w64Timer.c diff --git a/src/os/src/windows64/w64Wordexp.c b/src/os/src/windows/w64Wordexp.c similarity index 100% rename from src/os/src/windows64/w64Wordexp.c rename to src/os/src/windows/w64Wordexp.c diff --git a/src/os/src/windows64/w64Coredump.c b/src/os/src/windows64/w64Coredump.c deleted file mode 100644 index 95490e7ad0..0000000000 --- a/src/os/src/windows64/w64Coredump.c +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2019 TAOS Data, Inc. - * - * This program is free software: you can use, redistribute, and/or modify - * it under the terms of the GNU Affero General Public License, version 3 - * or later ("AGPL"), as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#define _DEFAULT_SOURCE -#include "os.h" -#include "tconfig.h" -#include "tglobal.h" -#include "tulog.h" -#include "tsystem.h" - -void taosSetCoreDump() {} \ No newline at end of file diff --git a/src/os/src/windows64/w64File.c b/src/os/src/windows64/w64File.c deleted file mode 100644 index 5cfcc8f79c..0000000000 --- a/src/os/src/windows64/w64File.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2019 TAOS Data, Inc. - * - * This program is free software: you can use, redistribute, and/or modify - * it under the terms of the GNU Affero General Public License, version 3 - * or later ("AGPL"), as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#define _DEFAULT_SOURCE -#include "os.h" - -void taosGetTmpfilePath(const char *fileNamePrefix, char *dstPath) { - const char* tdengineTmpFileNamePrefix = "tdengine-"; - char tmpPath[PATH_MAX]; - - char *tmpDir = getenv("tmp"); - if (tmpDir == NULL) { - tmpDir = ""; - } - - strcpy(tmpPath, tmpDir); - strcat(tmpPath, tdengineTmpFileNamePrefix); - if (strlen(tmpPath) + strlen(fileNamePrefix) + strlen("-%d-%s") < PATH_MAX) { - strcat(tmpPath, fileNamePrefix); - strcat(tmpPath, "-%d-%s"); - } - - char rand[8] = {0}; - taosRandStr(rand, tListLen(rand) - 1); - snprintf(dstPath, PATH_MAX, tmpPath, getpid(), rand); -} diff --git a/src/os/src/windows64/w64Getline.c b/src/os/src/windows64/w64Getline.c deleted file mode 100644 index 1dd56fd547..0000000000 --- a/src/os/src/windows64/w64Getline.c +++ /dev/null @@ -1,145 +0,0 @@ -/* getline.c -- Replacement for GNU C library function getline - -Copyright (C) 1993 Free Software Foundation, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -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. See the GNU -General Public License for more details. */ - -/* Written by Jan Brittenson, bson@gnu.ai.mit.edu. */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#if STDC_HEADERS -#include -#else -char *malloc(), *realloc(); -#endif - -/* Always add at least this many bytes when extending the buffer. */ -#define MIN_CHUNK 64 - -/* Read up to (and including) a TERMINATOR from STREAM into *LINEPTR -+ OFFSET (and null-terminate it). *LINEPTR is a pointer returned from -malloc (or NULL), pointing to *N characters of space. It is realloc'd -as necessary. Return the number of characters read (not including the -null terminator), or -1 on error or EOF. On a -1 return, the caller -should check feof(), if not then errno has been set to indicate -the error. */ - -int -getstr(lineptr, n, stream, terminator, offset) -char **lineptr; -size_t *n; -FILE *stream; -char terminator; -int offset; -{ - int nchars_avail; /* Allocated but unused chars in *LINEPTR. */ - char *read_pos; /* Where we're reading into *LINEPTR. */ - int ret; - - if (!lineptr || !n || !stream) - { - errno = EINVAL; - return -1; - } - - if (!*lineptr) - { - *n = MIN_CHUNK; - *lineptr = malloc(*n); - if (!*lineptr) - { - errno = ENOMEM; - return -1; - } - } - - nchars_avail = (int)(*n - offset); - read_pos = *lineptr + offset; - - for (;;) - { - int save_errno; - register int c = getc(stream); - - save_errno = errno; - - /* We always want at least one char left in the buffer, since we - always (unless we get an error while reading the first char) - NUL-terminate the line buffer. */ - - assert((*lineptr + *n) == (read_pos + nchars_avail)); - if (nchars_avail < 2) - { - if (*n > MIN_CHUNK) - *n *= 2; - else - *n += MIN_CHUNK; - - nchars_avail = (int)(*n + *lineptr - read_pos); - *lineptr = realloc(*lineptr, *n); - if (!*lineptr) - { - errno = ENOMEM; - return -1; - } - read_pos = *n - nchars_avail + *lineptr; - assert((*lineptr + *n) == (read_pos + nchars_avail)); - } - - if (ferror(stream)) - { - /* Might like to return partial line, but there is no - place for us to store errno. And we don't want to just - lose errno. */ - errno = save_errno; - return -1; - } - - if (c == EOF) - { - /* Return partial line, if any. */ - if (read_pos == *lineptr) - return -1; - else - break; - } - - *read_pos++ = c; - nchars_avail--; - - if (c == terminator) - /* Return the line. */ - break; - } - - /* Done - NUL terminate and return the number of chars read. */ - *read_pos = '\0'; - - ret = (int)(read_pos - (*lineptr + offset)); - return ret; -} - -int -getline(lineptr, n, stream) -char **lineptr; -size_t *n; -FILE *stream; -{ - return getstr(lineptr, n, stream, '\n', 0); -} \ No newline at end of file diff --git a/src/os/src/windows64/w64Msghdr.c b/src/os/src/windows64/w64Msghdr.c deleted file mode 100644 index 9d1924f311..0000000000 --- a/src/os/src/windows64/w64Msghdr.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2019 TAOS Data, Inc. - * - * This program is free software: you can use, redistribute, and/or modify - * it under the terms of the GNU Affero General Public License, version 3 - * or later ("AGPL"), as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include - -void taosFreeMsgHdr(void *hdr) { - WSAMSG *msgHdr = (WSAMSG *)hdr; - free(msgHdr->lpBuffers); -} - -int taosMsgHdrSize(void *hdr) { - WSAMSG *msgHdr = (WSAMSG *)hdr; - return msgHdr->dwBufferCount; -} - -void taosSendMsgHdr(void *hdr, int fd) { - WSAMSG *msgHdr = (WSAMSG *)hdr; - DWORD len; - - WSASendMsg(fd, msgHdr, 0, &len, 0, 0); - msgHdr->dwBufferCount = 0; -} - -void taosInitMsgHdr(void **hdr, void *dest, int maxPkts) { - WSAMSG *msgHdr = (WSAMSG *)malloc(sizeof(WSAMSG)); - memset(msgHdr, 0, sizeof(WSAMSG)); - *hdr = msgHdr; - - // see ws2def.h - // the size of LPSOCKADDR and sockaddr_in * is same, so it's safe - msgHdr->name = (LPSOCKADDR)dest; - msgHdr->namelen = sizeof(struct sockaddr_in); - int size = sizeof(WSABUF) * maxPkts; - msgHdr->lpBuffers = (LPWSABUF)malloc(size); - memset(msgHdr->lpBuffers, 0, size); - msgHdr->dwBufferCount = 0; -} - -void taosSetMsgHdrData(void *hdr, char *data, int dataLen) { - WSAMSG *msgHdr = (WSAMSG *)hdr; - msgHdr->lpBuffers[msgHdr->dwBufferCount].buf = data; - msgHdr->lpBuffers[msgHdr->dwBufferCount].len = dataLen; - msgHdr->dwBufferCount++; -} diff --git a/src/os/src/windows64/w64String.c b/src/os/src/windows64/w64String.c deleted file mode 100644 index 0b392466fa..0000000000 --- a/src/os/src/windows64/w64String.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2019 TAOS Data, Inc. - * - * This program is free software: you can use, redistribute, and/or modify - * it under the terms of the GNU Affero General Public License, version 3 - * or later ("AGPL"), as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#define _DEFAULT_SOURCE -#include "os.h" -#include "taosdef.h" -#include "tglobal.h" -#include "ttimer.h" -#include "tulog.h" -#include "tutil.h" - - -/* - * Get next token from string *stringp, where tokens are possibly-empty - * strings separated by characters from delim. - * - * Writes NULs into the string at *stringp to end tokens. - * delim need not remain constant from call to call. - * On return, *stringp points past the last NUL written (if there might - * be further tokens), or is NULL (if there are definitely no moretokens). - * - * If *stringp is NULL, strsep returns NULL. - */ -char *strsep(char **stringp, const char *delim) { - char *s; - const char *spanp; - int c, sc; - char *tok; - if ((s = *stringp) == NULL) - return (NULL); - for (tok = s;;) { - c = *s++; - spanp = delim; - do { - if ((sc = *spanp++) == c) { - if (c == 0) - s = NULL; - else - s[-1] = 0; - *stringp = s; - return (tok); - } - } while (sc != 0); - } - /* NOTREACHED */ -} - -char *getpass(const char *prefix) { - static char passwd[TSDB_KEY_LEN] = {0}; - - printf("%s", prefix); - scanf("%s", passwd); - - char n = getchar(); - return passwd; -} - -char *strndup(const char *s, size_t n) { - int len = strlen(s); - if (len >= n) { - len = n; - } - - char *r = calloc(len + 1, 1); - memcpy(r, s, len); - r[len] = 0; - return r; -} - -#ifdef _TD_GO_DLL_ -int64_t tsosStr2int64(char *str) { - char *endptr = NULL; - return strtoll(str, &endptr, 10); -} - -uint64_t htonll(uint64_t val) -{ - return (((uint64_t) htonl(val)) << 32) + htonl(val >> 32); -} -#endif \ No newline at end of file diff --git a/src/os/src/windows64/w64Wchar.c b/src/os/src/windows64/w64Wchar.c deleted file mode 100644 index d5930d1de9..0000000000 --- a/src/os/src/windows64/w64Wchar.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2019 TAOS Data, Inc. - * - * This program is free software: you can use, redistribute, and/or modify - * it under the terms of the GNU Affero General Public License, version 3 - * or later ("AGPL"), as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#define _DEFAULT_SOURCE -#include "os.h" -#include "tglobal.h" -#include "tulog.h" - -size_t twcslen(const wchar_t *wcs) { - int *wstr = (int *)wcs; - if (NULL == wstr) { - return 0; - } - - size_t n = 0; - while (1) { - if (0 == *wstr++) { - break; - } - n++; - } - - return n; -} - -int tasoUcs4Compare(void *f1_ucs4, void *f2_ucs4, int bytes) { - for (int i = 0; i < bytes; ++i) { - int32_t f1 = *(int32_t *)((char *)f1_ucs4 + i * 4); - int32_t f2 = *(int32_t *)((char *)f2_ucs4 + i * 4); - - if ((f1 == 0 && f2 != 0) || (f1 != 0 && f2 == 0)) { - return f1 - f2; - } else if (f1 == 0 && f2 == 0) { - return 0; - } - - if (f1 != f2) { - return f1 - f2; - } - } - - return 0; - -#if 0 - int32_t ucs4_max_len = bytes + 4; - char *f1_mbs = calloc(bytes, 1); - char *f2_mbs = calloc(bytes, 1); - if (taosUcs4ToMbs(f1_ucs4, ucs4_max_len, f1_mbs) < 0) { - return -1; - } - if (taosUcs4ToMbs(f2_ucs4, ucs4_max_len, f2_mbs) < 0) { - return -1; - } - int32_t ret = strcmp(f1_mbs, f2_mbs); - free(f1_mbs); - free(f2_mbs); - return ret; -#endif -} From d59ceb7ba2ec997c9e85c0590f61fbbd82813a0a Mon Sep 17 00:00:00 2001 From: slguan Date: Fri, 31 Jul 2020 16:12:55 +0800 Subject: [PATCH 14/56] [TD-992] --- src/os/CMakeLists.txt | 6 +++--- src/os/src/darwin/darwinEnv.c | 1 - src/os/src/darwin/darwinFile.c | 6 ------ src/os/src/darwin/darwinSemphone.c | 7 ------- src/os/src/darwin/darwinSocket.c | 7 ------- src/os/src/darwin/darwinSysInfo.c | 6 +----- src/os/src/darwin/darwinTimer.c | 7 ------- 7 files changed, 4 insertions(+), 36 deletions(-) diff --git a/src/os/CMakeLists.txt b/src/os/CMakeLists.txt index a8664669d0..b4ad4ad915 100644 --- a/src/os/CMakeLists.txt +++ b/src/os/CMakeLists.txt @@ -6,11 +6,11 @@ IF (TD_LINUX_64) ELSEIF (TD_LINUX_32) ADD_SUBDIRECTORY(src/linux32) ELSEIF (TD_DARWIN_64) - ADD_SUBDIRECTORY(src/darwin64) + ADD_SUBDIRECTORY(src/darwin) ELSEIF (TD_WINDOWS_64) - ADD_SUBDIRECTORY(src/windows64) + ADD_SUBDIRECTORY(src/windows) ELSEIF (TD_WINDOWS_32) - ADD_SUBDIRECTORY(src/windows32) + ADD_SUBDIRECTORY(src/windows) ENDIF () ADD_SUBDIRECTORY(src/detail) diff --git a/src/os/src/darwin/darwinEnv.c b/src/os/src/darwin/darwinEnv.c index 71df78c923..7e1031a5af 100644 --- a/src/os/src/darwin/darwinEnv.c +++ b/src/os/src/darwin/darwinEnv.c @@ -16,7 +16,6 @@ #define _DEFAULT_SOURCE #include "os.h" #include "tglobal.h" -#include "tulog.h" void osInit() { strcpy(configDir, "~/TDengine/cfg"); diff --git a/src/os/src/darwin/darwinFile.c b/src/os/src/darwin/darwinFile.c index 113ea7f1fa..66bdb5b939 100644 --- a/src/os/src/darwin/darwinFile.c +++ b/src/os/src/darwin/darwinFile.c @@ -15,13 +15,7 @@ #define _DEFAULT_SOURCE #include "os.h" -#include "os.h" -#include "taosdef.h" -#include "tglobal.h" -#include "tconfig.h" -#include "ttimer.h" #include "tulog.h" -#include "tutil.h" #define _SEND_FILE_STEP_ 1000 diff --git a/src/os/src/darwin/darwinSemphone.c b/src/os/src/darwin/darwinSemphone.c index 71571c8ba5..97ff543789 100644 --- a/src/os/src/darwin/darwinSemphone.c +++ b/src/os/src/darwin/darwinSemphone.c @@ -15,13 +15,6 @@ #define _DEFAULT_SOURCE #include "os.h" -#include "os.h" -#include "taosdef.h" -#include "tglobal.h" -#include "tconfig.h" -#include "ttimer.h" -#include "tulog.h" -#include "tutil.h" int tsem_init(dispatch_semaphore_t *sem, int pshared, unsigned int value) { *sem = dispatch_semaphore_create(value); diff --git a/src/os/src/darwin/darwinSocket.c b/src/os/src/darwin/darwinSocket.c index 32832b9d63..e51f2c4fba 100644 --- a/src/os/src/darwin/darwinSocket.c +++ b/src/os/src/darwin/darwinSocket.c @@ -15,13 +15,6 @@ #define _DEFAULT_SOURCE #include "os.h" -#include "os.h" -#include "taosdef.h" -#include "tglobal.h" -#include "tconfig.h" -#include "ttimer.h" -#include "tulog.h" -#include "tutil.h" int taosSetSockOpt(int socketfd, int level, int optname, void *optval, int optlen) { if (level == SOL_SOCKET && optname == SO_SNDBUF) { diff --git a/src/os/src/darwin/darwinSysInfo.c b/src/os/src/darwin/darwinSysInfo.c index ee2f82b307..108cc6239f 100644 --- a/src/os/src/darwin/darwinSysInfo.c +++ b/src/os/src/darwin/darwinSysInfo.c @@ -15,13 +15,9 @@ #define _DEFAULT_SOURCE #include "os.h" -#include "os.h" -#include "taosdef.h" -#include "tglobal.h" #include "tconfig.h" -#include "ttimer.h" +#include "tglobal.h" #include "tulog.h" -#include "tutil.h" static void taosGetSystemTimezone() { // get and set default timezone diff --git a/src/os/src/darwin/darwinTimer.c b/src/os/src/darwin/darwinTimer.c index 93546088f3..5fe65fb99e 100644 --- a/src/os/src/darwin/darwinTimer.c +++ b/src/os/src/darwin/darwinTimer.c @@ -15,13 +15,6 @@ #define _DEFAULT_SOURCE #include "os.h" -#include "os.h" -#include "taosdef.h" -#include "tglobal.h" -#include "tconfig.h" -#include "ttimer.h" -#include "tulog.h" -#include "tutil.h" int taosInitTimer(void (*callback)(int), int ms) { signal(SIGALRM, callback); From 1a2ba1e01bc2b76bf42b05bd616d298308665a05 Mon Sep 17 00:00:00 2001 From: Jeff Tao Date: Fri, 31 Jul 2020 08:16:39 +0000 Subject: [PATCH 15/56] add new document --- documentation20/webdocs/assets/dnode.png | Bin 0 -> 99250 bytes documentation20/webdocs/assets/modules.png | Bin 0 -> 89009 bytes documentation20/webdocs/assets/vnode.png | Bin 6969 -> 55635 bytes .../webdocs/markdowndocs/administrator-ch.md | 97 +++++++++------- .../webdocs/markdowndocs/taosd-ch.md | 106 ++++++++++++++++++ 5 files changed, 160 insertions(+), 43 deletions(-) create mode 100644 documentation20/webdocs/assets/dnode.png create mode 100644 documentation20/webdocs/assets/modules.png create mode 100644 documentation20/webdocs/markdowndocs/taosd-ch.md diff --git a/documentation20/webdocs/assets/dnode.png b/documentation20/webdocs/assets/dnode.png new file mode 100644 index 0000000000000000000000000000000000000000..cea87dcccba5d2761996e5dde998022d86487eb9 GIT binary patch literal 99250 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

$F}8eD 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
;xU3J2&p2y+Uxo%E`1Ah9P0E?&IHNoc9`Ns^@ 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 z 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

-y@*B(rc-GAEk-HY|} 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 literal 0 HcmV?d00001 diff --git a/documentation20/webdocs/assets/vnode.png b/documentation20/webdocs/assets/vnode.png index 5247717f62118a8e690e80a3538c1a8dd1ab9416..e6148d4907cf9a18bc52251f712d5c685651b7f5 100644 GIT binary patch literal 55635 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

MdQd7u@>x`~DROl+C*zznqX0 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 M%BjlcKQIgWKifJ>iU0rr literal 6969 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 + +taosd的启动入口是dnode模块,dnode然后启动其他模块,包括可选配置的http, monitor模块。taosc或dnode之间交互的消息都是通过rpc模块进行,dnode模块根据接收到的消息类型,将消息分发到vnode或mnode的消息队列,或由dnode模块自己消费。dnode的工作线程(worker)消费消息队列里的消息,交给mnode或vnode进行处理。下面对各个模块做简要说明。 + +## RPC模块 + +该模块负责taosd与taosc, 以及其他数据节点之间的通讯。TDengine没有采取标准的HTTP或gRPC等第三方工具,而是实现了自己的通讯模块RPC。 + +考虑到物联网场景下,数据写入的包一般不大,因此除支持TCP链接之外,RPC还支持UDP链接。当数据包小于15K时,RPC将采用UDP方式进行链接,否则将采用TCP链接。对于查询类的消息,RPC不管包的大小,总是采取TCP链接。对于UDP链接,RPC实现了自己的超时、重传、顺序检查等机制,以保证数据可靠传输。 + +RPC模块还提供数据压缩功能,如果数据包的字节数超过系统配置参数compressMsgSize, RPC在传输中将自动压缩数据,以节省带宽。 + +为保证数据的安全和数据的integrity, RPC模块采用MD5做数字签名,对数据的真实性和完整性进行认证。 + +## DNODE模块 + +该模块是整个taosd的入口,它具体负责如下任务: + +- 系统的初始化,包括 + - 从文件taos.cfg读取系统配置参数,从文件dnodeCfg.json读取数据节点的配置参数; + - 启动RPC模块,并建立起与taosc通讯的server链接,与其他数据节点通讯的server链接; + - 启动并初始化dnode的内部管理, 该模块将扫描该数据节点已有的vnode,并打开它们; + - 初始化可配置的模块,如mnode, http, monitor等。 +- 数据节点的管理,包括 + - 定时的向mnode发送status消息,报告自己的状态; + - 根据mnode的指示,创建、改变、删除vnode; + - 根据mnode的指示,修改自己的配置参数; +- 消息的分发、消费,包括 + - 为每一个vnode和mnode的创建并维护一个读队列、一个写队列; + - 将从taosc或其他数据节点来的消息,根据消息类型,将其直接分发到不同的消息队列,或由自己的管理模块直接消费; + - 维护一个读的线程池,消费读队列的消息,交给vnode或mnode处理。为支持高并发,一个读线程(Worker)可以消费多个队列的消息,一个读队列可以由多个worker消费; + - 维护一个写的线程池,消费写队列的消息,交给vnode或mnode处理。为保证写操作的序列化,一个写队列只能由一个写线程负责,但一个写线程可以负责多个写队列。 + +taosd的消息消费由dnode通过读写线程池进行控制,是系统的中枢。该模块内的结构体图如下: + +
+## VNODE模块 + +vnode是一独立的数据存储查询逻辑单元,但因为一个vnode只能容许一个DB,因此vnode内部没有account, DB, user等概念。为实现更好的模块化、封装以及未来的扩展,它有很多子模块,包括负责存储的TSDB,负责查询的Query, 负责数据复制的sync,负责数据库日志的的wal, 负责连续查询的cq(continuous query), 负责事件触发的流计算的event等模块,这些子模块只与vnode模块发生关系,与其他模块没有任何调用关系。模块图如下: + +
+vnode模块向下,与dnodeVRead,dnodeVWrite发生互动,向上,与子模块发生互动。它主要的功能有: + +- 协调各个子模块的互动。各个子模块之间都不直接调用,都需要通过vnode模块进行; +- 对于来自taosc或mnode的写操作,vnode模块将其分解为写日志(wal), 转发(sync), 本地存储(tsdb)子模块的操作; +- 对于查询操作,分发到query模块进行。 + +一个数据节点里有多个vnode, 因此vnode模块是有多个运行实例的。每个运行实例是完全独立的。 + +vnode与其子模块是通过API直接调用,而不是通过消息队列传递。而且各个子模块只与vnode模块有交互,不与dnode, rpc等模块发生任何直接关联。 + +## MNODE模块 + +mnode是整个系统的大脑,负责整个系统的资源调度,负责meta data的管理与存储。 + +一个运行的系统里,只有一个mnode,但它有多个副本(由系统配置参数numOfMpeers控制)。这些副本分布在不同的dnode里,目的是保证系统的高可靠运行。副本之间的数据复制是采用同步而非异步的方式,以确保数据的一致性,确保数据不会丢失。这些副本会自动选举一个Master,其他副本是slave。所有数据更新类的操作,都只能在master上进行,而查询类的可以在slave节点上进行。代码实现上,同步模块与vnode共享,但mnode被分配一个特殊的vgroup ID: 1,而且quorum大于1。整个集群系统是由多个dnode组成的,运行的mnode的副本数不可能超过dnode的个数,但不会超过配置的副本数。如果某个mnode副本宕机一段时间,只要超过半数的mnode副本仍在运行,运行的mnode会自动根据整个系统的资源情况,在其他dnode里再启动一个mnode, 以保证运行的副本数。 + +各个dnode通过信息交换,保存有mnode各个副本的End Point列表,并向其中的master节点定时(间隔由系统配置参数statusInterval控制)发送status消息,消息体里包含该dnode的CPU、内存、剩余存储空间、vnode个数,以及各个vnode的状态(存储空间、原始数据大小、记录条数、角色等)。这样mnode就了解整个系统的资源情况,如果用户创建新的表,就可以决定需要在哪个dnode创建;如果增加或删除dnode, 或者监测到某dnode数据过热、或离线太长,就可以决定需要挪动那些vnode,以实现负载均衡。 + +mnode里还负责account, user, DB, stable, table, vgroup, dnode的创建、删除与更新。mnode不仅把这些entity的meta data保存在内存,还做持久化存储。但为节省内存,各个表的标签值不保存在mnode(保存在vnode),而且子表不维护自己的schema, 而是与stable共享。为减小mnode的查询压力,taosc会缓存table、stable的schema。对于查询类的操作,各个slave mnode也可以提供,以减轻master压力。 + +## TSDB模块 +TSDB模块是VNODE中的负责快速高并发地存储和读取属于该VNODE的表的元数据及采集的时序数据的引擎。除此之外,TSDB还提供了表结构的修改、表标签值的修改等功能。TSDB提供API供VNODE和Query等模块调用。TSDB中存储了两类数据,1:元数据信息;2:时序数据 + +### 元数据信息 +TSDB中存储的元数据包含属于其所在的VNODE中表的类型,schema的定义等。对于超级表和超级表下的子表而言,又包含了tag的schema定义以及子表的tag值等。对于元数据信息而言,TSDB就相当于一个全内存的KV型数据库,属于该VNODE的表对象全部在内存中,方便快速查询表的信息。除此之外,TSDB还对其中的子表,按照tag的第一列取值做了全内存的索引,大大加快了对于标签的过滤查询。TSDB中的元数据的最新状态在落盘时,会以追加(append-only)的形式,写入到meta文件中。meta文件只进行追加操作,即便是元数据的删除,也会以一条记录的形式写入到文件末尾。TSDB也提供了对于元数据的修改操作,如表schema的修改,tag schema的修改以及tag值的修改等。 + +### 时序数据 +每个TSDB在创建时,都会事先分配一定量的内存缓冲区,且内存缓冲区的大小可配可修改。表采集的时序数据,在写入TSDB时,首先以追加的方式写入到分配的内存缓冲区中,同时建立基于时间戳的内存索引,方便快速查询。当内存缓冲区的数据积累到一定的程度时(达到内存缓冲区总大小的1/3),则会触发落盘操作,将缓冲区中的数据持久化到硬盘文件上。时序数据在内存缓冲区中是以行(row)的形式存储的。 + +而时序数据在写入到TSDB的数据文件时,是以列(column)的形式存储的。TSDB中的数据文件包含多个数据文件组,每个数据文件组中又包含.head、.data和.last三个文件,如(v2f1801.head、v2f1801.data、v2f1801.last)数据文件组。TSDB中的数据文件组是按照时间跨度进行分片的,默认是10天一个文件组,且可通过配置文件及建库选项进行配置。分片的数据文件组又按照编号递增排列,方便快速定位某一时间段的时序数据,高效定位数据文件组。时序数据在TSDB的数据文件中是以块的形式进行列式存储的,每个块中只包含一张表的数据,且数据在一个块中是按照时间顺序递增排列的。在一个数据文件组中,.head文件负责存储数据块的索引及统计信息,如每个块的位置,压缩算法,时间戳范围等。存储在.head文件中一张表的索引信息是按照数据块中存储的数据的时间递增排列的,方便进行折半查找等工作。.head和.last文件是存储真实数据块的文件,若数据块中的数据累计到一定程度,则会写入.data文件中,否则,会写入.last文件中,等待下次落盘时合并数据写入.data文件中,从而大大减少文件中块的个数,避免数据的过度碎片化。 + +## Query模块 +该模块负责整体系统的查询处理。客户端调用该该模块进行SQL语法解析,并将查询或写入请求发送到vnode,同时负责针对超级表的查询进行二阶段的聚合操作。在Vnode端,该模块调用TSDB模块读取系统中存储的数据进行查询处理。Query模块还定义了系统能够支持的全部查询函数,查询函数的实现机制与查询框架无耦合,可以在不修改查询流程的情况下动态增加查询函数。详细的设计请参见《TDengine 2.0查询模块设计》。 + +## SYNC模块 +该模块实现数据的多副本复制,包括vnode与mnode的数据复制,支持异步和同步两种复制方式,以满足meta data与时序数据不同复制的需求。因为它为mnode与vnode共享,系统为mnode副本预留了一个特殊的vgroup ID:1。因此vnode的ID是从2开始的。 + +每个vnode/mnode模块实例会有一对应的sync模块实例,他们是一一对应的。详细设计请见《TDengine 2.0 数据复制模块设计》 + +## WAL模块 +该模块负责将新插入的数据写入write ahead log(WAL), 为vnode, mnode共享。以保证服务器crash或其他故障,能从WAL中恢复数据。 + +每个vnode/mnode模块实例会有一对应的wal模块实例,是完全一一对应的。WAL的落盘操作由两个参数walLevel, fsync控制。看具体场景,如果要100%保证数据不会丢失,需要将walLevel配置为2,fsync设置为0,每条数据插入请求,都会实时落盘后,才会给应用确认 + +## HTTP模块 +该模块负责处理系统对外的RESTful接口,可以通过配置,由dnode启动或停止。 + +该模块将接收到的RESTful请求,做了各种合法性检查后,将其变成标准的SQL语句,通过taosc的异步接口,将请求发往整个系统中的任一dnode。收到处理后的结果后,再翻译成HTTP协议,返回给应用。 + +如果HTTP模块启动,就意味着启动了一个taosc的实例。任一一个dnode都可以启动该模块,以实现对RESTful请求的分布式处理。 + +## Monitor模块 +该模块负责检测一个dnode的运行状态,可以通过配置,由dnode启动或停止。原则上,每个dnode都应该启动一个monitor实例。 + +Monitor采集TDengine里的关键操作,比如创建、删除、更新账号、表、库等,而且周期性的收集CPU、内存、网络等资源的使用情况(采集周期由系统配置参数monitorInterval控制)。获得这些数据后,monitor模块将采集的数据写入系统的日志库(DB名字由系统配置参数monitorDbName控制)。 + +Monitor模块使用taosc来将采集的数据写入系统,因此每个monitor实例,都有一个taosc运行实例。 + From 9d6896cc168ac3fa757b272d5fcac835b073ebaf Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Fri, 31 Jul 2020 08:17:20 +0000 Subject: [PATCH 16/56] [TD-992] --- src/os/src/alpine/alpineEnv.c | 1 - src/os/src/detail/osDir.c | 2 -- src/os/src/detail/osFile.c | 1 - src/os/src/detail/osString.c | 1 - src/os/src/detail/osSysinfo.c | 2 -- src/os/src/detail/osTime.c | 6 ++---- src/os/src/detail/osTimer.c | 2 -- src/os/src/linux64/linuxEnv.c | 1 - 8 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/os/src/alpine/alpineEnv.c b/src/os/src/alpine/alpineEnv.c index 0a9d81311a..4f84412075 100644 --- a/src/os/src/alpine/alpineEnv.c +++ b/src/os/src/alpine/alpineEnv.c @@ -16,7 +16,6 @@ #define _DEFAULT_SOURCE #include "os.h" #include "tglobal.h" -#include "tulog.h" void osInit() { strcpy(configDir, "/etc/taos"); diff --git a/src/os/src/detail/osDir.c b/src/os/src/detail/osDir.c index c8d63f621e..9496b74405 100644 --- a/src/os/src/detail/osDir.c +++ b/src/os/src/detail/osDir.c @@ -17,7 +17,6 @@ #include "os.h" #include "tglobal.h" #include "tulog.h" -#include "osSysinfo.h" #ifndef TAOS_OS_FUNC_DIR @@ -65,5 +64,4 @@ void taosMvDir(char* destDir, char *srcDir) { uInfo("shell cmd:%s is executed", shellCmd); } - #endif \ No newline at end of file diff --git a/src/os/src/detail/osFile.c b/src/os/src/detail/osFile.c index ad6be83e41..516b7bb19e 100644 --- a/src/os/src/detail/osFile.c +++ b/src/os/src/detail/osFile.c @@ -15,7 +15,6 @@ #define _DEFAULT_SOURCE #include "os.h" -#include "osRand.h" #ifndef TAOS_OS_FUNC_FILE_GETTMPFILEPATH void taosGetTmpfilePath(const char *fileNamePrefix, char *dstPath) { diff --git a/src/os/src/detail/osString.c b/src/os/src/detail/osString.c index b4b8c9a294..31ffd6b87c 100644 --- a/src/os/src/detail/osString.c +++ b/src/os/src/detail/osString.c @@ -16,7 +16,6 @@ #define _DEFAULT_SOURCE #include "os.h" #include "tglobal.h" -#include "taosdef.h" #ifndef TAOS_OS_FUNC_STRING_STR2INT64 int64_t tsosStr2int64(char *str) { diff --git a/src/os/src/detail/osSysinfo.c b/src/os/src/detail/osSysinfo.c index 06000be81e..a03199e8d1 100644 --- a/src/os/src/detail/osSysinfo.c +++ b/src/os/src/detail/osSysinfo.c @@ -18,8 +18,6 @@ #include "tconfig.h" #include "tglobal.h" #include "tulog.h" -#include "tsystem.h" -#include "taosdef.h" #ifndef TAOS_OS_FUNC_SYSINFO diff --git a/src/os/src/detail/osTime.c b/src/os/src/detail/osTime.c index 28c13165fa..6d41692d80 100644 --- a/src/os/src/detail/osTime.c +++ b/src/os/src/detail/osTime.c @@ -17,12 +17,10 @@ #define _XOPEN_SOURCE #define _DEFAULT_SOURCE -#include -#include -#include - +#include "os.h" #include "taosdef.h" #include "tutil.h" + /* * mktime64 - Converts date to seconds. * Converts Gregorian date to seconds since 1970-01-01 00:00:00. diff --git a/src/os/src/detail/osTimer.c b/src/os/src/detail/osTimer.c index c425d1732e..22f7b94c3a 100644 --- a/src/os/src/detail/osTimer.c +++ b/src/os/src/detail/osTimer.c @@ -15,8 +15,6 @@ #define _DEFAULT_SOURCE #include "os.h" -#include "taosdef.h" -#include "tglobal.h" #include "ttimer.h" #include "tulog.h" diff --git a/src/os/src/linux64/linuxEnv.c b/src/os/src/linux64/linuxEnv.c index 0a9d81311a..4f84412075 100644 --- a/src/os/src/linux64/linuxEnv.c +++ b/src/os/src/linux64/linuxEnv.c @@ -16,7 +16,6 @@ #define _DEFAULT_SOURCE #include "os.h" #include "tglobal.h" -#include "tulog.h" void osInit() { strcpy(configDir, "/etc/taos"); From 938ff1237108992dd3c3016fbd10699fc626e922 Mon Sep 17 00:00:00 2001 From: Ping Xiao Date: Fri, 31 Jul 2020 16:24:21 +0800 Subject: [PATCH 17/56] TD-1036: remove unused dependency --- src/connector/jdbc/pom.xml | 34 ++-------------------------------- 1 file changed, 2 insertions(+), 32 deletions(-) diff --git a/src/connector/jdbc/pom.xml b/src/connector/jdbc/pom.xml index 2f0c3c78e7..da0c5b12d4 100755 --- a/src/connector/jdbc/pom.xml +++ b/src/connector/jdbc/pom.xml @@ -52,12 +52,7 @@ org.apache.commons commons-lang3 ${commons-lang3.version} - - - org.jacoco - jacoco-maven-plugin - 0.8.3 - + junit junit @@ -105,32 +100,7 @@ true - - - org.jacoco - jacoco-maven-plugin - 0.8.3 - - - com/**/* - - - - - pre-test - - prepare-agent - - - - post-test - test - - report - - - - + From e30127a4febbae6086f26c7eabfa6725ba65c08f Mon Sep 17 00:00:00 2001 From: Xiaxin Li <48907085+Aries-Lee1991@users.noreply.github.com> Date: Fri, 31 Jul 2020 16:39:21 +0800 Subject: [PATCH 18/56] Add files via upload --- .../webdocs/markdowndocs/cluster-ch.md | 142 ++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 documentation20/webdocs/markdowndocs/cluster-ch.md diff --git a/documentation20/webdocs/markdowndocs/cluster-ch.md b/documentation20/webdocs/markdowndocs/cluster-ch.md new file mode 100644 index 0000000000..43b35dbc66 --- /dev/null +++ b/documentation20/webdocs/markdowndocs/cluster-ch.md @@ -0,0 +1,142 @@ +#集群安装、管理 + +多个taosd的运行实例可以组成一个集群,以保证TDengine的高可靠运行,并提供水平扩展能力。要了解TDengine 2.0的集群管理,需要对集群的基本概念有所了解,请看TDengine 2.0整体架构一章。 + +集群的每个节点是由End Point来唯一标识的,End Point是由FQDN(Fully Qualified Domain Name)外加Port组成,比如 h1.taosdata.com:6030。一般FQDN就是服务器的hostname,可通过Linux命令“hostname"获取。端口是这个节点对外服务的端口号,缺省是6030,但可以通过taos.cfg里配置参数serverPort进行修改。 + +TDengine的集群管理极其简单,除添加和删除节点需要人工干预之外,其他全部是自动完成,最大程度的降低了运维的工作量。本章对集群管理的操作做详细的描述。 + +##安装、创建第一个节点 + +集群是由一个一个dnode组成的,是从一个dnode的创建开始的。创建第一个节点很简单,就按照["立即开始“](https://www.taosdata.com/cn/getting-started/)一章的方法进行安装、启动即可。 + +启动后,请执行taos, 启动taos shell,从shell里执行命令"show dnodes;",如下所示: + ``` +Welcome to the TDengine shell from Linux, Client Version:2.0.0.0 +Copyright (c) 2017 by TAOS Data, Inc. All rights reserved. + +taos> show dnodes; + id | end_point | vnodes | cores | status | role | create_time | +===================================================================================== + 1 | h1.taos.com:6030 | 0 | 2 | ready | any | 2020-07-31 03:49:29.202 | +Query OK, 1 row(s) in set (0.006385s) + +taos> + ``` +上述命令里,可以看到这个刚启动的这个节点的End Point是:h1.taos.com:6030 + +## 安装、创建后续节点 + +将新的节点添加到现有集群,具体有以下几步: + +1. 按照["立即开始“](https://www.taosdata.com/cn/getting-started/)一章的方法进行安装,但不要启动taosd + +2. 如果是使用涛思数据的官方安装包进行安装,在安装结束时,会询问集群的End Port, 输入第一个节点的End Point即可。如果是源码安装,请编辑配置文件taos.cfg(缺省是在/etc/taos/目录),增加一行: + + ``` + firstEp h1.taos.com:6030 + ``` + + 请注意将示例的“h1.taos.com:6030" 替换为你自己第一个节点的End Point + +3. 按照["立即开始“](https://www.taosdata.com/cn/getting-started/)一章的方法启动taosd + +4. 在Linux shell里执行命令"hostname"找出本机的FQDN, 假设为h2.taos.com。如果无法找到,可以查看taosd日志文件taosdlog.0里前面几行日志(一般在/var/log/taos目录),fqdn以及port都会打印出来。 + +5. 在第一个节点,使用CLI程序taos, 登录进TDengine系统, 使用命令: + + ``` + CREATE DNODE "h2.taos.com:6030"; + ``` + + 将新节点的End Point添加进集群的EP列表。**"fqdn:port"需要用双引号引起来**,否则出错。请注意将示例的“h2.taos.com:6030" 替换为你自己第一个节点的End Point + +6. 使用命令 + + ``` + SHOW DNODES; + ``` + + 查看新节点是否被成功加入。 + +按照上述步骤可以源源不断的将新的节点加入到集群。 + +**提示:** + +- firstEp, secondEp这两个参数仅仅在该节点第一次加入集群时有作用,加入集群后,该节点会保存最新的mnode的End Point列表,不再依赖这两个参数。 +- 两个没有配置first, second参数的dnode启动后,会独立运行起来。这个时候,无法将其中一个节点加入到另外一个节点,形成集群。**无法将两个独立的集群合并成为新的集群**。 + +##节点管理 + +###添加节点 +执行CLI程序taos, 使用root账号登录进系统, 执行: +``` +CREATE DNODE "fqdn:port"; +``` +将新节点的End Point添加进集群的EP列表。**"fqdn:port"需要用双引号引起来**,否则出错。一个节点对外服务的fqdn和port可以通过配置文件taos.cfg进行配置,缺省是自动获取。 + +###删除节点 +执行CLI程序taos, 使用root账号登录进TDengine系统,执行: +``` +DROP DNODE "fqdn:port"; +``` +其中fqdn是被删除的节点的FQDN,port是其对外服务器的端口号 + +###查看节点 +执行CLI程序taos,使用root账号登录进TDengine系统,执行: +``` +SHOW DNODES; +``` +它将列出集群中所有的dnode,每个dnode的fqdn:port, 状态(ready, offline等),vnode数目,还未使用的vnode数目等信息。在添加或删除一个节点后,可以使用该命令查看。 + +###查看虚拟节点组 + +为充分利用多核技术,并提供scalability,数据需要分片处理。因此TDengine会将一个DB的数据切分成多份,存放在多个vnode里。这些vnode可能分布在多个dnode里,这样就实现了水平扩展。一个vnode仅仅属于一个DB,但一个DB可以有多个vnode。vnode的是mnode根据当前系统资源的情况,自动进行分配的,无需任何人工干预。 + +执行CLI程序taos,使用root账号登录进TDengine系统,执行: +``` +SHOW VGROUPS; +``` +##高可用性 +TDengine通过多副本的机制来提供系统的高可用性。副本数是与DB关联的,一个集群里可以有多个DB,根据运营的需求,每个DB可以配置不同的副本数。创建数据库时,通过参数replica 指定副本数(缺省为1)。如果副本数为1,系统的可靠性无法保证,只要数据所在的节点宕机,就将无法提供服务。集群的节点数必须大于等于副本数,否则创建表时将返回错误“more dnodes are needed"。比如下面的命令将创建副本数为3的数据库demo: +``` +CREATE DATABASE demo replica 3; +``` +一个DB里的数据会被切片分到多个vnode group,vnode group里的vnode数目就是DB的副本数,同一个vnode group里各vnode的数据是完全一致的。为保证高可用性,vnode group里的vnode一定要分布在不同的dnode里(实际部署时,需要在不同的物理机上),只要一个vgroup里超过半数的vnode处于工作状态,这个vgroup就能正常的对外服务。 + +一个dnode里可能有多个DB的数据,因此一个dnode离线时,可能会影响到多个DB。如果一个vnode group里的一半或一半以上的vnode不工作,那么该vnode group就无法对外服务,无法插入或读取数据,这样会影响到它所属的DB的一部分表的d读写操作。 + +因为vnode的引入,无法简单的给出结论:“集群中过半dnode工作,集群就应该工作”。但是对于简单的情形,很好下结论。比如副本数为3,只有三个dnode,那如果仅有一个节点不工作,整个集群还是可以正常工作的,但如果有两个节点不工作,那整个集群就无法正常工作了。 + +##Mnode的高可用 +TDengine集群是由mnode (taosd的一个模块,逻辑节点) 负责管理的,为保证mnode的高可用,可以配置多个mnode副本,副本数由系统配置参数numOfMnodes决定,有效范围为1-3。为保证元数据的强一致性,mnode副本之间是通过同步的方式进行数据复制的。 + +一个集群有多个dnode, 但一个dnode至多运行一个mnode实例。多个dnode情况下,哪个dnode可以作为mnode呢?这是完全由系统根据整个系统资源情况,自动指定的。用户可通过CLI程序taos,在TDengine的console里,执行如下命令: +``` +SHOW MNODES; +``` +来查看mnode列表,该列表将列出mnode所处的dnode的End Point和角色(master, slave, unsynced 或offline)。 +当集群中第一个节点启动时,该节点一定会运行一个mnode实例,否则该dnode无法正常工作,因为一个系统是必须有至少一个mnode的。如果numOfMnodes配置为2,启动第二个dnode时,该dnode也将运行一个mnode实例。 + +为保证mnode服务的高可用性,numOfMnodes必须设置为2或更大。因为mnode保存的元数据必须是强一致的,如果numOfMnodes大于2,复制参数quorum自动设为2,也就是说,至少要保证有两个副本写入数据成功,才通知客户端应用写入成功。 + +##负载均衡 + +有三种情况,将触发负载均衡,而且都无需人工干预。 + +- 当一个新节点添加进集群时,系统将自动触发负载均衡,一些节点上的数据将被自动转移到新节点上,无需任何人工干预。 +- 当一个节点从集群中移除时,系统将自动把该节点上的数据转移到其他节点,无需任何人工干预。 +- 如果一个节点过热(数据量过大),系统将自动进行负载均衡,将该节点的一些vnode自动挪到其他节点。 + +当上述三种情况发生时,系统将启动一各个节点的负载计算,从而决定如何挪动。 + +##节点离线处理 +如果一个节点离线,TDengine集群将自动检测到。有如下两种情况: +- 改节点离线超过一定时间(taos.cfg里配置参数offlineThreshold控制时长),系统将自动把该节点删除,产生系统报警信息,触发负载均衡流程。如果该被删除的节点重现上线时,它将无法加入集群,需要系统管理员重新将其添加进集群才会开始工作。 +- 离线后,在offlineThreshold的时长内重新上线,系统将自动启动数据恢复流程,等数据完全恢复后,该节点将开始正常工作。 + +##Arbitrator的使用 + +如果副本数为偶数,当一个vnode group里一半vnode不工作时,是无法从中选出master的。同理,一半mnode不工作时,是无法选出mnode的master的,因为存在“split brain”问题。为解决这个问题,TDengine引入了arbitrator的概念。Arbitrator模拟一个vnode或mnode在工作,但只简单的负责网络连接,不处理任何数据插入或访问。只要包含arbitrator在内,超过半数的vnode或mnode工作,那么该vnode group或mnode组就可以正常的提供数据插入或查询服务。比如对于副本数为2的情形,如果一个节点A离线,但另外一个节点B正常,而且能连接到arbitrator, 那么节点B就能正常工作。 + +TDengine安装包里带有一个执行程序tarbitrator, 找任何一台Linux服务器运行它即可。该程序对系统资源几乎没有要求,只需要保证有网络连接即可。该应用的命令行参数`-p`可以指定其对外服务的端口号,缺省是6030。配置每个taosd实例时,可以在配置文件taos.cfg里将参数arbitrator设置为arbitrator的End Point。如果该参数配置了,当副本数为偶数数,系统将自动连接配置的arbitrator。 From 8cb9101509fae3f228236d2415239f46da9915a6 Mon Sep 17 00:00:00 2001 From: Yiqing Liu Date: Fri, 31 Jul 2020 16:45:29 +0800 Subject: [PATCH 19/56] Update taosd-ch.md change format --- documentation20/webdocs/markdowndocs/taosd-ch.md | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation20/webdocs/markdowndocs/taosd-ch.md b/documentation20/webdocs/markdowndocs/taosd-ch.md index 20f717c512..4af1dd0fc4 100644 --- a/documentation20/webdocs/markdowndocs/taosd-ch.md +++ b/documentation20/webdocs/markdowndocs/taosd-ch.md @@ -41,6 +41,7 @@ RPC模块还提供数据压缩功能,如果数据包的字节数超过系统 taosd的消息消费由dnode通过读写线程池进行控制,是系统的中枢。该模块内的结构体图如下:
+ ## VNODE模块 vnode是一独立的数据存储查询逻辑单元,但因为一个vnode只能容许一个DB,因此vnode内部没有account, DB, user等概念。为实现更好的模块化、封装以及未来的扩展,它有很多子模块,包括负责存储的TSDB,负责查询的Query, 负责数据复制的sync,负责数据库日志的的wal, 负责连续查询的cq(continuous query), 负责事件触发的流计算的event等模块,这些子模块只与vnode模块发生关系,与其他模块没有任何调用关系。模块图如下: From 56a9ce306ae8c2bd5778015bf9740808b2379f3f Mon Sep 17 00:00:00 2001 From: Jeff Tao Date: Fri, 31 Jul 2020 08:58:55 +0000 Subject: [PATCH 20/56] one more document --- .../webdocs/assets/replica-forward.jpg | Bin 0 -> 66595 bytes .../webdocs/assets/replica-master.png | Bin 0 -> 117209 bytes .../webdocs/assets/replica-restore.jpg | Bin 0 -> 173227 bytes .../webdocs/markdowndocs/replica-ch.md | 253 ++++++++++++++++++ 4 files changed, 253 insertions(+) create mode 100644 documentation20/webdocs/assets/replica-forward.jpg create mode 100644 documentation20/webdocs/assets/replica-master.png create mode 100644 documentation20/webdocs/assets/replica-restore.jpg create mode 100644 documentation20/webdocs/markdowndocs/replica-ch.md diff --git a/documentation20/webdocs/assets/replica-forward.jpg b/documentation20/webdocs/assets/replica-forward.jpg new file mode 100644 index 0000000000000000000000000000000000000000..00b8c357b9ca2f067127c7dfae37b386b268f8dd GIT binary patch literal 66595 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 literal 0 HcmV?d00001 diff --git a/documentation20/webdocs/assets/replica-master.png b/documentation20/webdocs/assets/replica-master.png new file mode 100644 index 0000000000000000000000000000000000000000..cb33f1ce98661563693215d8fc73b003235c7668 GIT binary patch literal 117209 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�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 z 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

D36-OEaLG5`e@@A>GiH)7^@3 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 literal 0 HcmV?d00001 diff --git a/documentation20/webdocs/assets/replica-restore.jpg b/documentation20/webdocs/assets/replica-restore.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6da1bed4cc90b8a119b2fddf5f66ef3ab1b0a2fd GIT binary patch literal 173227 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�f#aJIFZ1dP zuNJg0FsblHhoak+9WVG^=tBYsjn0MJS*U#R{g+ED|3!}mnDJsQMhqoP*lO`;84#sL zXmlQkld>p@IT(Ho8Ean=ysA34mk|e_`gnqbYSXyO9JWZ`;%H=m@?5LOz}8jrO*_sE zRiyl|!q#H9DzDz%96#`%($hL4RZD8BovOQtgnskYym27d1r{mg0VzKYU2q_`)qFa-b(!)-XHngY zl5D?rfS7Bu2$;a(dzR@t&Ns{zusIFbFirCXcnveNZzxMBjmhvTqs`oS6S!KRHT~$T z#-9!&9-EEFy`;JpE{QfvGY?SsxyIFn9#`~Q^blrWCT7|XHS>j~%ib)nU)=hZ>V@+s#@(F+RzCV7qL* z_nM?KcEM);hFdz67G@FsvEG{AZ6l=vPGsR(U=rp8@on&rompZiX7lE9D-VFQM+LvYo-@aK^gY6F6lMq8-3usfUDr1>9il$wRpK87!0#rlu}`+@ zET|Wly$9}L0YkK(I~^B0Gj{KGnQUmnmls+;!Ibrt?T*BS{ue^_-wCVYXxv9W^IA5t z*x%{^k96I|uYNpA<^`jXDE0KAn#obYq{ExECmSv8x82?s{cuzTlu?)hpL)-w^uhk79lIF6gx`2Xuq)=9( z-X7-_XvwRdHf>73vx;7Dujj&1(NKP-7`kGAV%tqiR#Rv@cJSU&uayM>ZYxDLVH(jJ zowP56n8rD1zmWg4T<^5|oe@`Vk4x=&dfANJT{C3G^ALpbx%4u++EM?onj^0Pld_%` zejRT;+dkCZW*c55WNiXej>~?x!jy&uh^F@+Yyu1i4SdEHTDPWZvkiDx(B|E1(NA`E z*V=48_uij>qvM<1s5fTXCkO_>a9@`RuG)-Dw{QW$5aQvC>nxPq@vDE2ejm=$9;uwL zAPW*e`UbfAaVmv4X*cSInGOo5VD#Yh=m{_y6c%UZi|G8C7%GsVKcw(5`6unm9q;n@ss6q`{MC|l94}$_M$0 z*40ws!JmoXCQdUsOJG7&$1I5x@bt0{Ait!2_%G7_OJA(>^RA$ElPRMsnCxJpGrXrOJ4k+{X2L?_2;QGsYtfRSWPA|s z)%#p**$`Wk4GLxOano(px+1*Ih9}J9*%;vfs zarA9;{YoL7KNYL7!$vtkvHOzZ`NPxb+B+2LF!SYukn)=-=$9m2Q>ePN>+*&Qz2_Ta zj2|6vF^+xqnfErp`lmK1$}9%f%mDi$h7_$tHGco4+7LU4j~7h8*b5S1oC+71KifX3 zIC_-MvteGAT~}m+MzV&{5n%cvUmAjz^m#SxzA{pnF;$mOpqVep=_uz8?dJRUawS*U z`;$W!OuzP#Rh7_>2hde8*V&G3*ma3{OVoq^mVK8SDFVLZF!f8^+9ue<$bv(ASyAiM#z!7u)9rWriV=RA|XUA+*&S(gBU(Ve%B>m8T zv`3UmC7OtA5|$8A{IOG9dVS<5e0?G4r;9^_=u^-jfV1X5c6vw*>}2q|2d1*r95WFb zFF6T^OYUbH|EWs*H|_K@BnEe72J4*uZDvc+-LqtC2W<&sgJgBpy8Drki?1u(!7vit zVSbM|0!lS*2Laj>T^?xf*sAe$v3$FM2Xkhf29qWJ z_Vis-#nWGNrbz5OVB!Ggo)J1=^S^<6XcM-Scp+#PDLxIb*A{vg4bve+nQv_Jg;lN2 z(FWR~t@TJt3q%%_=n*+O;3vqJ;?g}7-UO-@yu;ZcvGe@D;F^VI) zmVeK4MPtGC-`X;ok~vw*yVNzG?Yl&IsQ2|H>*rVLALOBA;bCmJvS513~_sdpzc4Ga`@KWy`&$v65M9UXN&f?&_>qzepFl@fi?w3C=>W`BmMOS7G*TF$4t8 zozNDvrEZ)S3D2Z>r}?iQI6Lp-o5mdNUdJFeO?3P2_C1?cpOzdyY8dRk;7vzyAvoTG z{Se)tf>jou8}G2(Eo3Y9mUOw(p`oAIQBM+f8ORA@ zD@|~hN30;U63RMF@g|hf1?wHi`MS?@HEir&s}vNzZCUZzxC!QEX0|~E30)SB&7F8Z zVY)h*Q^~KXpkFt%VPEm3Xw{7^Fz7g`@N^+JU%&wQ=iwe)f4c5kCW)*^sc5m4<) zZU+z(ZD5#&424n@@7kjIs3ZI59dCmuiX)OJdfh9ui~rgF8?H=DoA`}TKYq$=fBGnl z&lW?%6G-t6DhQv8x0#z#D_ObpsEg{tnlST4^@nP3MWIn-XV;;7H#<_1&XslcnT&eb zf9h~Qzl$i6BW0WuL-WRvTlc&# zkM;bZW@p!82Y!5Lolax^)F}3Ez^H#R}7n19nlbGMU zpD~O@x5Uu*%l!|A&m-W^S%+$I$#L?tyUZJf3kM=5EcE5R25Y~t-SJl&_fOcNe+H6{ z{$=2;JFJ>+?`e?eh37KA_n2##h_)K_h|cQOCk{Kg@Kxz;R-8Uj$awM85&KlD&YWl1 zhCph{0eqzaA6L$%SEBoxET4c*4~hTbOOk+0=vBiffmJBEn^hy4 z$)7gqu2dP|lz+GLq2=C$iGV;x14y=2G#)Y&g0)9CKR0&H@0~PTZCykeCx)F_Mj_L!1f8B=lnLjx~QOr;B+dFItF=d>dxioq}TT*#mmNKwPU z(;tvIF_&Ro*k(%-4L$q|v8OdD}rcF8`v zJ=Zqf3AngfFDcq+Ilr_bVWTJyakm-f+LDU%R?tfrlAXb0j+->xM!t!-iB-0xX{Q)1 z-cd|~3!2U=EhEnP&X@mrH%@TJ=lE30BlKO)ky|$l+_L1q*-HuKsO8i7>~TVC?p9H3 zk^G9!ajUQPnL3eQc|<)+zT|g*pZVzHc52iXB0$|$nWyM6EQo4EZJYuJ0N^kaT;nxA zwc?>KN%knYMET5ow;ItHzI@@-Lm=LX2l-61mO5MD1$ifP#k> zWgD>8N6`3^sjvu@gnOW+VzBLzrj?`I>H8*ca}R84v)XagV0R()=H<7OIg38{r( zqOa1uG)%EnAcfw0f`0_2c1S2BQx+D~4pEm-_BHqAWHo2p6+N%$=^6Ps_auK*Pm;W> z61eMR@USq71$gzT66&If?9g(&P-skX4<>V5=@FNL?^LMC8QT_k?ZTy6B=B+S*a?H5 zb|c8Sz0y6YLseY^SO6a>PEZ9X)KxzQCh@HD`BuPe;tjLy&Z(ttPr1U;9Rv4I5cG~P z6$?~^pq{)2WmTHz8> z;V}8tK{kCBd>jb{W5v)}Mg;sOHEf(~?L8OUQ#Uj;90wL38CdYCTIKT(reV z42fPbtd|SM80*n6klx-w6lkKYIm4pYp!BOa1%D{XnoxZ4eGy3rR)lRoN2z3R`0?R%DwU!_<0>$mRcOIt^sVPRo z7jlJFszOMl>TgqahvWV`2<=~aZ#FRK;lh+K5XHkC>m_>0ip=lbMT>!HGy#yoS5LkA zO@xYq`Ytl|2ri{h@tVZYn4H5{Q7J#e1DlKIJ=ljnU;?{dhY&e7N7ScX<-hXyf9GDs zogBL;g>TKJ3Hm^f?qX)5n^c8Xe`}J=kGSUR-0g zr0{m|69q(#S96UijjLg&M2|c%eLh_L#8Mk`Y07{?MMV9?zH!_jZ*r=+wQKp-te0)$Z||tyI+0%QuXZVtmfC-=N7+aAKyT){ zroKnCwn}z$K!F{A24`i8p$~VNye8%>G1SM107&(fCU|mw;ey|4rkG8%RY=X+$>uLU z9OgX{c#m+RaT6{LfYDM1iW;c>6#gqd-yL91hPgaaL!JkKp=p}+1L509-%YH4 zgoKR{AFrmEj4+uvL>*AZd@ulGwiMU!lyBQnj!}wfNVD6SRCr)bN z0fa9!V76<31K!0)N?b11eTyMy@YJ!??2n+SC7l ztvUVpAEQ6QqaUaj{~`yH6OYA^wGy2Gd# z%BE}%a(>*^>}6g*CkP*OJ9TNIg5$*gs7PFQs-V4VnJ!+(Qh$*eSzKR1iBrtx5@kdBNN{W zXXS>qH|fyu-8PQkWPT$xg@mS!HTIj|-KW)|oD-4u&!pD>%sn9e{>vG3^|Yz4(hn)t zAaD#veZ-JcUJV|Z%dlN66+kN+p4>nJLGE}daOSmpn*pzK)2Ea07Zvof@@aha4hldn zhxh+yxM$I!t{=c0y6?l=_TDAs*>hx|q^nRT=38?-^&@j+#|!3=-ZL=-{+JuiTk!)F zrLY5mmMvdcw;$(R3SDmn_8AX*s{1@fYPEE-^8Wu5p8zEhjlU4-ea4ppfIsXG>O~Ss z=75mkW`;+-<4Hlm8DxKZ!cdAMy&2_Vz}j|pr= zBtQ!BiCp1yW2{X0^nNIi&_gT#EGTA%iQV{cg%(-8Cu+~Bl^ zzUUUreu+za5(J6w_(1Bg<$*P29>SYYQJwo?GVqGQzp+Z?x{aN^}6lOyP??sAQpb!V|{xu*6}OQR15*d6u! zOzPFs`C_TGy`nb%I|J23xVa!hvgB8CTlpZT=v*m^b>+{BLik_4G*{Bw%+2P|2`2(v zcR9bYtZ7r)FtPE#d-HuU8C!@s%J$O2T@=SyHgRaYn;CO!z$T4(wP5Kp50B%+uZ{-a zZ`*~v5OicMWXzgAC?us*G~F37llm6qfQh?!722ykab*t;AWGMEd4IGFTJVxMgnNDC zL^C@p`Fo|Cvh91BTsbgsyrBpJT|rsIN)^%laRZg3)URz9Uzc+jgigaw$8Xn9tZje4 zhEg|T{p|LJ!K)5LDTMu+m0cMIpQX>hKM;9#q!usoH520e9qGJ2at>dXTx|5oWxl=o zp7}0C>pz*WTqn=9Lc~NBm9l3uZ4HZNtnS5hmOs?*c3*+q+ka^aD{o@5-+>c=qzYs) zX4%AaCZSpy4E}x&TvF)OXUVs^ae}XW=*|!OH3&mEQ){JdV()CpOm&h}$X96=J*$Rm z0*WCSyqG85%+`r6BSys7V=bq5wMKG-+O8I1ILn(Zp|tFARpEs#mDR;Y{rAvDz$ax< zE>#i#0M0$IZm`}UoJ#M@+xXO zk#~rGgDlVVXop)21@fZ12fmr8DZ5JQf{W8Wws zIG*{N=xKqg&>AT|$8={zuojp@Kj?&Ulq%!cg3{i%b$kd|njn{ceu>hO(u(eT=Zobl zh6}e48Ds@>UCam_F4RDK=-a zpMrM!Apqaa^x?zYC=RoA#2}nHhc^-9>v6b1^$9Dd>W5lHoOYsO{%Dc?>H4q1dPSmG zkR&FPdHWajr3XV+W$GsvBkK@F4k+O9Y z!G?KD=bi3U4mm&A-Um|O)u4qoNRYyx7^)YVQ7(vXQ5T;%WIlt>ipaKgYA$Ok(h{!t z-2Af!G$04KEZ8KsT5fDIaIZ91?aj}I93Cjtd!xF3m84d(U{e-aEj)~WQ0k{E7ua;$ zaTpSq)>q2T*gGDv>vR`9bgP)_^5qnpZ9(sPiLfg%6{aAL=f^$9rnQ3Og=>YXTX`=> zyQpJ4!u4!#rPYaU=P#w-aW|L#`Mr|Tb=e&Bv*vl!m@l9<5GAPVF)Kd3gcQnD;`-7Q zvCR#)ODi0X6|74i@SBrgvhkwCYxwO>Ml^DojIQ$Iss;$1(0svmAgTV;GJE2J960RF zfI-=2r|z<~haHc6`X;)+3^RK$G5FO!1}V-5HNhNGo2H;gl!+U8u;g<{vz^eZmG}Kr zixxH^-F>zXwxv1Wx$;4`#j86RqW*^Vb>|ivgihTJv?^nOsvvK?VW3FwSWubqn+qT4 zoicjQoQDrL(Q}wX8PC2|I;T+UiG-J{-R@e*7ig?`?RV?r`@K)k-VTx-HE8$2WuAa@ zlP%=4=rf@OWmX+#!*F*Zz6~keU&ty_KHvr&j~Snw22S^jF2lz&KwsCBZc_X9Zoi?4 zB#%xlo^&*3=bL)QG^(h-e$T^%HiN>i$_JGtguD21-Hc-7+6f}+NL+v!aA?^G@Lkug z0wSqy^)lpBc36gXvbOW(bJ_u5?Vq%#Ql%-}xrsRwDA7yeYub>3P=TU` z68U|&O#5?pTppb?iMhC7{bH@+qGhMvHYPrVDX-fr`p&U>qRV`G*G#5Qc$Z}Tuy<0c z_sU5s|9*dNPTi~GBeJV;^ZYc)FQ7HF9eGW!@D4X$hQ8xXbia%^&!NejsUJvK(d>OP zXp^V$&-r%C_kFyOrYd#U?dRif^PFfLx>7%N?boxIJ;(Dx&4GHO*)s*EG4u$615_Wb;pX^Px(4Pl>new)fLF(zotVg?Cs>ZY5NuZ> zj=$c>+3UM0=;UQWQ>0#R4QS`$M)B(fz35UO;Wq4mDBjClt>59zb1vIP-ddDg)Ucj0 z>E>tVs`{y;HFzTp!eR1`$SC@2UB8APRniu919DAHxn0ThHNMO1`H zjnoLCD2PaJLJA5}A_+n`kmUGnoI7*p&NEM$`_BEo_kF+T_Zua%&Dor@&faUU@?ZaT zTIh}%Q@6^b7)}9vNh}Dl_7S!KI8hbA1{Qgt8G!QRek1&PiuwNJJj1EF=>D|7rV4(+ zyq^f7`}3iFV4puk?Sz4^wUN%G2>m*+Q}?VMtKqAG+{oxPM5W~byJ!QTpdT{>U3~=V zHXxjoH8OXv4Za689`(^dY%H=>fB3sM7T4!GbT?pXp5-;P`|$)qoy_=ZO`H}nIjprR zkKaD}bDBN_SePc|b5bDH)AZJAD8oftbH*cG_)O$Z*NGWMOKwu3vD9ivsLwho zs_m9E8plodgM9NdyX~(j6zes|CYQIY)S%0?sX|KuNu@c+SVYpb`+GpD=mazP zDi(0Yh&Xp5YhgB*T%9WQqWtBg2S(49rEI6WC1Wg4h1tH#@x_~mOIstGTZ$^wYXVPK zRxpL;14!K$*`&_NcMjVu4t)qSK4=)CyWHkqtJdmNKH&Nl*Q1Uc@dR-=hcy5kW12-i znt18hTJXy6P(R)pq4JiuQ>RJ;2T1(#3aioc0GAePW`ASkuo2N6Q?Ydzb`w20WqyHL zHrM*wgtBPCui3C|^;Y}1hIQ#oGA$;EB?|kQcPJq11t#~9~gyIW{=^-3!E7K)^m37=?<0rHU=$q7igUW<3}+4g1mh(0>0I z;WMT6$ z*RTu{IUA-NhRp_Hfge}7mi(~ay4Sgw*DM>-X`G;?t{QMGHMDnGC`BG$0(k)=fD!|M zK-Au5o-;hlXjX9UwU6T%)=`w+Q8MY(pQfe#&g_u2T`U(CPmi2SKg{X6CD6^SM02K7 z5+Cq~Y)#L{daDeJT)bAWZIn0Rm+_(Z6*1tU53bgYi$WyTf&Zo>1Xe#I4qMO#5(H|A z>`cHyWC9m~#B_ws+g?=Yc)7ZtpU>cCPhV-j!X0&|qkdv$Y|d0XqBbNtv;4>iCDWZP+A>QDmxq4%YLt3$nWky&wOw}Do6}@iM|5zex_ODe8_Sq&${n-j zsuXr!vL~ogx!CXtGPB)q6Cc0!QP@Wx#;y9sdOfR&rj*don_g?;Z=T4Awm%)Q@RoPS z%ZXDC9BfEV(XB4F0G*l1k4>81wtmGo5xRfVf{R2`n8u5Tfyuil5Nzi!1RR{ncW8!~ zq+8G`MBy{nA5#~VX=mTt*X+1No_&63gKs|)S#wSDZQfnlg&kC2-xYS=-~*q=6LLlM zqN)r;xr@V?Y%j(kH0L%pe5$^XbfVz)s6^}3Ay|ENsI6yUX!8?%cM6_1r&6JGnCzU8 z`0Tc#{AfSkWlf#8x#8mx-vVJ;pIOM>B?t9KBrLm^`VP1CUMs+o&yR-?q)8;O1^jaz7o%5x#O8Q#JnYOPKwW}Ki)Pq2IY4$Rh24A4##T zckWc5MxS+7^4b}X60M77=%b0pk=MbR{W-oKeD&(bdVwAz`>jd0NgNw=G)V-M%u(~} ztEhcryvtmL$Z{_Z#PqA>qHEm9i~H~+bD=Tmz0XW9i|oiKx!JtbZt?b}ce_py-z1?0 z%AdH6ymHtI{R-V123*HlT)4K<>vn?r<56(Xhm##zoh0ZLC48H0mlwQ$fW-6HJobkU zv=mN^d#D{MDlQO>IXwT688^e*;Ytb_xk))U@&r_sNm2=FZ2Cl`_Bmc zgh^CSbO@GXM25F`v2mO}-b`sHVT%J7Q=128zanl4UOYOfe+8xP)HArKm}F+MwF_RducGwy1JUy47f9 zCXa^&L{4`*C)p#IbidOp=TnQ^B4ij326B zLUk=R?lnH1mX&PU>Iv9#G0EuA1nv zrFGhGGgBJy2UtyQ-q3(?xI%*3OTQhvE|eU*SXp*%xz5$v_3?*$vkkW+pMau~CcfKT zkH~x#Qaa)S;6ySsVn+tG$@XD<`V)h%8$+aJjq3nYShe5!SCpW< z<1a8lv3tMZ1Q%TV4iq#3klSUWTXJ4rE{(g6u1ylz@J+;$7*gH^GH4HQH0<2)a}b2y zYLz~`CHCl7uLv5p5J%HX?QKTxZ1gxBL|2<#)d?FoWnq5tZ_XrZ{7>Oj7ybsbD$(4J zJqiq7k-K~?|NW#nF*W37#|Uob$Q;P)yk3no8OUI#7vqGI*#L_$4_$gg9Y}8r6P5kz zb7C&&B6UE^Y_jhJ$cR~jV3~A1GfPMWbsHx3Nhy%jS5y=#FN9@_YBS>F$w(KDhW^XWW}iH0~L zNoE4K0lN~q2=zv>&JrccVbh%6MowD|aa|B!J$V1&p#x8B->5aqMy@#g1($qn|7)*? ziEH$NiE&3Ku$eX%0D~c93{M%3BCO;a_V|0-w_go^ZlGCeXXnc6O&Pb8zk%B&kJn#E z!Nna|Q2ur>N%$iS03u>o;VrDQP?d!nr||WN?~^dM30C6O8bP)d^U-#Me!mJjWrsqyYE~UNqe4L;(wX4?#2o6Q7alqW$+&HH-agY0Y73topYi|y~YeghpN}5 zq2+2Hj~tncscrg@XIra&SheoSMCIN!CTHbANrXl)#K0hnIMzm zc6Yt0Zsb_YwuqOIv_sc=DyZ>h#Gs4C$W;eWX-rKqSxOdx1l8c@6sx_b8_#qn#Jk0-kGjRR~3@%+K)8c z={s_L@RGzTF{!w?{b&>sfKoVi6zK&7Y5>xp6$Z*MjX6wTX7()K0Y)(~>;Mjl5v{Tp&V!tu z`MV8nig?y$$|NdVN>5>1-2UVe#O2IpCWFg6y@ zm#gs_IAj`(?18H46cFrtC$4AmQ-2HEoiQba-iz&&CzJz=P6{7wnB}d0vZd^Sx7|z) z{We_!x`>8#RR-(Oh2k|$%2i1^;n0Pb?u8XjHKjjU`g)&@v9#6>$d5n0C*+uBz&>NH zln4Xz0zoi)QQ=D}g8_w+L;!6Qeho~i9*}H@F8XV|nTkTmH)iTr%=G!J(7E?P?4HLd zhX*Ot@viq&AR32QSZ!h)_?3&QKtA3pYYb4Too2{5(qaQx@N)riW@bErYp|j>U{$!J zl}CRpq3b&GVLk}j#wP&5HWC-Yc>Y0u1B^TjmI%)-%7Ri<)N%2;rlMDoTIA`3fkVFL z%BtdvE4mP=E&N5qM*It4t~l}Ta@5A3avG84IlF8)X46AiUc#q7{ul2%Y+lNbSba_0 zok3_{z`}D*+^<~I%%LEXPklJInokvSYU^u(3vK$acP!DsVsQy#L{-(@q5?+Z^|Wr z4R)i>YLnoN**c)_i=)3`RwYRgb4f*!b32cLhBb!S#vlv90_=5EdtuTvNe(|!N)6L; z3O4BNtLgQ-^F;P6{?XY-vj=Z2Vmp47dx(0^7DuE^Ibn#D7!d0;+%ZVLsRV@+v{-0y zf9P}@!HS7l(IZSe{oX5K;OvI*jOpIKGb+B6V^&~8R)OFvBV7ep03igZ3S{TRsBYv~ zCEp5`y2N^I1?st!^Q9MGc7A!dA|bBwhqC-2=4De**3<|%SF1?Z&_%$!ZVrJcQzSIO zcn~X9=KoE^+BSO&lTvcK0n(sYKZ!}X>vs%rf*7;jy66a$BsoWQ4sRaV+#26ex|1Y( zeBU>bvi)dp*c4g1Lr5wjMH?*VkfZ0RV501o!9iTmUY9Na=2XZR*p}HmpX*%I34_A^YN9wtGs`hkpkMjkV?x35 zj_FOq=T%;+vtA;~MDN$+G%Dj$j=EVJ#7M?3$!OcA!BFz6MM(>55ff)Y}>_T#u&qVaC6ZJ?0+lskJu=TGO0B zTm@B~C8`s=g*k$CX>K-k_ZhJw+F6)Bw*9A-SI?=bvK4kZMzcp=1b>L+GaT~+M)O8jV*T@!yrH~wjPiH#JtL-1}%>fW?WOpd^qla^NLfL;%aRh^^Q%Cmpt^}LCLJKnHBtP@qOYbsDh<4P zuykeI_*+4AzX28nHk~wjo`pt>Jf026YSkGi!M1G>Jne_??!^ihg1`?|-I%8x`%Ps3 zOYB5L3;&^zTMbNk8>E3cb)^z$=IZMDpJ`$KW>&kd-(2{gH&RIaj3r!}hg0X1g{#S+ z^V5sG@5DEMGpUu&Z?1wIfx$Z^eFG8Xpi5Eo)fj;mb({?DS!4d5-N8KrU@bV3slwG1 zFlXNUoE`nYz3Mkl^yS9PcR_gZ)qx-y{pSUt{Iei_H|akUge}qlZtKdxyd>&=k%ZTG z`M&u+tuzYR_s=8&ZaYi3I`JCBdGP|=b|DGiuJe-s`q=~)=Ws)T^i^^v_{zrLL>`_+ z&wO%5>RNzoynsQ-4>e?btGc|m|R@m&xQ&6fB(`Tny- zQ9lkI9V`m;_l3+x&u=4R--FE+Mhx`?)0&I}quM5E6ICaJTy8@ztwsc*8 zT368joT~WWTW2o#MG^n~6@i|(t?>P{!1{sn1NHOyk@(B`acBPg@C7GIS!T=b8*QfZ zdKSae1Pg!v>v_c=cpiZn_3X=hbxH%ZkTk!W^1*J3596-nl?orM<7gIay3RL-*OA*y zO5CsoaAo7$uZPSEE^c_|-CAKc6}%ystqs(yyX6bw2LFTl-mh#rV>3qNn|%T@K2*6r z4=>B`zqj_yjB969I@_@+FXc48ho3dnJPx#!7zGYxl&s^_v(=aYePgnFY9F?Es_@8! zBW^;MkknDe7AtwiInaIQnDVyg8VS3bdknbs0|vuMbL9wmN&9nZ0joVHr*aK7Cssl8w#zEK z>=gCwj06C#KB;JC9w$c|ME@54{6FyOcd1(im<`N+O^?P%9CrkqyiN8>RF2;`sHNZI zuU=JZpS?WlR6b`oOoP3GD^X>A(^>CB?8MN^U^F7B1^k0b&X;WYl1KCY4{=Ek-L@hB zfR7u8Zf2r-x#fn$74^^VIx}LcyuL_@3?k|Raaf((%&e%dqDPaY2v`;*b#`|BAT4kx zUasju>anN|){*-yK3=u7H!v@^GJNdZYZW$S>mf?xE$i;-dG(`pZ*TRAef}-JY3rAW zoltOINM=%BZl=xGwtiHoqITmDsYF12coc*;unUN_R51hn&v;pbwWIc%DBPJy!NJbb zw9KyMeFGVJ#Z%Fq)tdqm4x*Y~1n&h8@&j;t9N|9R3Sn}&AEUWfzg!*46_|5@(;A^? z$iyt^+xJ;l&reUrpm*;znN{|vhQ-=hO$C?vVKTz1Bav2Lazy;m*C0j$m2(_*6C|F0 zfO9xqJZ0GWk^k*?OwVmvF}tedPc*r0cMprW36%mTe8mr47X1B44bb}-wu8^(QFLMb zcn5>Jra65t(pbVZ4$GO?Q1s@_nSnza59nL%A)f+|dh!;+c(`;u9dzGV?!vXF4Q5h+ z@{lneT!W!CJ{lR=Y^Jgta(jI1qI_I4<;p?n;$^D|O}5zOAm}5`8V=FI+#<;m6f@x) zw4{!wMIBT67ppWqyw-WaJ?gSt0tAN ze#if@V?ndy|COQ32=k%DC%Y#!vK%0aaD7e^-CY4(am-vSl8Cd9!+h|XaeGHS-%sVF zO{J$&O6P}dX~F^f?CG6uGmY=3Vz*!;0(QGAUoPNgwVY83&n`~*YhXuzgxmUMY(Z{C z{osKZUqSom=7sB{V(7K@Zrmecu#i(_^{A`^I4PmoZRh#an1I+?^ehHAJkZ!z;5oJ~ z&T$sthG!K|!zV{tX0pEL5#rM3!}g2+OvS{1=evi2EYq!$iS^V;Hv~kp^RDy(dxLC} zoDN{CO;ksaOI%gP(A0&`wFCH+R?eV692BxBLW+UA+7dyj_RpZMzmJ{zb5dV`{*q)g z3tFZmgNV~9;X}RVL4`(c7&D4gI*)M?>NErH?=zqY7S+kCCt+x!I$`dve|k;lyOUGF zie2(wQ2nVElaEmi`v(})2RbWogUe*NLCjmwXUB3tG~!X~fPhf-i>&c6zJ+x;X+`wULj+*R653gP_bQdSS`kk*4X~_vZ>tGU31hrLNH$isw%$<&7Z3W%TJ_cQs)cvke?ZzG z6hh+M?*`TR4YN@^5R40P@aOXm33Fp>OtJDk@QvzS&N`NPcDeyNm&yv=qc#w-gPSYE zR2uP@a&oe@nO+J)uH6Syi;b!JdKJWpcnJ4)xWVCG-Ho}%&f!#u=16?=P(UvnrcDU8 zjYBXSBhc0v2Zp2ZJ`Nu&vwdh}pM7|7Ck?S{LuS**UqH>WfEd|rnCjO(UE(^UH-RXx zer-F!#WRIw zhe$KE=<^g%>gNLRPbc}6Rjwf4Bl?cY%)_3i&h4EDqr=wouMD{IzaN>x|L5cXDv^Gk z^l4DD>;n$Gi21BeOEUokudCmIki=~eEcn~Ot~B8_ie&I*ys=x6s8FD~zW#7Grwdm^>Et^Obxo-|`t!ulp`O z7isR*e)`DOa;Et1S$a`L$AhsASJe8PK5pNj!?eGzky56rZj0$hJ_QVq|FnanW(s0R zji0`WAPLPjxw!0x{;tuZ=DgAIsn@`B2gEg2J6`@PMZ`aUM^$^EU8K_BbZv$2=9)H$6mFA<&Up!eb(g;t@Tu@p*G4#XSpgczy1 z#8}q4!5HbPW$yl*?z%6;rWbIGZ8>;{V%cH$RuVl zLA`=4V%l6ypF=vJsgR>nJ&WhZ91+v{YH;YC)ByIaS!-uE6#H?W_LWZ4*CJZ>fg<;> zg!a*z7I$E?ivCYAV*WDk`s7D*N}$orS2U-QxS$!50@%mTndBphUvyfsfsIQefyQMM z)SK=oWdG5hONr~gmlA&hWyB{c#9RLXgyzqNkhV|-r@vdb^8uOjX9Z_rJJOt@m%=xZ zEs3W`k}Zv9%dGAToMwsY0*w1K_jDJML{@KeoUrXgWU#pQ22x$kyj2wK;p#h)?70Qt z>H*282B4g~K4Jul$p6p#3F?&>`M=g00&xbA1&Bgr>Oe(wfD3b<9#Q?0^c9+~JJ7!S zO$4t)pR?8XLNQDM3xOA?D9HeI-jRQzp5*7QiC>aL1X#F_Z;#YMdG&(TE?iPQo+5u& zt}ARBdn53|tps%Sim`p3NXw#7!IQxsv%a+Al2w2w*8~c)q@wtH{U2j{l50T+1R7p^ zz~8hExZJ^j2(z9mPQ&G!IjP;PH1SYP-SgH$WGv#xAgf@$E@2f+$pA5^dg|)RUH&(i z3gI3C$9revQhl;ZO=vBs?U4cF9HJSqtFG_WZG8@C+Z#dT!i>*(Fc zJac(<^D;LcQALyMLVzUC5hmBM?jxBg_;V} zllLST!o=}U@iW2gb_XJ+*!ICpJiIkbAlt^9z@tHdQ(j^nwr7T!MT5lsZ_faD!7bv3 zw{5Ni+xTj8Z!)1B#HQ6G&9|Ge+6EpOUAg{#46E7{LuBbjIFYM<0(N3ado3Qr790b> z>8Okr&6Q?%M##5+Fujv%acsex{XO-2$Tz4L(LK9(z{C!@0#)Pr7|^j2VuYht7;GCY zw%=ayl4D$p3L`DS*H|X;?yD17YCb81ry}+%HwfNJ*p*yDbwTik2{sq>yjU-c66o_y zN9`4E72+4hcFPUN4I{+JLGpMLqyF9zLt!RaKG&IhDcuOMlH@pET;Mee7!h-&9l%nBB(%Ot!84!ZAn@P%60 zkDEo`5>&z4TL_-H8|j9M73!%y#yqVSWX0zsEJ)odS3JNk6Sz6;+n7^ayQ4>9egDwA z`n#&pi`YrbN;PBv0KvTa1`!E5cj9PA>@~s`?n7cDUH6WP_# z#j})&;oE`j_(JTs4F5O*#3Mr%2xK_MKzg?lflGtP^*N`iQaDBh?wx*C=DnsvCeDtD z4ki+-)vwR8N@79Rre-0T3Kl^AyZI_=E)4Jyi)uleW|BPoj@Qt|LPZ*EfOi!3qYhkG zG^@!w`x=5s_i_(8tr0yTJ_h)w^qevYhdA0%T+#i$ZfpEZDb#$Yu}@|zUf&<-$@VP4 z-hfa!$O;gtqgFSXlz#+4=;u=%DHbYDaZ<)*6uT0{r}JOp0bS%V18|(UDEy>dr99Ma zWdQ;eK=*wg#Yd4Q?F{6gZm0Rt)3t7faBK@=q*W<48hAcM>-}&~q!M=zsvD=R2w2 z|J*UE=x5%tU&WD|jT}v^uJf8x_JpQ7g62uLzhYuYlcx;i0LR~_%ilyEC(q53aZFRg z&|@H-5fdeVLN(L?Uu)6zdBOc<{mTB%Tnm&JKC7?n1?Si{5Yh^3g~oWzx0r>8ky8oun`~2`v z??M&E#p@J@Ihg~MMMHQ_2VENb8T9x80R~JsG`kqUQ3{wip-AOgi20a{0)25ii4Ej) z6`7jPr`Tg-M$^;eonRB?!oV=wj}6DdF6D-RnQk{kvmyXv@gcefE!aJ<4g~v@z;!?H z3d>THD}tSW`DIeTbQ1sm+W?4gc5y81IuQy@iOzRpx|Ljm72Gh+&+gXG(Hwp}-!y=n z6Obs-@~fuKEf5?4ZiN{OjT`_pdSy(!Py|^E4z-_ev1R-j59MZBGE&yn88bF!e*rv= z9fyougO)*@HvcfdP&04!{LM`VZLPS`+xjKYb9y>GaIWkAA3Ow>nOzCi!g~}8g(!I~ z11%F}RQ~;3fBe2gqrLyM=&d)?1DqRFvhBeU|EJ#BMT_^X7i^Wwtdjoax8@LJW7m94 z*bjO|{L712KiCo`?pK9=k&NrXQFqT#KAI?UpLynzVpiARuoxuTu%%b!rRWilE`H?jJO-d+V0EnQ>yY(8-R+Xq;=Nh#yPgx@LL7@SOfPlNiH4Pco0;s+yDVv$ zi`=Z2tquu8?*`wteOdonL~$)Gf0)QwJgm9!4%NgW)cfcviNO*tN%h&BeJVP$>;WQJ&fM+VmM+C@C$!?|55w zjr9Y@W|haefW3ga6Z&m>XKA zn|NDNF;Ru}h)ZUB@VA13vuy*Ca2WrXzbI|4qtc)ybBwqvudpQSQo}@~wPCLDvB=r3 zqu?gMp;?6?C=8Mo3Cv+EUtjHdxhX@&x9@a|Rq$)y9;YpZk0%_oN5Y zpAJ!V${om1)%qzCtm(%N$1<{?GR0f(PvPOiUA4gat#1}4I}OclT6B&adu;Uy@d;E| z`QbTOZwixQJZ_fba12TzB+)XK#FNawgu0KX8+N#s2M?JdQ$ zf~^=g(JP!@!aB_RUcGKbw>D=5oV%^2vEkqW-la;XcSav3bMO#&06oZ!x`x`gHp#@Q^COToL}FjDdK*uizZ`ABP@idO>H_89!xo-I;eF-6!D9wao&#Y~Ixl>_uvbwo+D@kDaz#^Q|PjV4HS95jV4t zyDfR*1R>#*;iX*k7+^#qtw8n)6yO~)MO}56C`5ttz$&`Y4HHpr==HB$yN1muvIbQrZx!PvHJxxkHu|Kvub!0PCvd}EV=4;V zVK#;@GX{G0;uiQ@RofUnBHLkWF-u)-TKip;0zHDcCf<_~s(h+eun&J7Y=}sBGt1E7 z^PM0piVl{pzH*j8__pvm> zvldeqLoW0PND=`#=PGgH3ja0+Xf~Zjz`Xw?%$Rzzo|6@pYwzZK-tL%cg9`3`l<;#>$P?q;eWrOCwmO5}v68wrtVUwW+@yGr1cRW-jW*d(ijblihE| z6&C$KkOtRP5IgZG$Q_V|*J3#q6WwKIuwAymgz}TXfa@1Zu+%bBKar~C6l861tOh>o z+27^$=9bKUblPr<1Lp>Q;XX-={KHy;m{N4QRT8m|KIw{|X3T$lO|O11tdXk@e2?2R z;L(2yHmcYj+-C2@ZSoZu!{*r0Kma>9)*B!A1OIVxwqUd1?IZ3E`Y-J7XZ~CL9{&un z&ir?mzou@P$GjZPCP=jIXln*Rlh%^#){IeN{16pHYJT)kMJh4SRIY0;=+pE}cx(eT zFxF%;5k9$vP#~-ojDY(ED6E;0GXqAQhTn%igPv^)UqQz->m}bmr8imUBOiZ)xCOl zW(mpWD-?~Lv@uwTp1TiF6jRN?_8H!K#PtuHkEef(^tEd9tQT*;)SfYFq<+7m+05)^ zb+pBI(pRg5z<<~?!pN>MQt$%klQ!6K5H}7Sc(FzB8t``t?7&I1Rk5?H<;Xtd8AFg79r7zS03;%ks9kjSe6 zT=j%y!XF7cxC$)4NPmT+CTVU{% z(amakzL7KNa>=dtr^Q>&mlWhP4OnIkSHA}IURX~(f(0D~DOuHC@D`o%wk)I_zo>i% zOJDUsJNb);#<;-BX^BE4=f%>#ACgY>`du=yp0~c|{>(D9$3&)@wfzb_CZpa)q+{f%>*NzE_!>3wF z-)=d@2E|LmLx;&v5G`r4vv4^H!_!y zp62hcJ7$;Ji-@?;=gY)_A-MZw@k}?-{^qAAqLaytSWp?k1C7hfVRW_cCQY>i^PUX%*5UoLph$O$$9%g-M0En>UXcs0Ussw-)^ ze~|6_N@@R1)gGD?RteRk?5TU_LysN2dOEG{1R>M#5^YX3NnD@;OOD0tMXoO zNi^~rxOz0m)Gp|dSN^D_$I5RaIfdoXt5;Bc5211R78!_VExb=$NI-KDGN_ch!a;{% z0OtxM!|u9SzV5=~ifZYABgSt2?@MpIYqM`p=;S^#dhzfSKZ^22xD~9B{pfeKQ&*sx zz4*llZnmTkm7G6pX)_Jr`P*=>CT`Gycf$b9E`%?ro=+-OM@S3xtT}*zu$)Vw2~AHH zAyw^!qsls6|Kf4X{j17cl*WHy@G*8f7$TM+@b3eI97PCx3_>SQ|;*zx8x+ zsKx8%aNA#bC76vzc@8n(`hM zTOIx;z>KW}IMR>6j-b2h(pb>B`lMCH8|29_A6N=`Sptx1;^`x35I3DWEO!>Vh2Wo} z;P9zhERB8qF`14&>T|#WBwyzVqyLxx906_BTR}YDflHU>DloyudpZe@fCkM>`+Mno zRXTe#mpNi+8*1_fJOu%JWcbF+hgQSHORe=yHt z9l(SQ7}_0?ZJT211(fe5)>!L*kY>luuC>`Ro%;2g$kE}PM*_*f|LB``Pd7I6Kbp_| zzj2cy*8*EWcA{?839|rF-A*jihp@2^w93|g1X3Dqb5jF$!D9`?y;>h3IYizhtLDz} z%FXS1;h*B-6oHVnR&VjK?9G^VUmd6tpSvb#0%VO&r#uXNF>9+~S{|tM6%Ct0ZsXn@ z4D-!5k_XP;1F77TKpXw-*f@QP)=M5yN&bGzr#$DU011qZ)FPm* zmH}o6`051crEYBe2SfkAe`fO?GLs3Qw*W}$Xb8z5O>~n0VnwtpAom7c>>rHjCnNWQ zP777rcBN7q66aT0_FL*7eD5D#>xZ5|H{1;h?79y^Q2$;e|K1qC)e!%8D1(XC@)o0U(gr{&f`Kq|kXHWb>aS1yrsSTxT<9PuTL*;fiJ`dy zufgVJ2Qo+G_bKs^5nio?lY}&hsd!K!Yxb>B5^y z5m*;nYIk$JJhBHiW5nz;4c0{$+q(>4%gU3M^TJ=ekxe=!HM}qIwR*bv&AE4)De3|< zOnLqC$WzXx3EguAhM+qFD|kI1ut@rpG9BM;%bsx0wLEh1_}ko@w^SHi;(R4fkl8&9 zpT&uSE*eq5jM;8ANF8_Nl6bE<3b!3N^zp2K=c6m%Y%S^v`=Qt^dGGbU!~|9T%lf9b z^mX;z>-Zc{(xKlRt%-G<2s8I@Je*e$uc!Rj_avD>HsYhc_p(2f3!zso1W0 zR+vTCxWm`I%GDWtG5G2^&w{~yCVjOE-29tu>vkC4%ed4Ow)Q$DOKXxUP{^vKt}Yh^ zzJR+hvivlEw_tq%mmc%Ht0pGRA7tQcqs+oiB>E)2o>@W2yDTuO=wqp|0Ukn3mrDgb zpAWb~#n^G%Ou-7I9>zaC>yNkQbk#}+pJTCx-w>YgHI){o522DoAa)+O#$1>U=&f+w zWCn??c$vS;g}8)Es)0!nP%0ziyoDa%W$xIGdtM< zz;UIh7x+>HA2@}Zbr9acXcj%31BV@e6(7@0p7}?ar}Qk>w12bYscQtKZyRmGW34DJ z1;@X7=SZB<`8bX&p$Q)caSXkp=_|^y{9wTmVNxY(6sw|V$k+V8 z9*#!sG}g%QQwWznXt+aEII#1%EgJ=IBeSo&@RtG~YY(zfaFri;;Hiwv6csfQTzNtG z+Bxk+F!7=T!WIcI9tRI5#)B33o>0~PawondVD|A%Pj6%n`s?YlvU40Zh1D!>;hmLW zEhEPlg5;=iQ}Ap_@ennMBrk9l-lU#`dH_At9$_Z-BE6ULYG4EWlv7sYf~l3k7l$`H)dd%kM6V+C%+yik3H#jKydfr8n(k`(Bi^V^ zK4F#O`y`g~)e0 zOUL+`2_~yCjRQt=UClFS;K`zZ&c(_)s7*AAfkpeL6uH^% zs|{`LbGUO%))%e5dG#C*n~dg|fS0uj5C;J+B`vTO(t+x(?RR2y(a535irBN<#*xzO zk-3@J9ham>-dg%$_j?vSZC>DYA@q#Twe~~k)lOxmU0Zo>?qpu@7Uze5&}aOA>o2M18V~AJVQy(&s=y;nzI$YvHoYZ_?;hN1k+|D$)5+-cixVcwV3g{oL3;jn-q`+jV#gn?Dx#_okJ?2 zz&?nN{+@tA^KgYH!8_SudH2Dn#g)5dB|oiG@;-UHKJ#`+!jD&Fi{k!7?ZrQa)0ty& zbqR5EM9_y9i>7|`hfm;yvLMXXruo!9sRDEcZXD!-x@S7m0_r%7opb6?Z&RSQ7K1M9 z|DR-Hup;w(pTHlLM;%hh`F`ScWikaG;LPIo29`3S$1DKGq%go$B>)g6B=J1!>vy>q7R?iOxHh}yf?qG{a;*{(Kp%|#kxDOpL!oNSU@Glrr z^{j6MbD28;k^<2|s1Juo&TzwcF(AAghcsb}(KiUDOg>&lpnTWLYelzfqQ%DP;okCC z4Ug76Hahh`_0ZQ7wIh;Iq|mrR^D4Zz*PlrW^m5 zwr}ggfa)DQ@`+xkbc=TE>=1UVh~OOzPRK!! zfpzVkm@l0TEad>F0I{<0CDCyF<;vZ2kzXKBz@p#94t+xWprimO^bpBxZdg^ILQRy{ z5?~kaW6`Ar#>J(<$~8)teEmBH+IFfwz4&=C(SoYpOjkA*d_~7&nqtbFMThX+H$dqJgV=@T9Bu9f$JdX-`vMmZ2Fz6e(WpyD4K{FuwW;@WT?VA`i<9a;M%Qj_lwE&_ z_UvO;Q%pBGP7iF?MW=-oMP2|^?%$=ii+|W(^^h!fyvPD@qwD=Tf$^1%AN@w&ub z*f^t0+B_H3HCmcWXJme7qo}4!LLm0J&8rS2COBRwtgO@{Yz)=2VC*BIV5?VjncZXU zt>a%l8R3gRoc&PexhkdaXw2B{8%6$R!0}k7Fh~Y?%yZ~#HyD&!oTR@6Xq+zNrQ|%I zlV4J*Wcdh{)VwjiCS<|xAAkI?BT98>RV|Us#`ep4fIkava5(;KflLM}Vk|Q&Jn{HV zH@CE76E3_QYWZZ+VauMf$EVG%%6|BTmc!?-T=DaB9sGi96)|~vT;J_2Q44x=Zk}o0 zF=Ya|S9Emh&0_cxXpN|S9aKzvGf|Y=Ak9j9)>%lzQYUw1b5c{#fj;YlTTHFxi$QSq zdg#AcCG}@Bz`uN7ZW;qmCL<-3NwR@37Qy%EFk^*x*~;HUjyUALR%T% zM9u>{YSmLtd!WClF~}FMayu-*+`o%pUQe9|MKW;)pEI8~{Z&EBMNp|T_z!T)7y@Qu zk*}y;k>NVDv~3$}70~3C8R~7ajE_KZzE}SyB8Q_b20P#uY0kY}z17WyuzdD@n>~L+ zTBQ2Q{b~OIRhAYhDVihl-{CX({WVr)E0ldD_I6)VpH$_g!9bgf{XguzcUV*Hwl4~T zq99_Ss3=hZK@p?UL`qadP(F-UK&3+EOmea~~B?;nwnWWMu##~kH1#`ukuoTf^5&1IH5 zr>meVD@0NQ>xIYm#xq9-7qD<2A@!pNXfViOQLvn+py!OoM*x#MaoN z!yOEuP~+7cKws&3!SM9u+l$8Q>A(oGWn&o~+MRxN6L@-0+JVZKCGp5KUfYf~f&e@=* z{|U1kwDIf@uev-V8Ry;O(>VAzbWLVq+b@w-5N8Mnz~H3VzkjJ*gXFJ2m)WFL@9^2a zYv><*G3p;&%f@)dYtqaxU<>cmL=$jV?`82m{t|hP=KKU#15hpKguD6=Uv+OOp34AN z9O#nBOTO(#7N}y1B!p`gH_QtSU|9oc^BW=N4q+~4I8vYw zEc0Uspd4Tx{NKGa^Dc1sXMc<@@6dQ=-%|j0ufVc_PB?;NHX)lD019)e`5(O2kqPb! z+*)1U|M3oHJT-a{u*1h?@wiU&FG9@q^oxUX0zr9aQ=&$Ie}KW%?LSATuh{^@h|;@=dL zCTHy5)RlY7{9hGQK2S`6k%mXD6U0Gb%E+km9MEU(igiBJ17+NfiZOEdfmO*_ZZ37n z&uuLg&nEGfqByam@TFZ34mM8ct_2D0W1yEy#E-;YF$E_xBmD`70g`P=nH>>(vT+*fRzOVXpz1Ik6fC^tkIp3WgGX#F z7_nczlDOwpWv$MoELHYIHeN6rfxk(7dMXK`fJ&s{DMlD?tWE54*wjim@pJ>cnI(-g z;hIv@U)IPq_6hIpsUPtakJ{j*xB9ulj)t4EUdMnlUMnmG)*I84U$vI-8$7@laS(uM zL+_bvj4ekZe77LLJsYY#UJ{LRaU>J$Ba1lL-KYXwJOU|z)agoOlK z20hll?p^_1lGsMwQO1=Co9S8pBDiMtzN>MWIaQ<-6|?y&HDckyqG=HSO-M4?>d*1Gh(Q;gUS>#1a?wQKn}_@H>< zP3S#fgKiy&t&Q#0!8nq-TNle925`Z&wHT%xsrppjn0yNFPLalenzf)%>O!JYKw4eH z6i0V}Xe%}l3m;HqpumC12@VQVh+BtAg?iyLMhfTQS!S%XtJ3PiR*(K3v+wqk_Bx$U z1Wh;ZCW?DJtVD=8d=2;~821B0w58SGfNS*>gyo>u6|+uog43SB*R+E}k!jp}N}-3v zspRTY<0Zc7b{chJIUg!2%##hjNwm^AmY`@Hpie<}&A2gV;gg0t=_{z(V@jf+xs2We z70TCr2Ga9O1A)O`?E7ltQhf0CiX$}lNPBtB6LS@y z7RDwrv*p@^*Ptb2Sadrna{F>)9Ldli*DL?FK3RfG24(gGVU^@A%x}UH!D2z&L>_24 z7mqyAK0A3Q5BBfiFB>(uf3oRC&BntUl$H-(bQWLt!(8-K&qs+FW4pJ0;1X0Qb7#H> zf3}XW9DeP}ZD9BW8|#jgI3?Zg-@|#CmebSqng3L_wCGs#iv9C<2ud1L0gOlBMga{u zh;8vQU|5+C2Pcq?JOkTs>cD&@KlU~9Estf2eU4w^GA%6DZ!Yqak9#4lyt<-+joNd$ zUX-s|%s-XC$2buNPLenhhDd=YeCY|;V4!K0F9ngrgQP@1=1#xn_p){Jpxtog;f3T# z9lq|gA^R})fo7gcZmnUiUUW@!+WDSQ6s#u0j^;anjXMNRE{w#X013P*lwi_oven9) z3&{~BL-+AIFQ4ur+pss@OKK`YX^jVzurOLb=glNV7cd_{1;OcaaRO-a1}>x|mfbLb z?=0nggIC}IWvUeLc%(5e2?ycyOH6cx((*PEwlqS~z1UhS;FUw6XWOUX1#UyJd z@)fw1o6UO(Mlvz7NlG-w9xS|LcP3vKwqb;Y7Q7Z{WL?#jzwb@9^tzgSdURdGjUY~C zV`1Dm=~z^sLFXM}6w*a1Tou9xwP;V(g)a%GIde5iI{;${er5i!l5}g*9zQPSqb@ioT+ zoVOj3%B<|WW>BYOwuyoHS_Y-6)_`Ct(Lt}N{pr!$m zKz7|(xPvoy8dTM};}nMX+Kz2>c%zEjdyng6A!b%Os219DXOD$nmS7VK^m+S$(tKxH z7*$6|qN>ti+tc5P+QS!4WCmniqw73D@Q+3Nmv{HrXp7F}z2|2ik1e4oL5y@TPNPN$ z=rw1viFIIxkU$oyLFJLFq;TTr`vuw^1x7pj!BB;ihhLt$_qr)8Kf8qXDAgXYT-KhU zG%eic?}PDmL>YJ~6DLDB2LGU~(<$}XDnC}ob^X@8`$J}A-OX)xyOud>%&m~2U}_F3 zh0=El3a8b;1ZnjsXeGpWNt2>6o{%|dlPDH8c-GzvS=+>p4#x6j_k9`+O#Ni+IjNy| zFEYAMnlJ*MA`9VjptwL8F2@RY55qYI&S@Z&7fao8-Zjp?zkB3CLG~tH zmV@m3AkRmt0$SS9(fK;2%SU|AI^GR1n%>zhvnRnX>IC?v$jz3Hna35#}a4z(Pm`+?u(0tmWQir?s-3iZ>*C*QHe$l6g1ayL<;?pEZe+RUvJ{tKpj6`@ylP zfyTim_y$|%7Jf)IZB6GNi9dfNev6`tdD-)0_0kW#aND2?0{}3Qx`S&W4qh#ssORg5 zNa_sWq+y4j6+{sCh9)T~4g%4wUNkjXUjZ$Op=7@qx%mxzN8cty(u;2a=Drs;!D^uCo`01t*vr{PUp^yr zthV7TIO&~sy&f4lt(I?6Fh7+TquKLeWuNiv4X7xV-N#J;2}fH-EUcr z6;H*Gc0k+#VCf?id-v*&Q)N`s7v@8zl#8i8d-O37X2)SsKDM~%Cn_2hFz6-#IzQ+d z*h}KhQCfjo9jfzr6YmGMTdMLY7{+~rMGgfvIN?OZ=A+-6Zy$5kk6vT66_tofFuEbBzY9aIpZ!|Hdc8+rw_Q%WvVaX%k4)x(hEO8x*n&PAA8x; zTMlL}Ig+*E@>MZj=>P=~$D8pSIhmvwV!yWyl%37?_0+^w_FZ{v!=;JFKbg39nB1oEIc_QtTYw2JhiaR;>#89IZ-dB?50NaB_<0<2MbCUS1w5)^oY)XwUH%D?~ikzn(89S53ldBg_|Vah`3RrLPfKxE=U z_bK;^asZ7af+Eh9<$hnfl( zNWWa6{aVXyewV^cwX=qv-kx@Jxm@OX4f8qYAgUO*&nAJ`Ln;gdPv0eS7p|66h_CLE z%I;IHNWu2(-t|^@zT-s83#-GACt55v{-j(GfRf=LAdeM?sakHNLbZ=jC~EbhK3;<~ zqQn5X=RQmSX%;qQ=9Uk&{fFWCV?HX^G#$@))O--j=6tR~BT~+MBZ6-Nviw-!fFc>* z(N5-?nR1#IoZItVo^^&Bx@Osp%Co*|Jid5)rAKXxY81jP-gd`$9$Xer1l~g(JCdm} zsYC=AQm#iwMcTHZ%GQ${?>>4=PGKxN``GuGA#=y0h2Emajx8hNYpJ9@VMilzA7~mV z=wJi2CLRX93CytOh+`;;Kf?*O+>Yu4-l1V!iMkZ&H@2{Zxx6({e!kCRw^^)?2#cjLu;ND znpEX=+QRLhKP!8=+~(v-&D@_>nuYqsF}r=A$=q91LrdG?IyJTo*QElJA1hdwP=i`W z+(=l_q1Hm&Avn?^xa8{U<>KWT<9Vv-M53NU-ukZV@lk>o<0~`E)p!wLp;g25rJzyt z4yxc~82`Z7oHa?wc+0S{BIO&wil`lJa>&xmXEH0wWWP@&e&N|cXnweG9$;|d2&~1o zBY?CB{}$2$$pB|VNjtX~HXCSCG=1ZG<7!eiDpF_vt*)~=w)a>4rnN#zKle^F7cB>D z90gm0LlHc{#ZLoqJ3!SWoaWvtX$mj=B@#`Sne=YFFpW?3GpMc^B#7+88mWu%Y8CeF z%!d@TXRl2iu=$}TkV7MqH&}|3@DAVr2i>=CvWpKhgP2hM#%Y5-wNl%qw zA1;osv!%@a%GHbydBuBQowrx={YWf6zsmgLE7675rrSU!Uc@O43u=^j=5+!s-rYJJ zsKOXIQ#cY!7j{qMy0j3>Ibd-qvBDimMX?+l=tm=Qtwy#UzhnLIU7PkIf1367^#4+7 zvJFbl6Z{vxEn)au-5miH(ii`~`6(((8g29=*U8LlU?gbcM4)ure9n`PKS1r`0@mkh zHvFD*>zBy)LyLd#x{#fjiA~s-%|V}TO_+$dU^+@HC|s8QUr~DhPrhRr{{APN3_Y&9 z1uGQqK=F6nq2;SpJ-`f`wP0of0@)Wi7Os z_?_QDd&7_mpx(Ag9|pMlRPVEIq~9$nWsVqtO%b6jK^-K~h~AxYOGsPL1-BE7;9 zi#hAE4qiBj%qdkgzWQzYf~lWFau>0%fEI#!oQ7e&Z?iJJd{wrKIC$W}9sh3%+zGIwVN51ZfOZA`rP(_$)f-~F;zl)xl>{85vs zsXYy(mdVa0=FdpuHAp>4iYN>7Ei8=iRX7=Kd$scg=i^OdCi*|CXIc&)*Hy9JARgRZ zj{UvtL|u$Yf;GwGH~5E%oh5qXBQBsJOw~J!qrl$5Y?6c1ai=Ine5C|8%94OsdOh_@ z-`LdlpGJ4H(BnS*!)A+}#d_>E>hefLE|S=Y;oK*!hTLo?kWQq7Z`LJR?3YFY)!E3ME9}cYwE9SVVI|cdMC1R$6j92FUjf%@{_aY}UsWn8pI2$17%NGf^OJWVaYH@+E_WQq6mt&&9d#kM+yhrNuo47^ zo7pqvhox@W`jWFKdmmFCHCt>qDek?VS|rmR_^#pljG31s1s$1LlT4BiO(+`C^9c_qLp$dhHkO zubhfAZb_Pe--n8;jmQ&)44V;Hq@)Grqgg z!Hk9Nq_OA%SuaGgkZ%jmF~}cL!E^;fBPJ>Q_5pkFMAaDxk5{tlP8Lwy{dT=wMY^8( z%q-#ve$TZVvM&73^lz!#2YYbqiQiD1!`MzRbG=U5g%?SxazJx@A`LAtsjO%VCOvxh z%#F9lVjNieQ{C6mMV#{2HSFDj+62f(Z0bN$Jw>n<&m#f5VK2}UMhVai9IyitXyDdK z)-ciH?zhL%`?YX>^F>cj#bw0i^=gGVmgS|5fBj4)^MTQ-(1$z~jTCvugawczN^&?Q zs}|qYP+62>Oko(=o(t{Pbo**=tl?hjJ8^6(v18qKi;HjHo{Ue&u>k_`lcy+rgtXK+ymwimy)ZFp_lvrAVOfzo!5^oiCE&L8?TexReb zN1-M3WZzY>=~zS(Tv%oc{OKLQTzD=xSOr@(8AFmT%(hafnv`>Zrz#s~J~0yq zH<9^4o?9$-^GMzse`niGm#I&jtjCUiuk98Q41+I7M`~$B6Jh*7g6iT9fbBP?Dh~G> zb8YV4Qlv@4G$t>HZ2Ge3eWvA5;?;L5mDy;L-YIkZu6u!Rvzmw!NCSprgN^}_1Bk3> z94m5P0)sKU6?_@s>WCQcB6d-?!#ND!f-y`aZS8~(PV{q1&Rcr7e2!d;M%<>Ti$mw& z2U~gXAY_G*zXWL`iDMY_9&r5bESoC0fPSB%w3@5)&_T)ma{Eb&f{(%}+pKQo2UXK6 zWGCo%OG%};3~&UonwS!Gv8jBPnqW;GFA4@}6>&}2h`)_)>$*4#mh;@!1Ana5JD}br z7ikU}_2C=lnGPMTU?wJCS6R|K_pXPbSA&8z^zI9Mn3!dR!(and2zxk~u0oAVAk;-! za;1)aC<J+7&I2;F`qX0$sXac}li@#NGik-gF&C37ZN)H&dcIqTlLNvc1aZD%u% z&lMt?j?L0wD;?~+uJex^!JL& zlM;iNIxMV8VFPMIWVs>-;+b=xple&<3QkRdy_I0E-&@=8q2jy}SBGA^usxH?o{G1P z#$E_tV;HX>j#X0^30c8^<~zrd7|&pmKs2&RU^&pJS7j{4kweO;TP&S7B)WX4Ne^on z@bc)JT2(xTdzq@x@&VdRY(g!isu9dMi^En?0=?Ek{2F-Qd1ubc*Zv`N%OumPG82Qd z^@yRxtS@p?rTRL80UziZW_c#I3N1NFlM&XbOwbafWCotH@rZO z&%&{H@O8oT6}=jC7)BAwKYganncMg-Q7x=n-=^td&2Fb;H&2iB>%tiKS!o-*|L^Cn z!%^cI2%ibo0hM14*YPj=##UIF08|%Rc`Hz@YN3OdSXx-qw!7B6EabuGN67S>;LfM+ zLz9uT_kcB1i+3AH+be>dFo!4)9$G_z1mFBBO*Y3Pp|XS)NjRU?MZ4Fhpk!t79X%L> zoZGNT0@*0M{YOEoh=3@3Ok*U{DX~>}cv}`*gTDpPP@K;&;i6e;5wnU-GOh=S46fP9AoS@3r0&1gTN0|iw5J4Xw zcECPlDD91J4>q5K{q9Iv^EFw+hpK-P(-*I!=s(%$iwED&h#?ha0oBK#WAD>*XUX?& z^)%f#KEPFUKcIIG$u#*&Hj zMu%F{dTwKduRQ|X2Yd8y>^-OVbnlMC1|e@j@CQ0TEYUq^0B%~!bOwOb%v|O0J40Je z01F*dhza+%b#J$Nm+X2;es{0=^zxsb0Y~g87r!qo(hy9w@smJ>a>jSCX z4>l6$Tng_tC#*IbE9bjYMuu<{zQhW=+=2bz66}%~;A-@FecQbtxe65_GiuL{8H`|E zPc5#9R4udKH=!C;P$yW|PyvZ*uW`QiR4Kp3@T~KjQU7~LiepF;Mlr zaB{W`(>FLuJB8w|8HxNBsGjaGlPP!ipSIYTFSgFeiVo6cG1r>93>e7~*t^Icq*Y0b zL(MH3F>s}B;hxRRtgP+HMeJf$t?Jj%szOmF$BhQ?YdS%UOb57@rHyslLk+cLSXDfV;$h*@EWr0BaW?_pDTgVC` zoq^B3u!X;hw-+`va>Li&@_KYB?ZPoRLGBU{{fi$ddk17-4fG<)w;#^r^p7Eun*7zU zLKRI0u-O*L$h^#CkT(TV!7R5@(j%mWbo1nrqVs!b8eVDH2T@rCHb1ijvQmg7e{ld5 zhI0}vjQ~UiKkf~XXKb~@J^;98g*^{G$5-m9(s=2qdi|8f8S}^e4t*SBH=prKVA0;f z^uoz*0~U7N1^l*J_-NdCGr^Q26Qo$f17-bVD12VKcEzWuCQRApTyq24iMUV^p@bvS zM;PF{K@~PYBLFw4BU~F=PW(>V^c+;hk*l3sZ>4G~O1wQD*YP66!VK zJ)mKLg6EvU^b{Lv@Q)F+g!d5?<|AMyOMk0}u08|YoiNMRc;>T!k;^-kdrLQb5&LQM zp-S%)0B_Ooju_xdNub~iTnokt7nVYgnjwW)xMU8eBuB5dwT1EQmKXj(*xd27s-oc= zaiy}Nd@x;2;i`iX=UwsuNeU+MCYf&6X#3I6+7pa*Nx&NK@SDcxt`myXWC2Lea2KYFWG4o$N$w-_$eZV}<8 zcU~-94JMQ>VW_DWW2_0B)uWuR_dSP`Hx`w?Hg)w-)D!(Jevc&9(|r(vw?m69&r3H6 z-xZ!m)QGLP_tpuVCT3{qvzk}F8>f-AM?QRa>g|=vCWJ-aBnCZwZX1N}~MtP`x z_yA43xKV#T_S?p96yZDQN}w5*Tbs!Qdhe;y_he??ae}ve^lQ~0-5O>Jk46lydpcc@ zOncPF#;rp>0@b*TKUl74r9x4 z5_q|=Ryy$;W{Kgc?xuSJi))_R_Q%Gr6lvAO>-l*-uP-;aYtJSgAy%U}R(v3=WWj1O z&kd3k>?PGftIHtI6q%~Yr5F08AhuL{;-`Jb4^3rQHEgme60BJC28dlxMT7+eIsT$Y za2#?bN&6~+N$;77)pVIMD@H7EHC)d%dP!=>pSN4GFMcQ5ZYto?!*3G9XJsRLN>6?J zXJiawPHYE9F8wB;EZkp(M5uNk85jEeZ>42}{zB-J)nW&b^F|<3R*jzTP;1g~cV>S4 zr3mQ$ZoNDwb0&z$P%vrJrhv}>X+`nI;DGC zP*4~>kS%nvi=(JP zJPp*R0`VJlJ4be?qjuqC-0SVB8LoPFyQH)G&0{tmw7NTgBk`h?$2D(SE?OXuuLNG4 z4|`n>;AJa7kB_iuL8y(|mf9eVcF*@?nC0R6ok=MzjHPQCy5kp}jlFy2c)oPOMw?7u zYc#BSjO+R2)9!LI!J=b#nXPXV)s-yXu-HF zVni?5nz)4<5*A4?VA(dV;^q`CpV5DtvW@$hq-}a?;H0`RhJ}f^gE>rd!uKRIuqzi1}L2eN~ zoVF&x8a~E9n22yXNW4b~GI(2F4xHRy0KORbU~ zbs(&gE(y1u*Sz7g(l{_av$ZTW^3zJ6(|*_HE6l?hDS&)FlYE}A6xL*-Vo@9{7#-96 z9dbp>j9&0S^0R##s!IC4Ca{K7i9OO^)^3gcWY87o$Gp8MK1KwSQSA9V@`tOHttb1P zfEBOU<9@fKe-MS)H;*m7POc-vJ3$-)G-we{AV0wK5hj#r@J-+bW>_d7rjafy;kFqo ze0MG^PN_AB%uY?cRky<6?V75gHHn)|R;JTf*r0r{-x~mBJ}wU*hHNG{aEG#hPf7}z zrG?J%sC&7;QP``pHD~5{Q8htz0FRvtv6sX-?M}Pjubz)tZ>+L`h&oczSB>i`k&elcE2ne;2d>wp z>9OJ!tsh=BB19HJi)$8Pc$Sl2Mcu~*9z|-Ee{J@&3;pgJ#pfb5Tzzg<##^{KpFlO- zcIuZf(6SfzGP!|zER~(!^o6EF)CJpiW`b(i$TvW0p*2M15xP9+mDTHlx3!NA^x`B7 zcMP;ms3siG=WEvV)K;3^!8~Fo1W!A?jb4+DTTk;qbv5x&VBInVEGz_)`&js@%yz)S z$g$?+NI#0kC6?=^`!RZY+6yU3?b^jr7Vd+U(fdr*_s84MU+ld@tf~ueSD{|$J<_st zKF-c%zHJzc3Br9vRg+hr1EPjyG{pc~DkCpm(|63(oONefCUw|mwN$0{pDl!Qo8S8; z?>Qcd*)6vD2kL91cO4aY!!ode$GxYFYa`Y0k`*UsO=iMqru5uYZ*kX#B;`t|H3oh$wREXDZ zW^6@vcTP6yDwYO>thMb`en&5hO%WJ;C!qP}_OLr|E7&%ptC&sHt*{uPfDM^2bmfv9 zz!AnXXXnMOk9ld{^Vv6KL3lLu+2u#zvmc(;6I26%2vGWra1wBTyOL|5ykxcnSK%}a zaT8c7#>=^LcL-jr*WMPc(GAa4$Cn(MGB5o>h_To?{r=G&iE+!pnFHQ$Dakk4=4bLL zxf{sJ!U&ot`YuGFRa(SG<3zkQx@O$*s~ud|rX8=y8RA>!i>lT8?U>%Zkpj8l?;6Vs zGpS49WJXxDH#@+xWwt>&*#_Cru2jj>IeK0q*^rQ>UOcN9LNo#aH`F?9t4gU@7o^wAz3eV0>) zRBrPlnxg3;*s=vl0dSmxZh$Y=U*xA=8ZM044qk{vx^P8$H8tGH>gdyFOE~u&q`3v% zfnoP91`XMsTif3y`dfB&*Q{l+!JPgA4Uzr;M$3)KU`}@H)waMS0GCje-5pkz zaJ7FFq`c5Q@zicgpWk%>!0aEX4Ioy*n~Ji5Zqu65m7MoIIr{X&i{FPtu- zsnHmD4lCgA+(|@gGk-6!0r+*mMQU14&~7C-GSO>mSeh1+J`^$^3{DeUkCTc>N^q+N zY-%w*4b{LJFU#JYHqdBd0=qsZY{+e^jb)Y^m|Y!6*1dZ6-Tm&Lkn+%1Mgygjx*nF| zjSI;TBjNyH(-1gwZCI##R5fA~=p_4YtN=IEOnPVZjip$oynO)h-V~cg8AbEVAN8o+ z#F1W6et_y{We*oCka#0+5+(!Iy}Ot~;C~?7d<_^wuOXeERcLv=Fv0QU_A9F?!9ELl z#05fhJ-LAnt7g@ZBT1a=S#0UI#P292Ls0Q&!kh!1gt!SaTSm+mQ8q3Vsu>c1;iUFD|u#_oNC-I&$NE2*t4NN_0Y8%q` z>gX~wYVhmNXEI$fk+?P5P4`GrWhPt`8%tjIvishzEaU}#LF-d2gL~OEL?`46iE{=G zYsS`Ly9P0ypl=4L0~rW`AE<>)wp6%htmJERuDpr z5IzQUhjobb#}<%(3L(i;x1ERcYb~F5kM2>6en+ivU*DEGSVTE2zM=1{jJD_k;H`tz zZR&6KzzM)Ki67`c_9Pb6A&?ul8i<%cXZWOR2;_zzO{A zv+<}mF#xJ4h2$YOFyN&E#`^ z>6!N%nl1=eJo|UN8-K&kvAn4db9_3sOAWD{tfEZ-cq4Od#|s%S`xkP;&+Cy_{Sqn0 zAP+5U&0v||2XDRlgX`n>sc7H+mB}&FwC>Kd#-zG((?7cU`3^5^G2b#!7@0 zR8TshLu|$XiKrVO%k&E@+L0}z7i!v*UwoMeI`=|BJ@-ZE?arqTh{B|>kKW3wnR!#R z;E?LFA)>ufJ+3F_|6Jc^ zmavx4IsD<7%+I1GR>yb<6Y5#V#6^Rg3Mm33I|FTmJ6O^sfRB4y$@Ujdm0~J-^ltW6 zc&!hW&KgwFx}zWU%&w!?LAH5TiVPo+sWZsQH21_f^R=gM>-MJdHbYJQv-L8*N@rzCw|=gQh(yKN1z1XLtrF~DZs#bS+?cC zxDa89+Ku?Tg|z$f3c#Fk5_{}3*)z4Xgod1COnIl!WRpudv8CTNh4?HTJ-#K)YVLW% za*wx|$fvXVA?FP#2W|KTqMrm32WjGjja2JiUz-#5rF(3I8#I_0_yGD?@}kG*@G^CC zaNjPP9AWQJ^@I7;1U95=_EKZ!W~z$oPIlZ)P+U_BxsZS-au)UitR3*rkFZ?gHDgAMbR4MoRzI4kU7Mr%2s?l`jYxs(;KG`f8ct@2Eu(9P_`?*A_ypVx>!Q;wP zg!cf9PTz@69YpE%g9CG6C6CvzV&$L;Md&iB8)psUS@bo&XlBSjBUjOa^N_N7^md8e zS4Q9A%hmToM;S31Be9*jKuIBR2mdNT_k-|ZVQiFxAsm_6pqufmfouoI3^i3vXwn0E z%SYedaPmBnrG_sg)`mMqi{E%Dg0K&{zI1I@x>V5mEbMDw%e>W2zp%D}$&Dg;Pl{aI zBGUc;H5|d2%e=wWV$2C2y2lF5yh~>CKg4J>8iNG*r{ggA*LfpeXjYg~0&S2Ziv3=> zas*%r&ociu%A6DiI|ZB^P9Mv?FR} zCFz%lX`vTA|6<)Zn}NYE8v)SRNAqmly!W&gpk%L~2s>n9en9d<{lBEK{uQmZ_?~HO zw}B9Uhc^DK3mQ(1mGDiI-bA#16go|Br#h1A-UM!8=n^k5ng>J z)8L_ptk3{%m?n^5f58pz&luq1#o`Klsw^;J(CXO{@AA`3o0^=RljHuDg2pg+y@Cy$ z*##@}2obML#!vOf@g;$hQHQRQrHNe~G|nj+yu*hrok1{%tCYeQ)PiRwB}d51LYM*a zD7~(vGv_xRR&x3zw&eUxJF3l$Sc9EMjUvGGG5cwbAofxd$dY)ggylrlG14+HeR5|T z#)TY-lP44KEF(SJA{u`6xzwCV)$(^WtFs3)EGNE79?2Tizc4!qtIUl{a8L7A;bL)| z0>RmIHxj3SYCJ~W52`qFucRSOm;46(tWG#b>weYMWu&%FFq`lILtG?txr5OrE(3QV zsl%ti+ndj1l$5cAM~AQx7+9E6Pt`ZLW>Y?j7@yx7zpY%PM(=V)e53qB8IN z$j!p+w6>*Z`2Y_`2`&onAR3Fla8SJfcw#{jSCO3@fx~K!LZ#5A%AcBeLmT9$wCs8d zJCe9rNsfDC3wC>LBPD(qISCf+2F~jVZ8c_*;omf@3KOKH-y+z{RjgFfZzY^%px2DH zHm=mwE1JsF+Hf)Y2e!9CS^5>d%zRon%U1*iCxh?UozG-GVY@-a%1@XA{16qFj}YLB z0ts!Yt0;M6X?M*xu?oFdZ|Ss}nxEacGvRV1f3?xakmFMlT8^$T4u4}t@8O~91db@UnhB@ZVn zxB!DFYN-!=hykjB6otWv8evl@sOGE+kXhy10er``yU@QWBo}dNP(3-jJ>r~@WtQ<5 z9iKSI7}_whK>9Iz3>-6=Eyl+n?KD||5peSA*fIlqS!q{*2gQrwj2J7nT}o!llN^IA zqv{hpcdcq1?$Hvs%!(~;Le`wA2=OLi2doUx=dHfz%5I5|X^y=6!W7$s-{QN!Lg5}6 zqa6pne}DK}#tn+I?d@Xq50?*`O#94dr^6KfN#N*$d|)wY7375JN@hv7VOAlVeRuwJ z5I)N}n(E1W(_ub%8lw;2pgEvQg&@+md|}{Ec4pD zA72i1JXw$%qfbuJ?%I%IDw^3%Qtv+@Ar>K$#Wkx=LRP`S%v^-9b^m}R`LloyXbP#<_x-bM{zB2}a$x)gMZHdWqx0IsSOt8-c3yxA`_9zt< zvU|{%RrXya+Oy?~GyOsN20O>w5;H-Ujz(px8d8!VMQx^m_hRy@?RCV7l-dfn( zE63hmF)};&*>f}POiF&4RQRLh`IyrQ?RShf!+{(;4+M)reMk*0p8~2!nY74TC}6z` zVyi4qTO}N7E7a75#w|U2*h*)zcR3Q`Otw{*i-8W!OU-TMTmk@&gIs}FAHld`dbF5; z#S5(W65PkBov30AwvM7?sG9}Kx#br6I;SZLb2s}0J#8;M-$=zKntdvsBZm6=R2gsP zc;0np;+FgRHym%(9$rfaBSOZ`1ogMe*{N97t(Od!5Iy)Y2d(Mbj^+ z<^zdy=cj2Q2@;wSLY3buD#i|?9-@}f7>_UaI-3vm^Z=`nG^8kHIh!5jX=>WJn4* z8Hl7*7EC&Xm4MfMJkTDNJ)+f!;oa*{xL$Un;HvW8JZZtu!9Y=R?rn7D(lgNoqVow% zkV~Hw$ejjXGQvewgBm<~6n(i4E)27dV5S%DS+<6IyXVw-ZTsVawKkOarm(|}2~Tbm zT$?}ij>LNdS_K%{I8Z$0#iVzc4Ro;ga$35vU`z}fwLyop;(UKshOh6wH7{MckIsEQ zX5BlL=cHRz*N968Ibl%018BNQIM4|7z<7@^3SzwIUoU)vVUW7%A)rjX>MZAlu@YR! znYKz{p^D7#8|#*`pVvs$&WY^ISJ;v4fc-j4S{w_j4=DO+?|lTa0W3@n>Ml*5x}Gjr z4wnx23d{yHm8*3-vK;a+#{0!x@N?UG%D!jl%GTspOWkK|087}lv;0@;V&TH)#weha z*BdYKZDQiWCN2j35~+TwP~NKPQg-`XM*LL=9T)W#A2q*w)Dgcfd_GHqx6(o| zj7PvbU0t@x(EVBOIivQx4j)`s^bdP&@_Rw7UR>+m826d{ztjk_JaC{&iW@NvD(X2F zyr!^PhfTPZ0&Uph2Gis6$KKw+BG!cIN!1VnNi$<0enO^?RrUr2ZwIZQpt?+6_=2h| zI0eM(0^uTT;m5#7_%qvQn?wZ{^4nxx{euJNJznI0Wd!_)&GHxS{!6_Ecd|3T3ReV$ z5oJq=ebAaRMHX7oZgk(*CdOu6cMsjK%lHrKej;41@aIr@#DB=FqP|2;^~^wyA7%Uj zfLc}xnQXE^0kvR-#`(|Oe|T)eDfbFvQNjw2S~WU&qeQsCB!G3MST}EbBf7RbC(7VR z%fOs<#||Z^yC-Eh^YifW$v46ie$)K3P5~1DS{ltxhdN#>n^&Au1PfX9gWwSzXV zn+7hG3TWSgl=cJejSMn0<$={)H8}zH;p`|+05O!3hxieOO*at15-o;snf4|aL*lF?} zZW^>%LxKYUQu-yby}7}pluu)XjQ$eY$p>x-*u8-N%u>=kKKaPucnN z!TG;hYXFGuKhS#6Khk;K+Ps?0s+~+FixO>%NDH<~YS%VhP{?Pm7i+aBy zwhP1DdbcclQgH@^?52xe5L9rYG3bK zOyoqu_c1p59x1o3s;RS~8j^fVK(p*!tZ8k=TN;EJ-hRHUW%zMv+)zxPOcKfGb-$1@ z5V0^mCtCH$R3bRrKiYlsg3>avbtz|`BwpoHdiiS>31Z$bi)XTIYEZug{SD;%AHl)@ z*}tvChD%dEmNfqodF5P(MCgR@_dmmR&3$YT(j`V{3zl-%1QzoI(RUtT!n9=*65&=S zOoM*h^;JV^G=WJy_B@9+Sofs?amXmzyi{|`@P9Gewb&PsQNqj;B^C#eRDr?QDdj4{ zW(N=cG3XWNv{JuuD=1&w;NAk=B_@`E79-NIGZuau2uNZ!hWz)?{Kbv^J38GppN&sp zy2v^pTKPd282l2k1MqBfOGl=K05{Q*g47d`CWlR1W`pp;O|xatVm0OI4e0)imMWdy zIQmp3iXhzKE_SIHf<8ylXoDx7-%(7S6TE8RBWFg{MgM&Hk3HECYIG=LI23R@1L5Dy{vfE`o_(PO{_=*PmKEEc zlmHS#07`8BA1S8N2UQU76qxq=&S zxe|)gk9$uNZt4iaaMCHD=;{^H2okGJuZ3So?=E4|lql%sUn)TlaD4yy7+YH>4O|89SO z=N`#O{kQ!^Eq;C;e7#L205Y^^l9S2k1zp|XASTP{_e!aztkZF5Qd6g`f~w) z?!ccr@aGQvxdZ=~>_9OBm?_LKbfC*2W*N;9v!G8FhyIr;ALMTU{!yc^@?Wj*_!sDR zTlDD-ZfXc~_V`x}g*5KAAK#6y!2MyP&;F!u{3YUn?$Wa5 zhE)YLD)T}(iJx7m`uwwe6LRI4IHv1DQ~+IODtfB6c-A>*c(6G570nw{{P=tAB|Bs7 zK%*pJr!OQUOBZY&kl8=^8wND^mcD2{ZE817cK8%Q{x|&*Nk_?@h{)-UWk_x4A1se2Q&`_ z{3Emb0tIgQ8ht0y>hQa(BZKUYT{L@vU}d707y1?ED zN>_QY@*SBz;kL*#AKZfKXza(6U}mVVUhI5g!K85e@nWuXkzf}W$ib`4bmYE&Hb(`j zN#F#<1XszU7EUBSM-;v^A-K(doju-ZZ z>x}H3!964E3SUA$q?mZV(hNzs*&#kyvJf;O*A2PIu=0+pKQC_l&qn0`!RHL4PKxgn z*6I%*xJ=WBoUmPy3>&s8-vwy~IS@r-RFC`X47jc6Nq%o5D!!#3H~(lV&Bx{PEW##6 z=T`3X-cJsvF&@+O*kt}m7bNTqpqy_!TK?o^=JEY@M@B3XU*%ZG-ts#)eDvkEh?J62 zqX1+xp1(|qluvyEP3-Ui{0FZw%yy78b`dI4L1G}-mWCMN4z1R@D;Tce3C2?SIFO4Z zO#@Uv6LGO=%Y~-df%Wrqi(j)8JjA6VbXdC-z~KPb&jHys+Jau70caRVh6J~%L7i7S z1J#j^M(8KV0dRIej{;331d$VFO*GCJ)QLv^ANJk_F2=R{8_y0=DkMcT2q6_x(P?al zLJ~Pd(IBK!Ig}2jxrwBx5z z&}}AUID@;t6U8<9Bj2Ad7J@Ifcpft3I_8PXYC(_!@Yw#5fb@sygzb8S?ZmV}(kRdi zlO}Z#cI82Jk0^Aoe|*w1-zV)jK52-f{NpoyC%qio4S&S+2)Mq$Gg=`uwrcE}{HRhB zm4g@XCk=DxouM#0}ul>e! zWn=ml-UAxubwaiB}H+NmJ~g;e6y zQUS>d=>Ff?eJ`5$fKp3pRTj7Z(al_P5scWZ}B z>$GOeM=Hv=I#l@4`pqX90N&WDBbg4yY;byKJFa{Z^ml_U>e4)T}&GeY%mX zzk2a2{gJS1TMqn#tYQ42v;v3xZv^0&%+aA(`14;}6o(%jo<5;Dzp?^V5|DnWW{zlFG9w+~qp8mg8Op(TSV*WR61d6hD zTph8?4OJ?GgS*W|q_uyunf|t$00Px0oJJUQvpEMfZ&u$1OcmU~r@j--_Hru((4)Ro z%geJ@6(xGr9qd_=6Qaf=Ot7EoAv^d9()#{qy4h}>7i1=Bf8@fG6f!7v*3XC2>dnt= z46B_whnpmy2gtX)g{}S596vZbaWq+b?ZeKr9ih`^9PZg&eCgieOF^*_qD&t))QX!E zMh!R(RQ$aX&T$GGnZRA;H2CB*)kR3fZ{IwZ_QBu01h;?s(0!KmJ)a-{32NUzs{#ML z@1<4?5F-D%ktKCZsh>DxUQLi>yX7HMAqQ<^O#ps}wTEoq&Q%Xm!Q(_6vAWNV))*eT zo(q=tvkPz~-By`S${W28*?{c{)Let{s_VdiZ`Cz1m4jWvw88(}L4`6C8N0j8Grk%n zh+~d+09gk@EAAxm3Y(!vwq@w9(fb8x;_aYiiL!rkkNMNWmOmReh4zIuVnGJYH4)sw zci7^m#6EYJlez9(kqh2EW?hKzca)79BMnz@);b6crtGHM!o<%Nj%kaRt6tC+f1xH| z)YnS1$l81U0CH)4+h^hTEuHArlEV?2!ecM+%fvoR{HD)PK);=v2=b5KWueY^E(s2B zt}~&P8Qyao;t13o^C!)c^9y?WyJ4B-gf9^`W}+vTh%4d9_tH?aM&Wi;nxUoFz8!A* zar}N^eB*^t#6cwYti!FjxFj-#M=}P@wk4HXX9fnZUnu3>TsLgyeuA8OQ5|DN12IS) zJw@x{quwX3m$IK|hwYN(@Z}AS6S|pDH^SYSEuaeR&^fJ1+HX8@wbXE76rWqWR-`f2 z6)A7{U=?B-sy1=d%Qw-IpzE8-ml7_7nB|G=Ob=pxKVZ<%uex?nPiNTZ-45OH)`zNd zFK?(sf~+Rmf#mHYw#FIIF+~O7HvSHJ9Z5*xzsP;oAc{iTN)ot^gzZH(*TYg)zU6xHk!8q4T*q{!9 zE^vJ*=wU3oRxeom)NF=p!<&nO8fO|hsTBzX*f)7}MR+i@c@Ptz`vF;oPlx!nq_znG z)!!{}4O`+b%=A7l3?95rke|6M>kfUyn&9&qF0uenDB2IR+)XJiNAlJ&9sBDB+j3c; z6RtIM#2@AI0MSc6qNA#CSJ_3)kLTjvPF`1?!}~zUOdWYB{~S3@MORq!Rzm@(2AAC@ zFItQ(<5xn>xaZ{<0qN$89JlAA25whRA3U?~Ez}vQ|CGFdB(xUg(?sA@%G*mZMybM| z&@hnOGn3G&k&H#|4V!xW_4GVzfS=TF+`3PRr~05Rgy zms_ENj>?M^siU1R+bJds$qQaplJ_}q7r%bZ8>>1`y;JGqm$H?TZHLoT6vqob&WkV@`+GTAp40RU-P0Y}* z{YK|u*s5{1#Vbe|@kMU+3PL$Z0Tyc!uiS3PqtK=gTZf1W_gKt)hf|eBuP#y0QbX}) z`idx~c z_YFd#TQ0-vLeN0b6zm8ZD3ES9hn~&)Uh2Xaeo9)npOI}VX_{T3NAKNzqQy@-CL|wF z=842oHWK0}l=Kw%en0B`$O%zQRWVj89GPp8f&w~!=HSD$oMlfA#3Jn*M0fRlMpcAa zXac;4=5~{^6ci@pBr>H_wI`rH%b-jda&&!NqC4$wSQyA_l5qpzahJ5t|XGT$3(vyCy+TT4$v++t8J)eKqqyt3k6LOnzl zJ&_cTkl^#}r-m}+1KQY!;$kg0A2rIFo1wxFEH<4Y8h^JKYVg>CR~`v&lUm3c`i!-t z89mk!iIq+-IsV}vw@!FFuu05u5_4)?>_q07$-ytHY_l{R=7kkepnbwRVg5>7Yl!Z<2w1=^F z<~Ir#qq+i6QltWNUxY;@L|2w^NBoC1$`(!ea{SQyk(tP}vsjZLVvtkEdK10A3VyXN z!SaV5id@Y?*bc6x(+sU(wl?fEy)J|{O^z7Y}w}-aAQ!WhZ9SK>#c7jkHpnzAX^VobzfJk!@twQoPVk-QO zk?kn+jF6%vFe`{6mEvX98^4Gaci$-{QpL~3KcEF?1sfZ=lVJsQFQ9 zG%@KsC!NO9B({UVnl6beB&kDjYmRcDXqU>QO0u@gr$+tIM7u4WGsMFB+=N~Nx**(- z?AY2%Yo%E`C%5c3=NhqT*wih!-hO2wQ2i zVT_6C?)zNT?HF4EOdEB9A4tx_X>1seqB4t=(vsmr&Z^~}aqV1Q4oa>}X zosc1ME$4*P6_*!F80Gy69U)ysa*K}_bHWU;nqIKc;J8kVtsy$P*h2-Tp-7o*5m4Bo z%-8)ifHI4GWQUVakDj-mkWDnYeSt;rxwKRq2sQ{vm%U}^vXd_<#&{`5-ekIZfh|$h zJhsO~raG+?Zw}abt^aLw&qk9^mn99JfE3prNf?%!eUe0bO7CO~Zwp9$gMv-MOMJH? zDj>!7i3QnQgr}H5HccTZcCGT-FDx*37#^lBn?zdGJ&8<5 zy>4Ofm0%IYEq?6;pFc^?n^K=00X2qGI*XVxk@)j9NH^G_+ueX*KhX8XkEVcCLE~OQ zYBo{7wLMECw5hFtAWe7bI5zgT&Tv-%Ui&n&C$f8|Ye2U}xOk86@}zgjQ~?}s7QQoH z7z2_!0M2|voNta83Y*X+R4mGpw*@LcK{UFhZ5MfGNe`vaM>@L+;wAIeJBXeSBR>s; z#k*^~0DMq>!@rUu^jCl9^LT4sRe`nmMmTe9VHc|NRbnv!>jBw)@49SRcsA~Q!X)Ki zGGYs(L6A>j1xy89HMIrIuQ*4$ko$G|KGqK?RRt!q%9Zf=C?KJE8{N$EwMkei^D^Q7 z17grS>xW~zHx3cD|I-Gze<`^1J>WF;O^Jk=)()49st7aypBhI)U8oJ01#mqgL%r*6#@XFXw6 zggOoQgkDF(ui$X)$){{*i4^p}hoJq%07-pGETz6U!-34G0_5TlJ(S5ECce@aOOb)? zu8P28CI3tuh;$jYX=Caw;libE5V|}uA|o=F#Ja{h{pTawT?a{vk%AuPv7KZ6*WozR zd`PITS)Uoe9@1xkCIK&2yO~hS<=em?KAzF$#rB$7y=@Z0vAOjgTwDgIJz=m5pec2G z3qe2nRpEt4RpyRd5AWrUYJ{MYAd=3Dsg!xxf(o)qn+54`i12;QJrC+;&pBGGD>Pw( z*QZQ6q(g;gb@w=|{2B+opLSMTzk`NkmZBL?M?LyyAY9`m|3HTVkTB5tp6nkvFmaP1oNiNOxi8N~4j5=A(~g?H^9A52mM(u3|BlS6L+ z^N+;hggv5}UnR;t3rVPDE}_nwiH(Lg5&qgd&4j8y@3WNfp44c?aOwCIm0^)#1N#3! zh;eq&{u{f91Hi{rcHcMe=k=Z0A4>S9FI^l&SUnM#}GFtJ=7!!&6y8av#5cP<2pZM?%>#bTh`$h+`!fgGde7i#WF%?d&CWo!kE;Dk zLx0(ujQY|q!-RUxhSnzKTjm+A;s~AV$Av-^RIBj-3$9) zmX4fl+@(sx`?-PDJy%~6#1t9Psq^GZ7PDKp_I^Bmr8ka=&34(r~NC5;rGA`)f9Yl_Ga0Wk%i*Ky??`g8{M{}ULZqMS=%Zte2 zppTx411;Y-jEpPw=-Z)SwWLDDh9Ny%HKT1Q+@Y<$nHF`KF+LT@nYf=?0c>nN;2(T5 zS~pS0mLVeF=hlr052jh?G5Kb6#ctYkiXNq$IfHDXrDD#;NRxz7EBSpVgKVQrH@`KO zV_8|J`F>XY@p)-m?a{>|p#HYaC)^?@)94-Bw#>4=`@hCfuO_ItPmxAn)5S9SoUxt5 z#C+{=uJtuPAgy#6H0Mj&kA7*SO!We?R@0v%-G(*Ht366w&wyDMDl~~h+iRHvo!@%$ zlm;8%vwF7l5S!x?ga6Fo{g=KA4fg=l?G7YON>#R;FyF}Y5p)NdJ9L#4s??CvE`)1j zsM2QGmfj6tC93W!cF!PpCGl+c;u9&zqr1p=oYa3;pXXmaXTlr_?8Uklp4QOOuF;lx zXHN}I=we&z=ykhlrPf7#GWm3qy;X(a{fx8y?1S#?qPo&E!IpvZnAmdU>VX1i2?4dZ zQ@M~UzYM% zL*uV#0=|ff?jcP!(*tlT56&-?l3~FtHAd{ApQvhjL-`0@%KqD zfcGtz%A;OA*bW;AuiFi`f*FS`iOsRJFL!E*SdWsp7*e+g zUYFA=+=H6)nY+X^vhGEM-@oy7g!!V%4@<*jW{);zZWm@w{;~am4?7ZndmI6q_Q2&b zA%d6IR7^8f>lqkn>7_r5ET|ABG?{^eOxl5~+{@1>fS6(E_!P|HBR4KVJd*>9i-EUg z?T%^+sqUkFVH1BQLW!?G5MlLqB7lVl!@iLr9G}I`CyXss1)p1<5fR(s&LlpK?Hr!< z^JTgGFx$V8T>Ix8CLEw+W&QH@W}~}H zko<`8W{;Z-3OJ}bY|i!A|E%m^;rIXS*?+k4Kj-W(Ns!oH#jg_g#oWGAfY`7eLH7`+ zfHNz69P@k7|SxLs2v z5D$OT5gcfJ=jJc8VHeb-p&l`d%G!IqUi{#=TeizZ+hotcP;+{29)Hy&Xjddpv`5zqR|F0+b4s76Qq}Vr?N5l4DKqS8{tN<0_01sFwXx;QtH_W!d0ZA> z2U*-5{-xbT%W}k-@J-!Ch@^?{L+pPRnM?5TVdKgGhW)(=@1}sXF6;fZz&;0x@CoI= zv?NIQw&n79Zdcc>M-PMiM$o$;mkX`;T*Lc&zY&7yMjGX`Xdm4)x;qShVTuEim8atHK)~&_HFDQp@w(H)x8>f-7wRlzVZRuq(etv)AYW+(F z(yyK)r_j-Mg>M5BrN|}gO z(=QpXb+#1G49mbWN5RU~4he*c?Z;60eC)ul3?7O9;m;E~XlVrOdV~(*$x?;wsfx<= zF(UQEj#)?I)tmv#wM@}`3^q63)@JA@yvvl^YnXscBHN(?7pa?%{MQvw0(@d^v_}1$U;wbAQ)DMlpulLd4L#JC7%W^gaU~SKF3aAiN2ORjMi*3Ol z3CZmGWBhRcmL-`3k$Y;GK1Q7IV=nI=%9oeb+2YdvqHo74B-dWF&I|8xaVwAmc*$wb z5$EfAY`oMbeDd3QVRrk12dZ*wbcXg157Uci=wdfkq-8LNe@45wKbSbrM6rb|D<}(O zDCIr&B677do}_vjq}|naTbyHy? zXyOr4{a|}oc>Zy;0(t(fjS%R0Z-&K^2YSmD;?kIr11oQ*wCW#jInY&NM-WM1j$#HG z?uV030xa8FG6GT~zz*Andh+$(l(ZRdbgxX>>=R?*`Z_%`Y|XIW0RYDGIy2CwO{a80J;; z^Q;k}80ufWMIeUqW)mIUP))gTZr4i4Bv3}fkG|-=apdLL>n{q)0(qXHz_w6R=_;lhtM?4?IG&*KPGXL#)hD-;_>5@h0Ucb%x77?D zUWnIGB*XxDt>R72ZUYWSMlQcU!CO{qj|!|Av=2!lpoDb$Y8qF>xxT9GPOIE69HH zs)ZHnMK`^&x6-~kDd&Dk&O3&l*T99_a!vs}O+j**@Elw|90d?G+!(&+N*=C~Q@f;! z`_pFE*)2B#m>KVM5+riFqVq8p&*TL!zqV zs>f%0?-5Tt$UA$reeq_Nr)cj4q1%4!WtxC7kpu5?^7g1Nkb_Hp>z%{<|vsua28|qPZo9B@9xoF`3ti2Wisq z+s)ST?4R(8SbQl#-nOc3J`KOqRGW%izu9xz=QMK0ce!H%MhrGc{@>GYXC1vkxxH08 z_nOy+?tQk3Mg{Q^`(Jr}@! zmhH4}WT~pa$2Czt8>fZo=0M>Ups-G40MSr15P5 z2eGq|i7wNAL!9PJN}=6og=UUr{;Jwnib!%E8kzSOI={|bWjL*`IbBcwNXv z$M+w8yi2M>l_~;^^*6X4KbMv-tAkHn9^+-tI+u811hQv5%2aF^mt8I8-8I`or zA4E6L9wcTU`5Z_`%VVON+Lr*qkdwmfGe!jAn=28AYJN1`Ef#&w+A%P!&S2i&>H1*) zL(4hJcAg&e8g0!BeXLoh4|TdoP!3T_kz_VDOGC(p^Pi0paA|MRaY|_xDbG@#yo~RH zhjJ|^K|p@X)1HXCBWId6+q9h`dcN9H9h^t#xqEt)Mzo{kBg%j_>2||_Q>4s14T()` zbH3se|Mtv2%Dl4pL!eqV&_p>TXUW>SGKb-qWLP&<6sjN2LHp%H9ok&<>led$A2-s6K-I~w0*IDDKY z(-_o^v_{yi1i^K@tlraQP$YrCLe&WA#X-zqRy;n<>ZUT3dOh#JFY5C+2yAc zW%J^*i%$G>sg>7MSKRTD^eP^ksU|!q4yI_5DCI5lvIN#Q@I{<%&XMq9+(0s(qZ5rw=`BX4+IK6CG#<*eC&e%3p>IOWb<;5U`S(; zSs&-9X8y|S+LkkAAC62IxcquW8s(ZZF$K~touQ1Rlqp(AK7z`}ko9YG&bA)5+?m7Q zAF$S{q3e8E=XE`UqX*gU=VmLbj2vS;{tn}aL6O@P7o?R&1i+1vivs=jaBP+ux4AZ; zO>F*SIiS(1*or=Q#|3PzN@`g1Fi#B&IKfzR{->YXat86K5K@_lh+p6`NS?i}g=ZVP zpx%WdfoTfdg2)#92>jq9XWN9RBSoJRPfH}|cCCh2URy=V!A zO#-pnN(Y`MI!C$TQT?jJt6J2)2l)v0MK-Jb!Lnb@|%}|CGg_wF2(-ZFD;| zm?Oy}J#AE~ymyH>pP`6~aG7}i9^oPY0d6FsOCQ*<0@pTAc9ZEQD8~q*Zl6jz!i_P{ z)O>^Kux zecL384Sm4n3n&XJF%7y`dOq8#R(&9~ajNS+hu3EkDO<;0=4TjdJhDD|oAaJ2$FwJ2 zXDS*wi`>1miw)v1e2GA&*Y$%q>3I(2{PiVoy)T%2M6!GnhCh=%M7!ujep$=hc}T^N z2yV@erSW+?LedO&I_=ypdffx!d)+ZigaW+5yP%M>HnNx-<&>+P%c%*=Yo`DPIXI}#U0bWfU za$^7zM8ReCuM!$v{~7ncj4t_O)b}^FpJECB+TK&gx4!)1cBIl+2evQ77}-8ZM0X-i zgfV@NEW&+r=c`265R!jhv6$~#oI1e&_Z_S_{-2(?noJf4^WA532T!X5% z%}~|m#=nPjDKp0u_MSs~g)yuWzGQ(K9jgX0_}O=tIIy2=<}K1g9q^gPvt{O3l_&0Q zBNm<;s*+)B-R_disFYV)R5R*rXFm8dyc zI;S@3wOkTOi_!uR_lO@cBLg}~&m~)-SK5>2_7+5(t`+X~vM$P)>u#ly%0Zb# zg5HMEzSf)B%Lrb3gTdQ96Vv10%jWW&+dKO<320nq0cTbZzq`S#&~i5FeKh^x$C$F(tYNMG=GPZAMR zbIg(&>l*uwl|DvQyJF65oasoOmkFVnd`MvFhf7gdBqeA*zUNKL3PjF}$%>v{G1J-5 zc%%N_=w>R3T%V1sRtxd2xcr#a3$H z*_Enm?(tmzIDbXM>h~MTBZvSf6SXJA}V=l6wRJn8}_s@@U(};nqe)? zFA5^TJHq?kFS5?;&QkDxOtKS45baU&LeU(`d(Nx)LI7onX5|SRO4#{y$y3Xcy-bVS zM`Bd+cfMWxAp?A)V>La@lzvRHN(k)$h{wyWBWc=KhN#o)X#N*Qg4@d`_FiyyfgTJS zs0*)ct$%gzK%--sp>3{&@6lXe$NA}+WF?UtEXm7cCWXV9lVjW}e~FetD3YPcIqx!P z!G3&Qu6%0DWgx#Y_wgNxP1BVo4VawV9df^$*vjBYGZv6R5BVLyEHcr3^d1Ax>p4s8 z34!j}!CKtPlX^3g3JUe6AIMVEA~rmfPpOGiQR%n(vKUJnC5gN!O)V?YcTj2F<>lPQ z&L>T`1XCyjyrEtf3v4#mTCcpb?RnGTEiUI@u~uv0dX2{RC;?HlFaADj2 zRpJF-N__V)5&CVF*+s~!>q0N>XQS8@Uz0_SocA`hRKW}d)N%(DkVg`HJdRt{LG8!n zf93@KpMHM^Nv&uUt@j$vHBxy7C~%9@DghvObFMm`SB`YWL4WawqsU1PAz8@Z58pq& z&EC^GyqACNr&+#@Q;;E>S~^NtV=XxN96XYt#BYEjgXSl$9nkHd;Rw(5@jvqN8?U%7so6_}p5nH04I- zsPfZi`#g{emr?}-gdd9HQMzf4^YygDtFe2p&)p0t`*Gkyf#;kN`u=@e zT%OfNKY!RdVdn(vTdTLfSd`>^KAqR}ba$K?>XZ+W-G6I4^UO)nbV+U{nUL-aI;KF=Zs#BAJpx>?fF&WLQa+NM=&Q&^8>_w3ZoHSRQ?jcv{uLV zj{72Fg5LaYH9UMFG5$B{Il{WyNOBw?bzm9-8a{P33!4!u>~ewBfi`9#EfVM6LXr_W zmy{~^yr2VanGSs{kpX7FCtatgcuBS*{%c8cXfpm~uxPGo_`?F(7fEN`v$amV_Mf$w zzQ})CsoaK+OD5oQ_4CHuYlz4CQ9WV-l1j~oOXr1%Xh7k+Iu@Pg9LI7IWhcDyaQ7@# znD~O?U=ma_ng=RqjW~|6gi=o9Z)eItN$xOw6k1MMgvPhcj*aEy@pbZTCWpDGMyeg& zqL#NTeR7+6x^(?*i_6Vt2VGT|F;Kvb&4nySHa99hj~c*~OSMqS*PHEf!hxHlV-cjH ztQlz-vvv2z74u8NSOQ&dts5Y};$gCmsE_Q)4_m~3xPtAbw&^z#iQJNxLX^BXl2UPb>(Un>E;ucs5v(ZKZbp{jGfm^pj5E zwdM77AcIS2$xj~dQ*);It7>lh+}*LrapbCG-Q~jGCX;Tp5&>z^uj3D9g!UIQTh`&<{c!e%J`J+C^S+ zF~*DDrr(g`CR*RCFC3}piHIxVguA&XM$tBn0(BSw^ zG0DZ5iEd@*-Sg|`ElGA5G|Cyhj}vqI?Sk7ZFC&wUNCLwj(WY3O*@v~>)3#pG2IxZ1sl6AN)wr?O_!ECt0g#ulOzEM&{y3QsmtKE4H z1rf37G-u~FXZaL=X?3Orb0K$w8l~1KjP8k^7ir=pw8?;?L2tBeW9LCe!Yn4i$fBJf zxubKaJM3FEG%*#%oPxSnoGe zD7-%VP{NV^$(M{&@F_~Mj&rrKnF_7P=bDDQow|)~iw|AkziTb^{A!1FqSA|LzDL{T zWxFZ5{1m9IyYjX& z)n#spCNHtAlowijX@!>M291Z%Yf~Tm;QGP3^u}H;0h>W8iZK4vVEsm$imwnHu4-}} zh}@Bp>RDATn$J_O-S-5^Gw;vw6|JN+F;mSj1@$*JE}cS8-r+WqY>yow=$&4Xa^~y3 zxjRIrOj;aew2P43*~j6!1>4YgOStsQsxx1qR}%9+IpJ$l%U!DW=1`r2Zy&lkIR8x0 zdSZcjyJfwz&=tKSu-=4rw?oKEb!Kgj1D7_cl(YN!DZN2XH*+}ObEAMV`4Vv%v-L%b z1ez_{NU0&EkgypALY-Xx(A@BX+?fQWUZk;{DRd_u-8{SZOsL<1`HWNZ8*)Urv~?>9 zUBT%)E80e$0bHL%sW;I=Edi@THpklKVb2xOk1E%=f~2<(j>d{O7HJ~eC)gxZ zEtY(UiHhRLi}{%9x*GSPm(@A8v+qo=c1^nTW#fqQ;2fzF>WcQjL1q3#=#J~nXSI_G zf|ZIW^Qu=1dGdBuRy_@;=NGu2`$2`~B!Q)XZS3fFi8htl`ibOEm`_*UgcLaxLwxfTd!t-Rl9x=Dc( z?c9`{y3)6-5h+C`UrD%C9FCm0XviZ99mG*Niml5$*6$u(m$Q(YeR$nrgPW7@yxr2W zVfdl^$1-$fMqfSOSqRZkzt8x4qNIrly49JYTx%qgquYY^7^g#liZ7(vAJU! z?QBeeDg>vz9|g(NC7x>57FwcUUQa2sTZEo?&PY-c7BzQ1uul$Ch`dh&%=u%CT!H=@ zH$TcMG%^NrgqQ|ZzQ;t1-<+6^69l>)VY4!_PFu};duxX&dfE6ws4Zm`-_4(la9zya zFbw#^_mX0rYOU&fBJAQ$r`WdGzRg}7w3V~4BJAZ}n14QJ2B@}cN-&>2Pv;xCJ)yj8 z04ILUGeJUuL1zJgGp^gye)5h05{+b%@RI)aerZQ*#uR~%?==mJbCv7DWS_mxoxBz# z`LaVd!;WH$nD$G=p~#7Bs=Swe-T+>vD(kDkt?njX8WQq{nRmF|Gxn<0Kly0;QkuEu zNF`oQOeXdfiS~D;w-Cf}xCCm>+J9k3iM>+LT4gs%X-Q4&nrF*=i$GZsP?L}&uiJu8ikIuQ6Fj=kL{2>2yP5hdmuKwSOFnNm==e zf%NbAcaYG)!na~bAId6#P1LvmkhS8xA&A*0GCzgT#lej6IDT`m&kp+;%Y;el*px9S z4S9fEe@DE*kBbTV_-}2t`$sDZ+9>@>4IOX)b9^3BpzmdbR4*hBso7DNIoJ^p5fJJprgEO!2gaLuu!fWw+C$iSu767c=I!6!s&mlx0H z1T*=&AA+|pnQBkyBvD7DQfULk0<3Ij6Ouhv0asYhVft!V>_1EvN@{Krhde2IU?-Vg zfl$hOxnuErMXU8*l+r^yP92P!{Sxgu+WU3&ou|I;F@C4y^C?Z^q zd!Sz>Ze85=RYDCTejMVlApcoqoQ#766iicPr0WX?QqV703Ox9Ck^FEJ1fQ8_yBjv^ z6cI~|{r@8cwp|vN)#iNof0zRQ;er29;Qx3Elq-)>{+S^Et_Z#h@+%FNqXaJQ5dX=i zBDB{I#4ku(CGmWAFv7Qdh=9QTCexT*UveM<>E|msF4Hc8UNOLsw|14t`)^WITg8X3 zK}C6j^V?A+{+&Z;MxtZY;f7QDO?%o}q$YgYu)**=%cp=iiJ{$2EhJ>pQtOPM#9xv zQi+b!WZWj2U~r2qsI>g>g+~enR2dScFanK*9}YWfE1?QoviQY!lM`Qg(XBi)NZC<* z`;pr;(;sgF;t0FDBZ1#v{8d86M3HR7w=9&uVGw>Z&Cv4tTw;T6uGPeC$Hiatxa(IK zAC3}lYgZK_cRpwCT)k;3iI&A1G-^sA1Qu6O8lsY34XyC4Fy9J3JodZjoh)c zG1Va_=%R{zAi{T7>Wk$!ws|~1gu4BRo=rowRzo;40UU_D_!pFnh18ZCl4b~^{Il}#DFqj>>d;&JBUpNH*D|fOa>f3(s1!F;1 zN!wJi8{Pb5tycO7^W?w}YXUtdM;g8@F6y(8pu{102GEO}I0-P5NRkfdJHCTuZEB!< ziOpfP!j?IL`47RBZB`AY>cMI6*O&w_&%|qxeoSyZ{NXJfi~v+$a#ytWHBPEqUx7fn z(T-2zsSrZ?he<&Mw~XsW&fdN`MQ0s8&u3UEaexs%>{}3e(-)lH6Nkl7#8b@rE5hSd zjG2^bLMjhft6#~cM@gsI>%-oV-D@ihT|*Q)-l@IZ$d%}@s`|!N1a7c z+PkyEKZLYwn)|}Lr%st3qxr%+yn>eOQ{XFrPR!i`!_8H0*v7RkDtmJT9=BP(?vdM+7Z7`>I zGF33;S5<4fUYyo-Q*^$--t8n;c4gYJ#a55yBbPFwo4!i45W*;+5b}0W7Lt9%&w&9R zGr^{9y+fSJF!BoEX84mgac!Bi$eY+X8i?@l_OVLY*Qr76b2eDNFc>L0<4KgItbp-z zn61F06BvqQRge-3P!?C6Wh)9+vg0F#+S3`&gfee#zVnbw_KQXdcFQDt=#6Y#My*x8 zPSnl_6D=k$7Spg3g4p)S^f>6k8h;6!A$=_+%`n~kykWwWO)f+0=0#

obpV&=sVc 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 literal 0 HcmV?d00001 diff --git a/documentation20/webdocs/markdowndocs/replica-ch.md b/documentation20/webdocs/markdowndocs/replica-ch.md new file mode 100644 index 0000000000..20f06f814a --- /dev/null +++ b/documentation20/webdocs/markdowndocs/replica-ch.md @@ -0,0 +1,253 @@ +# TDengine 2.0 数据复制模块设计 + +## 数据复制概述 + +数据复制(Replication)是指同一份数据在多个物理地点保存。它的目的是防止数据丢失,提高系统的高可用性(High Availability),而且通过应用访问多个副本,提升数据查询性能。 + +在高可靠的大数据系统里,数据复制是必不可少的一大功能。数据复制又分为实时复制与非实时复制。实时复制是指任何数据的更新(包括数据的增加、删除、修改)操作,会被实时的复制到所有副本,这样任何一台机器宕机或网络出现故障,整个系统还能提供最新的数据,保证系统的正常工作。而非实时复制,是指传统的数据备份操作,按照固定的时间周期,将一份数据全量或增量复制到其他地方。如果主节点宕机,副本是很大可能没有最新数据,因此在有些场景是无法满足要求的。 + +TDengine面向的是物联网场景,需要支持数据的实时复制,来最大程度保证系统的可靠性。实时复制有两种方式,一种是异步复制,一种是同步复制。异步复制(Asynchronous Replication)是指数据由Master转发给Slave后,Master并不需要等待Slave回复确认,这种方式效率高,但有极小的概率会丢失数据。同步复制是指Master将数据转发给Slave后,需要等待Slave的回复确认,才会通知应用写入成功,这种方式效率偏低,但能保证数据绝不丢失。 + +数据复制是与数据存储(写入、读取)密切相关的,但两者又是相对独立,可以完全脱耦的。在TDengine系统中,有两种不同类型的数据,一种是时序数据,由TSDB模块负责;一种是元数据(Meta Data), 由MNODE负责。这两种性质不同的数据都需要同步功能。数据复制模块通过不同的实例启动配置参数,为这两种类型数据都提供同步功能。 + +在阅读本文之前,请先阅读《[TDengine 2.0 整体架构](https://jira.taosdata.com:18090/pages/viewpage.action?pageId=6270432)》,了解TDengine的集群设计和基本概念 + +特别注明:本文中提到数据更新操作包括数据的增加、删除与修改。 + +## 基本概念和定义 + +TDengine里存在vnode, mnode, vnode用来存储时序数据,mnode用来存储元数据。但从同步数据复制的模块来看,两者没有本质的区别,因此本文里的虚拟节点不仅包括vnode, 也包括mnode, vgoup也指mnode group, 除非特别注明。 + +**版本(version)**: + +一个虚拟节点组里多个虚拟节点互为备份,来保证数据的有效与可靠,是依靠虚拟节点组的数据版本号来维持的。TDengine2.0设计里,对于版本的定义如下:客户端发起增加、删除、修改的流程,无论是一条记录还是多条,只要是在一个请求里,这个数据更新请求被TDengine的一个虚拟节点收到后,经过合法性检查后,可以被写入系统时,就会被分配一个版本号。这个版本号在一个虚拟节点里从1开始,是单调连续递增的。无论这条记录是采集的时序数据还是meta data, 一样处理。当Master转发一个写入请求到slave时,必须带上版本号。一个虚拟节点将一数据更新请求写入WAL时,需要带上版本号。 + +不同虚拟节点组的数据版本号是完全独立的,互不相干的。版本号本质上是数据更新记录的transaction ID,但用来标识数据集的版本。 + +**角色(role)**: + +一个虚拟节点可以是master, slave, unsynced或offline状态。 + +- master: 具有最新的数据,容许客户端往里写入数据,一个虚拟节点组,至多一个master. +- slave:与master是同步的,但不容许客户端往里写入数据,根据配置,可以容许客户端对其进行查询。 +- unsynced: 节点处于非同步状态,比如虚拟节点刚启动、或与其他虚拟节点的连接出现故障等。处于该状态时,该虚拟节点既不能提供写入,也不能提供查询服务 +- offline: 由于宕机或网络原因,无法访问到某虚拟节点时,其他虚拟节点将该虚拟节点标为离线。但请注意,该虚拟节点本身的状态可能是unsynced或其他,但不会是离线。 + +**Quorum:** + +指数据写入成功所需要的确认数。对于异步复制,quorum设为1,具有master角色的虚拟节点自己确认即可。对于同步复制,需要至少大于等于2。原则上,Quorum >=1 并且 Quorum <= replication(副本数)。这个参数在启动一个同步模块实例时需要提供。 + +**WAL:** Write Ahead Log + +TDengine的WAL与cassandra的commit log, mySQL的bin log, Postgres的WAL没本质区别。没有写入数据库文件,还保存在内存的数据都会先存在WAL。当数据已经成功写入数据库数据文件,相应的WAL会被删除。但需要特别指明的是,在TDengine系统里,有几点: + +- 每个虚拟节点有自己独立的wal +- WAL里包含而且仅仅包含来自客户端的数据更新操作,每个更新操作都会被打上一个版本号 + +**复制实例:** + +复制模块只是一可执行的代码,复制实例是指正在运行的复制模块的一个实例,一个节点里,可以存在多个实例。原则上,一个节点有多少虚拟节点,就可以启动多少实例。对于副本数为1的场景,应用可以决定是否需要启动同步实例。应用启动一个同步模块的实例时,需要提供的就是虚拟节点组的配置信息,包括: + +- 虚拟节点个数,即replication number +- 各虚拟节点所在节点的信息,包括node的end point +- quorum, 需要的数据写入成功的确认数 +- 虚拟节点的初始版本号 + +## 数据复制模块的基本工作原理 + +TDengine采取的是Master-Slave模式进行同步,与流行的RAFT一致性算法比较一致。总结下来,有几点: + +1. 一个vgroup里有一到多个虚拟节点,每个虚拟节点都有自己的角色 +2. 客户端只能向角色是master的虚拟节点发起数据更新操作,因为master具有最新版本的数据,如果向非Master发起数据更新操作,会直接收到错误 +3. 客户端可以向master, 也可以向角色是Slave的虚拟节点发起查询操作,但不能对unsynced的虚拟节点发起任何操作 +4. 如果master不存在,这个vgroup是不能对外提供数据更新和查询服务的 +5. master收到客户端的数据更新操作时,会将其转发给slave节点 +6. 一个虚拟节点的版本号比master低的时候,会发起数据恢复流程,成功后,才会成为slave + +数据实时复制有三个主要流程:选主、数据转发、数据恢复。后续做详细讨论。 + +## 虚拟节点之间的网络链接 + +虚拟节点之间通过TCP进行链接,节点之间的状态交换、数据包的转发都是通过这个TCP链接(peerFd)进行。为避免竞争,两个虚拟节点之间的TCP链接,总是由IP地址(UINT32)小的节点作为TCP客户端发起。一旦TCP链接被中断,虚拟节点能通过TCP socket自动检测到,将对方标为offline。如果监测到任何错误(比如数据恢复流程),虚拟节点将主动重置该链接。 + +一旦作为客户端的节点链接不成或中断,它将周期性的每隔一秒钟去试图去链接一次。因为TCP本身有心跳机制,虚拟节点之间不再另行提供心跳。 + +如果一个unsynced节点要发起数据恢复流程,它与Master将建立起专有的TCP链接(syncFd)。数据恢复完成后,该链接会被关闭。而且为限制资源的使用,系统只容许一定数量(配置参数tsMaxSyncNum)的数据恢复的socket存在。如果超过这个数字,系统会将新的数据恢复请求延后处理。 + +任意一个节点,无论有多少虚拟节点,都会启动而且只会启动一个TCP server, 来接受来自其他虚拟节点的上述两类TCP的链接请求。当TCP socket建立起来,客户端侧发送的消息体里会带有vgId(全局唯一的vgroup ID), TCP 服务器侧会检查该vgId是否已经在该节点启动运行。如果已经启动运行,就接受其请求。如果不存在,就直接将链接请求关闭。在TDengine代码里,mnode group的vgId设置为1。 + +## 选主流程 + +当同一组的两个虚拟节点之间(vnode A, vnode B)建立连接后,他们互换status消息。status消息里包含本地存储的同一虚拟节点组内所有虚拟节点的role和version。 + +如果一个虚拟节点(vnode A)检测到与同一虚拟节点组内另外一虚拟节点(vnode B)的链接中断,vnode A将立即把vnode B的role设置为offline。无论是接收到另外一虚拟节点发来的status消息,还是检测与另外一虚拟节点的链接中断,该虚拟节点都将进入状态处理流程。状态处理流程的规则如下: + +1. 如果检测到在线的节点数没有超过一半,则将自己的状态设置为unsynced. +2. 如果在线的虚拟节点数超过一半,会检查master节点是否存在,如果存在,则会决定是否将自己状态改为slave或启动数据恢复流程 +3. 如果master不存在,则会检查自己保存的各虚拟节点的状态信息与从另一节点接收到的是否一致,如果一致,说明节点组里状态已经稳定一致,则会触发选举流程。如果不一致,说明状态还没趋于一致,即使master不存在,也不进行选主。由于要求状态信息一致才进行选举,每个虚拟节点根据同样的信息,会选出同一个虚拟节点做master,无需投票表决。 +4. 自己的状态是根据规则自己决定并修改的,并不需要其他节点同意,包括成为master。一个节点无权修改其他节点的状态。 +5. 如果一个虚拟节点检测到自己或其他虚拟节点的role发生改变,该节点会广播它自己保存的各个虚拟节点的状态信息(role和version). + +具体的流程图如下: + +

+ +选择Master的具体规则如下: + +1. 如果只有一个副本,该副本永远就是master +2. 所有副本都在线时,版本最高的被选为master +3. 在线的虚拟节点数过半,而且有虚拟节点是slave的话,该虚拟节点自动成为master +4. 对于2和3,如果多个虚拟节点满足成为master的要求,那么虚拟节点组的节点列表里,最前面的选为master + +按照上面的规则,如果所有虚拟节点都是unsynced(比如全部重启),只有所有虚拟节点上线,才能选出master,该虚拟节点组才能开始对外提供服务。当一个虚拟节点的role发生改变时,sync模块回通过回调函数notifyRole通知应用。 + +## 数据转发流程 + +如果vnode A是master, vnode B是slave, vnode A能接受客户端的写请求,而vnode B不能。当vnode A收到写的请求后,遵循下面的流程: + +
+ +1. 应用对写请求做基本的合法性检查,通过,则给改请求包打上一个版本号(version, 单调递增) +2. 应用将打上版本号的写请求封装一个WAL Head, 写入WAL(Write Ahead Log) +3. 应用调用API syncForwardToPeer,如多vnode B是slave状态,sync模块将包含WAL Head的数据包通过Forward消息发送给vnode B,否则就不转发。 +4. vnode B收到Forward消息后,调用回调函数writeToCache, 交给应用处理 +5. vnode B应用在写入成功后,都需要调用syncAckForward通知sync模块已经写入成功。 +6. 如果quorum大于1,vnode B需要等待应用的回复确认,收到确认后,vnode B发送Forward Response消息给node A。 +7. 如果quorum大于1,vnode A需要等待vnode B或其他副本对Forward消息的确认。 +8. 如果quorum大于1,vnode A收到quorum-1条确认消息后,调用回调函数confirmForward,通知应用写入成功。 +9. 如果quorum为1,上述6,7,8步不会发生。 +10. 如果要等待slave的确认,master会启动2秒的定时器(可配置),如果超时,则认为失败。 + +对于回复确认,sync模块提供的是异步回调函数,因此APP在调用syncForwardToPeer之后,无需等待,可以处理下一个操作。在Master与Slave的TCP链接管道里,可能有多个Forward消息,这些消息是严格按照应用提供的顺序排好的。对于Forward Response也是一样,TCP管道里存在多个,但都是排序好的。这个顺序,SYNC模块并没有做特别的事情,是由APP单线程顺序写来保证的(TDengine里每个vnode的写数据,都是单线程)。 + +## 数据恢复流程 + +如果一虚拟节点(vnode B) 处于unsynced状态,master存在(vnode A),而且其版本号比master的低,它将立即启动数据恢复流程。在理解恢复流程时,需要澄清几个关于文件的概念和处理规则。 + +1. 每个文件(无论是archived data的file还是wal)都有一个index, 这需要应用来维护(vnode里,该index就是fileId*3 + 0/1/2, 对应data, head与last三个文件)。如果index为0,表示系统里最老的数据文件。对于mnode里的文件,数量是固定的,对应于acct, user, db, table等文件。 +2. 任何一个数据文件(file)有名字、大小,还有一个magic number。只有文件名、大小与magic number一致时,两个文件才判断是一样的,无需同步。Magic number可以是checksum, 也可以是简单的文件大小。怎么计算magic,换句话说,如何检测数据文件是否有效,完全由应用决定。 +3. 文件名的处理有点复杂,因为每台服务器的路径可能不一致。比如node A的TDengine的数据文件存放在 /etc/taos目录下,而node B的数据存放在 /home/jhtao目录下。因此同步模块需要应用在启动一个同步实例时提供一个path,这样两台服务器的绝对路径可以不一样,但仍然可以做对比,做同步。 +4. 当sync模块调用回调函数getFileInfo获得数据文件信息时,有如下的规则 + 1. index 为0,表示获取最老的文件,同时修改index返回给sync模块。如果index不为0,表示获取指定位置的文件。 + 2. 如果name为空,表示sync想获取位于index位置的文件信息,包括magic, size。Master节点会这么调用 + 3. 如果name不为空,表示sync想获取指定文件名和index的信息,slave节点会这么调用 + 4. 如果某个index的文件不存在,magic返回0,表示文件已经是最后一个。因此整个系统里,文件的index必须是连续的一段整数。 +5. 当sync模块调用回调函数getWalInfo获得wal信息时,有如下规则 + 1. index为0,表示获得最老的WAL文件, 返回时,index更新为具体的数字 + 2. 如果返回0,表示这是最新的一个WAL文件,如果返回值是1,表示后面还有更新的WAL文件 + 3. 返回的文件名为空,那表示没有WAL文件 +6. 无论是getFileInfo, 还是getWalInfo, 只要获取出错(不是文件不存在),返回-1即可,系统会报错,停止同步 + +整个数据恢复流程分为两大步骤,第一步,先恢复archived data(file), 然后恢复wal。具体流程如下: + +
+ +1. 通过已经建立的TCP链接,发送sync req给master节点 +2. master收到sync req后,以client的身份,向vnode B主动建立一新的专用于同步的TCP链接(syncFd) +3. 新的TCP链接建立成功后,master将开始retrieve流程,对应的,vnode B将同步启动restore流程 +4. Retrieve/Restore流程里,先处理所有archived data (vnode里的data, head, last文件),后处理WAL data。 +5. 对于archived data,master将通过回调函数getFileInfo获取数据文件的基本信息,包括文件名、magic以及文件大小。 +6. master 将获得的文件名、magic以及文件大小发给vnode B +7. vnode B将回调函数getFile获得magic和文件大小,如果两者一致,就认为无需同步,如果两者不一致 ,就认为需要同步。vnode B将结果通过消息FileAck发回master +8. 如果文件需要同步,master就调用sendfile把整个文件发往vnode B +9. 如果文件不需要同步,master(vnode A)就重复5,6,7,8,直到所有文件被处理完 + +对于WAL同步,流程如下: + +1. master节点调用回调函数getWalInfo,获取WAL的文件名。 +2. 如果getWalInfo返回值大于0,表示该文件还不是最后一个WAL,因此master调用sendfile一下把该文件发送给vnode B +3. 如果getWalInfo返回时为0,表示该文件是最后一个WAL,因为文件可能还处于写的状态中,sync模块要根据WAL Head的定义逐条读出记录,然后发往vnode B。 +4. vnode A读取TCP链接传来的数据,按照WAL Head,逐条读取,如果版本号比现有的大,调用回调函数writeToCache,交给应用处理。如果小,直接扔掉。 +5. 上述流程循环,直到所有WAL文件都被处理完。处理完后,master就会将新来的数据包通过Forward消息转发给slave。 + +从同步文件启动起,sync模块会通过inotify监控所有处理过的file以及wal。一旦发现被处理过的文件有更新变化,同步流程将中止,会重新启动。因为有可能落盘操作正在进行(比如历史数据导入,内存数据落盘),把已经处理过的文件进行了修改,需要重新同步才行。 + +对于最后一个WAL (LastWal)的处理逻辑有点复杂,因为这个文件往往是打开写的状态,有很多场景需要考虑,比如: + +- LastWal文件size在增长,需要重新读; +- LastWal文件虽然已经打开写,但内容为空; +- LastWal文件已经被关闭,应用生成了新的Last WAL文件; +- LastWal文件没有被关闭,但数据落盘的原因,没有读到完整的一条记录; +- LastWal文件没有被关闭,但数据落盘的原因,还有部分记录暂时读取不到; + +sync模块通过inotify监控LastWal文件的更新和关闭操作。而且在确认已经尽可能读完LastWal的数据后,会将对方同步状态设置为SYNC_CACHE。该状态下,master节点会将新的记录转发给vnode B,而此时vnode B并没有完成同步,需要把这些转发包先存在recv buffer里,等WAL处理完后,vnode A再把recv buffer里的数据包通过回调writeToCache交给应用处理。 + +等vnode B把这些buffered forwards处理完,同步流程才算结束,vnode B正式变为slave。 + +## Master分布均匀性问题 + +因为Master负责写、转发,消耗的资源会更多,因此Master在整个集群里分布均匀比较理想。 + +但在TDengine的设计里,如果多个虚拟节点都符合master条件,TDengine选在列表中最前面的做Master, 这样是否导致在集群里,Master数量的分布不均匀问题呢?这取决于应用的设计。 + +给一个具体例子,系统里仅仅有三个节点,IP地址分别为IP1, IP2, IP3. 在各个节点上,TDengine创建了多个虚拟节点组,每个虚拟节点组都有三个副本。如果三个副本的顺序在所有虚拟节点组里都是IP1, IP2, IP3, 那毫无疑问,master将集中在IP1这个节点,这是我们不想看到的。 + +但是,如果在创建虚拟节点组时,增加随机性,这个问题就不存在了。比如在vgroup 1, 顺序是IP1, IP2, IP3, 在vgroup 2里,顺序是IP2, IP3, IP1, 在vgroup 3里,顺序是IP3, IP1, IP2。最后master的分布会是均匀的。 + +因此在创建一个虚拟节点组时,应用需要保证节点的顺序是round robin或完全随机。 + +## 少数虚拟节点写入成功的问题 + +在某种情况下,写入成功的确认数大于0,但小于配置的Quorum, 虽然有虚拟节点数据更新成功,master仍然会认为数据更新失败,并通知客户端写入失败。 + +这个时候,系统存在数据不一致的问题,因为有的虚拟节点已经写入成功,而有的写入失败。一个处理方式是,Master重置(reset)与其他虚拟节点的连接,该虚拟节点组将自动进入选举流程。按照规则,已经成功写入数据的虚拟节点将成为新的master,组内的其他虚拟节点将从master那里恢复数据。 + +因为写入失败,客户端会重新写入数据。但对于TDengine而言,是OK的。因为时序数据都是有时间戳的,时间戳相同的数据更新操作,第一次会执行,但第二次会自动扔掉。对于Meta Data(增加、删除库、表等等)的操作,也是OK的。一张表、库已经被创建或删除,再创建或删除,不会被执行的。 + +在TDengine的设计里,虚拟节点与虚拟节点之间,是一个TCP链接,是一个pipeline,数据块一个接一个按顺序在这个pipeline里等待处理。一旦某个数据块的处理失败,这个链接会被重置,后续的数据块的处理都会失败。因此不会存在Pipeline里一个数据块更新失败,但下一个数据块成功的可能。 + +## Split Brain的问题 + +选举流程中,有个强制要求,那就是一定有超过半数的虚拟节点在线。但是如果replication正好是偶数,这个时候,完全可能存在splt brain问题。 + +为解决这个问题,TDengine提供Arbitrator的解决方法。Arbitrator是一个节点,它的任务就是接受任何虚拟节点的链接请求,并保持它。 + +在启动复制模块实例时,在配置参数中,应用可以提供Arbitrator的IP地址。如果是奇数个副本,复制模块不会与这个arbitrator去建立链接,但如果是偶数个副本,就会主动去建立链接。 + +Arbitrator的程序tarbitrator.c在复制模块的同一目录, 编译整个系统时,会在bin目录生成。命令行参数“-?”查看可以配置的参数,比如绑定的IP地址,监听的端口号。 + +## 与RAFT相比的异同 + +数据一致性协议流行的有两种,Paxos与Raft. 本设计的实现与Raft有很多类同之处,下面做一些比较 + +相同之处: + +- 三大流程一致:Raft里有Leader election, replication, safety,完全对应TDengine的选举、数据转发、数据恢复三个流程 +- 节点状态定义一致:Raft里每个节点有Leader, Follower, Candidate三个状态,TDengine里是Master, Slave, Unsynced, Offline。多了一个offlince, 但本质上是一样的,因为offline是外界看一个节点的状态,但该节点本身是处于master, slave 或unsynced的 +- 数据转发流程完全一样,Master(leader)需要等待回复确认。 +- 数据恢复流程几乎一样,Raft没有涉及历史数据同步问题,只考虑了WAL数据同步 + +不同之处: + +- 选举流程不一样:Raft里任何一个节点是candidate时,主动向其他节点发出vote request, 如果超过半数回答Yes, 这个candidate就成为Leader,开始一个新的term. 而TDengine的实现里,节点上线、离线或角色改变都会触发状态消息在节点组类传播,等节点组里状态稳定一致之后才触发选举流程,因为状态稳定一致,基于同样的状态信息,每个节点做出的决定会是一致的,一旦某个节点符合成为master的条件,无需其他节点认可,它会自动将自己设为master。TDengine里,任何一个节点检测到其他节点或自己的角色发生改变,就会给节点组内其他节点进行广播的。Raft里不存在这样的机制,因此需要投票来解决。 +- 对WAL的一条记录,Raft用term + index来做唯一标识。但TDengine只用version(类似index),在TDengine实现里,仅仅用version是完全可行的, 因为TDengine的选举机制,没有term的概念。 + +如果整个虚拟节点组全部宕机,重启,但不是所有虚拟节点都上线,这个时候TDengine是不会选出master的,因为未上线的节点有可能有最高version的数据。而RAFT协议,只要超过半数上线,就会选出Leader。 + +## Meta Data数据复制问题 + +TDengine里存在时序数据,也存在Meta Data。Meta Data对数据的可靠性要求更高,那么本设计能否满足要求呢?下面做个仔细分析 + +TDengine里Meta Data包括以下: + +- account 信息 +- 一个account下面,可以有多个user, 多个DB +- 一个DB下面有多个vgroup +- 一个DB下面有多个stable +- 一个vgroup下面有多个table +- 整个系统有多个mnode, dnode +- 一个dnode可以有多个vnode + +上述的account, user, DB, vgroup, table, stable, mnode, dnode都有自己的属性,这些属性是TDengine自己定义的,不会开放给用户进行修改。这些Meta Data的查询都比较简单,都可以采用key-value模型进行存储。这些Meta Data还具有几个特点: + +1. 上述的Meta Data之间有一定的层级关系,比如必须先创建DB,才能创建table, stable。只有先创建dnode,才可能创建vnode, 才可能创建vgroup。因此他们创建的顺序是绝对不能错的。 +2. 在客户端应用的数据更新操作得到TDengine服务器侧确认后,所执行的数据更新操作绝对不能丢失。否则会造成客户端应用与服务器的数据不一致。 +3. 上述的Meta Data是容许重复操作的。比如插入新记录后,再插入一次,删除一次后,再删除一次,更新一次后,再更新一次,不会对系统产生任何影响,不会改变系统任何状态。 + +对于特点1,本设计里,数据的写入是单线程的,按照到达的先后顺序,给每个数据更新操作打上版本号,版本号大的记录一定是晚于版本号小的写入系统,数据写入顺序是100%保证的,绝对不会让版本号大的记录先写入。复制过程中,数据块的转发也是严格按照顺序进行的,因此TDengine的数据复制设计是能保证Meta Data的创建顺序的。 + +对于特点2,只要Quorum数设置等于replica,那么一定能保证回复确认过的数据更新操作不会在服务器侧丢失。即使某节点永不起来,只要超过一半的节点还是online, 查询服务不会受到任何影响。这时,如果某个节点离线超过一定时长,系统可以自动补充新的节点,以保证在线的节点数在绝大部分时间是100%的。 + +对于特点3,完全可能发生,服务器确实持久化存储了某一数据更新操作,但客户端应用出了问题,认为操作不成功,它会重新发起操作。但对于Meta Data而言,没有关系,客户端可以再次发起同样的操作,不会有任何影响。 + +总结来看,只要quorum设置大于一,本数据复制的设计是能满足Meta Data的需求的。目前,还没有发现漏洞。 \ No newline at end of file From 197b9d41d084218aa5acf07621db3297a1302809 Mon Sep 17 00:00:00 2001 From: Jeff Tao Date: Fri, 31 Jul 2020 09:11:29 +0000 Subject: [PATCH 21/56] minor changes --- documentation20/webdocs/markdowndocs/faq-ch.md | 14 +++++++------- documentation20/webdocs/markdowndocs/replica-ch.md | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/documentation20/webdocs/markdowndocs/faq-ch.md b/documentation20/webdocs/markdowndocs/faq-ch.md index 574e69ccd9..621bef73bc 100644 --- a/documentation20/webdocs/markdowndocs/faq-ch.md +++ b/documentation20/webdocs/markdowndocs/faq-ch.md @@ -5,19 +5,19 @@ 2.0版本在之前版本的基础上,进行了完全的重构,配置文件和数据文件是不兼容的。在升级之前务必进行如下操作: 1. 删除配置文件,执行 sudo rm -rf /etc/taos/taos.cfg - 2. 删除日志文件,执行 sudo rm -rf /var/log/taos/ - 3. 确保数据已经不再需要的前提下,删除数据文件,执行 sudo rm -rf /var/lib/taos/ - 4. 安装最新稳定版本的TDengine -5. 如果数据需要迁移数据或者数据文件损坏,请联系涛思数据官方技术支持团队,进行协助解决 +5. 如果数据需要迁移数据或者数据文件损坏,请联系涛思数据官方技术支持团队,进行协助解决 -#### 2.
Windows平台下JDBCDriver找不到动态链接库 +#### 2. Windows平台下JDBCDriver找不到动态链接库,怎么办? +请看为此问题撰写的技术博客 -#### 3. 创建数据表时提示more dnodes are needed +#### 3. 创建数据表时提示more dnodes are needed +请看为此问题撰写的技术博客 -#### 4. TDengine crash时生成core文件的方法 +#### 4. 如何让TDengine crash时生成core文件? +请看为此问题撰写的技术博客 #### 5. 遇到错误"failed to connect to server", 我怎么办? diff --git a/documentation20/webdocs/markdowndocs/replica-ch.md b/documentation20/webdocs/markdowndocs/replica-ch.md index 20f06f814a..e304371908 100644 --- a/documentation20/webdocs/markdowndocs/replica-ch.md +++ b/documentation20/webdocs/markdowndocs/replica-ch.md @@ -24,7 +24,7 @@ TDengine里存在vnode, mnode, vnode用来存储时序数据,mnode用来存储 不同虚拟节点组的数据版本号是完全独立的,互不相干的。版本号本质上是数据更新记录的transaction ID,但用来标识数据集的版本。 -**角色(role)**: +**角色(role):** 一个虚拟节点可以是master, slave, unsynced或offline状态。 @@ -37,9 +37,9 @@ TDengine里存在vnode, mnode, vnode用来存储时序数据,mnode用来存储 指数据写入成功所需要的确认数。对于异步复制,quorum设为1,具有master角色的虚拟节点自己确认即可。对于同步复制,需要至少大于等于2。原则上,Quorum >=1 并且 Quorum <= replication(副本数)。这个参数在启动一个同步模块实例时需要提供。 -**WAL:** Write Ahead Log +**WAL:** -TDengine的WAL与cassandra的commit log, mySQL的bin log, Postgres的WAL没本质区别。没有写入数据库文件,还保存在内存的数据都会先存在WAL。当数据已经成功写入数据库数据文件,相应的WAL会被删除。但需要特别指明的是,在TDengine系统里,有几点: +TDengine的WAL(Write Ahead Log)与cassandra的commit log, mySQL的bin log, Postgres的WAL没本质区别。没有写入数据库文件,还保存在内存的数据都会先存在WAL。当数据已经成功写入数据库数据文件,相应的WAL会被删除。但需要特别指明的是,在TDengine系统里,有几点: - 每个虚拟节点有自己独立的wal - WAL里包含而且仅仅包含来自客户端的数据更新操作,每个更新操作都会被打上一个版本号 From e40c875d84a7acaf5a284e492eaea4d33f2e93d1 Mon Sep 17 00:00:00 2001 From: Hui Li Date: Fri, 31 Jul 2020 17:15:15 +0800 Subject: [PATCH 22/56] [dynamic link libtaos.so] --- src/dnode/CMakeLists.txt | 3 ++- src/kit/shell/CMakeLists.txt | 8 ++++---- src/kit/taosdemo/CMakeLists.txt | 8 ++++---- src/kit/taosdump/CMakeLists.txt | 8 ++++---- src/plugins/http/CMakeLists.txt | 3 ++- src/plugins/monitor/CMakeLists.txt | 3 ++- src/plugins/mqtt/CMakeLists.txt | 3 ++- 7 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/dnode/CMakeLists.txt b/src/dnode/CMakeLists.txt index f7c2961352..64d69e9f01 100644 --- a/src/dnode/CMakeLists.txt +++ b/src/dnode/CMakeLists.txt @@ -16,7 +16,8 @@ IF ((TD_LINUX_64) OR (TD_LINUX_32 AND TD_ARM)) AUX_SOURCE_DIRECTORY(src SRC) ADD_EXECUTABLE(taosd ${SRC}) - TARGET_LINK_LIBRARIES(taosd mnode taos_static monitor http mqtt tsdb twal vnode cJson lz4 balance sync) +# TARGET_LINK_LIBRARIES(taosd mnode taos_static monitor http mqtt tsdb twal vnode cJson lz4 balance sync) + TARGET_LINK_LIBRARIES(taosd mnode taos monitor http mqtt tsdb twal vnode cJson lz4 balance sync) IF (TD_ACCOUNT) TARGET_LINK_LIBRARIES(taosd account) diff --git a/src/kit/shell/CMakeLists.txt b/src/kit/shell/CMakeLists.txt index 01c5f5ea3a..3695f694f3 100644 --- a/src/kit/shell/CMakeLists.txt +++ b/src/kit/shell/CMakeLists.txt @@ -15,11 +15,11 @@ IF ((TD_LINUX_64) OR (TD_LINUX_32 AND TD_ARM)) LIST(REMOVE_ITEM SRC ./src/shellDarwin.c) ADD_EXECUTABLE(shell ${SRC}) - IF (TD_PAGMODE_LITE) +# IF (TD_PAGMODE_LITE) TARGET_LINK_LIBRARIES(shell taos) - ELSE () - TARGET_LINK_LIBRARIES(shell taos_static) - ENDIF () +# ELSE () +# TARGET_LINK_LIBRARIES(shell taos_static) +# ENDIF () SET_TARGET_PROPERTIES(shell PROPERTIES OUTPUT_NAME taos) ELSEIF (TD_WINDOWS_64) diff --git a/src/kit/taosdemo/CMakeLists.txt b/src/kit/taosdemo/CMakeLists.txt index a1593ce5a1..5045e8cd3f 100644 --- a/src/kit/taosdemo/CMakeLists.txt +++ b/src/kit/taosdemo/CMakeLists.txt @@ -11,10 +11,10 @@ IF ((TD_LINUX_64) OR (TD_LINUX_32 AND TD_ARM)) AUX_SOURCE_DIRECTORY(. SRC) ADD_EXECUTABLE(taosdemo ${SRC}) - IF (TD_PAGMODE_LITE) +# IF (TD_PAGMODE_LITE) TARGET_LINK_LIBRARIES(taosdemo taos) - ELSE () - TARGET_LINK_LIBRARIES(taosdemo taos_static) - ENDIF () +# ELSE () +# TARGET_LINK_LIBRARIES(taosdemo taos_static) +# ENDIF () ENDIF () diff --git a/src/kit/taosdump/CMakeLists.txt b/src/kit/taosdump/CMakeLists.txt index 2a14dbfb4a..1c5dd3eda2 100644 --- a/src/kit/taosdump/CMakeLists.txt +++ b/src/kit/taosdump/CMakeLists.txt @@ -13,11 +13,11 @@ IF ((TD_LINUX_64) OR (TD_LINUX_32 AND TD_ARM)) AUX_SOURCE_DIRECTORY(. SRC) ADD_EXECUTABLE(taosdump ${SRC}) - IF (TD_PAGMODE_LITE) +# IF (TD_PAGMODE_LITE) TARGET_LINK_LIBRARIES(taosdump taos) - ELSE () - TARGET_LINK_LIBRARIES(taosdump taos_static) - ENDIF () +# ELSE () +# TARGET_LINK_LIBRARIES(taosdump taos_static) +# ENDIF () ENDIF () diff --git a/src/plugins/http/CMakeLists.txt b/src/plugins/http/CMakeLists.txt index 3280a37c94..4dbfde8ce6 100644 --- a/src/plugins/http/CMakeLists.txt +++ b/src/plugins/http/CMakeLists.txt @@ -14,7 +14,8 @@ IF ((TD_LINUX_64) OR (TD_LINUX_32 AND TD_ARM)) INCLUDE_DIRECTORIES(inc) AUX_SOURCE_DIRECTORY(src SRC) ADD_LIBRARY(http ${SRC}) - TARGET_LINK_LIBRARIES(http taos_static z) +# TARGET_LINK_LIBRARIES(http taos_static z) + TARGET_LINK_LIBRARIES(http taos z) IF (TD_ADMIN) TARGET_LINK_LIBRARIES(http admin) diff --git a/src/plugins/monitor/CMakeLists.txt b/src/plugins/monitor/CMakeLists.txt index 9a20286797..9b6cbfeef3 100644 --- a/src/plugins/monitor/CMakeLists.txt +++ b/src/plugins/monitor/CMakeLists.txt @@ -11,5 +11,6 @@ IF ((TD_LINUX_64) OR (TD_LINUX_32 AND TD_ARM)) INCLUDE_DIRECTORIES(inc) AUX_SOURCE_DIRECTORY(./src SRC) ADD_LIBRARY(monitor ${SRC}) - TARGET_LINK_LIBRARIES(monitor taos_static) +# TARGET_LINK_LIBRARIES(monitor taos_static) + TARGET_LINK_LIBRARIES(monitor taos) ENDIF () diff --git a/src/plugins/mqtt/CMakeLists.txt b/src/plugins/mqtt/CMakeLists.txt index 5fc8f9039f..929232cfe1 100644 --- a/src/plugins/mqtt/CMakeLists.txt +++ b/src/plugins/mqtt/CMakeLists.txt @@ -14,7 +14,8 @@ IF ((TD_LINUX_64) OR (TD_LINUX_32 AND TD_ARM)) INCLUDE_DIRECTORIES(inc) AUX_SOURCE_DIRECTORY(src SRC) ADD_LIBRARY(mqtt ${SRC}) - TARGET_LINK_LIBRARIES(mqtt taos_static cJson mqttc) +# TARGET_LINK_LIBRARIES(mqtt taos_static cJson mqttc) + TARGET_LINK_LIBRARIES(mqtt taos cJson mqttc) IF (TD_ADMIN) TARGET_LINK_LIBRARIES(mqtt admin cJson) From 3b1814425da7ea4efb04175e2fc93a05e3980bdc Mon Sep 17 00:00:00 2001 From: Xiaxin Li <48907085+Aries-Lee1991@users.noreply.github.com> Date: Fri, 31 Jul 2020 17:32:21 +0800 Subject: [PATCH 23/56] Update replica-ch.md --- documentation20/webdocs/markdowndocs/replica-ch.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation20/webdocs/markdowndocs/replica-ch.md b/documentation20/webdocs/markdowndocs/replica-ch.md index e304371908..ab9471d730 100644 --- a/documentation20/webdocs/markdowndocs/replica-ch.md +++ b/documentation20/webdocs/markdowndocs/replica-ch.md @@ -10,7 +10,7 @@ TDengine面向的是物联网场景,需要支持数据的实时复制,来最 数据复制是与数据存储(写入、读取)密切相关的,但两者又是相对独立,可以完全脱耦的。在TDengine系统中,有两种不同类型的数据,一种是时序数据,由TSDB模块负责;一种是元数据(Meta Data), 由MNODE负责。这两种性质不同的数据都需要同步功能。数据复制模块通过不同的实例启动配置参数,为这两种类型数据都提供同步功能。 -在阅读本文之前,请先阅读《[TDengine 2.0 整体架构](https://jira.taosdata.com:18090/pages/viewpage.action?pageId=6270432)》,了解TDengine的集群设计和基本概念 +在阅读本文之前,请先阅读《[TDengine 2.0 整体架构](https://www.taosdata.com/cn/documentation20/architecture/)》,了解TDengine的集群设计和基本概念 特别注明:本文中提到数据更新操作包括数据的增加、删除与修改。 @@ -250,4 +250,4 @@ TDengine里Meta Data包括以下: 对于特点3,完全可能发生,服务器确实持久化存储了某一数据更新操作,但客户端应用出了问题,认为操作不成功,它会重新发起操作。但对于Meta Data而言,没有关系,客户端可以再次发起同样的操作,不会有任何影响。 -总结来看,只要quorum设置大于一,本数据复制的设计是能满足Meta Data的需求的。目前,还没有发现漏洞。 \ No newline at end of file +总结来看,只要quorum设置大于一,本数据复制的设计是能满足Meta Data的需求的。目前,还没有发现漏洞。 From 062f9b8c31d1f0db0df0016bc07580e90806ed47 Mon Sep 17 00:00:00 2001 From: Jeff Tao Date: Fri, 31 Jul 2020 09:37:49 +0000 Subject: [PATCH 24/56] tune --- .../webdocs/markdowndocs/Documentation-ch.md | 187 +++++++++--------- 1 file changed, 99 insertions(+), 88 deletions(-) diff --git a/documentation20/webdocs/markdowndocs/Documentation-ch.md b/documentation20/webdocs/markdowndocs/Documentation-ch.md index b6dbad07dc..12b1b1bd3a 100644 --- a/documentation20/webdocs/markdowndocs/Documentation-ch.md +++ b/documentation20/webdocs/markdowndocs/Documentation-ch.md @@ -1,117 +1,128 @@ -#TDengine文档 +# TDengine文档 -TDengine是一个高效的存储、查询、分析时序大数据的平台,专为物联网、车联网、工业互联网、运维监测等优化而设计。您可以像使用关系型数据库MySQL一样来使用它,但建议您在使用前仔细阅读一遍下面的文档,特别是[数据模型](data-model-and-architecture)与数据建模一节。除本文档之外,欢迎[下载产品白皮书](https://www.taosdata.com/downloads/TDengine%20White%20Paper.pdf)。 +TDengine是一个高效的存储、查询、分析时序大数据的平台,专为物联网、车联网、工业互联网、运维监测等优化而设计。您可以像使用关系型数据库MySQL一样来使用它,但建议您在使用前仔细阅读一遍下面的文档,特别是[数据模型](https://www.taosdata.com/cn/documentation20/data-model-and-architecture)与[数据建模](https://www.taosdata.com/cn/documentation20/model)一节。除本文档之外,欢迎[下载产品白皮书](https://www.taosdata.com/downloads/TDengine White Paper.pdf)。如需查阅TDengine 1.6 文档,请点击[这里](https://www.taosdata.com/cn/documentation16/)访问。 + +## TDengine介绍 -##TDengine 介绍 - TDengine 简介及特色 - TDengine 适用场景 -- TDengine 性能指标介绍和验证方法 -##立即开始 -- 快捷安装:可通过源码、安装包或docker安装,三秒钟搞定 -- 轻松启动:使用systemctl 启停TDengine -- 命令行程序TAOS:访问TDengine的简便方式 -- [极速体验](https://www.taosdata.com/cn/getting-started/#TDengine-极速体验):运行示例程序,快速体验高效的数据插入、查询 +## [立即开始](https://www.taosdata.com/cn/getting-started) -##数据模型和整体架构 -- 数据模型:关系型数据库模型,但要求每个采集点单独建表 -- 集群与基本逻辑单元:吸取NoSQL优点,支持水平扩展,支持高可靠 -- 存储模型与数据分区:标签数据与时序数据完全分离,按vnode和时间两个维度对数据切分 -- 数据写入与复制流程:先写入WAL、之后写入缓存,再给应用确认,支持多副本 -- 缓存与持久化:最新数据缓存在内存中,但落盘时采用列式存储、超高压缩比 -- 高效查询:支持各种函数、时间轴聚合、插值、多表聚合 +- [快捷安装](https://www.taosdata.com/cn/documentation20/getting-started/#快捷安装):可通过源码、安装包或docker安装,三秒钟搞定 +- [轻松启动](https://www.taosdata.com/cn/documentation20/getting-started/#轻松启动):使用systemctl 启停TDengine +- [命令行程序TAOS](https://www.taosdata.com/cn/documentation20/getting-started/#TDengine命令行程序):访问TDengine的简便方式 +- [极速体验](https://www.taosdata.com/cn/documentation20/getting-started/#TDengine-极速体验):运行示例程序,快速体验高效的数据插入、查询 -##数据建模 -- 创建库:为具有相似数据特征的数据采集点创建一个库 -- 创建超级表:为同一类型的数据采集点创建一个超级表 -- 创建表:使用超级表做模板,为每一个具体的数据采集点单独建表 +## [数据模型和整体架构](https://www.taosdata.com/cn/documentation20/architecture) -##高效写入数据 -- SQL写入:使用SQL insert命令向一张或多张表写入单条或多条记录 -- Telegraf 写入:配置Telegraf, 不用任何代码,将采集数据直接写入 -- Prometheus写入:配置Prometheus, 不用任何代码,将数据直接写入 -- EMQ X Broker:配置EMQ X,不用任何代码,就可将MQTT数据直接写入 +- [数据模型](https://www.taosdata.com/cn/documentation20/architecture/#数据模型):关系型数据库模型,但要求每个采集点单独建表 +- [集群与基本逻辑单元](https://www.taosdata.com/cn/documentation20/architecture/#集群与基本逻辑单元):吸取NoSQL优点,支持水平扩展,支持高可靠 +- [存储模型与数据分区、分片](https://www.taosdata.com/cn/documentation20/architecture/#存储模型与数据分区、分片):标签数据与时序数据完全分离,按vnode和时间两个维度对数据切分 +- [数据写入与复制流程](https://www.taosdata.com/cn/documentation20/architecture/#数据写入与复制流程):先写入WAL、之后写入缓存,再给应用确认,支持多副本 +- [缓存与持久化](https://www.taosdata.com/cn/documentation20/architecture/#缓存与持久化):最新数据缓存在内存中,但落盘时采用列式存储、超高压缩比 +- [数据查询](https://www.taosdata.com/cn/documentation20/architecture/#数据查询):支持各种函数、时间轴聚合、插值、多表聚合 -##高效查询数据 -- 主要查询功能:支持各种标准函数,设置过滤条件,时间段查询 -- 多表聚合查询:使用超级表,设置标签过滤条件,进行高效聚合查询 -- 降采样查询:按时间段分段聚合,支持插值 +## [数据建模](https://www.taosdata.com/cn/documentation20/model) -##高级功能 -- 连续查询(Continuous Query):基于滑动窗口,定时自动的对数据流进行查询计算 -- 数据订阅(Publisher/Subscriber):象典型的消息队列,应用可订阅接收到的最新数据 -- [缓存 (Cache)](https://www.taosdata.com/cn/documentation/advanced-features/#缓存-(Cache)):每个设备最新的数据都会缓存在内存中,可快速获取 -- [报警监测(Alarm monitoring)](https://www.taosdata.com/blog/2020/04/14/1438.html/):根据配置规则,自动监测超限行为数据,并主动推送 +- [创建库](https://www.taosdata.com/cn/documentation20/model/#创建库):为具有相似数据特征的数据采集点创建一个库 +- [创建超级表](https://www.taosdata.com/cn/documentation20/model/#创建超级表):为同一类型的数据采集点创建一个超级表 +- [创建表](https://www.taosdata.com/cn/documentation20/model/#创建表):使用超级表做模板,为每一个具体的数据采集点单独建表 -##连接器 -- C/C++ Connector:通过libtaos客户端的库,连接TDengine服务器的主要方法 -- Java Connector(JDBC):通过标准的JDBC API,给Java应用提供到TDengine的连接 -- Python Connector:给Python应用提供一个连接TDengine服务器的驱动 -- RESTful Connector:提供一最简单的连接TDengine服务器的方式 -- Go Connector:给Go应用提供一个连接TDengine服务器的驱动 -- Node.js Connector:给node应用提供一个链接TDengine服务器的驱动 +## [高效写入数据](https://www.taosdata.com/cn/documentation20/insert) -##与其他工具的连接 -- Grafana:获取并可视化保存在TDengine的数据 -- Matlab:通过配置Matlab的JDBC数据源访问保存在TDengine的数据 -- R:通过配置R的JDBC数据源访问保存在TDengine的数据 +- [SQL写入](https://www.taosdata.com/cn/documentation20/insert/#SQL写入):使用SQL insert命令向一张或多张表写入单条或多条记录 +- [Telegraf写入](https://www.taosdata.com/cn/documentation20/insert/#Telegraf直接写入):配置Telegraf, 不用任何代码,将采集数据直接写入 +- [Prometheus写入](https://www.taosdata.com/cn/documentation20/insert/#Prometheus直接写入):配置Prometheus, 不用任何代码,将数据直接写入 +- [EMQ X Broker](https://www.taosdata.com/cn/documentation20/insert/#EMQ-X-Broker直接写入):配置EMQ X,不用任何代码,就可将MQTT数据直接写入 -## TDengine集群的安装、管理 +## [高效查询数据](https://www.taosdata.com/cn/documentation20/queries) -- 安装:与单节点的安装一样,但要设好配置文件里的参数first -- 节点管理:增加、删除、查看集群的节点 -- mnode的管理:系统自动创建、无需任何人工干预 -- 负载均衡:一旦节点个数或负载有变化,自动进行 -- 节点离线处理:节点离线超过一定时长,将从集群中剔除 -- Arbitrator:对于偶数个副本的情形,使用它可以防止split brain。 +- [主要查询功能](https://www.taosdata.com/cn/documentation20/queries/#主要查询功能):支持各种标准函数,设置过滤条件,时间段查询 +- [多表聚合查询](https://www.taosdata.com/cn/documentation20/queries/#多表聚合查询):使用超级表,设置标签过滤条件,进行高效聚合查询 +- [降采样查询值](https://www.taosdata.com/cn/documentation20/queries/#降采样查询、插值):按时间段分段聚合,支持插值 -##TDengine的运营和维护 +## [高级功能](https://www.taosdata.com/cn/documentation20/advanced-features) -- 容量规划:根据场景,估算硬件资源 -- 容错和灾备:设置正确的WAL和数据副本数 -- 系统配置:端口,缓存大小,文件块大小和其他系统配置 -- 用户管理:添加、删除TDengine用户,修改用户密码 -- 数据导入:可按脚本文件导入,也可按数据文件导入 -- 数据导出:从shell按表导出,也可用taosdump工具做各种导出 -- 系统监控:检查系统现有的连接、查询、流式计算,日志和事件等 -- 文件目录结构:TDengine数据文件、配置文件等所在目录 Hui Li +- [连续查询(Continuous Query)](https://www.taosdata.com/cn/documentation20/advanced-features/#连续查询(Continuous-Query)):基于滑动窗口,定时自动的对数据流进行查询计算 +- [数据订阅(Publisher/Subscriber)](https://www.taosdata.com/cn/documentation20/advanced-features/#数据订阅(Publisher/Subscriber)):象典型的消息队列,应用可订阅接收到的最新数据 +- [缓存(Cache)](https://www.taosdata.com/cn/documentation20/advanced-features/#缓存(Cache)):每个设备最新的数据都会缓存在内存中,可快速获取 +- [报警监测](https://www.taosdata.com/cn/documentation20/advanced-features/#报警监测(Alert)):根据配置规则,自动监测超限行为数据,并主动推送 -##TAOS SQL -- 支持的数据类型:支持时间戳、整型、浮点型、布尔型、字符型等多种数据类型 -- 数据库管理:添加、删除、查看数据库 -- 表管理:添加、删除、查看、修改表 -- 超级表管理:添加、删除、查看、修改超级表 -- 标签管理:增加、删除、修改标签 -- 数据写入:支持单表单条、多条、多表多条写入,支持历史数据写入 -- 数据查询:支持时间段、值过滤、排序、查询结果手动分页等 -- SQL函数:支持各种聚合函数、选择函数、计算函数,如avg, min, diff等 -- 时间维度聚合:将表中数据按照时间段进行切割后聚合,降维处理 +## [连接器](https://www.taosdata.com/cn/documentation20/connector) + +- [C/C++ Connector](https://www.taosdata.com/cn/documentation20/connector/#C/C++-Connector):通过libtaos客户端的库,连接TDengine服务器的主要方法 +- [Java Connector(JDBC)](https://www.taosdata.com/cn/documentation20/connector/#Java-Connector):通过标准的JDBC API,给Java应用提供到TDengine的连接 +- [Python Connector](https://www.taosdata.com/cn/documentation20/connector/#Python-Connector):给Python应用提供一个连接TDengine服务器的驱动 +- [RESTful Connector](https://www.taosdata.com/cn/documentation20/connector/#RESTful-Connector):提供一最简单的连接TDengine服务器的方式 +- [Go Connector](https://www.taosdata.com/cn/documentation20/connector/#Go-Connector):给Go应用提供一个连接TDengine服务器的驱动 +- [Node.js Connector](https://www.taosdata.com/cn/documentation20/connector/#Node.js-Connector):给node应用提供一个链接TDengine服务器的驱动 + +## [与其他工具的连接](https://www.taosdata.com/cn/documentation20/connections-with-other-tools) + +- [Grafana](https://www.taosdata.com/cn/documentation20/connections-with-other-tools/#Grafana):获取并可视化保存在TDengine的数据 +- [Matlab](https://www.taosdata.com/cn/documentation20/connections-with-other-tools/#Matlab):通过配置Matlab的JDBC数据源访问保存在TDengine的数据 +- [R](https://www.taosdata.com/cn/documentation20/connections-with-other-tools/#R):通过配置R的JDBC数据源访问保存在TDengine的数据 + +## [TDengine集群的安装、管理](https://www.taosdata.com/cn/documentation20/cluster) + +- [安装](https://www.taosdata.com/cn/documentation20/cluster/#创建第一个节点):与单节点的安装一样,但要设好配置文件里的参数first +- [节点管理](https://www.taosdata.com/cn/documentation20/cluster/#节点管理):增加、删除、查看集群的节点 +- [mnode的管理](https://www.taosdata.com/cn/documentation20/cluster/#Mnode的高可用):系统自动创建、无需任何人工干预 +- [负载均衡](https://www.taosdata.com/cn/documentation20/cluster/#负载均衡):一旦节点个数或负载有变化,自动进行 +- [节点离线处理](https://www.taosdata.com/cn/documentation20/cluster/#节点离线处理):节点离线超过一定时长,将从集群中剔除 +- [Arbitrator](https://www.taosdata.com/cn/documentation20/cluster/#Arbitrator的使用):对于偶数个副本的情形,使用它可以防止split brain + +## [TDengine的运营和维护](https://www.taosdata.com/cn/documentation20/administrator) + +- [容量规划](https://www.taosdata.com/cn/documentation20/administrator/#容量规划):根据场景,估算硬件资源 +- [容错和灾备](https://www.taosdata.com/cn/documentation20/administrator/#容错和灾备):设置正确的WAL和数据副本数 +- [系统配置](https://www.taosdata.com/cn/documentation20/administrator/#服务端配置):端口,缓存大小,文件块大小和其他系统配置 +- [用户管理](https://www.taosdata.com/cn/documentation20/administrator/#用户管理):添加、删除TDengine用户,修改用户密码 +- [数据导入](https://www.taosdata.com/cn/documentation20/administrator/#数据导入):可按脚本文件导入,也可按数据文件导入 +- [数据导出](https://www.taosdata.com/cn/documentation20/administrator/#数据导出):从shell按表导出,也可用taosdump工具做各种导出 +- [系统监控](https://www.taosdata.com/cn/documentation20/administrator/#系统监控):检查系统现有的连接、查询、流式计算,日志和事件等 +- [文件目录结构](https://www.taosdata.com/cn/documentation20/administrator/#文件目录结构):TDengine数据文件、配置文件等所在目录 + +## [TAOS SQL](https://www.taosdata.com/cn/documentation20/taos-sql) + +- [支持的数据类型](https://www.taosdata.com/cn/documentation20/taos-sql/#支持的数据类型):支持时间戳、整型、浮点型、布尔型、字符型等多种数据类型 +- [数据库管理](https://www.taosdata.com/cn/documentation20/taos-sql/#数据库管理):添加、删除、查看数据库 +- [表管理](https://www.taosdata.com/cn/documentation20/taos-sql/#表管理):添加、删除、查看、修改表 +- [超级表管理](https://www.taosdata.com/cn/documentation20/taos-sql/#超级表STable管理):添加、删除、查看、修改超级表 +- [标签管理](https://www.taosdata.com/cn/documentation20/taos-sql/#超级表-STable-中-TAG-管理):增加、删除、修改标签 +- [数据写入](https://www.taosdata.com/cn/documentation20/taos-sql/#数据写入):支持单表单条、多条、多表多条写入,支持历史数据写入 +- [数据查询](https://www.taosdata.com/cn/documentation20/taos-sql/#数据查询):支持时间段、值过滤、排序、查询结果手动分页等 +- [SQL函数](https://www.taosdata.com/cn/documentation20/taos-sql/#SQL函数):支持各种聚合函数、选择函数、计算函数,如avg, min, diff等 +- [时间维度聚合](https://www.taosdata.com/cn/documentation20/taos-sql/#时间维度聚合):将表中数据按照时间段进行切割后聚合,降维处理 + +## TDengine的技术设计 -##TDengine的技术设计 - 系统模块:taosd的功能和模块划分 -- 技术博客:更多的技术分析和架构设计文章 +- 数据复制:支持实时同步、异步复制,保证系统的High Availibility +- [技术博客](https://www.taosdata.com/cn/blog/?categories=3):更多的技术分析和架构设计文章 ## 常用工具 -- [TDengine样例数据导入工具](https://www.taosdata.com/cn/documentation/blog/2020/01/18/如何快速验证性能和主要功能?tdengine样例数据导入工/) -- [TDengine性能对比测试工具](https://www.taosdata.com/cn/documentation/blog/2020/01/13/用influxdb开源的性能测试工具对比influxdb和tdengine/) +- [TDengine样例导入工具](https://www.taosdata.com/blog/2020/01/18/1166.html) +- [TDengine性能对比测试工具](https://www.taosdata.com/blog/2020/01/18/1166.html) -##TDengine与其他数据库的对比测试 +## TDengine与其他数据库的对比测试 -- [用InfluxDB开源的性能测试工具对比InfluxDB和TDengine](https://www.taosdata.com/cn/documentation/blog/2020/01/13/用influxdb开源的性能测试工具对比influxdb和tdengine/) -- [TDengine与OpenTSDB对比测试](https://www.taosdata.com/cn/documentation/blog/2019/08/21/tdengine与opentsdb对比测试/) -- [TDengine与Cassandra对比测试](https://www.taosdata.com/cn/documentation/blog/2019/08/14/tdengine与cassandra对比测试/) -- [TDengine与InfluxDB对比测试](https://www.taosdata.com/cn/documentation/blog/2019/07/19/tdengine与influxdb对比测试/) +- [用InfluxDB开源的性能测试工具对比InfluxDB和TDengine](https://www.taosdata.com/blog/2020/01/13/1105.html) +- [TDengine与OpenTSDB对比测试](https://www.taosdata.com/blog/2019/08/21/621.html) +- [TDengine与Cassandra对比测试](https://www.taosdata.com/blog/2019/08/14/573.html) +- [TDengine与InfluxDB对比测试](https://www.taosdata.com/blog/2019/07/19/419.html) - [TDengine与InfluxDB、OpenTSDB、Cassandra、MySQL、ClickHouse等数据库的对比测试报告](https://www.taosdata.com/downloads/TDengine_Testing_Report_cn.pdf) ##物联网大数据 -- [物联网、工业互联网大数据的特点](https://www.taosdata.com/blog/2019/07/09/物联网、工业互联网大数据的特点/) -- [物联网大数据平台应具备的功能和特点](https://www.taosdata.com/blog/2019/07/29/物联网大数据平台应具备的功能和特点/) -- [通用大数据架构为什么不适合处理物联网数据?](https://www.taosdata.com/blog/2019/07/09/通用互联网大数据处理架构为什么不适合处理物联/) -- [物联网、车联网、工业互联网大数据平台,为什么推荐使用TDengine?](https://www.taosdata.com/blog/2019/07/09/物联网、车联网、工业互联网大数据平台,为什么/) -##培训和FAQ -- FAQ:常见问题与答案 -- 应用案列:一些使用实例来解释如何使用TDengine +- [物联网、工业互联网大数据的特点](https://www.taosdata.com/blog/2019/07/09/105.html) +- [物联网大数据平台应具备的功能和特点](https://www.taosdata.com/blog/2019/07/29/542.html) +- [通用大数据架构为什么不适合处理物联网数据?](https://www.taosdata.com/blog/2019/07/09/107.html) +- [物联网、车联网、工业互联网大数据平台,为什么推荐使用TDengine?](https://www.taosdata.com/blog/2019/07/09/109.html) - \ No newline at end of file +## [培训和FAQ](https://www.taosdata.com/cn/faq) + +- [FAQ](https://www.taosdata.com/cn/documentation20/faq):常见问题与答案 +- [应用案列](https://www.taosdata.com/cn/blog/?categories=4):一些使用实例来解释如何使用TDengine \ No newline at end of file From 4878d145be8368dbc751b7760c5936be4ff73ea8 Mon Sep 17 00:00:00 2001 From: Xiaxin Li <48907085+Aries-Lee1991@users.noreply.github.com> Date: Fri, 31 Jul 2020 17:43:39 +0800 Subject: [PATCH 25/56] Update replica-ch.md --- documentation20/webdocs/markdowndocs/replica-ch.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation20/webdocs/markdowndocs/replica-ch.md b/documentation20/webdocs/markdowndocs/replica-ch.md index ab9471d730..98310ca8b7 100644 --- a/documentation20/webdocs/markdowndocs/replica-ch.md +++ b/documentation20/webdocs/markdowndocs/replica-ch.md @@ -10,7 +10,7 @@ TDengine面向的是物联网场景,需要支持数据的实时复制,来最 数据复制是与数据存储(写入、读取)密切相关的,但两者又是相对独立,可以完全脱耦的。在TDengine系统中,有两种不同类型的数据,一种是时序数据,由TSDB模块负责;一种是元数据(Meta Data), 由MNODE负责。这两种性质不同的数据都需要同步功能。数据复制模块通过不同的实例启动配置参数,为这两种类型数据都提供同步功能。 -在阅读本文之前,请先阅读《[TDengine 2.0 整体架构](https://www.taosdata.com/cn/documentation20/architecture/)》,了解TDengine的集群设计和基本概念 +在阅读本文之前,请先阅读《TDengine 2.0 整体架构》,了解TDengine的集群设计和基本概念 特别注明:本文中提到数据更新操作包括数据的增加、删除与修改。 From 59a3b682b375b3e4dc017fa94fa33b7a2d9402bf Mon Sep 17 00:00:00 2001 From: Xiaxin Li <48907085+Aries-Lee1991@users.noreply.github.com> Date: Fri, 31 Jul 2020 17:50:22 +0800 Subject: [PATCH 26/56] alter the file alter the file --- .../webdocs/markdowndocs/Evaluation-ch.md | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/documentation20/webdocs/markdowndocs/Evaluation-ch.md b/documentation20/webdocs/markdowndocs/Evaluation-ch.md index 411cb2dfb9..3aa596f76b 100644 --- a/documentation20/webdocs/markdowndocs/Evaluation-ch.md +++ b/documentation20/webdocs/markdowndocs/Evaluation-ch.md @@ -22,36 +22,36 @@ TDengine的模块之一是时序数据库。但除此之外,为减少研发的 |数据源特点和需求|不适用|可能适用|非常适用|简单说明| |---|---|---|---|---| -|总体数据量巨大| | | ✅ |TDengine在容量方面提供出色的水平扩展功能,并且具备匹配高压缩的存储结构和多级存储,达到业界最优的存储效率。| -|数据输入速度偶尔或者持续巨大| | | ✅ | TDengine的性能大大超过同类产品,可以在同样的硬件环境下持续处理大量的输入数据,并且提供很容易在用户环境里面运行的性能评估工具。| -|数据源数目巨大| | | ✅ |TDengine设计中包含专门针对大量数据源的优化,包括数据的写入和查询,尤其适合高效处理海量(千万或者更多量级)的数据源。| +|总体数据量巨大| | | √ |TDengine在容量方面提供出色的水平扩展功能,并且具备匹配高压缩的存储结构和多级存储,达到业界最优的存储效率。| +|数据输入速度偶尔或者持续巨大| | | √ | TDengine的性能大大超过同类产品,可以在同样的硬件环境下持续处理大量的输入数据,并且提供很容易在用户环境里面运行的性能评估工具。| +|数据源数目巨大| | | √ |TDengine设计中包含专门针对大量数据源的优化,包括数据的写入和查询,尤其适合高效处理海量(千万或者更多量级)的数据源。| ###系统架构要求 |系统架构要求|不适用|可能适用|非常适用|简单说明| |---|---|---|---|---| -|要求简单可靠的系统架构| | | ✅ |TDengine的系统架构非常简单可靠,自带消息队列,缓存,流式计算,监控等功能,无需集成额外的第三方产品。| -|要求容错和高可靠| | | ✅ |TDengine的集群功能,自动提供容错灾备等高可靠功能| -|标准化规范| | | ✅ |TDengine使用标准的SQL语言提供主要功能,遵守标准化规范| +|要求简单可靠的系统架构| | | √ |TDengine的系统架构非常简单可靠,自带消息队列,缓存,流式计算,监控等功能,无需集成额外的第三方产品。| +|要求容错和高可靠| | | √ |TDengine的集群功能,自动提供容错灾备等高可靠功能| +|标准化规范| | | √ |TDengine使用标准的SQL语言提供主要功能,遵守标准化规范| ###系统功能需求 |系统功能需求|不适用|可能适用|非常适用|简单说明| |---|---|---|---|---| -|要求完整的内置数据处理算法| | ✅ | |TDengine的实现了通用的数据处理算法,但是还没有做到妥善处理各行各业的所有要求,因此特殊类型的处理还需要应用层面处理。| -|需要大量的交叉查询处理| | ✅ | |这种类型的处理更多应该用关系型数据系统处理,或者应该考虑TDengine和关系型数据系统配合实现系统功能| +|要求完整的内置数据处理算法| | √ | |TDengine的实现了通用的数据处理算法,但是还没有做到妥善处理各行各业的所有要求,因此特殊类型的处理还需要应用层面处理。| +|需要大量的交叉查询处理| | √ | |这种类型的处理更多应该用关系型数据系统处理,或者应该考虑TDengine和关系型数据系统配合实现系统功能| ###系统性能需求 |系统性能需求|不适用|可能适用|非常适用|简单说明| |---|---|---|---|---| -|要求较大的总体处理能力| | | ✅ |TDengine的集群功能可以轻松地让多服务器配合达成处理能力的提升。| -|要求高速处理数据 | | | ✅ |TDengine的专门为IOT优化的存储和数据处理的设计,一般可以让系统得到超出同类产品多倍数的处理速度提升。| -|要求快速处理小粒度数据| | | ✅ |这方面TDengine性能可以完全对标关系型和NoSQL型数据处理系统。| +|要求较大的总体处理能力| | | √ |TDengine的集群功能可以轻松地让多服务器配合达成处理能力的提升。| +|要求高速处理数据 | | | √ |TDengine的专门为IOT优化的存储和数据处理的设计,一般可以让系统得到超出同类产品多倍数的处理速度提升。| +|要求快速处理小粒度数据| | | √ |这方面TDengine性能可以完全对标关系型和NoSQL型数据处理系统。| ###系统维护需求 |系统维护需求|不适用|可能适用|非常适用|简单说明| |---|---|---|---|---| -|要求系统可靠运行| | | ✅ |TDengine的系统架构非常稳定可靠,日常维护也简单便捷,对维护人员的要求简洁明了,最大程度上杜绝人为错误和事故。| -|要求运维学习成本可控| | | ✅ |同上| -|要求市场有大量人才储备| ✅ | | |TDengine作为新一代产品,目前人才市场里面有经验的人员还有限。但是学习成本低,我们作为厂家也提供运维的培训和辅助服务| +|要求系统可靠运行| | | √ |TDengine的系统架构非常稳定可靠,日常维护也简单便捷,对维护人员的要求简洁明了,最大程度上杜绝人为错误和事故。| +|要求运维学习成本可控| | | √ |同上| +|要求市场有大量人才储备| √ | | |TDengine作为新一代产品,目前人才市场里面有经验的人员还有限。但是学习成本低,我们作为厂家也提供运维的培训和辅助服务| ##TDengine 性能指标介绍和验证方法 From 4c0ae319ad5a2846e4db2cd79e79f61b9196e8aa Mon Sep 17 00:00:00 2001 From: Xiaxin Li <48907085+Aries-Lee1991@users.noreply.github.com> Date: Fri, 31 Jul 2020 17:55:51 +0800 Subject: [PATCH 27/56] Add files via upload --- .../webdocs/markdowndocs/Evaluation-ch.md | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/documentation20/webdocs/markdowndocs/Evaluation-ch.md b/documentation20/webdocs/markdowndocs/Evaluation-ch.md index 3aa596f76b..c71651a3b1 100644 --- a/documentation20/webdocs/markdowndocs/Evaluation-ch.md +++ b/documentation20/webdocs/markdowndocs/Evaluation-ch.md @@ -22,36 +22,36 @@ TDengine的模块之一是时序数据库。但除此之外,为减少研发的 |数据源特点和需求|不适用|可能适用|非常适用|简单说明| |---|---|---|---|---| -|总体数据量巨大| | | √ |TDengine在容量方面提供出色的水平扩展功能,并且具备匹配高压缩的存储结构和多级存储,达到业界最优的存储效率。| -|数据输入速度偶尔或者持续巨大| | | √ | TDengine的性能大大超过同类产品,可以在同样的硬件环境下持续处理大量的输入数据,并且提供很容易在用户环境里面运行的性能评估工具。| -|数据源数目巨大| | | √ |TDengine设计中包含专门针对大量数据源的优化,包括数据的写入和查询,尤其适合高效处理海量(千万或者更多量级)的数据源。| +|总体数据量巨大| | | R |TDengine在容量方面提供出色的水平扩展功能,并且具备匹配高压缩的存储结构和多级存储,达到业界最优的存储效率。| +|数据输入速度偶尔或者持续巨大| | | R | TDengine的性能大大超过同类产品,可以在同样的硬件环境下持续处理大量的输入数据,并且提供很容易在用户环境里面运行的性能评估工具。| +|数据源数目巨大| | | R |TDengine设计中包含专门针对大量数据源的优化,包括数据的写入和查询,尤其适合高效处理海量(千万或者更多量级)的数据源。| ###系统架构要求 |系统架构要求|不适用|可能适用|非常适用|简单说明| |---|---|---|---|---| -|要求简单可靠的系统架构| | | √ |TDengine的系统架构非常简单可靠,自带消息队列,缓存,流式计算,监控等功能,无需集成额外的第三方产品。| -|要求容错和高可靠| | | √ |TDengine的集群功能,自动提供容错灾备等高可靠功能| -|标准化规范| | | √ |TDengine使用标准的SQL语言提供主要功能,遵守标准化规范| +|要求简单可靠的系统架构| | | R |TDengine的系统架构非常简单可靠,自带消息队列,缓存,流式计算,监控等功能,无需集成额外的第三方产品。| +|要求容错和高可靠| | | R |TDengine的集群功能,自动提供容错灾备等高可靠功能| +|标准化规范| | | R |TDengine使用标准的SQL语言提供主要功能,遵守标准化规范| ###系统功能需求 |系统功能需求|不适用|可能适用|非常适用|简单说明| |---|---|---|---|---| -|要求完整的内置数据处理算法| | √ | |TDengine的实现了通用的数据处理算法,但是还没有做到妥善处理各行各业的所有要求,因此特殊类型的处理还需要应用层面处理。| -|需要大量的交叉查询处理| | √ | |这种类型的处理更多应该用关系型数据系统处理,或者应该考虑TDengine和关系型数据系统配合实现系统功能| +|要求完整的内置数据处理算法| | R | |TDengine的实现了通用的数据处理算法,但是还没有做到妥善处理各行各业的所有要求,因此特殊类型的处理还需要应用层面处理。| +|需要大量的交叉查询处理| | R | |这种类型的处理更多应该用关系型数据系统处理,或者应该考虑TDengine和关系型数据系统配合实现系统功能| ###系统性能需求 |系统性能需求|不适用|可能适用|非常适用|简单说明| |---|---|---|---|---| -|要求较大的总体处理能力| | | √ |TDengine的集群功能可以轻松地让多服务器配合达成处理能力的提升。| -|要求高速处理数据 | | | √ |TDengine的专门为IOT优化的存储和数据处理的设计,一般可以让系统得到超出同类产品多倍数的处理速度提升。| -|要求快速处理小粒度数据| | | √ |这方面TDengine性能可以完全对标关系型和NoSQL型数据处理系统。| +|要求较大的总体处理能力| | | R |TDengine的集群功能可以轻松地让多服务器配合达成处理能力的提升。| +|要求高速处理数据 | | | R |TDengine的专门为IOT优化的存储和数据处理的设计,一般可以让系统得到超出同类产品多倍数的处理速度提升。| +|要求快速处理小粒度数据| | | R |这方面TDengine性能可以完全对标关系型和NoSQL型数据处理系统。| ###系统维护需求 |系统维护需求|不适用|可能适用|非常适用|简单说明| |---|---|---|---|---| -|要求系统可靠运行| | | √ |TDengine的系统架构非常稳定可靠,日常维护也简单便捷,对维护人员的要求简洁明了,最大程度上杜绝人为错误和事故。| -|要求运维学习成本可控| | | √ |同上| -|要求市场有大量人才储备| √ | | |TDengine作为新一代产品,目前人才市场里面有经验的人员还有限。但是学习成本低,我们作为厂家也提供运维的培训和辅助服务| +|要求系统可靠运行| | | R |TDengine的系统架构非常稳定可靠,日常维护也简单便捷,对维护人员的要求简洁明了,最大程度上杜绝人为错误和事故。| +|要求运维学习成本可控| | | R |同上| +|要求市场有大量人才储备| R | | |TDengine作为新一代产品,目前人才市场里面有经验的人员还有限。但是学习成本低,我们作为厂家也提供运维的培训和辅助服务| ##TDengine 性能指标介绍和验证方法 From 8310bbc81990a4941266dfa83df878205ec456a0 Mon Sep 17 00:00:00 2001 From: Hongze Cheng Date: Fri, 31 Jul 2020 18:10:25 +0800 Subject: [PATCH 28/56] Fix last file info update bug --- src/tsdb/src/tsdbMemTable.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/tsdb/src/tsdbMemTable.c b/src/tsdb/src/tsdbMemTable.c index d5e90bcd60..5fb294fdce 100644 --- a/src/tsdb/src/tsdbMemTable.c +++ b/src/tsdb/src/tsdbMemTable.c @@ -574,6 +574,7 @@ static int tsdbCommitToFile(STsdbRepo *pRepo, int fid, SCommitIter *iters, SRWHe STsdbFileH *pFileH = pRepo->tsdbFileH; SFileGroup *pGroup = NULL; SMemTable * pMem = pRepo->imem; + bool newLast = false; TSKEY minKey = 0, maxKey = 0; tsdbGetFidKeyRange(pCfg->daysPerFile, pCfg->precision, fid, &minKey, &maxKey); @@ -603,6 +604,8 @@ static int tsdbCommitToFile(STsdbRepo *pRepo, int fid, SCommitIter *iters, SRWHe goto _err; } + newLast = TSDB_NLAST_FILE_OPENED(pHelper); + if (tsdbLoadCompIdx(pHelper, NULL) < 0) { tsdbError("vgId:%d failed to load SCompIdx part since %s", REPO_ID(pRepo), tstrerror(terrno)); goto _err; @@ -665,8 +668,12 @@ static int tsdbCommitToFile(STsdbRepo *pRepo, int fid, SCommitIter *iters, SRWHe rename(helperNewHeadF(pHelper)->fname, helperHeadF(pHelper)->fname); pGroup->files[TSDB_FILE_TYPE_HEAD].info = helperNewHeadF(pHelper)->info; - rename(helperNewLastF(pHelper)->fname, helperLastF(pHelper)->fname); - pGroup->files[TSDB_FILE_TYPE_LAST].info = helperNewLastF(pHelper)->info; + if (newLast) { + rename(helperNewLastF(pHelper)->fname, helperLastF(pHelper)->fname); + pGroup->files[TSDB_FILE_TYPE_LAST].info = helperNewLastF(pHelper)->info; + } else { + pGroup->files[TSDB_FILE_TYPE_LAST].info = helperLastF(pHelper)->info; + } pGroup->files[TSDB_FILE_TYPE_DATA].info = helperDataF(pHelper)->info; From 07065e76de599d5c710f220e18ebba8f8cb15d70 Mon Sep 17 00:00:00 2001 From: Xiaxin Li <48907085+Aries-Lee1991@users.noreply.github.com> Date: Fri, 31 Jul 2020 18:20:37 +0800 Subject: [PATCH 29/56] Add files via upload --- .../webdocs/markdowndocs/Evaluation-ch.md | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/documentation20/webdocs/markdowndocs/Evaluation-ch.md b/documentation20/webdocs/markdowndocs/Evaluation-ch.md index c71651a3b1..859653d20e 100644 --- a/documentation20/webdocs/markdowndocs/Evaluation-ch.md +++ b/documentation20/webdocs/markdowndocs/Evaluation-ch.md @@ -22,36 +22,36 @@ TDengine的模块之一是时序数据库。但除此之外,为减少研发的 |数据源特点和需求|不适用|可能适用|非常适用|简单说明| |---|---|---|---|---| -|总体数据量巨大| | | R |TDengine在容量方面提供出色的水平扩展功能,并且具备匹配高压缩的存储结构和多级存储,达到业界最优的存储效率。| -|数据输入速度偶尔或者持续巨大| | | R | TDengine的性能大大超过同类产品,可以在同样的硬件环境下持续处理大量的输入数据,并且提供很容易在用户环境里面运行的性能评估工具。| -|数据源数目巨大| | | R |TDengine设计中包含专门针对大量数据源的优化,包括数据的写入和查询,尤其适合高效处理海量(千万或者更多量级)的数据源。| +|总体数据量巨大| | | · |TDengine在容量方面提供出色的水平扩展功能,并且具备匹配高压缩的存储结构和多级存储,达到业界最优的存储效率。| +|数据输入速度偶尔或者持续巨大| | | · | TDengine的性能大大超过同类产品,可以在同样的硬件环境下持续处理大量的输入数据,并且提供很容易在用户环境里面运行的性能评估工具。| +|数据源数目巨大| | | · |TDengine设计中包含专门针对大量数据源的优化,包括数据的写入和查询,尤其适合高效处理海量(千万或者更多量级)的数据源。| ###系统架构要求 |系统架构要求|不适用|可能适用|非常适用|简单说明| |---|---|---|---|---| -|要求简单可靠的系统架构| | | R |TDengine的系统架构非常简单可靠,自带消息队列,缓存,流式计算,监控等功能,无需集成额外的第三方产品。| -|要求容错和高可靠| | | R |TDengine的集群功能,自动提供容错灾备等高可靠功能| -|标准化规范| | | R |TDengine使用标准的SQL语言提供主要功能,遵守标准化规范| +|要求简单可靠的系统架构| | | · |TDengine的系统架构非常简单可靠,自带消息队列,缓存,流式计算,监控等功能,无需集成额外的第三方产品。| +|要求容错和高可靠| | | · |TDengine的集群功能,自动提供容错灾备等高可靠功能| +|标准化规范| | | · |TDengine使用标准的SQL语言提供主要功能,遵守标准化规范| ###系统功能需求 |系统功能需求|不适用|可能适用|非常适用|简单说明| |---|---|---|---|---| -|要求完整的内置数据处理算法| | R | |TDengine的实现了通用的数据处理算法,但是还没有做到妥善处理各行各业的所有要求,因此特殊类型的处理还需要应用层面处理。| -|需要大量的交叉查询处理| | R | |这种类型的处理更多应该用关系型数据系统处理,或者应该考虑TDengine和关系型数据系统配合实现系统功能| +|要求完整的内置数据处理算法| | · | |TDengine的实现了通用的数据处理算法,但是还没有做到妥善处理各行各业的所有要求,因此特殊类型的处理还需要应用层面处理。| +|需要大量的交叉查询处理| | · | |这种类型的处理更多应该用关系型数据系统处理,或者应该考虑TDengine和关系型数据系统配合实现系统功能| ###系统性能需求 |系统性能需求|不适用|可能适用|非常适用|简单说明| |---|---|---|---|---| -|要求较大的总体处理能力| | | R |TDengine的集群功能可以轻松地让多服务器配合达成处理能力的提升。| -|要求高速处理数据 | | | R |TDengine的专门为IOT优化的存储和数据处理的设计,一般可以让系统得到超出同类产品多倍数的处理速度提升。| -|要求快速处理小粒度数据| | | R |这方面TDengine性能可以完全对标关系型和NoSQL型数据处理系统。| +|要求较大的总体处理能力| | | · |TDengine的集群功能可以轻松地让多服务器配合达成处理能力的提升。| +|要求高速处理数据 | | | · |TDengine的专门为IOT优化的存储和数据处理的设计,一般可以让系统得到超出同类产品多倍数的处理速度提升。| +|要求快速处理小粒度数据| | | · |这方面TDengine性能可以完全对标关系型和NoSQL型数据处理系统。| ###系统维护需求 |系统维护需求|不适用|可能适用|非常适用|简单说明| |---|---|---|---|---| -|要求系统可靠运行| | | R |TDengine的系统架构非常稳定可靠,日常维护也简单便捷,对维护人员的要求简洁明了,最大程度上杜绝人为错误和事故。| -|要求运维学习成本可控| | | R |同上| -|要求市场有大量人才储备| R | | |TDengine作为新一代产品,目前人才市场里面有经验的人员还有限。但是学习成本低,我们作为厂家也提供运维的培训和辅助服务| +|要求系统可靠运行| | | · |TDengine的系统架构非常稳定可靠,日常维护也简单便捷,对维护人员的要求简洁明了,最大程度上杜绝人为错误和事故。| +|要求运维学习成本可控| | | · |同上| +|要求市场有大量人才储备| · | | |TDengine作为新一代产品,目前人才市场里面有经验的人员还有限。但是学习成本低,我们作为厂家也提供运维的培训和辅助服务| ##TDengine 性能指标介绍和验证方法 From ac2ae239d07e8885bab667627c9c5eeb81952829 Mon Sep 17 00:00:00 2001 From: Xiaxin Li <48907085+Aries-Lee1991@users.noreply.github.com> Date: Fri, 31 Jul 2020 18:30:21 +0800 Subject: [PATCH 30/56] Add files via upload --- .../webdocs/markdowndocs/Evaluation-ch.md | 66 ++++++++++--------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/documentation20/webdocs/markdowndocs/Evaluation-ch.md b/documentation20/webdocs/markdowndocs/Evaluation-ch.md index 859653d20e..8899906c6a 100644 --- a/documentation20/webdocs/markdowndocs/Evaluation-ch.md +++ b/documentation20/webdocs/markdowndocs/Evaluation-ch.md @@ -1,60 +1,64 @@ # TDengine 介绍 ## TDengine 简介 + TDengine是涛思数据面对高速增长的物联网大数据市场和技术挑战推出的创新性的大数据处理产品,它不依赖任何第三方软件,也不是优化或包装了一个开源的数据库或流式计算产品,而是在吸取众多传统关系型数据库、NoSQL数据库、流式计算引擎、消息队列等软件的优点之后自主开发的产品,在时序空间大数据处理上,有着自己独到的优势。 TDengine的模块之一是时序数据库。但除此之外,为减少研发的复杂度、系统维护的难度,TDengine还提供缓存、消息队列、订阅、流式计算等功能,为物联网、工业互联网大数据的处理提供全栈的技术方案,是一个高效易用的物联网大数据平台。与Hadoop等典型的大数据平台相比,它具有如下鲜明的特点: -* __10倍以上的性能提升__:定义了创新的数据存储结构,单核每秒就能处理至少2万次请求,插入数百万个数据点,读出一千万以上数据点,比现有通用数据库快了十倍以上。 -* __硬件或云服务成本降至1/5__:由于超强性能,计算资源不到通用大数据方案的1/5;通过列式存储和先进的压缩算法,存储空间不到通用数据库的1/10 -* __全栈时序数据处理引擎__:将数据库、消息队列、缓存、流式计算等功能融合一起,应用无需再集成Kafka/Redis/HBase/Spark/HDFS等软件,大幅降低应用开发和维护的复杂度成本。 -* __强大的分析功能__:无论是十年前还是一秒钟前的数据,指定时间范围即可查询。数据可在时间轴上或多个设备上进行聚合。临时查询可通过Shell, Python, R, Matlab随时进行。 -* __与第三方工具无缝连接__:不用一行代码,即可与Telegraf, Grafana, EMQ, Prometheus, Matlab, R等集成。后续将支持OPC, Hadoop, Spark等, BI工具也将无缝连接。 -* __零运维成本、零学习成本__:安装、集群一秒搞定,无需分库分表,实时备份。标准SQL,支持JDBC, RESTful, 支持Python/Java/C/C++/Go, 与MySQL相似,零学习成本。 +- __10倍以上的性能提升__:定义了创新的数据存储结构,单核每秒就能处理至少2万次请求,插入数百万个数据点,读出一千万以上数据点,比现有通用数据库快了十倍以上。 +- __硬件或云服务成本降至1/5__:由于超强性能,计算资源不到通用大数据方案的1/5;通过列式存储和先进的压缩算法,存储空间不到通用数据库的1/10 +- __全栈时序数据处理引擎__:将数据库、消息队列、缓存、流式计算等功能融合一起,应用无需再集成Kafka/Redis/HBase/Spark/HDFS等软件,大幅降低应用开发和维护的复杂度成本。 +- __强大的分析功能__:无论是十年前还是一秒钟前的数据,指定时间范围即可查询。数据可在时间轴上或多个设备上进行聚合。临时查询可通过Shell, Python, R, Matlab随时进行。 +- __与第三方工具无缝连接__:不用一行代码,即可与Telegraf, Grafana, EMQ, Prometheus, Matlab, R等集成。后续将支持OPC, Hadoop, Spark等, BI工具也将无缝连接。 +- __零运维成本、零学习成本__:安装、集群一秒搞定,无需分库分表,实时备份。标准SQL,支持JDBC, RESTful, 支持Python/Java/C/C++/Go, 与MySQL相似,零学习成本。 采用TDengine,可将典型的物联网、车联网、工业互联网大数据平台的总拥有成本大幅降低。但需要指出的是,因充分利用了物联网时序数据的特点,它无法用来处理网络爬虫、微博、微信、电商、ERP、CRM等通用型数据。 ## TDengine 总体适用场景 -作为一个IoT大数据平台,TDengine的典型适用场景是在IoT范畴,而且用户有一定的数据量。本文后续的介绍主要针对这个范畴里面的系统。范畴之外的系统,比如CRM,ERP等,不在本文讨论范围内。 -### 数据源特点和需求 -从数据源角度,设计人员可以从如下几个角度分析TDengine在目标应用系统里面的适用性。 +作为一个IOT大数据平台,TDengine的典型适用场景是在IOT范畴,而且用户有一定的数据量。本文后续的介绍主要针对这个范畴里面的系统。范畴之外的系统,比如CRM,ERP等,不在本文讨论范围内。 + + +## 数据源特点和需求 +从数据源角度,设计人员可以从已经角度分析TDengine在目标应用系统里面的适用性。 |数据源特点和需求|不适用|可能适用|非常适用|简单说明| |---|---|---|---|---| -|总体数据量巨大| | | · |TDengine在容量方面提供出色的水平扩展功能,并且具备匹配高压缩的存储结构和多级存储,达到业界最优的存储效率。| -|数据输入速度偶尔或者持续巨大| | | · | TDengine的性能大大超过同类产品,可以在同样的硬件环境下持续处理大量的输入数据,并且提供很容易在用户环境里面运行的性能评估工具。| -|数据源数目巨大| | | · |TDengine设计中包含专门针对大量数据源的优化,包括数据的写入和查询,尤其适合高效处理海量(千万或者更多量级)的数据源。| +|总体数据量巨大| | | √ |TDengine在容量方面提供出色的水平扩展功能,并且具备匹配高压缩的存储结构,达到业界最优的存储效率。| +|数据输入速度偶尔或者持续巨大| | | √ | TDengine的性能大大超过同类产品,可以在同样的硬件环境下持续处理大量的输入数据,并且提供很容易在用户环境里面运行的性能评估工具。| +|数据源数目巨大| | | √ |TDengine设计中包含专门针对大量数据源的优化,包括数据的写入和查询,尤其适合高效处理海量(千万或者更多量级)的数据源。| -###系统架构要求 + + +## 系统架构要求 |系统架构要求|不适用|可能适用|非常适用|简单说明| |---|---|---|---|---| -|要求简单可靠的系统架构| | | · |TDengine的系统架构非常简单可靠,自带消息队列,缓存,流式计算,监控等功能,无需集成额外的第三方产品。| -|要求容错和高可靠| | | · |TDengine的集群功能,自动提供容错灾备等高可靠功能| -|标准化规范| | | · |TDengine使用标准的SQL语言提供主要功能,遵守标准化规范| +|要求简单可靠的系统架构| | | √ |TDengine的系统架构非常简单可靠,自带消息队列,缓存,流式计算,监控等功能,无需集成额外的第三方产品。| +|要求容错和高可靠| | | √ |TDengine的集群功能,自动提供容错灾备等高可靠功能| +|标准化规范| | | √ |TDengine使用标准的SQL语言提供主要功能,遵守标准化规范| -###系统功能需求 +## 系统功能需求 |系统功能需求|不适用|可能适用|非常适用|简单说明| |---|---|---|---|---| -|要求完整的内置数据处理算法| | · | |TDengine的实现了通用的数据处理算法,但是还没有做到妥善处理各行各业的所有要求,因此特殊类型的处理还需要应用层面处理。| -|需要大量的交叉查询处理| | · | |这种类型的处理更多应该用关系型数据系统处理,或者应该考虑TDengine和关系型数据系统配合实现系统功能| +|要求完整的内置数据处理算法| | √ | |TDengine的实现了通用的数据处理算法,但是还没有做到妥善处理各行各业的所有要求,因此特殊类型的处理还需要应用层面处理。| +|需要大量的交叉查询处理| | √ | |这种类型的处理更多应该用关系型数据系统处理,或者应该考虑TDengine和关系型数据系统配合实现系统功能| -###系统性能需求 + +## 系统性能需求 |系统性能需求|不适用|可能适用|非常适用|简单说明| |---|---|---|---|---| -|要求较大的总体处理能力| | | · |TDengine的集群功能可以轻松地让多服务器配合达成处理能力的提升。| -|要求高速处理数据 | | | · |TDengine的专门为IOT优化的存储和数据处理的设计,一般可以让系统得到超出同类产品多倍数的处理速度提升。| -|要求快速处理小粒度数据| | | · |这方面TDengine性能可以完全对标关系型和NoSQL型数据处理系统。| +|要求较大的总体处理能力| | | √ |TDengine的集群功能可以轻松地让多服务器配合达成处理能力的提升。| +|要求高速处理数据 | | | √ |TDengine的专门为IOT优化的存储和数据处理的设计,一般可以让系统得到超出同类产品多倍数的处理速度提升。| +|要求快速处理小粒度数据| | | √ |这方面TDengine性能可以完全对标关系型和NoSQL型数据处理系统。| -###系统维护需求 + +## 系统维护需求 |系统维护需求|不适用|可能适用|非常适用|简单说明| |---|---|---|---|---| -|要求系统可靠运行| | | · |TDengine的系统架构非常稳定可靠,日常维护也简单便捷,对维护人员的要求简洁明了,最大程度上杜绝人为错误和事故。| -|要求运维学习成本可控| | | · |同上| -|要求市场有大量人才储备| · | | |TDengine作为新一代产品,目前人才市场里面有经验的人员还有限。但是学习成本低,我们作为厂家也提供运维的培训和辅助服务| - -##TDengine 性能指标介绍和验证方法 - - +|要求系统可靠运行| | | √ |TDengine的系统架构非常稳定可靠,日常维护也简单便捷,对维护人员的要求简洁明了,最大程度上杜绝人为错误和事故。| +|要求运维学习成本可控| | | √ |同上| +|要求市场有大量人才储备| √ | | |TDengine作为新一代产品,目前人才市场里面有经验的人员还有限。但是学习成本低,我们作为厂家也提供运维的培训和辅助服务| +## TDengine 性能指标介绍和验证方法 From 6da71d38a1e4c8ad964bc71ffaf9b9f30c7ed9b9 Mon Sep 17 00:00:00 2001 From: Xiaxin Li <48907085+Aries-Lee1991@users.noreply.github.com> Date: Fri, 31 Jul 2020 18:52:23 +0800 Subject: [PATCH 31/56] Add files via upload --- documentation20/webdocs/markdowndocs/architecture-ch.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/documentation20/webdocs/markdowndocs/architecture-ch.md b/documentation20/webdocs/markdowndocs/architecture-ch.md index c4e6070761..c4534c499a 100644 --- a/documentation20/webdocs/markdowndocs/architecture-ch.md +++ b/documentation20/webdocs/markdowndocs/architecture-ch.md @@ -14,7 +14,9 @@ | D1004 | 1538548696600 | 11.8 | 221 | 0.28 | | Beijing.Haidian | 2 | | D1002 | 1538548696650 | 10.3 | 218 | 0.25 | | Beijing.Chaoyang | 3 | | D1001 | 1538548696800 | 12.3 | 221 | 0.31 | | Beijing.Chaoyang | 2 | +
表1:智能电表数据示例
+ 每一条记录都有设备ID,时间戳,采集的物理量(如上图中的电流、电压、相位),还有与每个设备相关的静态标签(如上述表一中的位置Location和分组groupId)。每个设备是受外界的触发,或按照设定的周期采集数据。采集的数据点是时序的,是一个数据流。 ### 数据特征 @@ -62,7 +64,6 @@ TDengine 的设计是基于单个硬件、软件系统不可靠,基于任何 ###主要逻辑单元 TDengine 分布式架构的逻辑结构图如下:
-
图 1 TDengine架构示意图
一个完整的 TDengine 系统是运行在一到多个物理节点上的,逻辑上,它包含数据节点(dnode)、TDengine客户端(taosc)以及应用(app)。系统中存在一到多个数据节点,这些数据节点组成一个集群(cluster)。应用通过taosc的API与TDengine集群进行互动。下面对每个逻辑单元进行简要介绍。 @@ -98,9 +99,7 @@ TDengine 分布式架构的逻辑结构图如下: ###一典型的操作流程 为解释vnode, mnode, taosc和应用之间的关系以及各自扮演的角色,下面对写入数据这个典型操作的流程进行剖析。
-
图 2 TDengine典型的操作流程
- 1. 应用通过JDBC、ODBC或其他API接口发起插入数据的请求。 2. taosc会检查缓存,看是有保存有该表的meta data。如果有,直接到第4步。如果没有,taosc将向mnode发出get meta-data请求。 3. mnode将该表的meta-data返回给taosc。Meta-data包含有该表的schema, 而且还有该表所属的vgroup信息(vnode ID以及所在的dnode的End Point,如果副本数为N,就有N组End Point)。如果taosc迟迟得不到mnode回应,而且存在多个mnode, taosc将向下一个mnode发出请求。 @@ -160,9 +159,7 @@ TDengine除vnode分片之外,还按照时间段进行分区。每个数据文 ###Master vnode写入流程 Master Vnode遵循下面的写入流程:
-
图 3 TDengine Master写入流程
- 1. Master vnode收到应用的数据插入请求,验证OK,进入下一步; 2. 如果系统配置参数walLevel打开(设置为2),vnode将把该请求的原始数据包写入数据库日志文件WAL,以保证TDengine能够在断电等因素导致的服务重启时从数据库日志文件中恢复数据,避免数据的丢失; 3. 如果有多个副本,vnode将把数据包转发给同一虚拟节点组内slave vnodes, 该转发包带有数据的版本号(version) @@ -173,9 +170,7 @@ Master Vnode遵循下面的写入流程: ### Slave vnode写入流程 对于slave vnode, 写入流程是:
-
图 4 TDengine Slave写入流程
- 1. Slave vnode收到Master vnode转发了的数据插入请求。 2. 如果系统配置参数walLevl设置为2,vnode将把该请求的原始数据包写入日志(WAL); 3. 写入内存,更新内存中的skip list。 From f9448e3d0cbda7afb627d2e8fddf7ec328c2ed13 Mon Sep 17 00:00:00 2001 From: Xiaxin Li <48907085+Aries-Lee1991@users.noreply.github.com> Date: Fri, 31 Jul 2020 19:07:43 +0800 Subject: [PATCH 32/56] Update replica-ch.md --- documentation20/webdocs/markdowndocs/replica-ch.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation20/webdocs/markdowndocs/replica-ch.md b/documentation20/webdocs/markdowndocs/replica-ch.md index 98310ca8b7..f93f3888c0 100644 --- a/documentation20/webdocs/markdowndocs/replica-ch.md +++ b/documentation20/webdocs/markdowndocs/replica-ch.md @@ -105,7 +105,7 @@ TDengine采取的是Master-Slave模式进行同步,与流行的RAFT一致性 如果vnode A是master, vnode B是slave, vnode A能接受客户端的写请求,而vnode B不能。当vnode A收到写的请求后,遵循下面的流程: -
+
1. 应用对写请求做基本的合法性检查,通过,则给改请求包打上一个版本号(version, 单调递增) 2. 应用将打上版本号的写请求封装一个WAL Head, 写入WAL(Write Ahead Log) @@ -140,7 +140,7 @@ TDengine采取的是Master-Slave模式进行同步,与流行的RAFT一致性 整个数据恢复流程分为两大步骤,第一步,先恢复archived data(file), 然后恢复wal。具体流程如下: -
+
1. 通过已经建立的TCP链接,发送sync req给master节点 2. master收到sync req后,以client的身份,向vnode B主动建立一新的专用于同步的TCP链接(syncFd) From b9acd0ccd7f45f619770199615092229df55471c Mon Sep 17 00:00:00 2001 From: Jeff Tao Date: Fri, 31 Jul 2020 11:56:19 +0000 Subject: [PATCH 33/56] minor changes --- .../webdocs/markdowndocs/Evaluation-ch.md | 14 +++++--------- documentation20/webdocs/markdowndocs/Model-ch.md | 4 ++-- documentation20/webdocs/markdowndocs/Queries-ch.md | 4 ++-- .../webdocs/markdowndocs/administrator-ch.md | 8 ++++---- documentation20/webdocs/markdowndocs/cluster-ch.md | 2 +- documentation20/webdocs/markdowndocs/insert-ch.md | 7 +++++-- 6 files changed, 19 insertions(+), 20 deletions(-) diff --git a/documentation20/webdocs/markdowndocs/Evaluation-ch.md b/documentation20/webdocs/markdowndocs/Evaluation-ch.md index 8899906c6a..e0eebf8885 100644 --- a/documentation20/webdocs/markdowndocs/Evaluation-ch.md +++ b/documentation20/webdocs/markdowndocs/Evaluation-ch.md @@ -20,7 +20,7 @@ TDengine的模块之一是时序数据库。但除此之外,为减少研发的 作为一个IOT大数据平台,TDengine的典型适用场景是在IOT范畴,而且用户有一定的数据量。本文后续的介绍主要针对这个范畴里面的系统。范畴之外的系统,比如CRM,ERP等,不在本文讨论范围内。 -## 数据源特点和需求 +### 数据源特点和需求 从数据源角度,设计人员可以从已经角度分析TDengine在目标应用系统里面的适用性。 |数据源特点和需求|不适用|可能适用|非常适用|简单说明| @@ -29,31 +29,27 @@ TDengine的模块之一是时序数据库。但除此之外,为减少研发的 |数据输入速度偶尔或者持续巨大| | | √ | TDengine的性能大大超过同类产品,可以在同样的硬件环境下持续处理大量的输入数据,并且提供很容易在用户环境里面运行的性能评估工具。| |数据源数目巨大| | | √ |TDengine设计中包含专门针对大量数据源的优化,包括数据的写入和查询,尤其适合高效处理海量(千万或者更多量级)的数据源。| - - -## 系统架构要求 +### 系统架构要求 |系统架构要求|不适用|可能适用|非常适用|简单说明| |---|---|---|---|---| |要求简单可靠的系统架构| | | √ |TDengine的系统架构非常简单可靠,自带消息队列,缓存,流式计算,监控等功能,无需集成额外的第三方产品。| |要求容错和高可靠| | | √ |TDengine的集群功能,自动提供容错灾备等高可靠功能| |标准化规范| | | √ |TDengine使用标准的SQL语言提供主要功能,遵守标准化规范| -## 系统功能需求 +### 系统功能需求 |系统功能需求|不适用|可能适用|非常适用|简单说明| |---|---|---|---|---| |要求完整的内置数据处理算法| | √ | |TDengine的实现了通用的数据处理算法,但是还没有做到妥善处理各行各业的所有要求,因此特殊类型的处理还需要应用层面处理。| |需要大量的交叉查询处理| | √ | |这种类型的处理更多应该用关系型数据系统处理,或者应该考虑TDengine和关系型数据系统配合实现系统功能| - -## 系统性能需求 +### 系统性能需求 |系统性能需求|不适用|可能适用|非常适用|简单说明| |---|---|---|---|---| |要求较大的总体处理能力| | | √ |TDengine的集群功能可以轻松地让多服务器配合达成处理能力的提升。| |要求高速处理数据 | | | √ |TDengine的专门为IOT优化的存储和数据处理的设计,一般可以让系统得到超出同类产品多倍数的处理速度提升。| |要求快速处理小粒度数据| | | √ |这方面TDengine性能可以完全对标关系型和NoSQL型数据处理系统。| - -## 系统维护需求 +### 系统维护需求 |系统维护需求|不适用|可能适用|非常适用|简单说明| |---|---|---|---|---| |要求系统可靠运行| | | √ |TDengine的系统架构非常稳定可靠,日常维护也简单便捷,对维护人员的要求简洁明了,最大程度上杜绝人为错误和事故。| diff --git a/documentation20/webdocs/markdowndocs/Model-ch.md b/documentation20/webdocs/markdowndocs/Model-ch.md index dfb079d13d..fbcc09924a 100644 --- a/documentation20/webdocs/markdowndocs/Model-ch.md +++ b/documentation20/webdocs/markdowndocs/Model-ch.md @@ -11,7 +11,7 @@ TDengine采用关系型数据模型,需要建库、建表。因此对于一个 ```cmd CREATE DATABASE power KEEP 365 DAYS 10 REPLICA 3 BLOCKS 4; ``` -上述语句将创建一个名为power的库,这个库的数据将保留365天(超过365天将被自动删除),每10天一个数据文件,副本数为3, 内存块数为4。详细的语法及参数请见TAOS SQL。 +上述语句将创建一个名为power的库,这个库的数据将保留365天(超过365天将被自动删除),每10天一个数据文件,副本数为3, 内存块数为4。详细的语法及参数请见TAOS SQL 注意:任何一张表或超级表是属于一个库的,在创建表之前,必须先创建库。 @@ -20,7 +20,7 @@ CREATE DATABASE power KEEP 365 DAYS 10 REPLICA 3 BLOCKS 4; ```cmd CREATE TABLE meters (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupdId int); ``` -与创建普通表一样,创建表时,需要提供表名(示例中为meters),表结构Schema,即数据列的定义,为采集的物理量(示例中为ts, current, voltage, phase),数据类型可以为整型、浮点型、字符串等。除此之外,还需要提供标签的schema (示例中为location, groupId),标签的数据类型可以为整型、浮点型、字符串等。采集点的静态属性往往可以作为标签,比如采集点的地理位置、设备型号、设备组ID、管理员ID等等。标签的schema可以事后增加、删除、修改。具体定义以及细节请见 TAOS SQL一节。 +与创建普通表一样,创建表时,需要提供表名(示例中为meters),表结构Schema,即数据列的定义,为采集的物理量(示例中为ts, current, voltage, phase),数据类型可以为整型、浮点型、字符串等。除此之外,还需要提供标签的schema (示例中为location, groupId),标签的数据类型可以为整型、浮点型、字符串等。采集点的静态属性往往可以作为标签,比如采集点的地理位置、设备型号、设备组ID、管理员ID等等。标签的schema可以事后增加、删除、修改。具体定义以及细节请见 TAOS SQL 一节。 每一种类型的数据采集点需要建立一个超级表,因此一个物联网系统,往往会有多个超级表。一个系统可以有多个DB,一个DB里可以有一到多个超级表。 diff --git a/documentation20/webdocs/markdowndocs/Queries-ch.md b/documentation20/webdocs/markdowndocs/Queries-ch.md index 0f4124f1fc..332aca598f 100644 --- a/documentation20/webdocs/markdowndocs/Queries-ch.md +++ b/documentation20/webdocs/markdowndocs/Queries-ch.md @@ -27,7 +27,7 @@ Query OK, 2 row(s) in set (0.001100s) ``` 为满足物联网场景的需求,TDengine支持几个特殊的函数,比如twa(时间加权平均),spread (最大值与最小值的差),last_row(最后一条记录)等,更多与物联网场景相关的函数将添加进来。TDengine还支持连续查询。 -具体的查询语法请看TAOS SQL。 +具体的查询语法请看TAOS SQL 。 ## 多表聚合查询 @@ -82,5 +82,5 @@ Query OK, 5 row(s) in set (0.001538s) 物联网场景里,每个数据采集点采集数据的时间是难同步的,但很多分析算法(比如FFT)需要把采集的数据严格按照时间等间隔的对齐,在很多系统里,需要应用自己写程序来处理,但使用TDengine的降采样操作就轻松解决。如果一个时间间隔里,没有采集的数据,TDengine还提供插值计算的功能。 -语法规则细节请见TAOS SQL。 +语法规则细节请见TAOS SQL 。 diff --git a/documentation20/webdocs/markdowndocs/administrator-ch.md b/documentation20/webdocs/markdowndocs/administrator-ch.md index 81c387a0a0..5109209d43 100644 --- a/documentation20/webdocs/markdowndocs/administrator-ch.md +++ b/documentation20/webdocs/markdowndocs/administrator-ch.md @@ -1,4 +1,4 @@ -# 系统管理 +# TDengine的运营与维护 ## 容量规划 @@ -43,9 +43,9 @@ Raw DataSize = numOfTables * rowSizePerTable * rowsPerTable ### 物理机或虚拟机台数 -根据上面的内存、CPU、存储的预估,就可以知道整个系统需要多少核、多少内存、多少存储空间。如果数据副本数不为1,总需求量再乘以副本数。 +根据上面的内存、CPU、存储的预估,就可以知道整个系统需要多少核、多少内存、多少存储空间。如果数据副本数不为1,总需求量需要再乘以副本数。 -根据总量,再根据单个物理机或虚拟机的资源,就可以轻松决定需要购置多少台机器了。 +因为TDengine具有很好的水平扩展能力,根据总量,再根据单个物理机或虚拟机的资源,就可以轻松决定需要购置多少台机器了。 ## 容错和灾备 @@ -125,7 +125,7 @@ TDengine集群中加入一个新的dnode时,涉及集群相关的一些参数 - statusInterval: dnode向mnode报告状态时长。单位为秒,默认值:1。 - maxTablesPerVnode: 每个vnode中能够创建的最大表个数。默认值:1000000。 - maxVgroupsPerDb: 每个数据库中能够使用的最大vnode个数。 -- arbitrator: 系统中裁决器的end point。 +- arbitrator: 系统中裁决器的end point,缺省为空 - timezone:时区。从系统中动态获取当前的时区设置。 - locale:系统区位信息及编码格式。系统中动态获取,如果自动获取失败,需要用户在配置文件设置或通过API设置。 - charset:字符集编码。系统中动态获取,如果自动获取失败,需要用户在配置文件设置或通过API设置。 diff --git a/documentation20/webdocs/markdowndocs/cluster-ch.md b/documentation20/webdocs/markdowndocs/cluster-ch.md index 43b35dbc66..67723a9eb1 100644 --- a/documentation20/webdocs/markdowndocs/cluster-ch.md +++ b/documentation20/webdocs/markdowndocs/cluster-ch.md @@ -1,4 +1,4 @@ -#集群安装、管理 +#TDengine 集群安装、管理 多个taosd的运行实例可以组成一个集群,以保证TDengine的高可靠运行,并提供水平扩展能力。要了解TDengine 2.0的集群管理,需要对集群的基本概念有所了解,请看TDengine 2.0整体架构一章。 diff --git a/documentation20/webdocs/markdowndocs/insert-ch.md b/documentation20/webdocs/markdowndocs/insert-ch.md index 2fd869cfe6..a92c7a7d00 100644 --- a/documentation20/webdocs/markdowndocs/insert-ch.md +++ b/documentation20/webdocs/markdowndocs/insert-ch.md @@ -18,9 +18,12 @@ TDengine也支持一次向多个表写入数据,比如下面这条命令就向 INSERT INTO d1001 VALUES (1538548685000, 10.3, 219, 0.31) (1538548695000, 12.6, 218, 0.33) d1002 VALUES (1538548696800, 12.3, 221, 0.31); ``` -**Tips:** 要提高写入效率,需要批量写入。一批写入的记录条数越多,插入效率就越高。但一条记录不能超过16K,一条SQL语句总长度不能超过64K(可通过参数maxSQLLength配置)。 +详细的SQL INSERT语法规则请见TAOS SQL -详细的SQL INSERT语法规则请见TAOS SQL +**Tips:** + +- 要提高写入效率,需要批量写入。一批写入的记录条数越多,插入效率就越高。但一条记录不能超过16K,一条SQL语句总长度不能超过64K(可通过参数maxSQLLength配置)。 +- TDengine支持多线程同时写入,要进一步提高写入速度,一个客户端需要打开20个以上的线程同时写。 ## Prometheus直接写入 [Prometheus](https://www.prometheus.io/)作为Cloud Native Computing Fundation毕业的项目,在性能监控以及K8S性能监控领域有着非常广泛的应用。TDengine提供一个小工具[Bailongma](https://github.com/taosdata/Bailongma),只需在Prometheus做简单配置,无需任何代码,就可将Prometheus采集的数据直接写入TDengine,并按规则在TDengine自动创建库和相关表项。博文[用Docker容器快速搭建一个Devops监控Demo](https://www.taosdata.com/blog/2020/02/03/1189.html)即是采用bailongma将Prometheus和Telegraf的数据写入TDengine中的示例,可以参考。 From 51d4c60683edc2ded8c09e5f6ac53133c31dc2b1 Mon Sep 17 00:00:00 2001 From: Xiaxin Li <48907085+Aries-Lee1991@users.noreply.github.com> Date: Fri, 31 Jul 2020 21:38:19 +0800 Subject: [PATCH 34/56] Add files via upload --- documentation20/webdocs/markdowndocs/Getting Started-ch.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation20/webdocs/markdowndocs/Getting Started-ch.md b/documentation20/webdocs/markdowndocs/Getting Started-ch.md index 4b109aa8e6..041ad72ac5 100644 --- a/documentation20/webdocs/markdowndocs/Getting Started-ch.md +++ b/documentation20/webdocs/markdowndocs/Getting Started-ch.md @@ -38,7 +38,7 @@ which systemd 如果系统中不存在`systemd`命令,请考虑[通过源码安装](#通过源码安装)TDengine。 -具体的安装过程,请参见[`TDengine多种安装包的安装和卸载`](https://www.taosdata.com/blog/2019/08/09/566.html) +具体的安装过程,请参见TDengine多种安装包的安装和卸载。 ## 轻松启动 From d41c70d85a1316c31e207dc7c38e8840c2f21fd2 Mon Sep 17 00:00:00 2001 From: Xiaxin Li <48907085+Aries-Lee1991@users.noreply.github.com> Date: Fri, 31 Jul 2020 21:59:11 +0800 Subject: [PATCH 35/56] alter the file format --- .../webdocs/markdowndocs/Evaluation-ch.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/documentation20/webdocs/markdowndocs/Evaluation-ch.md b/documentation20/webdocs/markdowndocs/Evaluation-ch.md index e0eebf8885..5b501b7f9f 100644 --- a/documentation20/webdocs/markdowndocs/Evaluation-ch.md +++ b/documentation20/webdocs/markdowndocs/Evaluation-ch.md @@ -6,12 +6,12 @@ TDengine是涛思数据面对高速增长的物联网大数据市场和技术挑 TDengine的模块之一是时序数据库。但除此之外,为减少研发的复杂度、系统维护的难度,TDengine还提供缓存、消息队列、订阅、流式计算等功能,为物联网、工业互联网大数据的处理提供全栈的技术方案,是一个高效易用的物联网大数据平台。与Hadoop等典型的大数据平台相比,它具有如下鲜明的特点: -- __10倍以上的性能提升__:定义了创新的数据存储结构,单核每秒就能处理至少2万次请求,插入数百万个数据点,读出一千万以上数据点,比现有通用数据库快了十倍以上。 -- __硬件或云服务成本降至1/5__:由于超强性能,计算资源不到通用大数据方案的1/5;通过列式存储和先进的压缩算法,存储空间不到通用数据库的1/10 -- __全栈时序数据处理引擎__:将数据库、消息队列、缓存、流式计算等功能融合一起,应用无需再集成Kafka/Redis/HBase/Spark/HDFS等软件,大幅降低应用开发和维护的复杂度成本。 -- __强大的分析功能__:无论是十年前还是一秒钟前的数据,指定时间范围即可查询。数据可在时间轴上或多个设备上进行聚合。临时查询可通过Shell, Python, R, Matlab随时进行。 -- __与第三方工具无缝连接__:不用一行代码,即可与Telegraf, Grafana, EMQ, Prometheus, Matlab, R等集成。后续将支持OPC, Hadoop, Spark等, BI工具也将无缝连接。 -- __零运维成本、零学习成本__:安装、集群一秒搞定,无需分库分表,实时备份。标准SQL,支持JDBC, RESTful, 支持Python/Java/C/C++/Go, 与MySQL相似,零学习成本。 +* __10倍以上的性能提升__:定义了创新的数据存储结构,单核每秒就能处理至少2万次请求,插入数百万个数据点,读出一千万以上数据点,比现有通用数据库快了十倍以上。 +* __硬件或云服务成本降至1/5__:由于超强性能,计算资源不到通用大数据方案的1/5;通过列式存储和先进的压缩算法,存储空间不到通用数据库的1/10 +* __全栈时序数据处理引擎__:将数据库、消息队列、缓存、流式计算等功能融合一起,应用无需再集成Kafka/Redis/HBase/Spark/HDFS等软件,大幅降低应用开发和维护的复杂度成本。 +* __强大的分析功能__:无论是十年前还是一秒钟前的数据,指定时间范围即可查询。数据可在时间轴上或多个设备上进行聚合。临时查询可通过Shell, Python, R, Matlab随时进行。 +* __与第三方工具无缝连接__:不用一行代码,即可与Telegraf, Grafana, EMQ, Prometheus, Matlab, R等集成。后续将支持OPC, Hadoop, Spark等, BI工具也将无缝连接。 +* __零运维成本、零学习成本__:安装、集群一秒搞定,无需分库分表,实时备份。标准SQL,支持JDBC, RESTful, 支持Python/Java/C/C++/Go, 与MySQL相似,零学习成本。 采用TDengine,可将典型的物联网、车联网、工业互联网大数据平台的总拥有成本大幅降低。但需要指出的是,因充分利用了物联网时序数据的特点,它无法用来处理网络爬虫、微博、微信、电商、ERP、CRM等通用型数据。 From e086732b3f0d0626c9ba124e3ee05f22efcb3f27 Mon Sep 17 00:00:00 2001 From: Jeff Tao Date: Fri, 31 Jul 2020 14:28:48 +0000 Subject: [PATCH 36/56] indent the SQL command --- .../webdocs/markdowndocs/cluster-ch.md | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/documentation20/webdocs/markdowndocs/cluster-ch.md b/documentation20/webdocs/markdowndocs/cluster-ch.md index 67723a9eb1..58fa9c6a5a 100644 --- a/documentation20/webdocs/markdowndocs/cluster-ch.md +++ b/documentation20/webdocs/markdowndocs/cluster-ch.md @@ -33,11 +33,11 @@ taos> 2. 如果是使用涛思数据的官方安装包进行安装,在安装结束时,会询问集群的End Port, 输入第一个节点的End Point即可。如果是源码安装,请编辑配置文件taos.cfg(缺省是在/etc/taos/目录),增加一行: - ``` - firstEp h1.taos.com:6030 - ``` + ``` + firstEp h1.taos.com:6030 + ``` - 请注意将示例的“h1.taos.com:6030" 替换为你自己第一个节点的End Point + 请注意将示例的“h1.taos.com:6030" 替换为你自己第一个节点的End Point 3. 按照["立即开始“](https://www.taosdata.com/cn/getting-started/)一章的方法启动taosd @@ -45,19 +45,19 @@ taos> 5. 在第一个节点,使用CLI程序taos, 登录进TDengine系统, 使用命令: - ``` - CREATE DNODE "h2.taos.com:6030"; - ``` + ``` + CREATE DNODE "h2.taos.com:6030"; + ``` - 将新节点的End Point添加进集群的EP列表。**"fqdn:port"需要用双引号引起来**,否则出错。请注意将示例的“h2.taos.com:6030" 替换为你自己第一个节点的End Point + 将新节点的End Point添加进集群的EP列表。**"fqdn:port"需要用双引号引起来**,否则出错。请注意将示例的“h2.taos.com:6030" 替换为你自己第一个节点的End Point 6. 使用命令 - ``` - SHOW DNODES; - ``` + ``` + SHOW DNODES; + ``` - 查看新节点是否被成功加入。 + 查看新节点是否被成功加入。 按照上述步骤可以源源不断的将新的节点加入到集群。 From adcc60dee0c72ddf36707a13c102dd9445fca57f Mon Sep 17 00:00:00 2001 From: haojun Liao Date: Fri, 31 Jul 2020 23:18:34 +0800 Subject: [PATCH 37/56] Update Queries-ch.md --- .../webdocs/markdowndocs/Queries-ch.md | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/documentation20/webdocs/markdowndocs/Queries-ch.md b/documentation20/webdocs/markdowndocs/Queries-ch.md index 332aca598f..5cc0779551 100644 --- a/documentation20/webdocs/markdowndocs/Queries-ch.md +++ b/documentation20/webdocs/markdowndocs/Queries-ch.md @@ -6,17 +6,16 @@ ## 主要查询功能 -TDengine采用SQL作为查询语言,应用程序可以通过C/C++, JDBC, GO, Python连接器发送SQL查询语句,用户还可以通过TAOS Shell直接手动执行SQL即席查询,十分方便。支持如下查询功能: +TDengine 采用 SQL 作为查询语言。应用程序可以通过 C/C++, Java, Go, Python 连接器发送 SQL 语句,用户可以通过 TDengine 提供的命令行(Command Line Interface, CLI)工具 TAOS Shell 手动执行 SQL 即席查询(Ad-Hoc Query)。TDengine 支持如下查询功能: -- 查询单列、或多列查询 -- 支持值过滤条件:\>, \<, =, \<> 大于,小于,等于,不等于等等 -- 支持对标签的模糊匹配 -- 支持Group by, Order by, Limit, Offset -- 支持列之间的四则运算 -- 支持时间戳对齐的JOIN操作 -- 支持多种函数: count, max, min, avg, sum, twa, stddev, leastsquares, top, bottom, first, last, percentile, apercentile, last_row, spread, diff +- 单列、多列数据查询 +- 标签和数值的多种过滤条件:\>, \<, =, \<>, like 等 +- 聚合结果的分组(Group by)、排序(Order by)、约束输出(Limit/Offset) +- 数值列及聚合结果的四则运算 +- 时间戳对齐的连接查询(Join Query)操作 +- 多种聚合/计算函数: count, max, min, avg, sum, twa, stddev, leastsquares, top, bottom, first, last, percentile, apercentile, last_row, spread, diff等 -例如:在TAOS Shell中,从表d1001中查询出vlotage >215的记录,按时间降序排列,仅仅输出2条。 +例如:在TAOS Shell中,从表d1001中查询出vlotage > 215的记录,按时间降序排列,仅仅输出2条。 ```mysql taos> select * from d1001 where voltage > 215 order by ts desc limit 2; ts | current | voltage | phase | @@ -31,7 +30,7 @@ Query OK, 2 row(s) in set (0.001100s) ## 多表聚合查询 -TDengine对每个数据采集点单独建表,但应用经常需要对数据点之间进行聚合。为高效的进行聚合操作,TDengine引入超级表(STable)的概念。超级表用来代表一特定类型的数据采集点,它是表的集合,包含多张表。这集合里每张表的Schema是一样的,但每张表都带有自己的静态标签,标签可以多个,可以随时增加、删除和修改。 +TDengine对每个数据采集点单独建表,但在实际应用中经常需要对不同的采集点数据进行聚合。为高效的进行聚合操作,TDengine引入超级表(STable)的概念。超级表用来代表一特定类型的数据采集点,它是包含多张表的表集合,集合里每张表的模式(schema)完全一致,但每张表都带有自己的静态标签,标签可以多个,可以随时增加、删除和修改。 应用可通过指定标签的过滤条件,对一个STable下的全部或部分表进行聚合或统计操作,这样大大简化应用的开发。其具体流程如下图所示: @@ -39,16 +38,16 @@ TDengine对每个数据采集点单独建表,但应用经常需要对数据点
多表聚合查询原理图
-1:应用将一个查询条件发往系统;2: taosc将超级表的名字发往Meta Node(管理节点);3:管理节点将超级表所拥有的vnode列表发回taosc;4:taosc将计算的请求连同标签过滤条件发往这些vnode对应的多个数据节点;5:每个vnode先在内存里查找出自己节点里符合标签过滤条件的表的集合,然后扫描存储的时序数据,完成相应的聚合计算,将结果返回给taosc;6:taosc将多个数据节点返回的结果做最后的聚合,将其返回给应用。 +1:应用将一个查询条件发往系统;2: taosc将超级表的名字发往 Meta Node(管理节点);3:管理节点将超级表所拥有的 vnode 列表发回 taosc;4:taosc将计算的请求连同标签过滤条件发往这些vnode对应的多个数据节点;5:每个vnode先在内存里查找出自己节点里符合标签过滤条件的表的集合,然后扫描存储的时序数据,完成相应的聚合计算,将结果返回给taosc;6:taosc将多个数据节点返回的结果做最后的聚合,将其返回给应用。 -由于TDengine在vnode内将标签数据与时序数据分离存储,通过先在内存里过滤标签数据,将需要扫描的数据集大幅减少,大幅提升了聚合计算速度。同时,由于数据分布在多个vnode/dnode,聚合计算操作在多个vnode里并发进行,又进一步提升了聚合的速度。 +由于TDengine在vnode内将标签数据与时序数据分离存储,通过先在内存里过滤标签数据,将需要扫描的数据集大幅减少,大幅提升聚合计算速度。同时,由于数据分布在多个vnode/dnode,聚合计算操作在多个vnode里并发进行,又进一步提升了聚合的速度。 -对普通表的聚合函数以及绝大部分操作都适用于超级表,语法完全一样,细节请看TAOS SQL。 +对普通表的聚合函数以及绝大部分操作都适用于超级表,语法完全一样,细节请看 TAOS SQL。 比如:在TAOS Shell,查找所有智能电表采集的电压平均值,并按照location分组 ```mysql -taos> select avg(voltage) from meters group by location; +taos> SELECT AVG(voltage) FROM meters GROUP BY location; avg(voltage) | location | ============================================================= 222.000000000 | Beijing.Haidian | @@ -58,18 +57,18 @@ Query OK, 2 row(s) in set (0.002136s) ## 降采样查询、插值 -物联网场景里,经常需要做down sampling,需要将采集的数据按时间段进行聚合。TDengine提供了一个简便的关键词interval让操作变得极为简单。比如:将智能电表d1001采集的电流值每10秒钟求和 +物联网场景里,经常需要通过降采样(down sampling)将采集的数据按时间段进行聚合。TDengine 提供了一个简便的关键词 interval 让按照时间窗口的查询操作变得极为简单。比如,将智能电表 d1001 采集的电流值每10秒钟求和 ```mysql -taos> SELECT sum(current) FROM d1001 interval(10s) ; +taos> SELECT sum(current) FROM d1001 INTERVAL(10s) ; ts | sum(current) | ====================================================== 2018-10-03 14:38:00.000 | 10.300000191 | 2018-10-03 14:38:10.000 | 24.900000572 | Query OK, 2 row(s) in set (0.000883s) ``` -降采样操作还适用于超级表,比如:将所有智能电表采集的电流值每秒钟求和 +降采样操作也适用于超级表,比如:将所有智能电表采集的电流值每秒钟求和 ```mysql -taos> SELECT sum(current) FROM meters interval(1s) ; +taos> SELECT SUM(current) FROM meters INTERVAL(1s) ; ts | sum(current) | ====================================================== 2018-10-03 14:38:04.000 | 10.199999809 | From dc64d4edc5f38afb4c778a03e2adad5aa566ec4d Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Fri, 31 Jul 2020 23:33:02 +0800 Subject: [PATCH 38/56] [TD-1037] --- src/inc/taosdef.h | 3 ++- src/os/inc/osString.h | 5 +++-- src/os/inc/osTime.h | 2 +- src/os/inc/osWindows.h | 2 ++ src/os/src/windows/CMakeLists.txt | 20 +++++++++++-------- src/os/src/windows/w64File.c | 8 ++++++-- src/rpc/CMakeLists.txt | 11 ++--------- src/util/CMakeLists.txt | 33 +------------------------------ 8 files changed, 29 insertions(+), 55 deletions(-) diff --git a/src/inc/taosdef.h b/src/inc/taosdef.h index c70ca8662e..c328e57453 100644 --- a/src/inc/taosdef.h +++ b/src/inc/taosdef.h @@ -22,6 +22,7 @@ extern "C" { #include #include +#include "osDef.h" #include "taos.h" #define TSDB__packed @@ -161,7 +162,7 @@ extern tDataTypeDescriptor tDataTypeDesc[11]; bool isValidDataType(int32_t type); //bool isNull(const char *val, int32_t type); -static inline __attribute__((always_inline)) bool isNull(const char *val, int32_t type) { +static FORCE_INLINE bool isNull(const char *val, int32_t type) { switch (type) { case TSDB_DATA_TYPE_BOOL: return *(uint8_t *)val == TSDB_DATA_BOOL_NULL; diff --git a/src/os/inc/osString.h b/src/os/inc/osString.h index 1e1953c81d..b2846a31bc 100644 --- a/src/os/inc/osString.h +++ b/src/os/inc/osString.h @@ -41,8 +41,9 @@ extern "C" { (dst)[(size)-1] = 0; \ } while (0); -// TAOS_OS_FUNC_STRING_STR2INT64 -int64_t tsosStr2int64(char *str); +#ifndef TAOS_OS_FUNC_STRING_STR2INT64 + int64_t tsosStr2int64(char *str); +#endif // USE_LIBICONV int32_t taosUcs4ToMbs(void *ucs4, int32_t ucs4_max_len, char *mbs); diff --git a/src/os/inc/osTime.h b/src/os/inc/osTime.h index e2d3e081a1..cd2553f753 100644 --- a/src/os/inc/osTime.h +++ b/src/os/inc/osTime.h @@ -23,7 +23,7 @@ extern "C" { #include "os.h" #include "taosdef.h" -#ifndef TAOS_OS_DEF_TIME +#ifndef TAOS_OS_FUNC_TIME_DEF #define MILLISECOND_PER_SECOND ((int64_t)1000L) #endif #define MILLISECOND_PER_MINUTE (MILLISECOND_PER_SECOND * 60) diff --git a/src/os/inc/osWindows.h b/src/os/inc/osWindows.h index b44a41832e..a8c2243253 100644 --- a/src/os/inc/osWindows.h +++ b/src/os/inc/osWindows.h @@ -43,6 +43,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -124,6 +125,7 @@ typedef int (*__compar_fn_t)(const void *, const void *); #define socklen_t int #define htobe64 htonll #define twrite write +#define getpid _getpid int gettimeofday(struct timeval *tv, struct timezone *tz); struct tm *localtime_r(const time_t *timep, struct tm *result); diff --git a/src/os/src/windows/CMakeLists.txt b/src/os/src/windows/CMakeLists.txt index dc60b736ea..60fab63cd1 100644 --- a/src/os/src/windows/CMakeLists.txt +++ b/src/os/src/windows/CMakeLists.txt @@ -1,11 +1,15 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8) PROJECT(TDengine) -IF (TD_WINDOWS_64) - INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/pthread) - INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/src/inc) - INCLUDE_DIRECTORIES(inc) - AUX_SOURCE_DIRECTORY(src SRC) - ADD_LIBRARY(os ${SRC}) - TARGET_LINK_LIBRARIES(os winmm IPHLPAPI ws2_32) -ENDIF () +INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/pthread) +INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/iconv) +INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/regex) +INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/src/inc) +INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/src/os/inc) +INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/src/util/inc) +INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/src/common/inc) +AUX_SOURCE_DIRECTORY(. SRC) + +ADD_LIBRARY(os ${SRC}) + +TARGET_LINK_LIBRARIES(os winmm IPHLPAPI ws2_32) diff --git a/src/os/src/windows/w64File.c b/src/os/src/windows/w64File.c index 54a95297ac..f2c59c3639 100644 --- a/src/os/src/windows/w64File.c +++ b/src/os/src/windows/w64File.c @@ -37,10 +37,9 @@ void taosGetTmpfilePath(const char *fileNamePrefix, char *dstPath) { snprintf(dstPath, PATH_MAX, tmpPath, getpid(), rand); } - #define _SEND_FILE_STEP_ 1000 -int taosTSendFileImp(FILE* out_file, FILE* in_file, int64_t* offset, int32_t count) { +int taosFSendFileImp(FILE* out_file, FILE* in_file, int64_t* offset, int32_t count) { fseek(in_file, (int32_t)(*offset), 0); int writeLen = 0; uint8_t buffer[_SEND_FILE_STEP_] = { 0 }; @@ -74,3 +73,8 @@ int taosTSendFileImp(FILE* out_file, FILE* in_file, int64_t* offset, int32_t cou return writeLen; } + +ssize_t taosTSendFileImp(int dfd, int sfd, off_t *offset, size_t size) { + uError("taosTSendFileImp no implemented yet"); + return 0; +} \ No newline at end of file diff --git a/src/rpc/CMakeLists.txt b/src/rpc/CMakeLists.txt index 902c8b66e4..15a8923d21 100644 --- a/src/rpc/CMakeLists.txt +++ b/src/rpc/CMakeLists.txt @@ -10,19 +10,12 @@ INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/lz4/inc) INCLUDE_DIRECTORIES(inc) IF ((TD_LINUX_64) OR (TD_LINUX_32 AND TD_ARM)) - AUX_SOURCE_DIRECTORY(./src SRC) + AUX_SOURCE_DIRECTORY(src SRC) ELSEIF (TD_DARWIN_64) - #LIST(APPEND SRC ./src/thaship.c) - #LIST(APPEND SRC ./src/trpc.c) - #LIST(APPEND SRC ./src/tstring.c) - #LIST(APPEND SRC ./src/tudp.c) AUX_SOURCE_DIRECTORY(src SRC) ELSEIF (TD_WINDOWS_64) INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/pthread) - LIST(APPEND SRC ./src/thaship.c) - LIST(APPEND SRC ./src/trpc.c) - LIST(APPEND SRC ./src/tstring.c) - LIST(APPEND SRC ./src/tudp.c) + AUX_SOURCE_DIRECTORY(src SRC) ENDIF () ADD_LIBRARY(trpc ${SRC}) diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 2521c582d1..d91ef075ef 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -34,38 +34,7 @@ ELSEIF (TD_WINDOWS_64) INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/iconv) INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/regex) INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/src/inc) - LIST(APPEND SRC ./src/hash.c) - LIST(APPEND SRC ./src/ihash.c) - LIST(APPEND SRC ./src/lz4.c) - LIST(APPEND SRC ./src/shash.c) - LIST(APPEND SRC ./src/tbase64.c) - LIST(APPEND SRC ./src/tcache.c) - LIST(APPEND SRC ./src/tcompression.c) - LIST(APPEND SRC ./src/textbuffer.c) - LIST(APPEND SRC ./src/tglobalcfg.c) - LIST(APPEND SRC ./src/thash.c) - LIST(APPEND SRC ./src/thashutil.c) - LIST(APPEND SRC ./src/thistogram.c) - LIST(APPEND SRC ./src/tidpool.c) - LIST(APPEND SRC ./src/tinterpolation.c) - LIST(APPEND SRC ./src/tlog.c) - LIST(APPEND SRC ./src/tlosertree.c) - LIST(APPEND SRC ./src/tmd5.c) - LIST(APPEND SRC ./src/tmem.c) - LIST(APPEND SRC ./src/tmempool.c) - LIST(APPEND SRC ./src/tmodule.c) - LIST(APPEND SRC ./src/tnote.c) - LIST(APPEND SRC ./src/tpercentile.c) - LIST(APPEND SRC ./src/tsched.c) - LIST(APPEND SRC ./src/tskiplist.c) - LIST(APPEND SRC ./src/tsocket.c) - LIST(APPEND SRC ./src/tstrbuild.c) - LIST(APPEND SRC ./src/ttime.c) - LIST(APPEND SRC ./src/ttimer.c) - LIST(APPEND SRC ./src/ttokenizer.c) - LIST(APPEND SRC ./src/ttypes.c) - LIST(APPEND SRC ./src/tutil.c) - LIST(APPEND SRC ./src/version.c) + AUX_SOURCE_DIRECTORY(src SRC) ADD_LIBRARY(tutil ${SRC}) TARGET_LINK_LIBRARIES(tutil iconv regex pthread osdetail winmm IPHLPAPI ws2_32 lz4) ELSEIF(TD_DARWIN_64) From 592b71484d01ca3909b468a760a9959c028d3622 Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Fri, 31 Jul 2020 23:44:23 +0800 Subject: [PATCH 39/56] [TD-992] --- cmake/define.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/define.inc b/cmake/define.inc index 1bb1692a2b..d840cb59e2 100755 --- a/cmake/define.inc +++ b/cmake/define.inc @@ -53,7 +53,7 @@ IF (TD_LINUX_64) ADD_DEFINITIONS(-D_M_X64) ADD_DEFINITIONS(-D_TD_LINUX_64) IF (NOT TD_ARM) - IF (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") + IF ((${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") OR (${CMAKE_CXX_COMPILER_ID} MATCHES "clang")) SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -Wno-missing-braces -fPIC -g3 -gdwarf-2 -msse4.2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE") ELSE () SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -fPIC -malign-double -g3 -gdwarf-2 -malign-stringops -msse4.2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE") From ffd6a89fb07e20d064f938d3d0adcaed6b342694 Mon Sep 17 00:00:00 2001 From: haojun Liao Date: Fri, 31 Jul 2020 23:52:03 +0800 Subject: [PATCH 40/56] Update architecture-ch.md --- .../webdocs/markdowndocs/architecture-ch.md | 59 +++++++++++++------ 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/documentation20/webdocs/markdowndocs/architecture-ch.md b/documentation20/webdocs/markdowndocs/architecture-ch.md index c4534c499a..d935293f98 100644 --- a/documentation20/webdocs/markdowndocs/architecture-ch.md +++ b/documentation20/webdocs/markdowndocs/architecture-ch.md @@ -4,16 +4,16 @@ ### 物联网典型场景 在典型的物联网、车联网、运维监测场景中,往往有多种不同类型的数据采集设备,采集一个到多个不同的物理量。而同一种采集设备类型,往往又有多个具体的采集设备分布在不同的地点。大数据处理系统就是要将各种采集的数据汇总,然后进行计算和分析。对于同一类设备,其采集的数据都是很规则的。以智能电表为例,假设每个智能电表采集电流、电压、相位三个量,其采集的数据类似如下的表格: -| Device ID | Time Stamp | current | voltage | phase | | location | groupId | -| :-------: | :-----------: | :-----: | :-----: | :---: | :--- | :--------------: | :-----: | -| D1001 | 1538548685000 | 10.3 | 219 | 0.31 | | Beijing.Chaoyang | 2 | -| D1002 | 1538548684000 | 10.2 | 220 | 0.23 | | Beijing.Chaoyang | 3 | -| D1003 | 1538548686500 | 11.5 | 221 | 0.35 | | Beijing.Haidian | 3 | -| D1004 | 1538548685500 | 13.4 | 223 | 0.29 | | Beijing.Haidian | 2 | -| D1001 | 1538548695000 | 12.6 | 218 | 0.33 | | Beijing.Chaoyang | 2 | -| D1004 | 1538548696600 | 11.8 | 221 | 0.28 | | Beijing.Haidian | 2 | -| D1002 | 1538548696650 | 10.3 | 218 | 0.25 | | Beijing.Chaoyang | 3 | -| D1001 | 1538548696800 | 12.3 | 221 | 0.31 | | Beijing.Chaoyang | 2 | +| Device ID | Time Stamp | current | voltage | phase | location | groupId | +| :-------: | :-----------: | :-----: | :-----: | :---: | :--------------: | :-----: | +| D1001 | 1538548685000 | 10.3 | 219 | 0.31 | Beijing.Chaoyang | 2 | +| D1002 | 1538548684000 | 10.2 | 220 | 0.23 | Beijing.Chaoyang | 3 | +| D1003 | 1538548686500 | 11.5 | 221 | 0.35 | Beijing.Haidian | 3 | +| D1004 | 1538548685500 | 13.4 | 223 | 0.29 | Beijing.Haidian | 2 | +| D1001 | 1538548695000 | 12.6 | 218 | 0.33 | Beijing.Chaoyang | 2 | +| D1004 | 1538548696600 | 11.8 | 221 | 0.28 | Beijing.Haidian | 2 | +| D1002 | 1538548696650 | 10.3 | 218 | 0.25 | Beijing.Chaoyang | 3 | +| D1001 | 1538548696800 | 12.3 | 221 | 0.31 | Beijing.Chaoyang | 2 |
表1:智能电表数据示例
@@ -22,18 +22,18 @@ ### 数据特征 除时序特征外,仔细研究发现,物联网、车联网、运维监测类数据还具有很多其他明显的特征。 -1. 数据是结构化的; +1. 数据高度结构化; 2. 数据极少有更新或删除操作; 3. 无需传统数据库的事务处理; 4. 相对互联网应用,写多读少; 5. 流量平稳,根据设备数量和采集频次,可以预测出来; 6. 用户关注的是一段时间的趋势,而不是某一特点时间点的值; -7. 数据是有保留期限的; -8. 数据的查询分析一定是基于时间段和地理区域的; -9. 除存储查询外,还往往需要各种统计和实时计算操作; +7. 数据有保留期限; +8. 数据的查询分析一定是基于时间段和地理区域; +9. 除存储查询外,还需要各种统计和实时计算操作; 10. 数据量巨大,一天采集的数据就可以超过100亿条。 -充分利用上述特征,TDengine采取了一特殊的优化的存储和计算设计来处理时序数据,能将系统处理能力显著提高。 +充分利用上述特征,TDengine 采取了特殊的优化的存储和计算设计来处理时序数据,能将系统处理能力显著提高。 ### 关系型数据库模型 因为采集的数据一般是结构化数据,而且为降低学习门槛,TDengine采用传统的关系型数据库模型管理数据。因此用户需要先创建库,然后创建表,之后才能插入或查询数据。TDengine采用的是结构化存储,而不是NoSQL的key-value存储。 @@ -262,9 +262,32 @@ dataDir /mnt/disk6/taos 2 TDengine提供了多种多样针对表和超级表的查询处理功能,除了常规的聚合查询之外,还提供针对时序数据的窗口查询、统计聚合等功能。TDengine的查询处理需要客户端、vnode, mnode节点协同完成。 5.1 单表查询 +SQL语句的解析和校验工作在客户端完成。解析SQL语句并生成抽象语法树(Abstract Syntax Tree, AST),然后对其进行校验和检查。以及向管理节点(mnode)请求查询中指定表的元数据信息(table metadata)。 -5.4 时间轴聚合、插值 +根据元数据信息中的FQDN信息,将查询请求序列化后发送到该表所在的数据节点(dnode)。dnode接收到查询请求后,识别出该查询请求指向的虚拟节点(vnode),将消息转发到vnode的查询执行队列。vnode的查询执行线程建立基础的查询执行环境,并立即返回该查询请求,同时开始执行该查询。 -5.2 多表聚合查询 +客户端在获取查询结果的时候,dnode的查询执行队列中的工作线程会等待vnode执行线程执行完成,才能将查询结果返回到请求的客户端。 -5.3 预计算 \ No newline at end of file +5.2 时间轴聚合、插值 + +时序数据有别于普通数据的显著特征是每条记录均具有时间戳,因此针对具有时间戳数据在时间轴上进行聚合是不同于普通数据库的重要功能。从这点上来看,与流计算引擎的窗口查询有相似的地方。 + +在TDengine中引入关键词interval来进行时间轴上固定长度时间窗口的切分,并按照时间窗口对数据进行聚合,对窗口范围内的数据按需进行聚合。例如: +select count(*) from D1001 interval(1h) + +针对D1001设备采集的数据,按照1小时的时间窗口返回每小时存储的记录数量。 + +在需要连续获得查询结果的应用场景下,如果给定的时间区间存在数据缺失,会导致该区间数据结果也丢失。TDengine提供策略针对时间轴聚合计算的结果进行插值,通过使用关键词Fill就能够对时间轴聚合结果进行插值。例如: +select count(*) from D1001 interval(1h) fill(prev) + +针对D1001设备采集数据统计每小时记录数,如果某一个小时不存在数据,这返回之前一个小时的统计数据。TDengine提供前向插值(prev)、线性插值(linear)、NULL值填充(NULL)、特定值填充(value)。 + +5.3 多表聚合查询 +多表聚合查询与单表查询的整体流程相同,但是存在如下的差异: + +1)由于多表可能分布在不同的节点(dnode),因此多表的聚合查询需要首先获得表所在的全部数据节点的信息,并且同时向相关的dnode发出查询请求。 +2)每个vnode的计算获得的中间结果(partial results)需要进行第二阶段的聚合才能形成最终结果,第二阶段的聚合过程在客户端完成。 +3)由于表标签信息存储在vnode中,因此针对标签信息的查询也需要vnode完成。客户端将标签的过滤表达式封装在查询请求结构体中发送给vnode,由vnode的查询执行线程从中抽取出标签查询条件,然后执行查询。标签查询与过滤是在针对表的查询之前完成。标签查询完成以后,将符合条件的表纳入到接下来的查询处理流程中。 + +5.4 预计算 +为有效提升查询处理的性能,针对物联网数据的不可更改的特点,在数据块头部记录该数据块中存储数据的统计信息:包括最大值、最小值、和。我们称之为预计算单元。如果查询处理涉及整个数据块的全部数据,直接使用预计算结果,完全不需要读取数据块的内容。由于预计算数据量远小于磁盘上存储的数据块数据的大小,对于磁盘IO为瓶颈的查询处理,使用预计算结果可以极大地减小读取IO压力,加速查询处理的流程。预计算机制与Postgre SQL的索引BRIN(block range index)有异曲同工之妙。 From 42441ccedbe3c38c5025e7bca4bce7f7a507c40c Mon Sep 17 00:00:00 2001 From: Jeff Tao Date: Sat, 1 Aug 2020 00:29:14 +0000 Subject: [PATCH 41/56] minior changes --- .../webdocs/markdowndocs/Model-ch.md | 7 +- .../webdocs/markdowndocs/administrator-ch.md | 10 +- .../webdocs/markdowndocs/architecture-ch.md | 96 ++++++++++--------- .../webdocs/markdowndocs/cluster-ch.md | 8 +- .../webdocs/markdowndocs/insert-ch.md | 2 +- .../webdocs/markdowndocs/replica-ch.md | 4 +- .../webdocs/markdowndocs/taosd-ch.md | 6 +- 7 files changed, 71 insertions(+), 62 deletions(-) diff --git a/documentation20/webdocs/markdowndocs/Model-ch.md b/documentation20/webdocs/markdowndocs/Model-ch.md index fbcc09924a..8a8d4191ed 100644 --- a/documentation20/webdocs/markdowndocs/Model-ch.md +++ b/documentation20/webdocs/markdowndocs/Model-ch.md @@ -4,7 +4,7 @@ TDengine采用关系型数据模型,需要建库、建表。因此对于一个具体的应用场景,需要考虑库的设计,超级表和普通表的设计。本节不讨论细致的语法规则,只介绍概念。 -##创建库 +## 创建库 不同类型的数据采集点往往具有不同的数据特征,包括数据采集频率的高低,数据保留时间的长短,副本的数目,数据块的大小等等。为让各种场景下TDengine都能最大效率的工作,TDengine建议将不同数据特征的表创建在不同的库里,因为每个库可以配置不同的存储策略。创建一个库时,除SQL标准的选项外,应用还可以指定保留时长、副本数、内存块个数、时间精度、文件块里最大最小记录条数、是否压缩、一个数据文件覆盖的天数等多种参数。比如: @@ -31,7 +31,7 @@ CREATE TABLE d1001 USING meters TAGS ("Beijing.Chaoyang", 2); ``` 其中d1001是表名,meters是超级表的表名,后面紧跟标签Location的具体标签值”Beijing.Chaoyang",标签groupId的具体标签值2。虽然在创建表时,需要指定标签值,但可以事后修改。详细细则请见 TAOS SQL。 -TDengine建议将数据采集点的全局唯一ID作为表名。但对于有的场景,并没有唯一的ID,可以将多个ID组合成一个唯一的ID。不建议将具有唯一性的ID作为标签值。 +TDengine建议将数据采集点的全局唯一ID作为表名(比如设备序列号)。但对于有的场景,并没有唯一的ID,可以将多个ID组合成一个唯一的ID。不建议将具有唯一性的ID作为标签值。 **自动建表**:在某些特殊场景中,用户在写数据时并不确定某个数据采集点的表是否存在,此时可在写入数据时使用自动建表语法来创建不存在的表,若该表已存在则不会建立新表。比如: @@ -40,4 +40,5 @@ INSERT INTO d1001 USING METERS TAGS ("Beijng.Chaoyang", 2) VALUES (now, 10.2, 21 ``` 上述SQL语句将记录(now, 10.2, 219, 0.32) 插入进表d1001。如果表d1001还未创建,则使用超级表meters做模板自动创建,同时打上标签值“Beijing.Chaoyang", 2。 -**多列模型**:TDengine支持多列模型,只要这些物理量是同时采集的,这些量就可以作为不同列放在同一张表里。有的数据采集点有多组采集量,每一组的数据采集时间是不一样的,这时需要对同一个采集点建多张表。但还有一种极限的设计,单列模型,无论是否同时采集,每个采集的物理量单独建表。TDengine建议,只要采集时间一致,就采用多列模型,因为插入效率以及存储效率更高。 \ No newline at end of file +**多列模型**:TDengine支持多列模型,只要这些物理量是同时采集的,这些量就可以作为不同列放在同一张表里。有的数据采集点有多组采集量,每一组的数据采集时间是不一样的,这时需要对同一个采集点建多张表。但还有一种极限的设计,单列模型,无论是否同时采集,每个采集的物理量单独建表。TDengine建议,只要采集时间一致,就采用多列模型,因为插入效率以及存储效率更高。 + diff --git a/documentation20/webdocs/markdowndocs/administrator-ch.md b/documentation20/webdocs/markdowndocs/administrator-ch.md index 5109209d43..ea9231bae6 100644 --- a/documentation20/webdocs/markdowndocs/administrator-ch.md +++ b/documentation20/webdocs/markdowndocs/administrator-ch.md @@ -6,7 +6,7 @@ ### 内存需求 -每个DB可以创建固定数目的vnode,默认与CPU核数相同,可通过maxVgroupsPerDb配置;每个vnode会占用固定大小的内存(大小与数据库的配置参数blocks和cache有关);每个Table会占用与Tag总大小有关的内存;此外,系统会有一些固定的内存开销。因此,每个DB需要的系统内存可通过如下公式计算: +每个DB可以创建固定数目的vnode,默认与CPU核数相同,可通过maxVgroupsPerDb配置;每个vnode会占用固定大小的内存(大小与数据库的配置参数blocks和cache有关);每个Table会占用与标签总长度有关的内存;此外,系统会有一些固定的内存开销。因此,每个DB需要的系统内存可通过如下公式计算: ``` Memory Size = maxVgroupsPerDb * (blocks * cache + 10Mb) + numOfTables * (tagSizePerTable + 0.5Kb) @@ -22,7 +22,7 @@ Memory Size = maxVgroupsPerDb * (blocks * cache + 10Mb) + numOfTables * (tagSize CPU的需求取决于如下两方面: -- 数据插入:TDengine单核每秒能至少处理一万个插入请求。每个插入请求可以带多条记录,一次插入一条记录与插入10条记录,消耗的计算资源差别很小。因此没次插入,条数越大,插入效率越高。如果一个插入请求带200条以上记录,单核就能达到每秒插入100万条记录的速度。但对前端数据采集的要求越高,因为需要缓存记录,然后一批插入。 +- 数据插入:TDengine单核每秒能至少处理一万个插入请求。每个插入请求可以带多条记录,一次插入一条记录与插入10条记录,消耗的计算资源差别很小。因此每次插入,条数越大,插入效率越高。如果一个插入请求带200条以上记录,单核就能达到每秒插入100万条记录的速度。但对前端数据采集的要求越高,因为需要缓存记录,然后一批插入。 - 查询需求:TDengine提供高效的查询,但是每个场景的查询差异很大,查询频次变化也很大,难以给出客观数字。需要用户针对自己的场景,写一些查询语句,才能确定。 因此仅对数据插入而言,CPU是可以估算出来的,但查询所耗的计算资源无法估算。在实际运营过程中,不建议CPU使用率超过50%,超过后,需要增加新的节点,以获得更多计算资源。 @@ -45,7 +45,7 @@ Raw DataSize = numOfTables * rowSizePerTable * rowsPerTable 根据上面的内存、CPU、存储的预估,就可以知道整个系统需要多少核、多少内存、多少存储空间。如果数据副本数不为1,总需求量需要再乘以副本数。 -因为TDengine具有很好的水平扩展能力,根据总量,再根据单个物理机或虚拟机的资源,就可以轻松决定需要购置多少台机器了。 +因为TDengine具有很好的水平扩展能力,根据总量,再根据单个物理机或虚拟机的资源,就可以轻松决定需要购置多少台物理机或虚拟机了。 ## 容错和灾备 @@ -136,8 +136,8 @@ TDengine系统的前台交互客户端应用程序为taos,它与taosd共享同 客户端配置参数列表及解释 -- first: taos启动时,主动连接的集群中第一个taosd实例的end point, 缺省值为 localhost:6030。 -- second: taos启动时,如果first连接不上,尝试连接集群中第二个taosd实例的end point, 缺省值为空。 +- firstEp: taos启动时,主动连接的集群中第一个taosd实例的end point, 缺省值为 localhost:6030。 +- secondEp: taos启动时,如果first连接不上,尝试连接集群中第二个taosd实例的end point, 缺省值为空。 - charset:字符集编码。系统中动态获取,如果自动获取失败,需要用户在配置文件设置或通过API设置。 - locale:系统区位信息及编码格式。系统中动态获取,如果自动获取失败,需要用户在配置文件设置或通过API设置。 diff --git a/documentation20/webdocs/markdowndocs/architecture-ch.md b/documentation20/webdocs/markdowndocs/architecture-ch.md index d935293f98..5401c64685 100644 --- a/documentation20/webdocs/markdowndocs/architecture-ch.md +++ b/documentation20/webdocs/markdowndocs/architecture-ch.md @@ -6,17 +6,17 @@ | Device ID | Time Stamp | current | voltage | phase | location | groupId | | :-------: | :-----------: | :-----: | :-----: | :---: | :--------------: | :-----: | -| D1001 | 1538548685000 | 10.3 | 219 | 0.31 | Beijing.Chaoyang | 2 | -| D1002 | 1538548684000 | 10.2 | 220 | 0.23 | Beijing.Chaoyang | 3 | -| D1003 | 1538548686500 | 11.5 | 221 | 0.35 | Beijing.Haidian | 3 | -| D1004 | 1538548685500 | 13.4 | 223 | 0.29 | Beijing.Haidian | 2 | -| D1001 | 1538548695000 | 12.6 | 218 | 0.33 | Beijing.Chaoyang | 2 | -| D1004 | 1538548696600 | 11.8 | 221 | 0.28 | Beijing.Haidian | 2 | -| D1002 | 1538548696650 | 10.3 | 218 | 0.25 | Beijing.Chaoyang | 3 | -| D1001 | 1538548696800 | 12.3 | 221 | 0.31 | Beijing.Chaoyang | 2 | - +| d1001 | 1538548685000 | 10.3 | 219 | 0.31 | Beijing.Chaoyang | 2 | +| d1002 | 1538548684000 | 10.2 | 220 | 0.23 | Beijing.Chaoyang | 3 | +| d1003 | 1538548686500 | 11.5 | 221 | 0.35 | Beijing.Haidian | 3 | +| d1004 | 1538548685500 | 13.4 | 223 | 0.29 | Beijing.Haidian | 2 | +| d1001 | 1538548695000 | 12.6 | 218 | 0.33 | Beijing.Chaoyang | 2 | +| d1004 | 1538548696600 | 11.8 | 221 | 0.28 | Beijing.Haidian | 2 | +| d1002 | 1538548696650 | 10.3 | 218 | 0.25 | Beijing.Chaoyang | 3 | +| d1001 | 1538548696800 | 12.3 | 221 | 0.31 | Beijing.Chaoyang | 2 | +
表1:智能电表数据示例
- + 每一条记录都有设备ID,时间戳,采集的物理量(如上图中的电流、电压、相位),还有与每个设备相关的静态标签(如上述表一中的位置Location和分组groupId)。每个设备是受外界的触发,或按照设定的周期采集数据。采集的数据点是时序的,是一个数据流。 ### 数据特征 @@ -39,13 +39,13 @@ 因为采集的数据一般是结构化数据,而且为降低学习门槛,TDengine采用传统的关系型数据库模型管理数据。因此用户需要先创建库,然后创建表,之后才能插入或查询数据。TDengine采用的是结构化存储,而不是NoSQL的key-value存储。 ### 一个数据采集点一张表 -为充分利用其数据的时序性和其他数据特点,TDengine要求**对每个数据采集点单独建表**(比如有一千万个智能电表,就需创建一千万张表,上述表格中的D1001, D1002, D1003, D1004都需单独建表),用来存储这个采集点所采集的时序数据。这种设计有几大优点: +为充分利用其数据的时序性和其他数据特点,TDengine要求**对每个数据采集点单独建表**(比如有一千万个智能电表,就需创建一千万张表,上述表格中的d1001, d1002, d1003, d1004都需单独建表),用来存储这个采集点所采集的时序数据。这种设计有几大优点: 1. 能保证一个采集点的数据在存储介质上是一块一块连续的。如果读取一个时间段的数据,它能大幅减少随机读取操作,成数量级的提升读取和查询速度。 2. 由于不同采集设备产生数据的过程完全独立,每个设备的数据源是唯一的,一张表也就只有一个写入者,这样就可采用无锁方式来写,写入速度就能大幅提升。 3. 对于一个数据采集点而言,其产生的数据是时序的,因此写的操作可用追加的方式实现,进一步大幅提高数据写入速度。 -如果采用传统的方式,将多个设备的数据写入一张表,由于网络延时不可控,不同设备的数据到达服务器的时序是无法保证的,写入操作是要有锁保护的,而且一个设备的数据是难以保证连续存储在一起的。**采用一个采集点一张表的方式,能最大程度的保证单个数据采集点的插入和查询的性能是最优的。** +如果采用传统的方式,将多个设备的数据写入一张表,由于网络延时不可控,不同设备的数据到达服务器的时序是无法保证的,写入操作是要有锁保护的,而且一个设备的数据是难以保证连续存储在一起的。**采用一个数据采集点一张表的方式,能最大程度的保证单个数据采集点的插入和查询的性能是最优的。** TDengine 建议用数据采集点的名字(如上表中的D1001)来做表名。每个数据采集点可能同时采集多个物理量(如上表中的curent, voltage, phase),每个物理量对应一张表中的一列,数据类型可以是整型、浮点型、字符串等。除此之外,表的第一列必须是时间戳,即数据类型为 timestamp。对采集的数据,TDengine将自动按照时间戳建立索引,但对采集的物理量不建任何索引。数据是用列式存储方式保存。 @@ -58,10 +58,10 @@ TDengine 建议用数据采集点的名字(如上表中的D1001)来做表名。 当对多个具有相同数据类型的数据采集点进行聚合操作时,TDengine将先把满足标签过滤条件的表从超级表的中查找出来,然后再扫描这些表的时序数据,进行聚合操作,这样能将需要扫描的数据集大幅减少,从而大幅提高聚合计算的性能。 -##集群与基本逻辑单元 +## 集群与基本逻辑单元 TDengine 的设计是基于单个硬件、软件系统不可靠,基于任何单台计算机都无法提供足够计算能力和存储能力处理海量数据的假设进行设计的。因此 TDengine 从研发的第一天起,就按照分布式高可靠架构进行设计,是支持水平扩展的,这样任何单台或多台服务器发生硬件故障或软件错误都不影响系统的可用性和可靠性。同时,通过节点虚拟化并辅以自动化负载均衡技术,TDengine 能最高效率地利用异构集群中的计算和存储资源降低硬件投资。 -###主要逻辑单元 +### 主要逻辑单元 TDengine 分布式架构的逻辑结构图如下:
图 1 TDengine架构示意图
@@ -71,11 +71,11 @@ TDengine 分布式架构的逻辑结构图如下: **数据节点(dnode):** dnode 是 TDengine 服务器侧执行代码 taosd 在物理节点上的一个运行实例,一个工作的系统必须有至少一个数据节点。dnode包含零到多个逻辑的虚拟节点(VNODE),零或者至多一个逻辑的管理节点(mnode). dnode在系统中的唯一标识由实例的End Point(EP)决定。EP是dnode所在物理节点的FQDN(Fully Qualified Domain Name)和系统所配置的网络端口号(Port)的组合。通过配置不同的端口,一个物理节点(一台物理机、虚拟机或容器)可以运行多个实例,或有多个数据节点。 -**虚拟节点(vnode)**: 为更好的支持数据分片、负载均衡,防止数据过热或倾斜,数据节点被虚拟化成多个虚拟节点(vnode,图中V)。每个 vnode 都是一个相对独立的工作单元,是时序数据存储的基本单元,具有独立的运行线程、内存空间与持久化存储的路径。一个 vnode 包含一定数量的表(数据采集点)。当创建一张新表时,系统会检查是否需要创建新的 vnode。一个数据节点上能创建的 vnode 的数量取决于该数据节点所在物理节点的硬件资源。一个 vnode 只属于一个DB,但一个DB可以有多个 vnode。一个 vnode 除存储的时序数据外,也保存有所包含的表的SCHEMA、标签值等。一个虚拟节点由所属的数据节点的EP,以及所属的Vgroup ID在系统内唯一标识,是由管理节点创建并管理的。 +**虚拟节点(vnode)**: 为更好的支持数据分片、负载均衡,防止数据过热或倾斜,数据节点被虚拟化成多个虚拟节点(vnode,图中V2, V3, V4等)。每个 vnode 都是一个相对独立的工作单元,是时序数据存储的基本单元,具有独立的运行线程、内存空间与持久化存储的路径。一个 vnode 包含一定数量的表(数据采集点)。当创建一张新表时,系统会检查是否需要创建新的 vnode。一个数据节点上能创建的 vnode 的数量取决于该数据节点所在物理节点的硬件资源。一个 vnode 只属于一个DB,但一个DB可以有多个 vnode。一个 vnode 除存储的时序数据外,也保存有所包含的表的SCHEMA、标签值等。一个虚拟节点由所属的数据节点的EP,以及所属的Vgroup ID在系统内唯一标识,是由管理节点创建并管理的。 -**管理节点(mnode):** 一个虚拟的逻辑单元,负责所有数据节点运行状态的监控和维护,以及节点之间的负载均衡(图中M)。同时,管理节点也负责元数据(包括用户、数据库、表、静态标签等)的存储和管理,因此也称为 Meta Node。TDengine 集群中可配置多个(最多不超过5个) mnode,它们自动构建成为一个管理节点集群(图中M0, M1, M2)。mnode 间采用 master/slave 的机制进行管理,而且采取强一致方式进行数据同步, 任何数据更新操作只能在 Master 上进行。mnode 集群的创建由系统自动完成,无需人工干预。每个dnode上至多有一个mnode,由所属的数据节点的EP来唯一标识。每个dnode通过内部消息交互自动获取整个集群中所有 mnode 所在的 dnode 的EP。 +**管理节点(mnode):** 一个虚拟的逻辑单元,负责所有数据节点运行状态的监控和维护,以及节点之间的负载均衡(图中M)。同时,管理节点也负责元数据(包括用户、数据库、表、静态标签等)的存储和管理,因此也称为 Meta Node。TDengine 集群中可配置多个(最多不超过5个) mnode,它们自动构建成为一个虚拟管理节点组(图中M0, M1, M2)。mnode 间采用 master/slave 的机制进行管理,而且采取强一致方式进行数据同步, 任何数据更新操作只能在 Master 上进行。mnode 集群的创建由系统自动完成,无需人工干预。每个dnode上至多有一个mnode,由所属的数据节点的EP来唯一标识。每个dnode通过内部消息交互自动获取整个集群中所有 mnode 所在的 dnode 的EP。 -**虚拟节点组(VGroup):** 不同数据节点上的 vnode 可以组成一个虚拟节点组(vnode group)来保证系统的高可靠。虚拟节点组内采取master/slave的方式进行管理。写操作只能在 master vnode 上进行,系统采用异步复制的方式将数据同步到 slave vnode,这样确保了一份数据在多个物理节点上有拷贝。一个 vgroup 里虚拟节点个数就是数据的副本数。如果一个DB的副本数为N,系统必须有至少N个数据节点。副本数在创建DB时通过参数 replica 可以指定,缺省为1。使用 TDengine 的多副本特性,可以不再需要昂贵的磁盘阵列等存储设备,获得同样的数据高可靠性。虚拟节点组由管理节点创建、管理,并且由管理节点分配一系统唯一的ID,vnode group ID。如果两个虚拟节点的vnode group ID相同,说明他们属于同一个组,数据互为备份。虚拟节点组里虚拟节点的个数是可以动态改变的,容许只有一个,也就是没有数据复制。Vnode group ID是永远不变的,即使一个虚拟节点组被删除,它的ID也不会被收回重复利用。 +**虚拟节点组(VGroup):** 不同数据节点上的 vnode 可以组成一个虚拟节点组(vnode group)来保证系统的高可靠。虚拟节点组内采取master/slave的方式进行管理。写操作只能在 master vnode 上进行,系统采用异步复制的方式将数据同步到 slave vnode,这样确保了一份数据在多个物理节点上有拷贝。一个 vgroup 里虚拟节点个数就是数据的副本数。如果一个DB的副本数为N,系统必须有至少N个数据节点。副本数在创建DB时通过参数 replica 可以指定,缺省为1。使用 TDengine 的多副本特性,可以不再需要昂贵的磁盘阵列等存储设备,获得同样的数据高可靠性。虚拟节点组由管理节点创建、管理,并且由管理节点分配一系统唯一的ID,vnode group ID。如果两个虚拟节点的vnode group ID相同,说明他们属于同一个组,数据互为备份。虚拟节点组里虚拟节点的个数是可以动态改变的,容许只有一个,也就是没有数据复制。Vnode group ID是永远不变的,即使一个虚拟节点组被删除,它的ID也不会被收回重复利用。 **TAOSC:** taosc是TDengine给应用提供的驱动程序(driver),负责处理应用与集群的接口交互,内嵌于JDBC、ODBC driver中,或者C、Python、Go语言连接库里。应用都是通过taosc,而不是直接连接集群中的数据节点与整个集群进行交互的。这个模块负责获取并缓存元数据;将插入、查询等请求转发到正确的数据节点;在把结果返回给应用时,还需要负责最后一级的聚合、排序、过滤等操作。对于JDBC, ODBC, C/C++接口而言,这个模块是在应用所处的物理节点上运行,但消耗的资源很小。同时,为支持全分布式的RESTful接口,taosc在TDengine集群的每个dnode上都有一运行实例。 @@ -96,7 +96,7 @@ TDengine 分布式架构的逻辑结构图如下: **重定向**:无论是dnode还是taosc,最先都是要发起与mnode的链接,但mnode是系统自动创建并维护的,因此对于用户来说,并不知道哪个dnode在运行mnode。TDengine只要求向系统中任何一个工作的dnode发起链接即可。因为任何一个正在运行的dnode,都维护有目前运行的mnode EP List。当收到一个来自新启动的dnode或taosc的链接请求,如果自己不是mnode,则将mnode EP List回复给对方,taosc或新启动的dnode收到这个list, 就重新尝试建立链接。当mnode EP List发生改变,通过节点之间的消息交互,各个数据节点就很快获取最新列表,并通知taosc。 -###一典型的操作流程 +### 一典型的操作流程 为解释vnode, mnode, taosc和应用之间的关系以及各自扮演的角色,下面对写入数据这个典型操作的流程进行剖析。
图 2 TDengine典型的操作流程
@@ -117,7 +117,7 @@ TDengine 分布式架构的逻辑结构图如下: ## 存储模型与数据分区、分片 -###存储模型 +### 存储模型 TDengine存储的数据包括采集的时序数据以及库、表相关的元数据、标签数据等,这些数据具体分为三部分: - 时序数据:存放于vnode里,由data、head和last三个文件组成,数据量大,查询量取决于应用场景。容许乱序写入,但暂时不支持删除和更新操作。通过采用一个采集点一张表的模型,一个时间段的数据是连续存储,对单张表的写入是简单的追加操作,一次读,可以读到多条记录,这样保证对单个采集点的插入和查询操作,性能达到最优。 @@ -129,7 +129,7 @@ TDengine存储的数据包括采集的时序数据以及库、表相关的元数 - 能够极大地降低标签数据存储的冗余度:一般的NoSQL数据库或时序数据库,采用的K-V存储,其中的Key包含时间戳、设备ID、各种标签。每条记录都带有这些重复的内容,浪费存储空间。而且如果应用要在历史数据上增加、修改或删除标签,需要遍历数据,重写一遍,操作成本极其昂贵。 - 能够实现极为高效的多表之间的聚合查询:做多表之间聚合查询时,先把符合标签过滤条件的表查找出来,然后再查找这些表相应的数据块,这样大幅减少要扫描的数据集,从而大幅提高查询效率。而且标签数据采用全内存的结构进行管理和维护,千万级别规模的标签数据查询可以在毫秒级别返回。 -###数据分片 +### 数据分片 对于海量的数据管理,为实现水平扩展,一般都需要采取分片(Sharding)分区(Partitioning)策略。TDengine是通过vnode来实现数据分片的,通过一个时间段一个数据文件来实现时序数据分区的。 vnode(虚拟数据节点)负责为采集的时序数据提供写入、查询和计算功能。为便于负载均衡、数据恢复、支持异构环境,TDengine将一个数据节点根据其计算和存储资源切分为多个vnode。这些vnode的管理是TDengine自动完成的,对应用完全透明。 @@ -140,12 +140,12 @@ vnode(虚拟数据节点)负责为采集的时序数据提供写入、查询和 每张表的meda data(包含schema, 标签等)也存放于vnode里,而不是集中存放于mnode,实际上这是对Meta数据的分片,这样便于高效并行的进行标签过滤操作。 -###数据分区 -TDengine除vnode分片之外,还按照时间段进行分区。每个数据文件只包含一个时间段的时序数据,时间段的长度由DB的配置参数days决定。这种按时间段分区的方法还便于高效实现数据的保留策略,只要数据文件超过规定的天数(系统配置参数keep),将被自动删除。而且不同的时间段可以存放于不同的路径和存储介质,以便于大数据的冷热管理,实现多级存储。 +### 数据分区 +TDengine除vnode分片之外,还对时序数据按照时间段进行分区。每个数据文件只包含一个时间段的时序数据,时间段的长度由DB的配置参数days决定。这种按时间段分区的方法还便于高效实现数据的保留策略,只要数据文件超过规定的天数(系统配置参数keep),将被自动删除。而且不同的时间段可以存放于不同的路径和存储介质,以便于大数据的冷热管理,实现多级存储。 总的来说,**TDengine是通过vnode以及时间两个维度,对大数据进行切分**,便于并行高效的管理,实现水平扩展。 -###负载均衡 +### 负载均衡 每个dnode都定时向 mnode(虚拟管理节点)报告其状态(包括硬盘空间、内存大小、CPU、网络、虚拟节点个数等),因此mnode了解整个集群的状态。基于整体状态,当mnode发现某个dnode负载过重,它会将dnode上的一个或多个vnode挪到其他dnode。在挪动过程中,对外服务继续进行,数据插入、查询和计算操作都不受影响。 如果mnode一段时间没有收到dnode的状态报告,mnode会认为这个dnode已经离线。如果离线时间超过一定时长(时长由配置参数offlineThreshold决定),该dnode将被mnode强制剔除出集群。该dnode上的vnodes如果副本数大于一,系统将自动在其他dnode上创建新的副本,以保证数据的副本数。如果该dnode上还有mnode, 而且mnode的副本数大于一,系统也将自动在其他dnode上创建新的mnode, 以保证mnode的副本数。 @@ -154,11 +154,12 @@ TDengine除vnode分片之外,还按照时间段进行分区。每个数据文 负载均衡过程无需任何人工干预,应用也无需重启,将自动连接新的节点,完全透明。 -##数据写入与复制流程 +## 数据写入与复制流程 如果一个数据库有N个副本,那一个虚拟节点组就有N个虚拟节点,但是只有一个是Master,其他都是slave。当应用将新的记录写入系统时,只有Master vnode能接受写的请求。如果slave vnode收到写的请求,系统将通知taosc需要重新定向。 -###Master vnode写入流程 +### Master vnode写入流程 Master Vnode遵循下面的写入流程:
+
图 3 TDengine Master写入流程
1. Master vnode收到应用的数据插入请求,验证OK,进入下一步; 2. 如果系统配置参数walLevel打开(设置为2),vnode将把该请求的原始数据包写入数据库日志文件WAL,以保证TDengine能够在断电等因素导致的服务重启时从数据库日志文件中恢复数据,避免数据的丢失; @@ -170,6 +171,7 @@ Master Vnode遵循下面的写入流程: ### Slave vnode写入流程 对于slave vnode, 写入流程是:
+
图 4 TDengine Slave写入流程
1. Slave vnode收到Master vnode转发了的数据插入请求。 2. 如果系统配置参数walLevl设置为2,vnode将把该请求的原始数据包写入日志(WAL); @@ -202,24 +204,24 @@ Vnode会保持一个数据版本号(Version),对内存数据进行持久化存 3. 在线的虚拟节点数过半,而且有虚拟节点是slave的话,该虚拟节点自动成为master 4. 对于2和3,如果多个虚拟节点满足成为master的要求,那么虚拟节点组的节点列表里,最前面的选为master -更多的关于数据复制的流程,请见[TDengine 2.0 数据复制模块设计](https://jira.taosdata.com:18090/pages/viewpage.action?pageId=6266055)。 +更多的关于数据复制的流程,请见TDengine 2.0数据复制模块设计。 -###同步复制 +### 同步复制 对于数据一致性要求更高的场景,异步数据复制无法满足要求,因为有极小的概率丢失数据,因此TDengine提供同步复制的机制供用户选择。在创建数据库时,除指定副本数replica之外,用户还需要指定新的参数quorum。如果quorum大于一,它表示每次Master转发给副本时,需要等待quorum-1个回复确认,才能通知应用,数据在slave已经写入成功。如果在一定的时间内,得不到quorum-1个回复确认,master vnode将返回错误给应用。 -采用同步复制,系统的性能会有所下降,而且latency会增加。因为元数据要强一致,Mnode之间的数据同步就是采用的同步复制。 +采用同步复制,系统的性能会有所下降,而且latency会增加。因为元数据要强一致,mnode之间的数据同步缺省就是采用的同步复制。 注:vnode之间的同步复制仅仅企业版支持 -##缓存与持久化 -###缓存 +## 缓存与持久化 +### 缓存 TDengine采用时间驱动缓存管理策略(First-In-First-Out,FIFO),又称为写驱动的缓存管理机制。这种策略有别于读驱动的数据缓存模式(Least-Recent-Used,LRU),直接将最近写入的数据保存在系统的缓存中。当缓存达到临界值的时候,将最早的数据批量写入磁盘。一般意义上来说,对于物联网数据的使用,用户最为关心的是刚产生的数据,即当前状态。TDengine充分利用这一特性,将最近到达的(当前状态)数据保存在缓存中。 TDengine通过查询函数向用户提供毫秒级的数据获取能力。直接将最近到达的数据保存在缓存中,可以更加快速地响应用户针对最近一条或一批数据的查询分析,整体上提供更快的数据库查询响应能力。从这个意义上来说,**可通过设置合适的配置参数将TDengine作为数据缓存来使用,而不需要再部署Redis或其他额外的缓存系统**,可有效地简化系统架构,降低运维的成本。需要注意的是,TDengine重启以后系统的缓存将被清空,之前缓存的数据均会被批量写入磁盘,缓存的数据将不会像专门的Key-value缓存系统再将之前缓存的数据重新加载到缓存中。 每个vnode有自己独立的内存,而且由多个固定大小的内存块组成,不同vnode之间完全隔离。数据写入时,类似于日志的写法,数据被顺序追加写入内存,但每个vnode维护有自己的skip list,便于迅速查找。当一半以上的内存块写满时,启动落盘操作,而且后续写的操作在新的内存块进行。这样,一个vnode里有一半内存块是保留有最近的数据的,以达到缓存、快速查找的目的。一个vnode的内存块的个数由配置参数blocks决定,内存块的大小由配置参数cache决定。 -###持久化存储 +### 持久化存储 TDengine采用数据驱动的方式让缓存中的数据写入硬盘进行持久化存储。当vnode中缓存的数据达到一定规模时,为了不阻塞后续数据的写入,TDengine也会拉起落盘线程将缓存的数据写入持久化存储。TDengine在数据落盘时会打开新的数据库日志文件,在落盘成功后则会删除老的数据库日志文件,避免日志文件无限制的增长。 为充分利用时序数据特点,TDengine将一个vnode保存在持久化存储的数据切分成多个文件,每个文件只保存固定天数的数据,这个天数由系统配置参数days决定。切分成多个文件后,给定查询的起止日期,无需任何索引,就可以立即定位需要打开哪些数据文件,大大加快读取速度。 @@ -234,7 +236,7 @@ TDengine采用数据驱动的方式让缓存中的数据写入硬盘进行持久 数据写入磁盘时,根据系统配置参数comp决定是否压缩数据。TDengine提供了三种压缩选项:无压缩、一阶段压缩和两阶段压缩,分别对应comp值为0、1和2的情况。一阶段压缩根据数据的类型进行了相应的压缩,压缩算法包括delta-delta编码、simple 8B方法、zig-zag编码、LZ4等算法。二阶段压缩在一阶段压缩的基础上又用通用压缩算法进行了压缩,压缩率更高。 -###多级存储 +### 多级存储 在默认配置下,TDengine会将所有数据保存在/var/lib/taos目录下,而且每个vnode的数据文件保存在该目录下的不同目录。为扩大存储空间,尽量减少文件读取的瓶颈,提高数据吞吐率 TDengine可通过配置系统参数dataDir让多个挂载的硬盘被系统同时使用。除此之外,TDengine也提供了数据分级存储的功能,即根据数据文件的新老程度存储在不同的存储介质上。比如最新的数据存储在SSD上,超过一周的数据存储在本地硬盘上,超过4周的数据存储在网络存储设备上,这样来降低存储成本,而又保证高效的访问数据。数据在不同存储介质上的移动是由系统自动完成的,对应用是完全透明的。数据的分级存储也是通过系统参数dataDir来配置。 dataDir的配置格式如下: @@ -258,36 +260,40 @@ dataDir /mnt/disk6/taos 2 注:多级存储功能仅企业版支持 -##数据查询 +## 数据查询 TDengine提供了多种多样针对表和超级表的查询处理功能,除了常规的聚合查询之外,还提供针对时序数据的窗口查询、统计聚合等功能。TDengine的查询处理需要客户端、vnode, mnode节点协同完成。 -5.1 单表查询 +### 单表查询 SQL语句的解析和校验工作在客户端完成。解析SQL语句并生成抽象语法树(Abstract Syntax Tree, AST),然后对其进行校验和检查。以及向管理节点(mnode)请求查询中指定表的元数据信息(table metadata)。 -根据元数据信息中的FQDN信息,将查询请求序列化后发送到该表所在的数据节点(dnode)。dnode接收到查询请求后,识别出该查询请求指向的虚拟节点(vnode),将消息转发到vnode的查询执行队列。vnode的查询执行线程建立基础的查询执行环境,并立即返回该查询请求,同时开始执行该查询。 +根据元数据信息中的End Point信息,将查询请求序列化后发送到该表所在的数据节点(dnode)。dnode接收到查询请求后,识别出该查询请求指向的虚拟节点(vnode),将消息转发到vnode的查询执行队列。vnode的查询执行线程建立基础的查询执行环境,并立即返回该查询请求,同时开始执行该查询。 客户端在获取查询结果的时候,dnode的查询执行队列中的工作线程会等待vnode执行线程执行完成,才能将查询结果返回到请求的客户端。 -5.2 时间轴聚合、插值 +### 按时间轴聚合、降采样、插值 时序数据有别于普通数据的显著特征是每条记录均具有时间戳,因此针对具有时间戳数据在时间轴上进行聚合是不同于普通数据库的重要功能。从这点上来看,与流计算引擎的窗口查询有相似的地方。 在TDengine中引入关键词interval来进行时间轴上固定长度时间窗口的切分,并按照时间窗口对数据进行聚合,对窗口范围内的数据按需进行聚合。例如: -select count(*) from D1001 interval(1h) +```mysql +select count(*) from d1001 interval(1h) +``` -针对D1001设备采集的数据,按照1小时的时间窗口返回每小时存储的记录数量。 +针对d1001设备采集的数据,按照1小时的时间窗口返回每小时存储的记录数量。 在需要连续获得查询结果的应用场景下,如果给定的时间区间存在数据缺失,会导致该区间数据结果也丢失。TDengine提供策略针对时间轴聚合计算的结果进行插值,通过使用关键词Fill就能够对时间轴聚合结果进行插值。例如: -select count(*) from D1001 interval(1h) fill(prev) +```mysql +select count(*) from d1001 interval(1h) fill(prev) +``` -针对D1001设备采集数据统计每小时记录数,如果某一个小时不存在数据,这返回之前一个小时的统计数据。TDengine提供前向插值(prev)、线性插值(linear)、NULL值填充(NULL)、特定值填充(value)。 +针对d1001设备采集数据统计每小时记录数,如果某一个小时不存在数据,这返回之前一个小时的统计数据。TDengine提供前向插值(prev)、线性插值(linear)、NULL值填充(NULL)、特定值填充(value)。 -5.3 多表聚合查询 +### 多表聚合查询 多表聚合查询与单表查询的整体流程相同,但是存在如下的差异: -1)由于多表可能分布在不同的节点(dnode),因此多表的聚合查询需要首先获得表所在的全部数据节点的信息,并且同时向相关的dnode发出查询请求。 -2)每个vnode的计算获得的中间结果(partial results)需要进行第二阶段的聚合才能形成最终结果,第二阶段的聚合过程在客户端完成。 -3)由于表标签信息存储在vnode中,因此针对标签信息的查询也需要vnode完成。客户端将标签的过滤表达式封装在查询请求结构体中发送给vnode,由vnode的查询执行线程从中抽取出标签查询条件,然后执行查询。标签查询与过滤是在针对表的查询之前完成。标签查询完成以后,将符合条件的表纳入到接下来的查询处理流程中。 +- 由于多表可能分布在不同的节点(dnode),因此多表的聚合查询需要首先获得表所在的全部数据节点的信息,并且同时向相关的dnode发出查询请求。 +- 每个vnode的计算获得的中间结果(partial results)需要进行第二阶段的聚合才能形成最终结果,第二阶段的聚合过程在客户端完成。 +- 由于表标签信息存储在vnode中,因此针对标签信息的查询也需要vnode完成。客户端将标签的过滤表达式封装在查询请求结构体中发送给vnode,由vnode的查询执行线程从中抽取出标签查询条件,然后执行查询。标签查询与过滤是在针对表的查询之前完成。标签查询完成以后,将符合条件的表纳入到接下来的查询处理流程中。 -5.4 预计算 +### 预计算 为有效提升查询处理的性能,针对物联网数据的不可更改的特点,在数据块头部记录该数据块中存储数据的统计信息:包括最大值、最小值、和。我们称之为预计算单元。如果查询处理涉及整个数据块的全部数据,直接使用预计算结果,完全不需要读取数据块的内容。由于预计算数据量远小于磁盘上存储的数据块数据的大小,对于磁盘IO为瓶颈的查询处理,使用预计算结果可以极大地减小读取IO压力,加速查询处理的流程。预计算机制与Postgre SQL的索引BRIN(block range index)有异曲同工之妙。 diff --git a/documentation20/webdocs/markdowndocs/cluster-ch.md b/documentation20/webdocs/markdowndocs/cluster-ch.md index 58fa9c6a5a..6102d5b020 100644 --- a/documentation20/webdocs/markdowndocs/cluster-ch.md +++ b/documentation20/webdocs/markdowndocs/cluster-ch.md @@ -29,7 +29,7 @@ taos> 将新的节点添加到现有集群,具体有以下几步: -1. 按照["立即开始“](https://www.taosdata.com/cn/getting-started/)一章的方法进行安装,但不要启动taosd +1. 按照["立即开始“](https://www.taosdata.com/cn/getting-started/)一章的方法进行安装,**但不要启动taosd** 2. 如果是使用涛思数据的官方安装包进行安装,在安装结束时,会询问集群的End Port, 输入第一个节点的End Point即可。如果是源码安装,请编辑配置文件taos.cfg(缺省是在/etc/taos/目录),增加一行: @@ -64,7 +64,7 @@ taos> **提示:** - firstEp, secondEp这两个参数仅仅在该节点第一次加入集群时有作用,加入集群后,该节点会保存最新的mnode的End Point列表,不再依赖这两个参数。 -- 两个没有配置first, second参数的dnode启动后,会独立运行起来。这个时候,无法将其中一个节点加入到另外一个节点,形成集群。**无法将两个独立的集群合并成为新的集群**。 +- 两个没有配置firstEp, secondEp参数的dnode启动后,会独立运行起来。这个时候,无法将其中一个节点加入到另外一个节点,形成集群。**无法将两个独立的集群合并成为新的集群**。 ##节点管理 @@ -135,8 +135,10 @@ SHOW MNODES; - 改节点离线超过一定时间(taos.cfg里配置参数offlineThreshold控制时长),系统将自动把该节点删除,产生系统报警信息,触发负载均衡流程。如果该被删除的节点重现上线时,它将无法加入集群,需要系统管理员重新将其添加进集群才会开始工作。 - 离线后,在offlineThreshold的时长内重新上线,系统将自动启动数据恢复流程,等数据完全恢复后,该节点将开始正常工作。 +**注意:**如果一个虚拟节点组(包括mnode组)里每个节点都处于离线或unsynced状态,必须等该虚拟节点组里的所有节点都上线、都能交换状态信息后,才能选出Master,该虚拟节点组才能对外提供服务。比如整个集群有3个节点,副本数为3,如果3个节点都宕机,然后2个节点重启,是无法工作的,只有等3个节点都重启成功,才能对外服务。 + ##Arbitrator的使用 -如果副本数为偶数,当一个vnode group里一半vnode不工作时,是无法从中选出master的。同理,一半mnode不工作时,是无法选出mnode的master的,因为存在“split brain”问题。为解决这个问题,TDengine引入了arbitrator的概念。Arbitrator模拟一个vnode或mnode在工作,但只简单的负责网络连接,不处理任何数据插入或访问。只要包含arbitrator在内,超过半数的vnode或mnode工作,那么该vnode group或mnode组就可以正常的提供数据插入或查询服务。比如对于副本数为2的情形,如果一个节点A离线,但另外一个节点B正常,而且能连接到arbitrator, 那么节点B就能正常工作。 +如果副本数为偶数,当一个vnode group里一半或超过一半的vnode不工作时,是无法从中选出master的。同理,一半或超过一半的mnode不工作时,是无法选出mnode的master的,因为存在“split brain”问题。为解决这个问题,TDengine引入了arbitrator的概念。Arbitrator模拟一个vnode或mnode在工作,但只简单的负责网络连接,不处理任何数据插入或访问。只要包含arbitrator在内,超过半数的vnode或mnode工作,那么该vnode group或mnode组就可以正常的提供数据插入或查询服务。比如对于副本数为2的情形,如果一个节点A离线,但另外一个节点B正常,而且能连接到arbitrator, 那么节点B就能正常工作。 TDengine安装包里带有一个执行程序tarbitrator, 找任何一台Linux服务器运行它即可。该程序对系统资源几乎没有要求,只需要保证有网络连接即可。该应用的命令行参数`-p`可以指定其对外服务的端口号,缺省是6030。配置每个taosd实例时,可以在配置文件taos.cfg里将参数arbitrator设置为arbitrator的End Point。如果该参数配置了,当副本数为偶数数,系统将自动连接配置的arbitrator。 diff --git a/documentation20/webdocs/markdowndocs/insert-ch.md b/documentation20/webdocs/markdowndocs/insert-ch.md index a92c7a7d00..b74e7a16ca 100644 --- a/documentation20/webdocs/markdowndocs/insert-ch.md +++ b/documentation20/webdocs/markdowndocs/insert-ch.md @@ -23,7 +23,7 @@ INSERT INTO d1001 VALUES (1538548685000, 10.3, 219, 0.31) (1538548695000, 12.6, **Tips:** - 要提高写入效率,需要批量写入。一批写入的记录条数越多,插入效率就越高。但一条记录不能超过16K,一条SQL语句总长度不能超过64K(可通过参数maxSQLLength配置)。 -- TDengine支持多线程同时写入,要进一步提高写入速度,一个客户端需要打开20个以上的线程同时写。 +- TDengine支持多线程同时写入,要进一步提高写入速度,一个客户端需要打开20个以上的线程同时写。但线程数达到一定数量后,无法再提高,甚至还会下降,因为线程切频繁切换,带来额外开销。 ## Prometheus直接写入 [Prometheus](https://www.prometheus.io/)作为Cloud Native Computing Fundation毕业的项目,在性能监控以及K8S性能监控领域有着非常广泛的应用。TDengine提供一个小工具[Bailongma](https://github.com/taosdata/Bailongma),只需在Prometheus做简单配置,无需任何代码,就可将Prometheus采集的数据直接写入TDengine,并按规则在TDengine自动创建库和相关表项。博文[用Docker容器快速搭建一个Devops监控Demo](https://www.taosdata.com/blog/2020/02/03/1189.html)即是采用bailongma将Prometheus和Telegraf的数据写入TDengine中的示例,可以参考。 diff --git a/documentation20/webdocs/markdowndocs/replica-ch.md b/documentation20/webdocs/markdowndocs/replica-ch.md index f93f3888c0..c32928b42d 100644 --- a/documentation20/webdocs/markdowndocs/replica-ch.md +++ b/documentation20/webdocs/markdowndocs/replica-ch.md @@ -224,9 +224,9 @@ Arbitrator的程序tarbitrator.c在复制模块的同一目录, 编译整个系 如果整个虚拟节点组全部宕机,重启,但不是所有虚拟节点都上线,这个时候TDengine是不会选出master的,因为未上线的节点有可能有最高version的数据。而RAFT协议,只要超过半数上线,就会选出Leader。 -## Meta Data数据复制问题 +## Meta Data的数据复制 -TDengine里存在时序数据,也存在Meta Data。Meta Data对数据的可靠性要求更高,那么本设计能否满足要求呢?下面做个仔细分析 +TDengine里存在时序数据,也存在Meta Data。Meta Data对数据的可靠性要求更高,那么TDengine设计能否满足要求呢?下面做个仔细分析 TDengine里Meta Data包括以下: diff --git a/documentation20/webdocs/markdowndocs/taosd-ch.md b/documentation20/webdocs/markdowndocs/taosd-ch.md index 4af1dd0fc4..8143137c79 100644 --- a/documentation20/webdocs/markdowndocs/taosd-ch.md +++ b/documentation20/webdocs/markdowndocs/taosd-ch.md @@ -41,7 +41,7 @@ RPC模块还提供数据压缩功能,如果数据包的字节数超过系统 taosd的消息消费由dnode通过读写线程池进行控制,是系统的中枢。该模块内的结构体图如下:
- + ## VNODE模块 vnode是一独立的数据存储查询逻辑单元,但因为一个vnode只能容许一个DB,因此vnode内部没有account, DB, user等概念。为实现更好的模块化、封装以及未来的扩展,它有很多子模块,包括负责存储的TSDB,负责查询的Query, 负责数据复制的sync,负责数据库日志的的wal, 负责连续查询的cq(continuous query), 负责事件触发的流计算的event等模块,这些子模块只与vnode模块发生关系,与其他模块没有任何调用关系。模块图如下: @@ -82,9 +82,9 @@ TSDB中存储的元数据包含属于其所在的VNODE中表的类型,schema 该模块负责整体系统的查询处理。客户端调用该该模块进行SQL语法解析,并将查询或写入请求发送到vnode,同时负责针对超级表的查询进行二阶段的聚合操作。在Vnode端,该模块调用TSDB模块读取系统中存储的数据进行查询处理。Query模块还定义了系统能够支持的全部查询函数,查询函数的实现机制与查询框架无耦合,可以在不修改查询流程的情况下动态增加查询函数。详细的设计请参见《TDengine 2.0查询模块设计》。 ## SYNC模块 -该模块实现数据的多副本复制,包括vnode与mnode的数据复制,支持异步和同步两种复制方式,以满足meta data与时序数据不同复制的需求。因为它为mnode与vnode共享,系统为mnode副本预留了一个特殊的vgroup ID:1。因此vnode的ID是从2开始的。 +该模块实现数据的多副本复制,包括vnode与mnode的数据复制,支持异步和同步两种复制方式,以满足meta data与时序数据不同复制的需求。因为它为mnode与vnode共享,系统为mnode副本预留了一个特殊的vgroup ID:1。因此vnode group的ID是从2开始的。 -每个vnode/mnode模块实例会有一对应的sync模块实例,他们是一一对应的。详细设计请见《TDengine 2.0 数据复制模块设计》 +每个vnode/mnode模块实例会有一对应的sync模块实例,他们是一一对应的。详细设计请见TDengine 2.0 数据复制模块设计 ## WAL模块 该模块负责将新插入的数据写入write ahead log(WAL), 为vnode, mnode共享。以保证服务器crash或其他故障,能从WAL中恢复数据。 From 08a45c1d8794f72bb8865fa53fe0f3444dff935a Mon Sep 17 00:00:00 2001 From: Bomin Zhang Date: Sat, 1 Aug 2020 09:39:49 +0800 Subject: [PATCH 42/56] td-962: update link --- documentation20/webdocs/markdowndocs/advanced features-ch.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation20/webdocs/markdowndocs/advanced features-ch.md b/documentation20/webdocs/markdowndocs/advanced features-ch.md index c767daddce..60bd6ddfdb 100644 --- a/documentation20/webdocs/markdowndocs/advanced features-ch.md +++ b/documentation20/webdocs/markdowndocs/advanced features-ch.md @@ -119,9 +119,9 @@ taos_consume taos_unsubscribe ``` -这些API的文档请见 [C/C++ 数据订阅接口](TODO: update link), +这些API的文档请见 [C/C++ 数据订阅接口](connector/#C/C++-Connector), 下面仍以智能电表场景为例介绍一下它们的具体用法(超级表和子表结构请参考上一节“连续查询”), -完整的示例代码可以在[这里](TODO: update link)找到。 +完整的示例代码可以在 [这里](https://github.com/taosdata/TDengine/blob/master/tests/examples/c/subscribe.c) 找到。 如果我们希望当某个电表的电流超过一定限制(比如10A)后能得到通知并进行一些处理, 有两种方法: 一是分别对每张子表进行查询,每次查询后记录最后一条数据的时间戳,后续只查询这个时间戳之后的数据: From 0d1be106078e41c6b029bc2b47adfdcbc091dca0 Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Sat, 1 Aug 2020 10:02:44 +0800 Subject: [PATCH 43/56] Update administrator-ch.md --- documentation20/webdocs/markdowndocs/administrator-ch.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation20/webdocs/markdowndocs/administrator-ch.md b/documentation20/webdocs/markdowndocs/administrator-ch.md index ea9231bae6..ad03162ad4 100644 --- a/documentation20/webdocs/markdowndocs/administrator-ch.md +++ b/documentation20/webdocs/markdowndocs/administrator-ch.md @@ -22,8 +22,8 @@ Memory Size = maxVgroupsPerDb * (blocks * cache + 10Mb) + numOfTables * (tagSize CPU的需求取决于如下两方面: -- 数据插入:TDengine单核每秒能至少处理一万个插入请求。每个插入请求可以带多条记录,一次插入一条记录与插入10条记录,消耗的计算资源差别很小。因此每次插入,条数越大,插入效率越高。如果一个插入请求带200条以上记录,单核就能达到每秒插入100万条记录的速度。但对前端数据采集的要求越高,因为需要缓存记录,然后一批插入。 -- 查询需求:TDengine提供高效的查询,但是每个场景的查询差异很大,查询频次变化也很大,难以给出客观数字。需要用户针对自己的场景,写一些查询语句,才能确定。 +* __数据插入__ TDengine单核每秒能至少处理一万个插入请求。每个插入请求可以带多条记录,一次插入一条记录与插入10条记录,消耗的计算资源差别很小。因此每次插入,条数越大,插入效率越高。如果一个插入请求带200条以上记录,单核就能达到每秒插入100万条记录的速度。但对前端数据采集的要求越高,因为需要缓存记录,然后一批插入。 +* __查询需求__ TDengine提供高效的查询,但是每个场景的查询差异很大,查询频次变化也很大,难以给出客观数字。需要用户针对自己的场景,写一些查询语句,才能确定。 因此仅对数据插入而言,CPU是可以估算出来的,但查询所耗的计算资源无法估算。在实际运营过程中,不建议CPU使用率超过50%,超过后,需要增加新的节点,以获得更多计算资源。 From f9614aa8c95a11d2274c5fec753a3c8906b0ac49 Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Sat, 1 Aug 2020 02:11:30 +0000 Subject: [PATCH 44/56] open log while compile in clang --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4afdb6154e..60d295690e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -189,8 +189,8 @@ matrix: - cd debug script: - - cmake .. > /dev/null - - make > /dev/null + - cmake .. + - make - os: linux arch: arm64 From bbc9be5ba697d2622e03dbb1fec7b4def01ce748 Mon Sep 17 00:00:00 2001 From: Hui Li Date: Sat, 1 Aug 2020 10:16:36 +0800 Subject: [PATCH 45/56] [modify install show info] --- packaging/tools/install.sh | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/packaging/tools/install.sh b/packaging/tools/install.sh index aee4bbadf6..5a5dd88034 100644 --- a/packaging/tools/install.sh +++ b/packaging/tools/install.sh @@ -79,19 +79,19 @@ osinfo=$(cat /etc/os-release | grep "NAME" | cut -d '"' -f2) #echo "osinfo: ${osinfo}" os_type=0 if echo $osinfo | grep -qwi "ubuntu" ; then - echo "This is ubuntu system" +# echo "This is ubuntu system" os_type=1 elif echo $osinfo | grep -qwi "debian" ; then - echo "This is debian system" +# echo "This is debian system" os_type=1 elif echo $osinfo | grep -qwi "Kylin" ; then - echo "This is Kylin system" +# echo "This is Kylin system" os_type=1 elif echo $osinfo | grep -qwi "centos" ; then - echo "This is centos system" +# echo "This is centos system" os_type=2 elif echo $osinfo | grep -qwi "fedora" ; then - echo "This is fedora system" +# echo "This is fedora system" os_type=2 else echo "${osinfo}: This is an officially unverified linux system, If there are any problems with the installation and operation, " @@ -135,7 +135,7 @@ do esac done -echo "verType=${verType} interactiveFqdn=${interactiveFqdn}" +#echo "verType=${verType} interactiveFqdn=${interactiveFqdn}" function kill_taosd() { pid=$(ps -ef | grep "taosd" | grep -v "grep" | awk '{print $2}') @@ -240,8 +240,10 @@ function install_config() { # first full-qualified domain name (FQDN) for TDengine cluster system echo - echo -e -n "${GREEN}Enter FQDN:port (like h1.taosdata.com:6030) of an existing TDengine cluster node to join OR leave it blank to build one${NC} :" - read firstEp + echo -e -n "${GREEN}Enter FQDN:port (like h1.taosdata.com:6030) of an existing TDengine cluster node to join${NC}" + echo + echo -e -n "${GREEN}OR leave it blank to build one${NC}:" + read firstEp while true; do if [ ! -z "$firstEp" ]; then # check the format of the firstEp @@ -672,7 +674,8 @@ function install_TDengine() { if [ ! -z "$firstEp" ]; then echo - echo -e "${GREEN_DARK}Please run${NC}: taos -h $firstEp ${GREEN_DARK} to login into cluster, then execute ${NC}: create dnode 'newDnodeFQDN:port'; ${GREEN_DARK}in TAOS shell to add this new node into the clsuter${NC}" + echo -e "${GREEN_DARK}Please run${NC}: taos -h $firstEp${GREEN_DARK} to login into cluster, then${NC}" + echo -e "${GREEN_DARK}execute ${NC}: create dnode 'newDnodeFQDN:port'; ${GREEN_DARK}to add this new node${NC}" echo fi echo -e "\033[44;32;1mTDengine is installed successfully!${NC}" From 700df6a0718ae1275bd5f87ea5fc052d0bae3c3f Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Sat, 1 Aug 2020 02:25:43 +0000 Subject: [PATCH 46/56] change cmake option --- cmake/define.inc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmake/define.inc b/cmake/define.inc index d840cb59e2..429a7cd8fe 100755 --- a/cmake/define.inc +++ b/cmake/define.inc @@ -61,6 +61,9 @@ IF (TD_LINUX_64) ELSE () SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -fPIC -g -fsigned-char -fpack-struct=8 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE") ENDIF () + MESSAGE(STATUS "CMAKE_CXX_COMPILER_ID: " ${CMAKE_CXX_COMPILER_ID}) + MESSAGE(STATUS "COMMON_FLAGS: " ${COMMON_FLAGS}) + FIND_PATH(ICONV_INCLUDE_EXIST iconv.h /usr/include/ /usr/local/include/) IF (ICONV_INCLUDE_EXIST) ADD_DEFINITIONS(-DUSE_LIBICONV) From d1bb163cab8aeb454fcc64d6deac7a388e6614a6 Mon Sep 17 00:00:00 2001 From: Hui Li Date: Sat, 1 Aug 2020 10:31:16 +0800 Subject: [PATCH 47/56] [modify install show info] --- packaging/tools/install.sh | 14 +++++++------- packaging/tools/post.sh | 13 ++++++++----- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/packaging/tools/install.sh b/packaging/tools/install.sh index 5a5dd88034..ce5c052e97 100644 --- a/packaging/tools/install.sh +++ b/packaging/tools/install.sh @@ -241,9 +241,9 @@ function install_config() { # first full-qualified domain name (FQDN) for TDengine cluster system echo echo -e -n "${GREEN}Enter FQDN:port (like h1.taosdata.com:6030) of an existing TDengine cluster node to join${NC}" - echo + echo echo -e -n "${GREEN}OR leave it blank to build one${NC}:" - read firstEp + read firstEp while true; do if [ ! -z "$firstEp" ]; then # check the format of the firstEp @@ -672,11 +672,11 @@ function install_TDengine() { echo -e "${GREEN_DARK}To access TDengine ${NC}: use ${GREEN_UNDERLINE}taos${NC} in shell${NC}" fi - if [ ! -z "$firstEp" ]; then - echo - echo -e "${GREEN_DARK}Please run${NC}: taos -h $firstEp${GREEN_DARK} to login into cluster, then${NC}" - echo -e "${GREEN_DARK}execute ${NC}: create dnode 'newDnodeFQDN:port'; ${GREEN_DARK}to add this new node${NC}" - echo + if [ ! -z "$firstEp" ]; then + echo + echo -e "${GREEN_DARK}Please run${NC}: taos -h $firstEp${GREEN_DARK} to login into cluster, then${NC}" + echo -e "${GREEN_DARK}execute ${NC}: create dnode 'newDnodeFQDN:port'; ${GREEN_DARK}to add this new node${NC}" + echo fi echo -e "\033[44;32;1mTDengine is installed successfully!${NC}" echo diff --git a/packaging/tools/post.sh b/packaging/tools/post.sh index ef66f9fa4f..cffe06e30c 100755 --- a/packaging/tools/post.sh +++ b/packaging/tools/post.sh @@ -113,7 +113,9 @@ function install_config() { # first full-qualified domain name (FQDN) for TDengine cluster system echo - echo -e -n "${GREEN}Enter FQDN:port (like h1.taosdata.com:6030) of an existing TDengine cluster node to join OR leave it blank to build one${NC} :" + echo -e -n "${GREEN}Enter FQDN:port (like h1.taosdata.com:6030) of an existing TDengine cluster node to join${NC}" + echo + echo -e -n "${GREEN}OR leave it blank to build one${NC}:" read firstEp while true; do if [ ! -z "$firstEp" ]; then @@ -265,10 +267,11 @@ function install_TDengine() { echo -e "${GREEN_DARK}To access TDengine ${NC}: use ${GREEN_UNDERLINE}taos${NC} in shell${NC}" - if [ ! -z "$firstEp" ]; then - echo - echo -e "${GREEN_DARK}Please run${NC}: taos -h $firstEp ${GREEN_DARK} to login into cluster, then execute ${NC}: create dnode 'newDnodeFQDN:port'; ${GREEN_DARK}in TAOS shell to add this new node into the clsuter${NC}" - echo + if [ ! -z "$firstEp" ]; then + echo + echo -e "${GREEN_DARK}Please run${NC}: taos -h $firstEp${GREEN_DARK} to login into cluster, then${NC}" + echo -e "${GREEN_DARK}execute ${NC}: create dnode 'newDnodeFQDN:port'; ${GREEN_DARK}to add this new node${NC}" + echo fi echo echo -e "\033[44;32;1mTDengine is installed successfully!${NC}" From ea640ac08d73165759edc2ff7a20dadb5aaa44d5 Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Sat, 1 Aug 2020 02:49:04 +0000 Subject: [PATCH 48/56] compile options --- cmake/define.inc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cmake/define.inc b/cmake/define.inc index 429a7cd8fe..4a905975aa 100755 --- a/cmake/define.inc +++ b/cmake/define.inc @@ -53,11 +53,12 @@ IF (TD_LINUX_64) ADD_DEFINITIONS(-D_M_X64) ADD_DEFINITIONS(-D_TD_LINUX_64) IF (NOT TD_ARM) - IF ((${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") OR (${CMAKE_CXX_COMPILER_ID} MATCHES "clang")) - SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -Wno-missing-braces -fPIC -g3 -gdwarf-2 -msse4.2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE") - ELSE () - SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -fPIC -malign-double -g3 -gdwarf-2 -malign-stringops -msse4.2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE") - ENDIF () + #IF ((${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") OR (${CMAKE_CXX_COMPILER_ID} MATCHES "clang")) + # SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -Wno-missing-braces -fPIC -g3 -gdwarf-2 -msse4.2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE") + #ELSE () + # SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -fPIC -malign-double -g3 -gdwarf-2 -malign-stringops -msse4.2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE") + #ENDIF () + SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -fPIC -malign-double -g3 -gdwarf-2 -malign-stringops -msse4.2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE") ELSE () SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -fPIC -g -fsigned-char -fpack-struct=8 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE") ENDIF () From 4200bf01f94648a96e1bd29ed712c5e9b06e1e9a Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Sat, 1 Aug 2020 02:49:40 +0000 Subject: [PATCH 49/56] compile options --- cmake/define.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/define.inc b/cmake/define.inc index 4a905975aa..1e052142d6 100755 --- a/cmake/define.inc +++ b/cmake/define.inc @@ -58,7 +58,7 @@ IF (TD_LINUX_64) #ELSE () # SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -fPIC -malign-double -g3 -gdwarf-2 -malign-stringops -msse4.2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE") #ENDIF () - SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -fPIC -malign-double -g3 -gdwarf-2 -malign-stringops -msse4.2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE") + SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -fPIC -malign-double -g3 -gdwarf-2 -msse4.2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE") ELSE () SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -fPIC -g -fsigned-char -fpack-struct=8 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE") ENDIF () From 8a29fd30c099c8a612c79e3a6683484bd89a971a Mon Sep 17 00:00:00 2001 From: Xiaowei Su <46439638+Shawshank-Smile@users.noreply.github.com> Date: Sat, 1 Aug 2020 10:56:01 +0800 Subject: [PATCH 50/56] Update faq-ch.md --- documentation20/webdocs/markdowndocs/faq-ch.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/documentation20/webdocs/markdowndocs/faq-ch.md b/documentation20/webdocs/markdowndocs/faq-ch.md index 621bef73bc..bca9cff8e6 100644 --- a/documentation20/webdocs/markdowndocs/faq-ch.md +++ b/documentation20/webdocs/markdowndocs/faq-ch.md @@ -68,7 +68,8 @@ windows下插入nchar类的数据中如果有中文,请先确认系统的地 ​ Connection = DriverManager.getConnection(url, properties); -#### 12. TDengine GO windows驱动的编译 +#### 12.TDengine GO windows驱动的如何编译? +请看为此问题撰写的技术博客 From a9d963e229982afc3870af1103014f7c5149ddb8 Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Sat, 1 Aug 2020 03:00:21 +0000 Subject: [PATCH 51/56] remove compile options malign --- cmake/define.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/define.inc b/cmake/define.inc index 1e052142d6..c3e699bbd6 100755 --- a/cmake/define.inc +++ b/cmake/define.inc @@ -58,7 +58,7 @@ IF (TD_LINUX_64) #ELSE () # SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -fPIC -malign-double -g3 -gdwarf-2 -malign-stringops -msse4.2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE") #ENDIF () - SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -fPIC -malign-double -g3 -gdwarf-2 -msse4.2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE") + SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -Wno-missing-braces -fPIC -g3 -gdwarf-2 -msse4.2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE") ELSE () SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -fPIC -g -fsigned-char -fpack-struct=8 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE") ENDIF () From 09da8164f1eb0ef80b13a28c24c541c310c4675f Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Sat, 1 Aug 2020 03:13:11 +0000 Subject: [PATCH 52/56] yml --- .travis.yml | 4 ++-- cmake/define.inc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 60d295690e..6e49709c85 100644 --- a/.travis.yml +++ b/.travis.yml @@ -189,8 +189,8 @@ matrix: - cd debug script: - - cmake .. - - make + - cmake .. > /dev/null + - make > /dev/null - os: linux arch: arm64 diff --git a/cmake/define.inc b/cmake/define.inc index c3e699bbd6..f6438c0873 100755 --- a/cmake/define.inc +++ b/cmake/define.inc @@ -58,7 +58,7 @@ IF (TD_LINUX_64) #ELSE () # SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -fPIC -malign-double -g3 -gdwarf-2 -malign-stringops -msse4.2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE") #ENDIF () - SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -Wno-missing-braces -fPIC -g3 -gdwarf-2 -msse4.2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE") + SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -fPIC -g3 -gdwarf-2 -msse4.2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE") ELSE () SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -fPIC -g -fsigned-char -fpack-struct=8 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE") ENDIF () From 19da158e9dc944efd752ea3324520c4afc79d422 Mon Sep 17 00:00:00 2001 From: yihaoDeng Date: Sat, 1 Aug 2020 11:15:53 +0800 Subject: [PATCH 53/56] update administrator-ch.md --- documentation20/webdocs/markdowndocs/administrator-ch.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/documentation20/webdocs/markdowndocs/administrator-ch.md b/documentation20/webdocs/markdowndocs/administrator-ch.md index ad03162ad4..6535647981 100644 --- a/documentation20/webdocs/markdowndocs/administrator-ch.md +++ b/documentation20/webdocs/markdowndocs/administrator-ch.md @@ -226,9 +226,7 @@ Query OK, 9 row(s) affected (0.004763s) **taosdump工具导入** -TDengine提供了方便的数据库导入导出工具taosdump。用户可以将taosdump从一个系统导出的数据,导入到其他系统中。具体使用方法,请参见博客: - -[TDengine DUMP工具使用指南]: https://www.taosdata.com/blog/2020/03/09/1334.html +TDengine提供了方便的数据库导入导出工具taosdump。用户可以将taosdump从一个系统导出的数据,导入到其他系统中。具体使用方法,请参见博客:TDengine DUMP工具使用指南 ## 数据导出 @@ -246,9 +244,7 @@ select * from >> data.csv **用taosdump导出数据** -TDengine提供了方便的数据库导出工具taosdump。用户可以根据需要选择导出所有数据库、一个数据库或者数据库中的一张表,所有数据或一时间段的数据,甚至仅仅表的定义。具体使用方法,请参见博客: - -[TDengine DUMP工具使用指南]: https://www.taosdata.com/blog/2020/03/09/1334.html +TDengine提供了方便的数据库导出工具taosdump。用户可以根据需要选择导出所有数据库、一个数据库或者数据库中的一张表,所有数据或一时间段的数据,甚至仅仅表的定义。具体使用方法,请参见博客:TDengine DUMP工具使用指南 ## 系统连接、任务查询管理 From b133cd49b1e22f335c1564079142a468d26ece40 Mon Sep 17 00:00:00 2001 From: JUN JIE NAN Date: Sat, 1 Aug 2020 12:26:04 +0800 Subject: [PATCH 54/56] Removed extra " in hashTest includes --- src/util/tests/hashTest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/tests/hashTest.cpp b/src/util/tests/hashTest.cpp index 6ffce61e61..f9f636db90 100644 --- a/src/util/tests/hashTest.cpp +++ b/src/util/tests/hashTest.cpp @@ -5,7 +5,7 @@ #include #include "hash.h" -#include "taos.h"" +#include "taos.h" namespace { // the simple test code for basic operations @@ -153,4 +153,4 @@ TEST(testCase, hashTest) { stringKeyTest(); noLockPerformanceTest(); multithreadsTest(); -} \ No newline at end of file +} From 90c9eae23ee588508e0e9b5e65fcb3ca2a8fb10e Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Sat, 1 Aug 2020 12:37:38 +0800 Subject: [PATCH 55/56] fd maybe reused while close httpcontext --- src/plugins/http/src/httpContext.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/http/src/httpContext.c b/src/plugins/http/src/httpContext.c index ad72ac8823..e367911695 100644 --- a/src/plugins/http/src/httpContext.c +++ b/src/plugins/http/src/httpContext.c @@ -31,8 +31,8 @@ static void httpRemoveContextFromEpoll(HttpContext *pContext) { HttpThread *pThread = pContext->pThread; if (pContext->fd >= 0) { epoll_ctl(pThread->pollFd, EPOLL_CTL_DEL, pContext->fd, NULL); - taosCloseSocket(pContext->fd); - pContext->fd = -1; + int32_t fd = atomic_val_compare_exchange_32(&pContext->fd, pContext->fd, -1); + taosCloseSocket(fd); } } From bc7ab520526d69a863c074af40660631fb4d88f2 Mon Sep 17 00:00:00 2001 From: Yiqing Liu Date: Sat, 1 Aug 2020 15:11:44 +0800 Subject: [PATCH 56/56] change format change format --- documentation20/webdocs/markdowndocs/connector-ch.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/documentation20/webdocs/markdowndocs/connector-ch.md b/documentation20/webdocs/markdowndocs/connector-ch.md index 71f1dd31d3..04f7c2bc5c 100644 --- a/documentation20/webdocs/markdowndocs/connector-ch.md +++ b/documentation20/webdocs/markdowndocs/connector-ch.md @@ -45,11 +45,11 @@ C/C++的API类似于MySQL的C API。应用程序使用时,需要包含TDengine 创建数据库连接,初始化连接上下文。其中需要用户提供的参数包含: - * ip:TDengine管理主节点的IP地址 - * user:用户名 - * pass:密码 - * db:数据库名字,如果用户没有提供,也可以正常连接,用户可以通过该连接创建新的数据库,如果用户提供了数据库名字,则说明该数据库用户已经创建好,缺省使用该数据库 - * port:端口号 + - ip:TDengine管理主节点的IP地址 + - user:用户名 + - pass:密码 + - db:数据库名字,如果用户没有提供,也可以正常连接,用户可以通过该连接创建新的数据库,如果用户提供了数据库名字,则说明该数据库用户已经创建好,缺省使用该数据库 + - port:端口号 返回值为空表示失败。应用程序需要保存返回的参数,以便后续API调用。