提交 ac881a7e 编写于 作者: H Haojun Liao

other: merge 3.0

上级 e63d3df1
/*
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _TD_SHELL_H_
#define _TD_SHELL_H_
#include "os.h"
#include "taos.h"
#include "taosdef.h"
#define MAX_USERNAME_SIZE 64
#define MAX_DBNAME_SIZE 64
#define MAX_IP_SIZE 20
#define MAX_HISTORY_SIZE 1000
#define MAX_COMMAND_SIZE 1048586
#define HISTORY_FILE ".taos_history"
#define DEFAULT_RES_SHOW_NUM 100
typedef struct SShellHistory {
char* hist[MAX_HISTORY_SIZE];
int hstart;
int hend;
} SShellHistory;
typedef struct SShellArguments {
char* host;
char* password;
char* user;
char* auth;
char* database;
char* timezone;
bool is_raw_time;
bool is_use_passwd;
bool dump_config;
char file[TSDB_FILENAME_LEN];
char dir[TSDB_FILENAME_LEN];
int threadNum;
int check;
bool status;
bool verbose;
char* commands;
int abort;
int port;
int pktLen;
int pktNum;
char* pktType;
char* netTestRole;
} SShellArguments;
/**************** Function declarations ****************/
extern void shellParseArgument(int argc, char* argv[], SShellArguments* arguments);
extern TAOS* shellInit(SShellArguments* args);
extern void* shellLoopQuery(void* arg);
extern void taos_error(TAOS_RES* tres, int64_t st);
extern int regex_match(const char* s, const char* reg, int cflags);
int32_t shellReadCommand(TAOS* con, char command[]);
int32_t shellRunCommand(TAOS* con, char* command);
void shellRunCommandOnServer(TAOS* con, char command[]);
void read_history();
void write_history();
void source_file(TAOS* con, char* fptr);
void source_dir(TAOS* con, SShellArguments* args);
void get_history_path(char* history);
void shellCheck(TAOS* con, SShellArguments* args);
void cleanup_handler(void* arg);
void exitShell();
int shellDumpResult(TAOS_RES* con, char* fname, int* error_no, bool printMode);
void shellGetGrantInfo(void *con);
int isCommentLine(char *line);
/**************** Global variable declarations ****************/
extern char PROMPT_HEADER[];
extern char CONTINUE_PROMPT[];
extern int prompt_size;
extern SShellHistory history;
extern SShellArguments args;
extern int64_t result;
#endif
/*
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _TD_SHELL_COMMAND_H_
#define _TD_SHELL_COMMAND_H_
#include "shell.h"
#define LEFT 1
#define RIGHT 2
#define UP 3
#define DOWN 4
typedef struct Command Command;
struct Command {
char * buffer;
char * command;
unsigned commandSize;
unsigned bufferSize;
unsigned cursorOffset;
unsigned screenOffset;
unsigned endOffset;
};
extern void backspaceChar(Command *cmd);
extern void clearLineBefore(Command *cmd);
extern void clearLineAfter(Command *cmd);
extern void deleteChar(Command *cmd);
extern void moveCursorLeft(Command *cmd);
extern void moveCursorRight(Command *cmd);
extern void positionCursorHome(Command *cmd);
extern void positionCursorEnd(Command *cmd);
extern void showOnScreen(Command *cmd);
extern void updateBuffer(Command *cmd);
extern int isReadyGo(Command *cmd);
extern void resetCommand(Command *cmd, const char s[]);
int countPrefixOnes(unsigned char c);
void clearScreen(int ecmd_pos, int cursor_pos);
void printChar(char c, int times);
void positionCursor(int step, int direction);
#endif
/*
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _TD_SHELL_INT_H_
#define _TD_SHELL_INT_H_
#include "os.h"
#include "taos.h"
#include "taosdef.h"
#include "taoserror.h"
#include "tconfig.h"
#include "tglobal.h"
#include "trpc.h"
#include "ttypes.h"
#include "tutil.h"
#define SHELL_MAX_HISTORY_SIZE 1000
#define SHELL_MAX_COMMAND_SIZE 1048586
#define SHELL_HISTORY_FILE ".taos_history"
#define SHELL_DEFAULT_RES_SHOW_NUM 100
#define SHELL_DEFAULT_MAX_BINARY_DISPLAY_WIDTH 30
#define SHELL_MAX_PKG_LEN 2 * 1024 * 1024
#define SHELL_MIN_PKG_LEN 1
#define SHELL_DEF_PKG_LEN 1024
#define SHELL_MAX_PKG_NUM 1 * 1024 * 1024
#define SHELL_MIN_PKG_NUM 1
#define SHELL_DEF_PKG_NUM 100
typedef struct {
char* hist[SHELL_MAX_HISTORY_SIZE];
char file[TSDB_FILENAME_LEN];
int32_t hstart;
int32_t hend;
} SShellHistory;
typedef struct {
const char* host;
const char* user;
const char* auth;
const char* database;
const char* cfgdir;
const char* commands;
const char* netrole;
char file[PATH_MAX];
char password[TSDB_USET_PASSWORD_LEN];
bool is_gen_auth;
bool is_raw_time;
bool is_version;
bool is_dump_config;
bool is_check;
bool is_startup;
bool is_help;
uint16_t port;
int32_t pktLen;
int32_t pktNum;
int32_t displayWidth;
int32_t abort;
} SShellArgs;
typedef struct {
const char* clientVersion;
const char* promptHeader;
const char* promptContinue;
const char* osname;
int32_t promptSize;
char programVersion[32];
} SShellOsDetails;
typedef struct {
SShellArgs args;
SShellHistory history;
SShellOsDetails info;
TAOS* conn;
TdThread pid;
tsem_t cancelSem;
int64_t result;
} SShellObj;
// shellArguments.c
int32_t shellParseArgs(int32_t argc, char* argv[]);
// shellCommand.c
int32_t shellReadCommand(char* command);
// shellEngine.c
int32_t shellExecute();
// shellUtil.c
int32_t shellCheckIntSize();
void shellPrintVersion();
void shellPrintHelp();
void shellGenerateAuth();
void shellDumpConfig();
void shellCheckServerStatus();
bool shellRegexMatch(const char* s, const char* reg, int32_t cflags);
void shellExit();
// shellNettest.c
void shellTestNetWork();
// shellMain.c
extern SShellObj shell;
extern void taos_init();
#endif /*_TD_SHELL_INT_H_*/
/*
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TDENGINE_SYNC_MSG_H
#define TDENGINE_SYNC_MSG_H
#ifdef __cplusplus
extern "C" {
#endif
#include "tsync.h"
typedef enum {
TAOS_SMSG_START = 0,
TAOS_SMSG_SYNC_DATA = 1,
TAOS_SMSG_SYNC_DATA_RSP = 2,
TAOS_SMSG_SYNC_FWD = 3,
TAOS_SMSG_SYNC_FWD_RSP = 4,
TAOS_SMSG_SYNC_REQ = 5,
TAOS_SMSG_SYNC_REQ_RSP = 6,
TAOS_SMSG_SYNC_MUST = 7,
TAOS_SMSG_SYNC_MUST_RSP = 8,
TAOS_SMSG_STATUS = 9,
TAOS_SMSG_STATUS_RSP = 10,
TAOS_SMSG_SETUP = 11,
TAOS_SMSG_SETUP_RSP = 12,
TAOS_SMSG_SYNC_FILE = 13,
TAOS_SMSG_SYNC_FILE_RSP = 14,
TAOS_SMSG_TEST = 15,
TAOS_SMSG_END = 16
} ESyncMsgType;
typedef enum {
SYNC_STATUS_BROADCAST,
SYNC_STATUS_BROADCAST_RSP,
SYNC_STATUS_SETUP_CONN,
SYNC_STATUS_SETUP_CONN_RSP,
SYNC_STATUS_EXCHANGE_DATA,
SYNC_STATUS_EXCHANGE_DATA_RSP,
SYNC_STATUS_CHECK_ROLE,
SYNC_STATUS_CHECK_ROLE_RSP
} ESyncStatusType;
#pragma pack(push, 1)
typedef struct {
int8_t type; // msg type
int8_t protocol; // protocol version
uint16_t signature; // fixed value
int32_t code; //
int32_t cId; // cluster Id
int32_t vgId; // vg ID
int32_t len; // content length, does not include head
uint32_t cksum;
} SSyncHead;
typedef struct {
SSyncHead head;
uint16_t port;
uint16_t tranId;
int32_t sourceId; // only for arbitrator
char fqdn[TSDB_FQDN_LEN];
} SSyncMsg;
typedef struct {
SSyncHead head;
int8_t sync;
int8_t reserved;
uint16_t tranId;
int8_t reserverd[4];
} SSyncRsp;
typedef struct {
int8_t role;
uint64_t version;
} SPeerStatus;
typedef struct {
SSyncHead head;
int8_t role;
int8_t ack;
int8_t type;
int8_t reserved[3];
uint16_t tranId;
uint64_t version;
SPeerStatus peersStatus[TAOS_SYNC_MAX_REPLICA];
} SPeersStatus;
typedef struct {
SSyncHead head;
uint64_t fversion;
} SFileVersion;
typedef struct {
SSyncHead head;
int8_t ack;
} SFileAck;
typedef struct {
SSyncHead head;
uint64_t version;
int32_t code;
} SFwdRsp;
#pragma pack(pop)
#define SYNC_PROTOCOL_VERSION 1
#define SYNC_SIGNATURE ((uint16_t)(0xCDEF))
extern char *statusType[];
uint16_t syncGenTranId();
int32_t syncCheckHead(SSyncHead *pHead);
void syncBuildSyncFwdMsg(SSyncHead *pHead, int32_t vgId, int32_t len);
void syncBuildSyncFwdRsp(SFwdRsp *pMsg, int32_t vgId, uint64_t version, int32_t code);
void syncBuildSyncReqMsg(SSyncMsg *pMsg, int32_t vgId);
void syncBuildSyncDataMsg(SSyncMsg *pMsg, int32_t vgId);
void syncBuildSyncSetupMsg(SSyncMsg *pMsg, int32_t vgId);
void syncBuildPeersStatus(SPeersStatus *pMsg, int32_t vgId);
void syncBuildSyncTestMsg(SSyncMsg *pMsg, int32_t vgId);
void syncBuildFileAck(SFileAck *pMsg, int32_t vgId);
void syncBuildFileVersion(SFileVersion *pMsg, int32_t vgId);
#ifdef __cplusplus
}
#endif
#endif // TDENGINE_VNODEPEER_H
/*
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TDENGINE_SYNC_H
#define TDENGINE_SYNC_H
#ifdef __cplusplus
extern "C" {
#endif
#define TAOS_SYNC_MAX_REPLICA 5
#define TAOS_SYNC_MAX_INDEX 0x7FFFFFFF
typedef enum {
TAOS_SYNC_ROLE_OFFLINE = 0,
TAOS_SYNC_ROLE_UNSYNCED = 1,
TAOS_SYNC_ROLE_SYNCING = 2,
TAOS_SYNC_ROLE_SLAVE = 3,
TAOS_SYNC_ROLE_MASTER = 4
} ESyncRole;
typedef enum {
TAOS_SYNC_STATUS_INIT = 0,
TAOS_SYNC_STATUS_START = 1,
TAOS_SYNC_STATUS_FILE = 2,
TAOS_SYNC_STATUS_CACHE = 3
} ESyncStatus;
typedef struct {
uint32_t nodeId; // node ID assigned by TDengine
uint16_t nodePort; // node sync Port
char nodeFqdn[TSDB_FQDN_LEN]; // node FQDN
} SNodeInfo;
typedef struct {
int8_t quorum; // number of confirms required, >=1
int8_t replica; // number of replications, >=1
SNodeInfo nodeInfo[TAOS_SYNC_MAX_REPLICA];
} SSyncCfg;
typedef struct {
int32_t selfIndex;
uint32_t nodeId[TAOS_SYNC_MAX_REPLICA];
int32_t role[TAOS_SYNC_MAX_REPLICA];
} SNodesRole;
// get the wal file from index or after
// return value, -1: error, 1:more wal files, 0:last WAL. if name[0]==0, no WAL file
typedef int32_t (*FGetWalInfo)(int32_t vgId, char *fileName, int64_t *fileId);
// when a forward pkt is received, call this to handle data
typedef int32_t (*FWriteToCache)(int32_t vgId, void *pHead, int32_t qtype, void *pMsg);
// when forward is confirmed by peer, master call this API to notify app
typedef void (*FConfirmForward)(int32_t vgId, void *mhandle, int32_t code);
// when role is changed, call this to notify app
typedef void (*FNotifyRole)(int32_t vgId, int8_t role);
// if a number of retrieving data failed, call this to start flow control
typedef void (*FNotifyFlowCtrl)(int32_t vgId, int32_t level);
// when data file is synced successfully, notity app
typedef void (*FStartSyncFile)(int32_t vgId);
typedef void (*FStopSyncFile)(int32_t vgId, uint64_t fversion);
// get file version
typedef int32_t (*FGetVersion)(int32_t vgId, uint64_t *fver, uint64_t *vver);
typedef int32_t (*FSendFile)(void *tsdb, SOCKET socketFd);
typedef int32_t (*FRecvFile)(void *tsdb, SOCKET socketFd);
typedef struct {
int32_t vgId; // vgroup ID
uint64_t version; // initial version
SSyncCfg syncCfg; // configuration from mgmt
char path[TSDB_FILENAME_LEN]; // path to the file
void * pTsdb;
FGetWalInfo getWalInfoFp;
FWriteToCache writeToCacheFp;
FConfirmForward confirmForward;
FNotifyRole notifyRoleFp;
FNotifyFlowCtrl notifyFlowCtrlFp;
FStartSyncFile startSyncFileFp;
FStopSyncFile stopSyncFileFp;
FGetVersion getVersionFp;
FSendFile sendFileFp;
FRecvFile recvFileFp;
} SSyncInfo;
typedef void *tsync_h;
int32_t syncInit();
void syncCleanUp();
int64_t syncStart(const SSyncInfo *);
void syncStop(int64_t rid);
int32_t syncReconfig(int64_t rid, const SSyncCfg *);
int32_t syncForwardToPeer(int64_t rid, void *pHead, void *mhandle, int32_t qtype, bool force);
void syncConfirmForward(int64_t rid, uint64_t version, int32_t code, bool force);
void syncRecover(int64_t rid); // recover from other nodes:
int32_t syncGetNodesRole(int64_t rid, SNodesRole *);
extern char *syncRole[];
//global configurable parameters
extern int32_t sDebugFlag;
extern char tsArbitrator[];
extern uint16_t tsSyncPort;
#ifdef __cplusplus
}
#endif
#endif // TDENGINE_SYNC_H
/*
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define _GNU_SOURCE
#define _XOPEN_SOURCE
#define _DEFAULT_SOURCE
#include "os.h"
#include "shell.h"
#include "shellCommand.h"
#include "tglobal.h"
#include "tutil.h"
#define SHELL_SQL_LEN 1024
static int32_t tbNum = 0;
static int32_t tbMallocNum = 0;
static char ** tbNames = NULL;
static int32_t checkedNum = 0;
static int32_t errorNum = 0;
typedef struct {
TdThread threadID;
int threadIndex;
int totalThreads;
void * taos;
char * db;
} ShellThreadObj;
static int32_t shellUseDb(TAOS *con, char *db) {
if (db == NULL) {
fprintf(stdout, "no dbname input\n");
return -1;
}
char sql[SHELL_SQL_LEN] = {0};
snprintf(sql, SHELL_SQL_LEN, "use %s", db);
TAOS_RES *pSql = taos_query(con, sql);
int32_t code = taos_errno(pSql);
if (code != 0) {
fprintf(stdout, "failed to execute sql:%s since %s", sql, taos_errstr(pSql));
}
taos_free_result(pSql);
return code;
}
static int32_t shellShowTables(TAOS *con, char *db) {
char sql[SHELL_SQL_LEN] = {0};
snprintf(sql, SHELL_SQL_LEN, "show %s.tables", db);
TAOS_RES *pSql = taos_query(con, sql);
int32_t code = taos_errno(pSql);
if (code != 0) {
fprintf(stdout, "failed to execute sql:%s since %s\n", sql, taos_errstr(pSql));
} else {
TAOS_ROW row;
while ((row = taos_fetch_row(pSql))) {
int32_t tbIndex = tbNum++;
if (tbMallocNum < tbNum) {
tbMallocNum = (tbMallocNum * 2 + 1);
char** tbNames1 = taosMemoryRealloc(tbNames, tbMallocNum * sizeof(char *));
if (tbNames1 == NULL) {
fprintf(stdout, "failed to malloc tablenames, num:%d\n", tbMallocNum);
code = TSDB_CODE_TSC_OUT_OF_MEMORY;
break;
}
tbNames = tbNames1;
}
tbNames[tbIndex] = taosMemoryMalloc(TSDB_TABLE_NAME_LEN);
strncpy(tbNames[tbIndex], (const char *)row[0], TSDB_TABLE_NAME_LEN);
if (tbIndex % 100000 == 0 && tbIndex != 0) {
fprintf(stdout, "%d tablenames fetched\n", tbIndex);
}
}
}
taos_free_result(pSql);
fprintf(stdout, "total %d tablenames fetched, over\n", tbNum);
return code;
}
static void shellFreeTbnames() {
for (int32_t i = 0; i < tbNum; ++i) {
taosMemoryFree(tbNames[i]);
}
taosMemoryFree(tbNames);
}
static void *shellCheckThreadFp(void *arg) {
ShellThreadObj *pThread = (ShellThreadObj *)arg;
setThreadName("shellCheckThrd");
int32_t interval = tbNum / pThread->totalThreads + 1;
int32_t start = pThread->threadIndex * interval;
int32_t end = (pThread->threadIndex + 1) * interval;
if (end > tbNum) end = tbNum + 1;
char file[32] = {0};
snprintf(file, 32, "tb%d.txt", pThread->threadIndex);
TdFilePtr pFile = taosOpenFile(file, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_TRUNC);
if (!fp) {
fprintf(stdout, "failed to open %s, reason:%s", file, strerror(errno));
return NULL;
}
char sql[SHELL_SQL_LEN];
for (int32_t t = start; t < end; ++t) {
char *tbname = tbNames[t];
if (tbname == NULL) break;
snprintf(sql, SHELL_SQL_LEN, "select * from %s limit 1", tbname);
TAOS_RES *pSql = taos_query(pThread->taos, sql);
int32_t code = taos_errno(pSql);
if (code != 0) {
int32_t len = snprintf(sql, SHELL_SQL_LEN, "drop table %s.%s;\n", pThread->db, tbname);
taosWriteFile(pFile, sql, len);
atomic_add_fetch_32(&errorNum, 1);
}
int32_t cnum = atomic_add_fetch_32(&checkedNum, 1);
if (cnum % 5000 == 0 && cnum != 0) {
fprintf(stdout, "%d tables checked\n", cnum);
}
taos_free_result(pSql);
}
taosFsync(pFile);
taosCloseFile(&pFile);
return NULL;
}
static void shellRunCheckThreads(TAOS *con, SShellArguments *_args) {
TdThreadAttr thattr;
ShellThreadObj *threadObj = (ShellThreadObj *)taosMemoryCalloc(_args->threadNum, sizeof(ShellThreadObj));
for (int t = 0; t < _args->threadNum; ++t) {
ShellThreadObj *pThread = threadObj + t;
pThread->threadIndex = t;
pThread->totalThreads = _args->threadNum;
pThread->taos = con;
pThread->db = _args->database;
taosThreadAttrInit(&thattr);
taosThreadAttrSetDetachState(&thattr, PTHREAD_CREATE_JOINABLE);
if (taosThreadCreate(&(pThread->threadID), &thattr, shellCheckThreadFp, (void *)pThread) != 0) {
fprintf(stderr, "ERROR: thread:%d failed to start\n", pThread->threadIndex);
exit(0);
}
}
for (int t = 0; t < _args->threadNum; ++t) {
taosThreadJoin(threadObj[t].threadID, NULL);
}
for (int t = 0; t < _args->threadNum; ++t) {
taos_close(threadObj[t].taos);
}
taosMemoryFree(threadObj);
}
void shellCheck(TAOS *con, SShellArguments *_args) {
int64_t start = taosGetTimestampMs();
if (shellUseDb(con, _args->database) != 0) {
shellFreeTbnames();
return;
}
if (shellShowTables(con, _args->database) != 0) {
shellFreeTbnames();
return;
}
fprintf(stdout, "total %d tables will be checked by %d threads\n", tbNum, _args->threadNum);
shellRunCheckThreads(con, _args);
int64_t end = taosGetTimestampMs();
fprintf(stdout, "total %d tables checked, failed:%d, time spent %.2f seconds\n", checkedNum, errorNum,
(end - start) / 1000.0);
}
/*
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define __USE_XOPEN
#include "os.h"
#include "shell.h"
#include "shellCommand.h"
#include "tbase64.h"
#include "tscLog.h"
#define OPT_ABORT 1 /* �Cabort */
int indicator = 1;
struct termios oldtio;
void insertChar(Command *cmd, char *c, int size);
void printHelp() {
char indent[10] = " ";
printf("taos shell is used to test the TDengine database\n");
printf("%s%s\n", indent, "-h");
printf("%s%s%s\n", indent, indent, "TDengine server IP address to connect. The default host is localhost.");
printf("%s%s\n", indent, "-p");
printf("%s%s%s\n", indent, indent, "The password to use when connecting to the server.");
printf("%s%s\n", indent, "-P");
printf("%s%s%s\n", indent, indent, "The TCP/IP port number to use for the connection");
printf("%s%s\n", indent, "-u");
printf("%s%s%s\n", indent, indent, "The user name to use when connecting to the server.");
printf("%s%s\n", indent, "-c");
printf("%s%s%s\n", indent, indent, "Configuration directory.");
printf("%s%s\n", indent, "-s");
printf("%s%s%s\n", indent, indent, "Commands to run without enter the shell.");
printf("%s%s\n", indent, "-r");
printf("%s%s%s\n", indent, indent, "Output time as unsigned long..");
printf("%s%s\n", indent, "-f");
printf("%s%s%s\n", indent, indent, "Script to run without enter the shell.");
printf("%s%s\n", indent, "-d");
printf("%s%s%s\n", indent, indent, "Database to use when connecting to the server.");
printf("%s%s\n", indent, "-t");
printf("%s%s%s\n", indent, indent, "Time zone of the shell, default is local.");
printf("%s%s\n", indent, "-D");
printf("%s%s%s\n", indent, indent, "Use multi-thread to import all SQL files in the directory separately.");
printf("%s%s\n", indent, "-T");
printf("%s%s%s\n", indent, indent, "Number of threads when using multi-thread to import data.");
exit(EXIT_SUCCESS);
}
char DARWINCLIENT_VERSION[] = "Welcome to the TDengine shell from %s, Client Version:%s\n"
"Copyright (c) 2020 by TAOS Data, Inc. All rights reserved.\n\n";
char g_password[SHELL_MAX_PASSWORD_LEN];
void shellParseArgument(int argc, char *argv[], SShellArguments *arguments) {
wordexp_t full_path;
for (int i = 1; i < argc; i++) {
// for host
if (strcmp(argv[i], "-h") == 0) {
if (i < argc - 1) {
arguments->host = argv[++i];
} else {
fprintf(stderr, "option -h requires an argument\n");
exit(EXIT_FAILURE);
}
}
// for password
else if ((strncmp(argv[i], "-p", 2) == 0)
|| (strncmp(argv[i], "--password", 10) == 0)) {
strcpy(tsOsName, "Darwin");
printf(DARWINCLIENT_VERSION, tsOsName, taos_get_client_info());
if ((strlen(argv[i]) == 2)
|| (strncmp(argv[i], "--password", 10) == 0)) {
printf("Enter password: ");
taosSetConsoleEcho(false);
if (scanf("%s", g_password) > 1) {
fprintf(stderr, "password read error\n");
}
taosSetConsoleEcho(true);
getchar();
} else {
tstrncpy(g_password, (char *)(argv[i] + 2), SHELL_MAX_PASSWORD_LEN);
}
arguments->password = g_password;
arguments->is_use_passwd = true;
strcpy(argv[i], "");
argc -= 1;
}
// for management port
else if (strcmp(argv[i], "-P") == 0) {
if (i < argc - 1) {
arguments->port = atoi(argv[++i]);
} else {
fprintf(stderr, "option -P requires an argument\n");
exit(EXIT_FAILURE);
}
}
// for user
else if (strcmp(argv[i], "-u") == 0) {
if (i < argc - 1) {
arguments->user = argv[++i];
} else {
fprintf(stderr, "option -u requires an argument\n");
exit(EXIT_FAILURE);
}
} else if (strcmp(argv[i], "-c") == 0) {
if (i < argc - 1) {
if (strlen(argv[++i]) >= TSDB_FILENAME_LEN) {
fprintf(stderr, "config file path: %s overflow max len %d\n", argv[i], TSDB_FILENAME_LEN - 1);
exit(EXIT_FAILURE);
}
strcpy(configDir, argv[i]);
} else {
fprintf(stderr, "Option -c requires an argument\n");
exit(EXIT_FAILURE);
}
} else if (strcmp(argv[i], "-s") == 0) {
if (i < argc - 1) {
arguments->commands = argv[++i];
} else {
fprintf(stderr, "option -s requires an argument\n");
exit(EXIT_FAILURE);
}
} else if (strcmp(argv[i], "-r") == 0) {
arguments->is_raw_time = true;
}
// For temperory batch commands to run TODO
else if (strcmp(argv[i], "-f") == 0) {
if (i < argc - 1) {
strcpy(arguments->file, argv[++i]);
} else {
fprintf(stderr, "option -f requires an argument\n");
exit(EXIT_FAILURE);
}
}
// for default database
else if (strcmp(argv[i], "-d") == 0) {
if (i < argc - 1) {
arguments->database = argv[++i];
} else {
fprintf(stderr, "option -d requires an argument\n");
exit(EXIT_FAILURE);
}
}
// For time zone
else if (strcmp(argv[i], "-t") == 0) {
if (i < argc - 1) {
arguments->timezone = argv[++i];
} else {
fprintf(stderr, "option -t requires an argument\n");
exit(EXIT_FAILURE);
}
}
// For import directory
else if (strcmp(argv[i], "-D") == 0) {
if (i < argc - 1) {
if (wordexp(argv[++i], &full_path, 0) != 0) {
fprintf(stderr, "Invalid path %s\n", argv[i]);
exit(EXIT_FAILURE);
}
strcpy(arguments->dir, full_path.we_wordv[0]);
wordfree(&full_path);
} else {
fprintf(stderr, "option -D requires an argument\n");
exit(EXIT_FAILURE);
}
}
// For time zone
else if (strcmp(argv[i], "-T") == 0) {
if (i < argc - 1) {
arguments->threadNum = atoi(argv[++i]);
} else {
fprintf(stderr, "option -T requires an argument\n");
exit(EXIT_FAILURE);
}
}
// For temperory command TODO
else if (strcmp(argv[i], "--help") == 0) {
printHelp();
exit(EXIT_FAILURE);
} else {
fprintf(stderr, "wrong options\n");
printHelp();
exit(EXIT_FAILURE);
}
}
}
int32_t shellReadCommand(TAOS *con, char *command) {
unsigned hist_counter = history.hend;
char utf8_array[10] = "\0";
Command cmd;
memset(&cmd, 0, sizeof(cmd));
cmd.buffer = (char *)taosMemoryCalloc(1, MAX_COMMAND_SIZE);
cmd.command = (char *)taosMemoryCalloc(1, MAX_COMMAND_SIZE);
showOnScreen(&cmd);
// Read input.
char c;
while (1) {
c = getchar();
if (c < 0) { // For UTF-8
int count = countPrefixOnes(c);
utf8_array[0] = c;
for (int k = 1; k < count; k++) {
c = getchar();
utf8_array[k] = c;
}
insertChar(&cmd, utf8_array, count);
} else if (c < '\033') {
// Ctrl keys. TODO: Implement ctrl combinations
switch (c) {
case 1: // ctrl A
positionCursorHome(&cmd);
break;
case 3:
printf("\n");
resetCommand(&cmd, "");
kill(0, SIGINT);
break;
case 4: // EOF or Ctrl+D
printf("\n");
taos_close(con);
// write the history
write_history();
exitShell();
break;
case 5: // ctrl E
positionCursorEnd(&cmd);
break;
case 8:
backspaceChar(&cmd);
break;
case '\n':
case '\r':
printf("\n");
if (isReadyGo(&cmd)) {
sprintf(command, "%s%s", cmd.buffer, cmd.command);
taosMemoryFreeClear(cmd.buffer);
taosMemoryFreeClear(cmd.command);
return 0;
} else {
updateBuffer(&cmd);
}
break;
case 11: // Ctrl + K;
clearLineAfter(&cmd);
break;
case 12: // Ctrl + L;
system("clear");
showOnScreen(&cmd);
break;
case 21: // Ctrl + U
clearLineBefore(&cmd);
break;
}
} else if (c == '\033') {
c = getchar();
switch (c) {
case '[':
c = getchar();
switch (c) {
case 'A': // Up arrow
if (hist_counter != history.hstart) {
hist_counter = (hist_counter + MAX_HISTORY_SIZE - 1) % MAX_HISTORY_SIZE;
resetCommand(&cmd, (history.hist[hist_counter] == NULL) ? "" : history.hist[hist_counter]);
}
break;
case 'B': // Down arrow
if (hist_counter != history.hend) {
int next_hist = (hist_counter + 1) % MAX_HISTORY_SIZE;
if (next_hist != history.hend) {
resetCommand(&cmd, (history.hist[next_hist] == NULL) ? "" : history.hist[next_hist]);
} else {
resetCommand(&cmd, "");
}
hist_counter = next_hist;
}
break;
case 'C': // Right arrow
moveCursorRight(&cmd);
break;
case 'D': // Left arrow
moveCursorLeft(&cmd);
break;
case '1':
if ((c = getchar()) == '~') {
// Home key
positionCursorHome(&cmd);
}
break;
case '2':
if ((c = getchar()) == '~') {
// Insert key
}
break;
case '3':
if ((c = getchar()) == '~') {
// Delete key
deleteChar(&cmd);
}
break;
case '4':
if ((c = getchar()) == '~') {
// End key
positionCursorEnd(&cmd);
}
break;
case '5':
if ((c = getchar()) == '~') {
// Page up key
}
break;
case '6':
if ((c = getchar()) == '~') {
// Page down key
}
break;
case 72:
// Home key
positionCursorHome(&cmd);
break;
case 70:
// End key
positionCursorEnd(&cmd);
break;
}
break;
}
} else if (c == 0x7f) {
// press delete key
backspaceChar(&cmd);
} else {
insertChar(&cmd, &c, 1);
}
}
return 0;
}
void *shellLoopQuery(void *arg) {
if (indicator) {
getOldTerminalMode();
indicator = 0;
}
TAOS *con = (TAOS *)arg;
setThreadName("shellLoopQuery");
taosThreadCleanupPush(cleanup_handler, NULL);
char *command = taosMemoryMalloc(MAX_COMMAND_SIZE);
if (command == NULL){
tscError("failed to malloc command");
return NULL;
}
int32_t err = 0;
do {
// Read command from shell.
memset(command, 0, MAX_COMMAND_SIZE);
setTerminalMode();
err = shellReadCommand(con, command);
if (err) {
break;
}
resetTerminalMode();
} while (shellRunCommand(con, command) == 0);
taosMemoryFreeClear(command);
exitShell();
taosThreadCleanupPop(1);
return NULL;
}
void get_history_path(char *history) { sprintf(history, "%s/%s", getpwuid(getuid())->pw_dir, HISTORY_FILE); }
void clearScreen(int ecmd_pos, int cursor_pos) {
struct winsize w;
if (ioctl(0, TIOCGWINSZ, &w) < 0 || w.ws_col == 0 || w.ws_row == 0) {
//fprintf(stderr, "No stream device, and use default value(col 120, row 30)\n");
w.ws_col = 120;
w.ws_row = 30;
}
int cursor_x = cursor_pos / w.ws_col;
int cursor_y = cursor_pos % w.ws_col;
int command_x = ecmd_pos / w.ws_col;
positionCursor(cursor_y, LEFT);
positionCursor(command_x - cursor_x, DOWN);
fprintf(stdout, "\033[2K");
for (int i = 0; i < command_x; i++) {
positionCursor(1, UP);
fprintf(stdout, "\033[2K");
}
fflush(stdout);
}
void showOnScreen(Command *cmd) {
struct winsize w;
if (ioctl(0, TIOCGWINSZ, &w) < 0 || w.ws_col == 0 || w.ws_row == 0) {
//fprintf(stderr, "No stream device\n");
w.ws_col = 120;
w.ws_row = 30;
}
TdWchar wc;
int size = 0;
// Print out the command.
char *total_string = taosMemoryMalloc(MAX_COMMAND_SIZE);
memset(total_string, '\0', MAX_COMMAND_SIZE);
if (strcmp(cmd->buffer, "") == 0) {
sprintf(total_string, "%s%s", PROMPT_HEADER, cmd->command);
} else {
sprintf(total_string, "%s%s", CONTINUE_PROMPT, cmd->command);
}
int remain_column = w.ws_col;
/* size = cmd->commandSize + prompt_size; */
for (char *str = total_string; size < cmd->commandSize + prompt_size;) {
int ret = taosMbToWchar(&wc, str, MB_CUR_MAX);
if (ret < 0) break;
size += ret;
/* assert(size >= 0); */
int width = taosWcharWidth(wc);
if (remain_column > width) {
printf("%lc", wc);
remain_column -= width;
} else {
if (remain_column == width) {
printf("%lc\n\r", wc);
remain_column = w.ws_col;
} else {
printf("\n\r%lc", wc);
remain_column = w.ws_col - width;
}
}
str = total_string + size;
}
taosMemoryFree(total_string);
/* for (int i = 0; i < size; i++){ */
/* char c = total_string[i]; */
/* if (k % w.ws_col == 0) { */
/* printf("%c\n\r", c); */
/* } */
/* else { */
/* printf("%c", c); */
/* } */
/* k += 1; */
/* } */
// Position the cursor
int cursor_pos = cmd->screenOffset + prompt_size;
int ecmd_pos = cmd->endOffset + prompt_size;
int cursor_x = cursor_pos / w.ws_col;
int cursor_y = cursor_pos % w.ws_col;
// int cursor_y = cursor % w.ws_col;
int command_x = ecmd_pos / w.ws_col;
int command_y = ecmd_pos % w.ws_col;
// int command_y = (command.size() + prompt_size) % w.ws_col;
positionCursor(command_y, LEFT);
positionCursor(command_x, UP);
positionCursor(cursor_x, DOWN);
positionCursor(cursor_y, RIGHT);
fflush(stdout);
}
void cleanup_handler(void *arg) { resetTerminalMode(); }
void exitShell() {
resetTerminalMode();
exit(EXIT_SUCCESS);
}
/*
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define _GNU_SOURCE
#define _XOPEN_SOURCE
#define _DEFAULT_SOURCE
#include "os.h"
#include "shell.h"
#include "shellCommand.h"
#include "tglobal.h"
#include "tutil.h"
static char **shellSQLFiles = NULL;
static int32_t shellSQLFileNum = 0;
static char shellTablesSQLFile[TSDB_FILENAME_LEN] = {0};
typedef struct {
TdThread threadID;
int threadIndex;
int totalThreads;
void *taos;
} ShellThreadObj;
static int shellGetFilesNum(const char *directoryName, const char *prefix)
{
char cmd[1024] = { 0 };
sprintf(cmd, "ls %s/*.%s | wc -l ", directoryName, prefix);
char buf[1024] = { 0 };
if (taosSystem(cmd, buf, sizeof(buf)) < 0) {
fprintf(stderr, "ERROR: failed to execute:%s, error:%s\n", cmd, strerror(errno));
exit(0);
}
int fileNum = 0;
if (sscanf(buf, "%d", &fileNum) != 1) {
fprintf(stderr, "ERROR: failed to execute:%s, parse result error\n", cmd);
exit(0);
}
if (fileNum <= 0) {
fprintf(stderr, "ERROR: directory:%s is empry\n", directoryName);
exit(0);
}
return fileNum;
}
static void shellParseDirectory(const char *directoryName, const char *prefix, char **fileArray, int totalFiles)
{
char cmd[1024] = { 0 };
sprintf(cmd, "ls %s/*.%s | sort", directoryName, prefix);
char buf[1024] = { 0 };
if (taosSystem(cmd, buf, sizeof(buf)) < 0) {
fprintf(stderr, "ERROR: failed to execute:%s, error:%s\n", cmd, strerror(errno));
exit(0);
}
int fileNum = 0;
while (sscanf(buf, "%128s", fileArray[fileNum++])) {
if (strcmp(fileArray[fileNum-1], shellTablesSQLFile) == 0) {
fileNum--;
}
if (fileNum >= totalFiles) {
break;
}
}
if (fileNum != totalFiles) {
fprintf(stderr, "ERROR: directory:%s changed while read\n", directoryName);
exit(0);
}
}
static void shellCheckTablesSQLFile(const char *directoryName)
{
sprintf(shellTablesSQLFile, "%s/tables.sql", directoryName);
if (taosFStatFile(shellTablesSQLFile, NULL, NULL) < 0) {
shellTablesSQLFile[0] = 0;
}
}
static void shellMallocSQLFiles()
{
shellSQLFiles = (char**)taosMemoryCalloc(shellSQLFileNum, sizeof(char*));
for (int i = 0; i < shellSQLFileNum; i++) {
shellSQLFiles[i] = taosMemoryCalloc(1, TSDB_FILENAME_LEN);
}
}
static void shellGetDirectoryFileList(char *inputDir)
{
if (!taosDirExist(inputDir)) {
fprintf(stderr, "ERROR: %s not exist\n", inputDir);
exit(0);
}
if (taosIsDir(inputDir)) {
shellCheckTablesSQLFile(inputDir);
shellSQLFileNum = shellGetFilesNum(inputDir, "sql");
int totalSQLFileNum = shellSQLFileNum;
if (shellTablesSQLFile[0] != 0) {
shellSQLFileNum--;
}
shellMallocSQLFiles();
shellParseDirectory(inputDir, "sql", shellSQLFiles, shellSQLFileNum);
fprintf(stdout, "\nstart to dispose %d files in %s\n", totalSQLFileNum, inputDir);
}
else {
fprintf(stderr, "ERROR: %s is not a directory\n", inputDir);
exit(0);
}
}
static void shellSourceFile(TAOS *con, char *fptr) {
wordexp_t full_path;
int read_len = 0;
char * cmd = taosMemoryMalloc(tsMaxSQLStringLen);
size_t cmd_len = 0;
char * line = NULL;
if (wordexp(fptr, &full_path, 0) != 0) {
fprintf(stderr, "ERROR: illegal file name\n");
taosMemoryFree(cmd);
return;
}
char *fname = full_path.we_wordv[0];
if (fname == NULL) {
fprintf(stderr, "ERROR: invalid filename\n");
taosMemoryFree(cmd);
return;
}
/*
if (access(fname, F_OK) != 0) {
fprintf(stderr, "ERROR: file %s is not exist\n", fptr);
wordfree(&full_path);
taosMemoryFree(cmd);
return;
}
if (access(fname, R_OK) != 0) {
fprintf(stderr, "ERROR: file %s is not readable\n", fptr);
wordfree(&full_path);
taosMemoryFree(cmd);
return;
}
*/
// FILE *f = fopen(fname, "r");
TdFilePtr pFile = taosOpenFile(fname, TD_FILE_READ | TD_FILE_STREAM);
if (pFile == NULL) {
fprintf(stderr, "ERROR: failed to open file %s\n", fname);
wordfree(&full_path);
taosMemoryFree(cmd);
return;
}
fprintf(stdout, "begin import file:%s\n", fname);
int lineNo = 0;
while ((read_len = taosGetLineFile(pFile, &line)) != -1) {
++lineNo;
if (read_len >= tsMaxSQLStringLen) continue;
line[--read_len] = '\0';
if (read_len == 0 || isCommentLine(line)) { // line starts with #
continue;
}
if (line[read_len - 1] == '\\') {
line[read_len - 1] = ' ';
memcpy(cmd + cmd_len, line, read_len);
cmd_len += read_len;
continue;
}
memcpy(cmd + cmd_len, line, read_len);
TAOS_RES* pSql = taos_query(con, cmd);
int32_t code = taos_errno(pSql);
if (code != 0) {
fprintf(stderr, "DB error: %s: %s (%d)\n", taos_errstr(pSql), fname, lineNo);
}
/* free local resouce: allocated memory/metric-meta refcnt */
taos_free_result(pSql);
memset(cmd, 0, MAX_COMMAND_SIZE);
cmd_len = 0;
}
taosMemoryFree(cmd);
if(line != NULL) taosMemoryFree(line);
wordfree(&full_path);
taosCloseFile(&pFile);
}
void* shellImportThreadFp(void *arg)
{
ShellThreadObj *pThread = (ShellThreadObj*)arg;
setThreadName("shellImportThrd");
for (int f = 0; f < shellSQLFileNum; ++f) {
if (f % pThread->totalThreads == pThread->threadIndex) {
char *SQLFileName = shellSQLFiles[f];
shellSourceFile(pThread->taos, SQLFileName);
}
}
return NULL;
}
static void shellRunImportThreads(SShellArguments* _args)
{
TdThreadAttr thattr;
ShellThreadObj *threadObj = (ShellThreadObj *)taosMemoryCalloc(_args->threadNum, sizeof(ShellThreadObj));
for (int t = 0; t < _args->threadNum; ++t) {
ShellThreadObj *pThread = threadObj + t;
pThread->threadIndex = t;
pThread->totalThreads = _args->threadNum;
pThread->taos = taos_connect(_args->host, _args->user, _args->password, _args->database, tsDnodeShellPort);
if (pThread->taos == NULL) {
fprintf(stderr, "ERROR: thread:%d failed connect to TDengine, error:%s\n", pThread->threadIndex, "null taos"/*taos_errstr(pThread->taos)*/);
exit(0);
}
taosThreadAttrInit(&thattr);
taosThreadAttrSetDetachState(&thattr, PTHREAD_CREATE_JOINABLE);
if (taosThreadCreate(&(pThread->threadID), &thattr, shellImportThreadFp, (void*)pThread) != 0) {
fprintf(stderr, "ERROR: thread:%d failed to start\n", pThread->threadIndex);
exit(0);
}
}
for (int t = 0; t < _args->threadNum; ++t) {
taosThreadJoin(threadObj[t].threadID, NULL);
}
for (int t = 0; t < _args->threadNum; ++t) {
taos_close(threadObj[t].taos);
}
taosMemoryFree(threadObj);
}
void source_dir(TAOS* con, SShellArguments* _args) {
shellGetDirectoryFileList(_args->dir);
int64_t start = taosGetTimestampMs();
if (shellTablesSQLFile[0] != 0) {
shellSourceFile(con, shellTablesSQLFile);
int64_t end = taosGetTimestampMs();
fprintf(stdout, "import %s finished, time spent %.2f seconds\n", shellTablesSQLFile, (end - start) / 1000.0);
}
shellRunImportThreads(_args);
int64_t end = taosGetTimestampMs();
fprintf(stdout, "import %s finished, time spent %.2f seconds\n", _args->dir, (end - start) / 1000.0);
}
/*******************************************************************
* Copyright (c) 2017 by TAOS Technologies, Inc.
* All rights reserved.
*
* This file is proprietary and confidential to TAOS Technologies.
* No part of this file may be reproduced, stored, transmitted,
* disclosed or used in any form or by any means other than as
* expressly provided by the written permission from Jianhui Tao
*
* ****************************************************************/
#include <assert.h>
#include <regex.h>
#include <stdio.h>
#include "../../../../include/client/taos.h"
#include "os.h"
#include "shell.h"
#include "shellCommand.h"
extern char configDir[];
char WINCLIENT_VERSION[] = "Welcome to the TDengine shell from %s, Client Version:%s\n"
"Copyright (c) 2020 by TAOS Data, Inc. All rights reserved.\n\n";
void printVersion() {
printf("version: %s\n", version);
}
void printHelp() {
char indent[10] = " ";
printf("taos shell is used to test the TDengine database\n");
printf("%s%s\n", indent, "-h");
printf("%s%s%s\n", indent, indent, "TDengine server FQDN to connect. The default host is localhost.");
printf("%s%s\n", indent, "-p");
printf("%s%s%s\n", indent, indent, "The password to use when connecting to the server.");
printf("%s%s\n", indent, "-P");
printf("%s%s%s\n", indent, indent, "The TCP/IP port number to use for the connection");
printf("%s%s\n", indent, "-u");
printf("%s%s%s\n", indent, indent, "The user name to use when connecting to the server.");
printf("%s%s\n", indent, "-A");
printf("%s%s%s\n", indent, indent, "The user auth to use when connecting to the server.");
printf("%s%s\n", indent, "-c");
printf("%s%s%s\n", indent, indent, "Configuration directory.");
printf("%s%s\n", indent, "-C");
printf("%s%s%s\n", indent, indent, "Dump configuration.");
printf("%s%s\n", indent, "-s");
printf("%s%s%s\n", indent, indent, "Commands to run without enter the shell.");
printf("%s%s\n", indent, "-r");
printf("%s%s%s\n", indent, indent, "Output time as unsigned long..");
printf("%s%s\n", indent, "-f");
printf("%s%s%s\n", indent, indent, "Script to run without enter the shell.");
printf("%s%s\n", indent, "-d");
printf("%s%s%s\n", indent, indent, "Database to use when connecting to the server.");
printf("%s%s\n", indent, "-t");
printf("%s%s%s\n", indent, indent, "Time zone of the shell, default is local.");
printf("%s%s\n", indent, "-n");
printf("%s%s%s\n", indent, indent, "Net role when network connectivity test, default is startup, options: client|server|rpc|startup|sync|speed|fqdn.");
printf("%s%s\n", indent, "-l");
printf("%s%s%s\n", indent, indent, "Packet length used for net test, default is 1000 bytes.");
printf("%s%s\n", indent, "-N");
printf("%s%s%s\n", indent, indent, "Packet numbers used for net test, default is 100.");
printf("%s%s\n", indent, "-S");
printf("%s%s%s\n", indent, indent, "Packet type used for net test, default is TCP.");
printf("%s%s\n", indent, "-V");
printf("%s%s%s\n", indent, indent, "Print program version.");
exit(EXIT_SUCCESS);
}
char g_password[SHELL_MAX_PASSWORD_LEN];
void shellParseArgument(int argc, char *argv[], SShellArguments *arguments) {
for (int i = 1; i < argc; i++) {
// for host
if (strcmp(argv[i], "-h") == 0) {
if (i < argc - 1) {
arguments->host = argv[++i];
} else {
fprintf(stderr, "option -h requires an argument\n");
exit(EXIT_FAILURE);
}
}
// for password
else if ((strncmp(argv[i], "-p", 2) == 0)
|| (strncmp(argv[i], "--password", 10) == 0)) {
arguments->is_use_passwd = true;
strcpy(tsOsName, "Windows");
printf(WINCLIENT_VERSION, tsOsName, taos_get_client_info());
if ((strlen(argv[i]) == 2)
|| (strncmp(argv[i], "--password", 10) == 0)) {
printf("Enter password: ");
taosSetConsoleEcho(false);
if (scanf("%s", g_password) > 1) {
fprintf(stderr, "password read error!\n");
}
taosSetConsoleEcho(true);
getchar();
} else {
tstrncpy(g_password, (char *)(argv[i] + 2), SHELL_MAX_PASSWORD_LEN);
}
arguments->password = g_password;
strcpy(argv[i], "");
argc -= 1;
}
// for management port
else if (strcmp(argv[i], "-P") == 0) {
if (i < argc - 1) {
arguments->port = atoi(argv[++i]);
} else {
fprintf(stderr, "option -P requires an argument\n");
exit(EXIT_FAILURE);
}
}
// for user
else if (strcmp(argv[i], "-u") == 0) {
if (i < argc - 1) {
arguments->user = argv[++i];
} else {
fprintf(stderr, "option -u requires an argument\n");
exit(EXIT_FAILURE);
}
} else if (strcmp(argv[i], "-A") == 0) {
if (i < argc - 1) {
arguments->auth = argv[++i];
} else {
fprintf(stderr, "option -A requires an argument\n");
exit(EXIT_FAILURE);
}
} else if (strcmp(argv[i], "-c") == 0) {
if (i < argc - 1) {
char *tmp = argv[++i];
if (strlen(tmp) >= TSDB_FILENAME_LEN) {
fprintf(stderr, "config file path: %s overflow max len %d\n", tmp, TSDB_FILENAME_LEN - 1);
exit(EXIT_FAILURE);
}
strcpy(configDir, tmp);
} else {
fprintf(stderr, "Option -c requires an argument\n");
exit(EXIT_FAILURE);
}
} else if (strcmp(argv[i], "-C") == 0) {
arguments->dump_config = true;
} else if (strcmp(argv[i], "-s") == 0) {
if (i < argc - 1) {
arguments->commands = argv[++i];
} else {
fprintf(stderr, "option -s requires an argument\n");
exit(EXIT_FAILURE);
}
} else if (strcmp(argv[i], "-r") == 0) {
arguments->is_raw_time = true;
}
// For temperory batch commands to run TODO
else if (strcmp(argv[i], "-f") == 0) {
if (i < argc - 1) {
strcpy(arguments->file, argv[++i]);
} else {
fprintf(stderr, "option -f requires an argument\n");
exit(EXIT_FAILURE);
}
}
// for default database
else if (strcmp(argv[i], "-d") == 0) {
if (i < argc - 1) {
arguments->database = argv[++i];
} else {
fprintf(stderr, "option -d requires an argument\n");
exit(EXIT_FAILURE);
}
}
// For time zone
else if (strcmp(argv[i], "-t") == 0) {
if (i < argc - 1) {
arguments->timezone = argv[++i];
} else {
fprintf(stderr, "option -t requires an argument\n");
exit(EXIT_FAILURE);
}
}
else if (strcmp(argv[i], "-n") == 0) {
if (i < argc - 1) {
arguments->netTestRole = argv[++i];
} else {
fprintf(stderr, "option -n requires an argument\n");
exit(EXIT_FAILURE);
}
}
else if (strcmp(argv[i], "-l") == 0) {
if (i < argc - 1) {
arguments->pktLen = atoi(argv[++i]);
} else {
fprintf(stderr, "option -l requires an argument\n");
exit(EXIT_FAILURE);
}
}
else if (strcmp(argv[i], "-N") == 0) {
if (i < argc - 1) {
arguments->pktNum = atoi(argv[++i]);
} else {
fprintf(stderr, "option -N requires an argument\n");
exit(EXIT_FAILURE);
}
}
else if (strcmp(argv[i], "-S") == 0) {
if (i < argc - 1) {
arguments->pktType = argv[++i];
} else {
fprintf(stderr, "option -S requires an argument\n");
exit(EXIT_FAILURE);
}
}
else if (strcmp(argv[i], "-V") == 0) {
printVersion();
exit(EXIT_SUCCESS);
}
// For temperory command TODO
else if (strcmp(argv[i], "--help") == 0) {
printHelp();
exit(EXIT_SUCCESS);
} else {
fprintf(stderr, "wrong options\n");
printHelp();
exit(EXIT_FAILURE);
}
}
}
void shellPrintContinuePrompt() { printf("%s", CONTINUE_PROMPT); }
void shellPrintPrompt() { printf("%s", PROMPT_HEADER); }
void updateBuffer(Command *cmd) {
if (regex_match(cmd->buffer, "(\\s+$)|(^$)", REG_EXTENDED)) strcat(cmd->command, " ");
strcat(cmd->buffer, cmd->command);
memset(cmd->command, 0, MAX_COMMAND_SIZE);
cmd->cursorOffset = 0;
}
int isReadyGo(Command *cmd) {
char *total = taosMemoryMalloc(MAX_COMMAND_SIZE);
memset(total, 0, MAX_COMMAND_SIZE);
sprintf(total, "%s%s", cmd->buffer, cmd->command);
char *reg_str =
"(^.*;\\s*$)|(^\\s*$)|(^\\s*exit\\s*$)|(^\\s*q\\s*$)|(^\\s*quit\\s*$)|(^"
"\\s*clear\\s*$)";
if (regex_match(total, reg_str, REG_EXTENDED | REG_ICASE)) {
taosMemoryFree(total);
return 1;
}
taosMemoryFree(total);
return 0;
}
void insertChar(Command *cmd, char c) {
// TODO: Check if the length enough.
if (cmd->cursorOffset >= MAX_COMMAND_SIZE) {
fprintf(stdout, "sql is larger than %d bytes", MAX_COMMAND_SIZE);
return;
}
cmd->command[cmd->cursorOffset++] = c;
}
int32_t shellReadCommand(TAOS *con, char command[]) {
Command cmd;
memset(&cmd, 0, sizeof(cmd));
cmd.buffer = (char *)taosMemoryCalloc(1, MAX_COMMAND_SIZE);
cmd.command = (char *)taosMemoryCalloc(1, MAX_COMMAND_SIZE);
// Read input.
char c;
while (1) {
c = getchar();
switch (c) {
case '\n':
case '\r':
if (isReadyGo(&cmd)) {
sprintf(command, "%s%s", cmd.buffer, cmd.command);
taosMemoryFree(cmd.buffer);
cmd.buffer = NULL;
taosMemoryFree(cmd.command);
cmd.command = NULL;
return 0;
} else {
shellPrintContinuePrompt();
updateBuffer(&cmd);
}
break;
default:
insertChar(&cmd, c);
}
}
return 0;
}
void *shellLoopQuery(void *arg) {
TAOS *con = (TAOS *)arg;
char *command = taosMemoryMalloc(MAX_COMMAND_SIZE);
if (command == NULL) return NULL;
int32_t err = 0;
do {
memset(command, 0, MAX_COMMAND_SIZE);
shellPrintPrompt();
// Read command from shell.
err = shellReadCommand(con, command);
if (err) {
break;
}
} while (shellRunCommand(con, command) == 0);
return NULL;
}
void get_history_path(char *history) { sprintf(history, "C:/TDengine/%s", HISTORY_FILE); }
void exitShell() { exit(EXIT_SUCCESS); }
/*
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "shellInt.h"
#define SHELL_HOST "The auth string to use when connecting to the server."
#define SHELL_PORT "The TCP/IP port number to use for the connection."
#define SHELL_USER "The user name to use when connecting to the server."
#define SHELL_PASSWORD "The password to use when connecting to the server."
#define SHELL_AUTH "The auth string to use when connecting to the server."
#define SHELL_GEN_AUTH "Generate auth string from password."
#define SHELL_CFG_DIR "Configuration directory."
#define SHELL_DMP_CFG "Dump configuration."
#define SHELL_CMD "Commands to run without enter the shell."
#define SHELL_RAW_TIME "Output time as uint64_t."
#define SHELL_FILE "Script to run without enter the shell."
#define SHELL_DB "Database to use when connecting to the server."
#define SHELL_CHECK "Check the service status."
#define SHELL_STARTUP "Check the details of the service status."
#define SHELL_WIDTH "Set the default binary display width, default is 30."
#define SHELL_NET_ROLE "Net role when network connectivity test, options: client|server."
#define SHELL_PKG_LEN "Packet length used for net test, default is 1024 bytes."
#define SHELL_PKT_NUM "Packet numbers used for net test, default is 100."
#define SHELL_VERSION "Print program version."
#define SHELL_EMAIL "<support@taosdata.com>"
void shellPrintHelp() {
char indent[] = " ";
printf("Usage: taos [OPTION...] \n\n");
printf("%s%s%s%s\n", indent, "-a,", indent, SHELL_AUTH);
printf("%s%s%s%s\n", indent, "-A,", indent, SHELL_GEN_AUTH);
printf("%s%s%s%s\n", indent, "-c,", indent, SHELL_CFG_DIR);
printf("%s%s%s%s\n", indent, "-C,", indent, SHELL_DMP_CFG);
printf("%s%s%s%s\n", indent, "-d,", indent, SHELL_DB);
printf("%s%s%s%s\n", indent, "-f,", indent, SHELL_FILE);
printf("%s%s%s%s\n", indent, "-h,", indent, SHELL_HOST);
printf("%s%s%s%s\n", indent, "-k,", indent, SHELL_CHECK);
printf("%s%s%s%s\n", indent, "-l,", indent, SHELL_PKG_LEN);
printf("%s%s%s%s\n", indent, "-n,", indent, SHELL_NET_ROLE);
printf("%s%s%s%s\n", indent, "-N,", indent, SHELL_PKT_NUM);
printf("%s%s%s%s\n", indent, "-p,", indent, SHELL_PASSWORD);
printf("%s%s%s%s\n", indent, "-P,", indent, SHELL_PORT);
printf("%s%s%s%s\n", indent, "-r,", indent, SHELL_RAW_TIME);
printf("%s%s%s%s\n", indent, "-s,", indent, SHELL_CMD);
printf("%s%s%s%s\n", indent, "-t,", indent, SHELL_STARTUP);
printf("%s%s%s%s\n", indent, "-u,", indent, SHELL_USER);
printf("%s%s%s%s\n", indent, "-w,", indent, SHELL_WIDTH);
printf("%s%s%s%s\n", indent, "-V,", indent, SHELL_VERSION);
printf("\n\nReport bugs to %s.\n", SHELL_EMAIL);
}
static int32_t shellParseSingleOpt(int32_t key, char *arg) {
SShellArgs *pArgs = &shell.args;
switch (key) {
case 'h':
pArgs->host = arg;
break;
case 'P':
pArgs->port = atoi(arg);
break;
case 'u':
pArgs->user = arg;
break;
case 'p':
break;
case 'a':
pArgs->auth = arg;
break;
case 'A':
pArgs->is_gen_auth = true;
break;
case 'c':
pArgs->cfgdir = arg;
break;
case 'C':
pArgs->is_dump_config = true;
break;
case 's':
pArgs->commands = arg;
break;
case 'r':
pArgs->is_raw_time = true;
break;
case 'f':
tstrncpy(pArgs->file, arg, sizeof(pArgs->file));
break;
case 'd':
pArgs->database = arg;
break;
case 'k':
pArgs->is_check = true;
break;
case 't':
pArgs->is_startup = true;
break;
case 'w':
pArgs->displayWidth = atoi(arg);
break;
case 'n':
pArgs->netrole = arg;
break;
case 'l':
pArgs->pktLen = atoi(arg);
break;
case 'N':
pArgs->pktNum = atoi(arg);
break;
case 'V':
pArgs->is_version = true;
break;
case '?':
pArgs->is_help = true;
break;
case 1:
pArgs->abort = 1;
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
int32_t shellParseArgsWithoutArgp(int argc, char *argv[]) {
SShellArgs *pArgs = &shell.args;
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "--usage") == 0 || strcmp(argv[i], "-?") == 0) {
shellParseSingleOpt('?', NULL);
return 0;
}
char *key = argv[i];
int32_t keyLen = strlen(key);
if (keyLen != 2) {
fprintf(stderr, "invalid option %s\n", key);
return -1;
}
if (key[0] != '-') {
fprintf(stderr, "invalid option %s\n", key);
return -1;
}
if (key[1] == 'h' || key[1] == 'P' || key[1] == 'u' || key[1] == 'a' || key[1] == 'c' || key[1] == 's' ||
key[1] == 'f' || key[1] == 'd' || key[1] == 'w' || key[1] == 'n' || key[1] == 'l' || key[1] == 'N') {
if (i + 1 >= argc) {
fprintf(stderr, "option %s requires an argument\n", key);
return -1;
}
char *val = argv[i + 1];
if (val[0] == '-') {
fprintf(stderr, "option %s requires an argument\n", key);
return -1;
}
shellParseSingleOpt(key[1], val);
i++;
} else if (key[1] == 'p' || key[1] == 'A' || key[1] == 'c' || key[1] == 'r' || key[1] == 'k' || key[1] == 't' ||
key[1] == 'V') {
shellParseSingleOpt(key[1], NULL);
} else {
fprintf(stderr, "invalid option %s\n", key);
return -1;
}
}
return 0;
}
#ifdef LINUX
#include <argp.h>
#include <termio.h>
const char *argp_program_version = version;
const char *argp_program_bug_address = SHELL_EMAIL;
static struct argp_option shellOptions[] = {
{"host", 'h', "HOST", 0, SHELL_HOST},
{"port", 'P', "PORT", 0, SHELL_PORT},
{"user", 'u', "USER", 0, SHELL_USER},
{0, 'p', 0, 0, SHELL_PASSWORD},
{"auth", 'a', "AUTH", 0, SHELL_AUTH},
{"generate-auth", 'A', 0, 0, SHELL_GEN_AUTH},
{"config-dir", 'c', "DIR", 0, SHELL_CFG_DIR},
{"dump-config", 'C', 0, 0, SHELL_DMP_CFG},
{"commands", 's', "COMMANDS", 0, SHELL_CMD},
{"raw-time", 'r', 0, 0, SHELL_RAW_TIME},
{"file", 'f', "FILE", 0, SHELL_FILE},
{"database", 'd', "DATABASE", 0, SHELL_DB},
{"check", 'k', 0, 0, SHELL_CHECK},
{"startup", 't', 0, 0, SHELL_STARTUP},
{"display-width", 'w', "WIDTH", 0, SHELL_WIDTH},
{"netrole", 'n', "NETROLE", 0, SHELL_NET_ROLE},
{"pktlen", 'l', "PKTLEN", 0, SHELL_PKG_LEN},
{"pktnum", 'N', "PKTNUM", 0, SHELL_PKT_NUM},
{0},
};
static error_t shellParseOpt(int32_t key, char *arg, struct argp_state *state) { return shellParseSingleOpt(key, arg); }
static struct argp shellArgp = {shellOptions, shellParseOpt, "", ""};
static void shellParseArgsUseArgp(int argc, char *argv[]) {
argp_program_version = shell.info.programVersion;
argp_parse(&shellArgp, argc, argv, 0, 0, &shell.args);
}
#endif
static void shellInitArgs(int argc, char *argv[]) {
for (int i = 1; i < argc; i++) {
if (strncmp(argv[i], "-p", 2) == 0) {
printf(shell.info.clientVersion, tsOsName, taos_get_client_info());
if (strlen(argv[i]) == 2) {
printf("Enter password: ");
taosSetConsoleEcho(false);
if (scanf("%20s", shell.args.password) > 1) {
fprintf(stderr, "password reading error\n");
}
taosSetConsoleEcho(true);
if (EOF == getchar()) {
fprintf(stderr, "getchar() return EOF\n");
}
} else {
tstrncpy(shell.args.password, (char *)(argv[i] + 2), sizeof(shell.args.password));
strcpy(argv[i], "-p");
}
}
}
if (strlen(shell.args.password) == 0) {
tstrncpy(shell.args.password, TSDB_DEFAULT_PASS, sizeof(shell.args.password));
}
SShellArgs *pArgs = &shell.args;
pArgs->user = TSDB_DEFAULT_USER;
pArgs->pktLen = SHELL_DEF_PKG_LEN;
pArgs->pktNum = SHELL_DEF_PKG_NUM;
pArgs->displayWidth = SHELL_DEFAULT_MAX_BINARY_DISPLAY_WIDTH;
}
static int32_t shellCheckArgs() {
SShellArgs *pArgs = &shell.args;
if (pArgs->host != NULL && (strlen(pArgs->host) <= 0 || strlen(pArgs->host) > TSDB_FQDN_LEN)) {
printf("Invalid host:%s\n", pArgs->host);
return -1;
}
if (pArgs->user != NULL && (strlen(pArgs->user) <= 0 || strlen(pArgs->user) > TSDB_USER_LEN)) {
printf("Invalid user:%s\n", pArgs->user);
return -1;
}
if (pArgs->auth != NULL && (strlen(pArgs->auth) <= 0 || strlen(pArgs->auth) > TSDB_PASSWORD_LEN)) {
printf("Invalid auth:%s\n", pArgs->auth);
return -1;
}
if (pArgs->database != NULL && (strlen(pArgs->database) <= 0 || strlen(pArgs->database) > TSDB_DB_NAME_LEN)) {
printf("Invalid database:%s\n", pArgs->database);
return -1;
}
if (pArgs->file[0] != 0) {
char fullname[PATH_MAX] = {0};
if (taosExpandDir(pArgs->file, fullname, PATH_MAX) == 0) {
tstrncpy(pArgs->file, fullname, PATH_MAX);
}
}
if (pArgs->cfgdir != NULL) {
if (strlen(pArgs->cfgdir) <= 0 || strlen(pArgs->cfgdir) >= PATH_MAX) {
printf("Invalid cfgdir:%s\n", pArgs->cfgdir);
return -1;
} else {
if (taosExpandDir(pArgs->cfgdir, configDir, PATH_MAX) != 0) {
tstrncpy(configDir, pArgs->cfgdir, PATH_MAX);
}
}
}
if (pArgs->commands != NULL && (strlen(pArgs->commands) <= 0)) {
printf("Invalid commands:%s\n", pArgs->commands);
return -1;
}
if (pArgs->netrole != NULL && !(strcmp(pArgs->netrole, "client") == 0 || strcmp(pArgs->netrole, "server") == 0)) {
printf("Invalid netrole:%s\n", pArgs->netrole);
return -1;
}
if (pArgs->password != NULL && (strlen(pArgs->password) <= 0)) {
printf("Invalid password\n");
return -1;
}
if (pArgs->pktLen < SHELL_MIN_PKG_LEN || pArgs->pktLen > SHELL_MAX_PKG_LEN) {
printf("Invalid pktLen:%d, range:[%d, %d]\n", pArgs->pktLen, SHELL_MIN_PKG_LEN, SHELL_MAX_PKG_LEN);
return -1;
}
if (pArgs->pktNum < SHELL_MIN_PKG_NUM || pArgs->pktNum > SHELL_MAX_PKG_NUM) {
printf("Invalid pktNum:%d, range:[%d, %d]\n", pArgs->pktNum, SHELL_MIN_PKG_NUM, SHELL_MAX_PKG_NUM);
return -1;
}
if (pArgs->displayWidth <= 0 || pArgs->displayWidth > 10 * 1024) {
printf("Invalid displayWidth:%d, range:[1, 10 * 1024]\n", pArgs->displayWidth);
return -1;
}
return 0;
}
int32_t shellParseArgs(int32_t argc, char *argv[]) {
shellInitArgs(argc, argv);
shell.info.clientVersion =
"Welcome to the TDengine shell from %s, Client Version:%s\n"
"Copyright (c) 2020 by TAOS Data, Inc. All rights reserved.\n\n";
shell.info.promptHeader = "taos> ";
shell.info.promptContinue = " -> ";
shell.info.promptSize = 6;
snprintf(shell.info.programVersion, sizeof(shell.info.programVersion), "version: %s", version);
#if defined(_TD_WINDOWS_64) || defined(_TD_WINDOWS_32)
shell.info.osname = "Windows";
snprintf(shell.history.file, TSDB_FILENAME_LEN, "C:/TDengine/%s", SHELL_HISTORY_FILE);
if (shellParseArgsWithoutArgp(argc, argv) != 0) return -1;
#elif defined(_TD_DARWIN_64)
shell.info.osname = "Darwin";
snprintf(shell.history.file, TSDB_FILENAME_LEN, "%s/%s", getpwuid(getuid())->pw_dir, SHELL_HISTORY_FILE);
if (shellParseArgsWithoutArgp(argc, argv) != 0) return -1;
#else
shell.info.osname = "Linux";
snprintf(shell.history.file, TSDB_FILENAME_LEN, "%s/%s", getenv("HOME"), SHELL_HISTORY_FILE);
shellParseArgsUseArgp(argc, argv);
// if (shellParseArgsWithoutArgp(argc, argv) != 0) return -1;
if (shell.args.abort) {
return -1;
}
#endif
return shellCheckArgs();
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
/*
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define _GNU_SOURCE
#include "shellInt.h"
static void shellWorkAsClient() {
SShellArgs *pArgs = &shell.args;
SRpcInit rpcInit = {0};
SEpSet epSet = {.inUse = 0, .numOfEps = 1};
SRpcMsg rpcRsp = {0};
void *clientRpc = NULL;
char pass[TSDB_PASSWORD_LEN + 1] = {0};
taosEncryptPass_c((uint8_t *)("_pwd"), strlen("_pwd"), pass);
rpcInit.label = "CHK";
rpcInit.numOfThreads = 1;
rpcInit.sessions = 16;
rpcInit.connType = TAOS_CONN_CLIENT;
rpcInit.idleTime = tsShellActivityTimer * 1000;
rpcInit.user = "_dnd";
rpcInit.ckey = "_key";
rpcInit.spi = 1;
rpcInit.secret = pass;
clientRpc = rpcOpen(&rpcInit);
if (clientRpc == NULL) {
printf("failed to init net test client since %s\n", terrstr());
goto _OVER;
}
if (pArgs->host == NULL) {
pArgs->host = tsFirst;
}
char fqdn[TSDB_FQDN_LEN] = {0};
tstrncpy(fqdn, pArgs->host, TSDB_FQDN_LEN);
strtok(fqdn, ":");
if (pArgs->port == 0) {
pArgs->port = tsServerPort;
}
printf("network test client is initialized, the server is %s:%u\n", fqdn, pArgs->port);
tstrncpy(epSet.eps[0].fqdn, fqdn, TSDB_FQDN_LEN);
epSet.eps[0].port = (uint16_t)pArgs->port;
int32_t totalSucc = 0;
uint64_t startTime = taosGetTimestampUs();
for (int32_t i = 0; i < pArgs->pktNum; ++i) {
SRpcMsg rpcMsg = {.ahandle = (void *)0x9525, .msgType = TDMT_DND_NET_TEST};
rpcMsg.pCont = rpcMallocCont(pArgs->pktLen);
rpcMsg.contLen = pArgs->pktLen;
printf("request is sent, size:%d\n", rpcMsg.contLen);
rpcSendRecv(clientRpc, &epSet, &rpcMsg, &rpcRsp);
if (rpcRsp.code == 0 && rpcRsp.contLen == rpcMsg.contLen) {
printf("response is received, size:%d\n", rpcMsg.contLen);
if (rpcRsp.code == 0) totalSucc++;
} else {
printf("response not received since %s\n", tstrerror(rpcRsp.code));
}
rpcFreeCont(rpcRsp.pCont);
rpcRsp.pCont = NULL;
}
uint64_t endTime = taosGetTimestampUs();
uint64_t elT = endTime - startTime;
printf("\ntotal succ:%5d/%d\tcost:%8.2lf ms\tspeed:%8.2lf MB/s\n", totalSucc, pArgs->pktNum, elT / 1000.0,
pArgs->pktLen / (elT / 1000000.0) / 1024.0 / 1024.0 * totalSucc);
_OVER:
if (clientRpc != NULL) {
rpcClose(clientRpc);
}
if (rpcRsp.pCont != NULL) {
rpcFreeCont(rpcRsp.pCont);
}
}
static void shellProcessMsg(void *p, SRpcMsg *pRpc, SEpSet *pEpSet) {
printf("request is received, size:%d\n", pRpc->contLen);
fflush(stdout);
SRpcMsg rsp = {.handle = pRpc->handle, .refId = pRpc->refId, .ahandle = pRpc->ahandle, .code = 0};
rsp.pCont = rpcMallocCont(pRpc->contLen);
if (rsp.pCont == NULL) {
rsp.code = TSDB_CODE_OUT_OF_MEMORY;
} else {
rsp.contLen = pRpc->contLen;
}
rpcSendResponse(&rsp);
}
void shellNettestHandler(int32_t signum, void *sigInfo, void *context) { shellExit(); }
static void shellWorkAsServer() {
SShellArgs *pArgs = &shell.args;
if (pArgs->port == 0) {
pArgs->port = tsServerPort;
}
SRpcInit rpcInit = {0};
rpcInit.localPort = pArgs->port;
rpcInit.label = "CHK";
rpcInit.numOfThreads = tsNumOfRpcThreads;
rpcInit.cfp = (RpcCfp)shellProcessMsg;
rpcInit.sessions = 10;
rpcInit.connType = TAOS_CONN_SERVER;
rpcInit.idleTime = tsShellActivityTimer * 1000;
void *serverRpc = rpcOpen(&rpcInit);
if (serverRpc == NULL) {
printf("failed to init net test server since %s", terrstr());
} else {
printf("network test server is initialized, port:%u\n", pArgs->port);
taosSetSignal(SIGTERM, shellNettestHandler);
while (1) taosMsleep(10);
}
}
void shellTestNetWork() {
if (strcmp(shell.args.netrole, "client") == 0) {
shellWorkAsClient();
}
if (strcmp(shell.args.netrole, "server") == 0) {
shellWorkAsServer();
}
}
/*
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define _BSD_SOURCE
#define _GNU_SOURCE
#define _XOPEN_SOURCE
#define _DEFAULT_SOURCE
#include "shellInt.h"
bool shellRegexMatch(const char *s, const char *reg, int32_t cflags) {
regex_t regex = {0};
char msgbuf[100] = {0};
/* Compile regular expression */
if (regcomp(&regex, reg, cflags) != 0) {
fprintf(stderr, "Fail to compile regex");
shellExit();
}
/* Execute regular expression */
int32_t reti = regexec(&regex, s, 0, NULL, 0);
if (!reti) {
regfree(&regex);
return true;
} else if (reti == REG_NOMATCH) {
regfree(&regex);
return false;
} else {
regerror(reti, &regex, msgbuf, sizeof(msgbuf));
fprintf(stderr, "Regex match failed: %s\n", msgbuf);
regfree(&regex);
shellExit();
}
return false;
}
int32_t shellCheckIntSize() {
if (sizeof(int8_t) != 1) {
printf("taos int8 size is %d(!= 1)", (int)sizeof(int8_t));
return -1;
}
if (sizeof(int16_t) != 2) {
printf("taos int16 size is %d(!= 2)", (int)sizeof(int16_t));
return -1;
}
if (sizeof(int32_t) != 4) {
printf("taos int32 size is %d(!= 4)", (int)sizeof(int32_t));
return -1;
}
if (sizeof(int64_t) != 8) {
printf("taos int64 size is %d(!= 8)", (int)sizeof(int64_t));
return -1;
}
return 0;
}
void shellPrintVersion() { printf("version: %s\n", version); }
void shellGenerateAuth() {
char secretEncrypt[TSDB_PASSWORD_LEN + 1] = {0};
taosEncryptPass_c((uint8_t *)shell.args.password, strlen(shell.args.password), secretEncrypt);
printf("%s\n", secretEncrypt);
fflush(stdout);
}
void shellDumpConfig() {
SConfig *pCfg = taosGetCfg();
if (pCfg == NULL) {
printf("TDengine read global config failed!\n");
} else {
cfgDumpCfg(pCfg, 1, true);
}
fflush(stdout);
}
void shellCheckServerStatus() {
TSDB_SERVER_STATUS code;
do {
char details[1024] = {0};
code = taos_check_server_status(shell.args.host, shell.args.port, details, 1024);
switch (code) {
case TSDB_SRV_STATUS_UNAVAILABLE:
printf("0: unavailable\n");
break;
case TSDB_SRV_STATUS_NETWORK_OK:
printf("1: network ok\n");
break;
case TSDB_SRV_STATUS_SERVICE_OK:
printf("2: service ok\n");
break;
case TSDB_SRV_STATUS_SERVICE_DEGRADED:
printf("3: service degraded\n");
break;
case TSDB_SRV_STATUS_EXTING:
printf("4: exiting\n");
break;
}
if (strlen(details) != 0) {
printf("%s\n\n", details);
}
fflush(stdout);
if (code == TSDB_SRV_STATUS_NETWORK_OK && shell.args.is_startup) {
taosMsleep(1000);
} else {
break;
}
} while (1);
}
void shellExit() {
if (shell.conn != NULL) {
taos_close(shell.conn);
shell.conn = NULL;
}
taos_cleanup();
exit(EXIT_FAILURE);
}
\ No newline at end of file
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册