From ee602ffb6673b74852da24d5415b38db602a272e Mon Sep 17 00:00:00 2001 From: dapan1121 Date: Tue, 29 Dec 2020 02:52:57 +0000 Subject: [PATCH 01/29] fix bug --- src/client/src/tscFunctionImpl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/client/src/tscFunctionImpl.c b/src/client/src/tscFunctionImpl.c index 22240efe14..3a01a9b281 100644 --- a/src/client/src/tscFunctionImpl.c +++ b/src/client/src/tscFunctionImpl.c @@ -921,6 +921,10 @@ static void minMax_function(SQLFunctionCtx *pCtx, char *pOutput, int32_t isMin, *notNullElems = pCtx->size - pCtx->preAggVals.statis.numOfNull; assert(*notNullElems >= 0); + if (*notNullElems == 0){ + return; + } + void * tval = NULL; int16_t index = 0; From 7da9fce97a9132f55a86dc4efb04a6a44d4c5579 Mon Sep 17 00:00:00 2001 From: dapan1121 Date: Tue, 29 Dec 2020 06:14:34 +0000 Subject: [PATCH 02/29] fix bug --- src/client/src/tscSQLParser.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/client/src/tscSQLParser.c b/src/client/src/tscSQLParser.c index 9151f98ee3..b9d2762d9c 100644 --- a/src/client/src/tscSQLParser.c +++ b/src/client/src/tscSQLParser.c @@ -4478,6 +4478,7 @@ int32_t parseFillClause(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SQuerySQL* pQuery const char* msg = "illegal value or data overflow"; const char* msg1 = "value is expected"; const char* msg2 = "invalid fill option"; + const char* msg3 = "top/bottom not support fill"; if (pItem->pVar.nType != TSDB_DATA_TYPE_BINARY) { return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg2); @@ -4560,6 +4561,14 @@ int32_t parseFillClause(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SQuerySQL* pQuery return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg2); } + int32_t numOfExprs = tscSqlExprNumOfExprs(pQueryInfo); + for(int32_t i = 0; i < numOfExprs; ++i) { + SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, i); + if (pExpr->functionId == TSDB_FUNC_TOP || pExpr->functionId == TSDB_FUNC_BOTTOM) { + return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg3); + } + } + return TSDB_CODE_SUCCESS; } From ea63bec03952eb3990f95cb60e05cc28454d88e5 Mon Sep 17 00:00:00 2001 From: Hui Li Date: Tue, 29 Dec 2020 14:18:01 +0800 Subject: [PATCH 03/29] [TD-2103] taosdemo function enhancement --- deps/libcurl/include/curl/curl.h | 2415 +++++++++++ deps/libcurl/include/curl/curlbuild.h | 198 + deps/libcurl/include/curl/curlrules.h | 262 ++ deps/libcurl/include/curl/curlver.h | 77 + deps/libcurl/include/curl/easy.h | 102 + deps/libcurl/include/curl/mprintf.h | 74 + deps/libcurl/include/curl/multi.h | 435 ++ deps/libcurl/include/curl/stdcheaders.h | 33 + deps/libcurl/include/curl/typecheck-gcc.h | 622 +++ deps/libcurl/lib/libcurl.a | Bin 0 -> 734534 bytes src/kit/CMakeLists.txt | 1 + src/kit/taosdemox/CMakeLists.txt | 25 + src/kit/taosdemox/insert.json | 53 + src/kit/taosdemox/query.json | 17 + src/kit/taosdemox/subscribe.json | 17 + src/kit/taosdemox/taosdemox.c | 4621 +++++++++++++++++++++ 16 files changed, 8952 insertions(+) create mode 100644 deps/libcurl/include/curl/curl.h create mode 100644 deps/libcurl/include/curl/curlbuild.h create mode 100644 deps/libcurl/include/curl/curlrules.h create mode 100644 deps/libcurl/include/curl/curlver.h create mode 100644 deps/libcurl/include/curl/easy.h create mode 100644 deps/libcurl/include/curl/mprintf.h create mode 100644 deps/libcurl/include/curl/multi.h create mode 100644 deps/libcurl/include/curl/stdcheaders.h create mode 100644 deps/libcurl/include/curl/typecheck-gcc.h create mode 100644 deps/libcurl/lib/libcurl.a create mode 100644 src/kit/taosdemox/CMakeLists.txt create mode 100644 src/kit/taosdemox/insert.json create mode 100644 src/kit/taosdemox/query.json create mode 100644 src/kit/taosdemox/subscribe.json create mode 100644 src/kit/taosdemox/taosdemox.c diff --git a/deps/libcurl/include/curl/curl.h b/deps/libcurl/include/curl/curl.h new file mode 100644 index 0000000000..84229bb698 --- /dev/null +++ b/deps/libcurl/include/curl/curl.h @@ -0,0 +1,2415 @@ +#ifndef __CURL_CURL_H +#define __CURL_CURL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * If you have libcurl problems, all docs and details are found here: + * http://curl.haxx.se/libcurl/ + * + * curl-library mailing list subscription and unsubscription web interface: + * http://cool.haxx.se/mailman/listinfo/curl-library/ + */ + +#include "curlver.h" /* libcurl version defines */ +#include "curlbuild.h" /* libcurl build definitions */ +#include "curlrules.h" /* libcurl rules enforcement */ + +/* + * Define WIN32 when build target is Win32 API + */ + +#if (defined(_WIN32) || defined(__WIN32__)) && \ + !defined(WIN32) && !defined(__SYMBIAN32__) +#define WIN32 +#endif + +#include +#include + +#if defined(__FreeBSD__) && (__FreeBSD__ >= 2) +/* Needed for __FreeBSD_version symbol definition */ +#include +#endif + +/* The include stuff here below is mainly for time_t! */ +#include +#include + +#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__) +#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || \ + defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)) +/* The check above prevents the winsock2 inclusion if winsock.h already was + included, since they can't co-exist without problems */ +#include +#include +#endif +#endif + +/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish + libc5-based Linux systems. Only include it on systems that are known to + require it! */ +#if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \ + defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \ + defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \ + (defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) +#include +#endif + +#if !defined(WIN32) && !defined(_WIN32_WCE) +#include +#endif + +#if !defined(WIN32) && !defined(__WATCOMC__) && !defined(__VXWORKS__) +#include +#endif + +#ifdef __BEOS__ +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void CURL; + +/* + * libcurl external API function linkage decorations. + */ + +#ifdef CURL_STATICLIB +# define CURL_EXTERN +#elif defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__) +# if defined(BUILDING_LIBCURL) +# define CURL_EXTERN __declspec(dllexport) +# else +# define CURL_EXTERN __declspec(dllimport) +# endif +#elif defined(BUILDING_LIBCURL) && defined(CURL_HIDDEN_SYMBOLS) +# define CURL_EXTERN CURL_EXTERN_SYMBOL +#else +# define CURL_EXTERN +#endif + +#ifndef curl_socket_typedef +/* socket typedef */ +#if defined(WIN32) && !defined(__LWIP_OPT_H__) && !defined(LWIP_HDR_OPT_H) +typedef SOCKET curl_socket_t; +#define CURL_SOCKET_BAD INVALID_SOCKET +#else +typedef int curl_socket_t; +#define CURL_SOCKET_BAD -1 +#endif +#define curl_socket_typedef +#endif /* curl_socket_typedef */ + +struct curl_httppost { + struct curl_httppost *next; /* next entry in the list */ + char *name; /* pointer to allocated name */ + long namelength; /* length of name length */ + char *contents; /* pointer to allocated data contents */ + long contentslength; /* length of contents field, see also + CURL_HTTPPOST_LARGE */ + char *buffer; /* pointer to allocated buffer contents */ + long bufferlength; /* length of buffer field */ + char *contenttype; /* Content-Type */ + struct curl_slist* contentheader; /* list of extra headers for this form */ + struct curl_httppost *more; /* if one field name has more than one + file, this link should link to following + files */ + long flags; /* as defined below */ + +/* specified content is a file name */ +#define CURL_HTTPPOST_FILENAME (1<<0) +/* specified content is a file name */ +#define CURL_HTTPPOST_READFILE (1<<1) +/* name is only stored pointer do not free in formfree */ +#define CURL_HTTPPOST_PTRNAME (1<<2) +/* contents is only stored pointer do not free in formfree */ +#define CURL_HTTPPOST_PTRCONTENTS (1<<3) +/* upload file from buffer */ +#define CURL_HTTPPOST_BUFFER (1<<4) +/* upload file from pointer contents */ +#define CURL_HTTPPOST_PTRBUFFER (1<<5) +/* upload file contents by using the regular read callback to get the data and + pass the given pointer as custom pointer */ +#define CURL_HTTPPOST_CALLBACK (1<<6) +/* use size in 'contentlen', added in 7.46.0 */ +#define CURL_HTTPPOST_LARGE (1<<7) + + char *showfilename; /* The file name to show. If not set, the + actual file name will be used (if this + is a file part) */ + void *userp; /* custom pointer used for + HTTPPOST_CALLBACK posts */ + curl_off_t contentlen; /* alternative length of contents + field. Used if CURL_HTTPPOST_LARGE is + set. Added in 7.46.0 */ +}; + +/* This is the CURLOPT_PROGRESSFUNCTION callback proto. It is now considered + deprecated but was the only choice up until 7.31.0 */ +typedef int (*curl_progress_callback)(void *clientp, + double dltotal, + double dlnow, + double ultotal, + double ulnow); + +/* This is the CURLOPT_XFERINFOFUNCTION callback proto. It was introduced in + 7.32.0, it avoids floating point and provides more detailed information. */ +typedef int (*curl_xferinfo_callback)(void *clientp, + curl_off_t dltotal, + curl_off_t dlnow, + curl_off_t ultotal, + curl_off_t ulnow); + +#ifndef CURL_MAX_WRITE_SIZE + /* Tests have proven that 20K is a very bad buffer size for uploads on + Windows, while 16K for some odd reason performed a lot better. + We do the ifndef check to allow this value to easier be changed at build + time for those who feel adventurous. The practical minimum is about + 400 bytes since libcurl uses a buffer of this size as a scratch area + (unrelated to network send operations). */ +#define CURL_MAX_WRITE_SIZE 16384 +#endif + +#ifndef CURL_MAX_HTTP_HEADER +/* The only reason to have a max limit for this is to avoid the risk of a bad + server feeding libcurl with a never-ending header that will cause reallocs + infinitely */ +#define CURL_MAX_HTTP_HEADER (100*1024) +#endif + +/* This is a magic return code for the write callback that, when returned, + will signal libcurl to pause receiving on the current transfer. */ +#define CURL_WRITEFUNC_PAUSE 0x10000001 + +typedef size_t (*curl_write_callback)(char *buffer, + size_t size, + size_t nitems, + void *outstream); + + + +/* enumeration of file types */ +typedef enum { + CURLFILETYPE_FILE = 0, + CURLFILETYPE_DIRECTORY, + CURLFILETYPE_SYMLINK, + CURLFILETYPE_DEVICE_BLOCK, + CURLFILETYPE_DEVICE_CHAR, + CURLFILETYPE_NAMEDPIPE, + CURLFILETYPE_SOCKET, + CURLFILETYPE_DOOR, /* is possible only on Sun Solaris now */ + + CURLFILETYPE_UNKNOWN /* should never occur */ +} curlfiletype; + +#define CURLFINFOFLAG_KNOWN_FILENAME (1<<0) +#define CURLFINFOFLAG_KNOWN_FILETYPE (1<<1) +#define CURLFINFOFLAG_KNOWN_TIME (1<<2) +#define CURLFINFOFLAG_KNOWN_PERM (1<<3) +#define CURLFINFOFLAG_KNOWN_UID (1<<4) +#define CURLFINFOFLAG_KNOWN_GID (1<<5) +#define CURLFINFOFLAG_KNOWN_SIZE (1<<6) +#define CURLFINFOFLAG_KNOWN_HLINKCOUNT (1<<7) + +/* Content of this structure depends on information which is known and is + achievable (e.g. by FTP LIST parsing). Please see the url_easy_setopt(3) man + page for callbacks returning this structure -- some fields are mandatory, + some others are optional. The FLAG field has special meaning. */ +struct curl_fileinfo { + char *filename; + curlfiletype filetype; + time_t time; + unsigned int perm; + int uid; + int gid; + curl_off_t size; + long int hardlinks; + + struct { + /* If some of these fields is not NULL, it is a pointer to b_data. */ + char *time; + char *perm; + char *user; + char *group; + char *target; /* pointer to the target filename of a symlink */ + } strings; + + unsigned int flags; + + /* used internally */ + char * b_data; + size_t b_size; + size_t b_used; +}; + +/* return codes for CURLOPT_CHUNK_BGN_FUNCTION */ +#define CURL_CHUNK_BGN_FUNC_OK 0 +#define CURL_CHUNK_BGN_FUNC_FAIL 1 /* tell the lib to end the task */ +#define CURL_CHUNK_BGN_FUNC_SKIP 2 /* skip this chunk over */ + +/* if splitting of data transfer is enabled, this callback is called before + download of an individual chunk started. Note that parameter "remains" works + only for FTP wildcard downloading (for now), otherwise is not used */ +typedef long (*curl_chunk_bgn_callback)(const void *transfer_info, + void *ptr, + int remains); + +/* return codes for CURLOPT_CHUNK_END_FUNCTION */ +#define CURL_CHUNK_END_FUNC_OK 0 +#define CURL_CHUNK_END_FUNC_FAIL 1 /* tell the lib to end the task */ + +/* If splitting of data transfer is enabled this callback is called after + download of an individual chunk finished. + Note! After this callback was set then it have to be called FOR ALL chunks. + Even if downloading of this chunk was skipped in CHUNK_BGN_FUNC. + This is the reason why we don't need "transfer_info" parameter in this + callback and we are not interested in "remains" parameter too. */ +typedef long (*curl_chunk_end_callback)(void *ptr); + +/* return codes for FNMATCHFUNCTION */ +#define CURL_FNMATCHFUNC_MATCH 0 /* string corresponds to the pattern */ +#define CURL_FNMATCHFUNC_NOMATCH 1 /* pattern doesn't match the string */ +#define CURL_FNMATCHFUNC_FAIL 2 /* an error occurred */ + +/* callback type for wildcard downloading pattern matching. If the + string matches the pattern, return CURL_FNMATCHFUNC_MATCH value, etc. */ +typedef int (*curl_fnmatch_callback)(void *ptr, + const char *pattern, + const char *string); + +/* These are the return codes for the seek callbacks */ +#define CURL_SEEKFUNC_OK 0 +#define CURL_SEEKFUNC_FAIL 1 /* fail the entire transfer */ +#define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking can't be done, so + libcurl might try other means instead */ +typedef int (*curl_seek_callback)(void *instream, + curl_off_t offset, + int origin); /* 'whence' */ + +/* This is a return code for the read callback that, when returned, will + signal libcurl to immediately abort the current transfer. */ +#define CURL_READFUNC_ABORT 0x10000000 +/* This is a return code for the read callback that, when returned, will + signal libcurl to pause sending data on the current transfer. */ +#define CURL_READFUNC_PAUSE 0x10000001 + +typedef size_t (*curl_read_callback)(char *buffer, + size_t size, + size_t nitems, + void *instream); + +typedef enum { + CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */ + CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */ + CURLSOCKTYPE_LAST /* never use */ +} curlsocktype; + +/* The return code from the sockopt_callback can signal information back + to libcurl: */ +#define CURL_SOCKOPT_OK 0 +#define CURL_SOCKOPT_ERROR 1 /* causes libcurl to abort and return + CURLE_ABORTED_BY_CALLBACK */ +#define CURL_SOCKOPT_ALREADY_CONNECTED 2 + +typedef int (*curl_sockopt_callback)(void *clientp, + curl_socket_t curlfd, + curlsocktype purpose); + +struct curl_sockaddr { + int family; + int socktype; + int protocol; + unsigned int addrlen; /* addrlen was a socklen_t type before 7.18.0 but it + turned really ugly and painful on the systems that + lack this type */ + struct sockaddr addr; +}; + +typedef curl_socket_t +(*curl_opensocket_callback)(void *clientp, + curlsocktype purpose, + struct curl_sockaddr *address); + +typedef int +(*curl_closesocket_callback)(void *clientp, curl_socket_t item); + +typedef enum { + CURLIOE_OK, /* I/O operation successful */ + CURLIOE_UNKNOWNCMD, /* command was unknown to callback */ + CURLIOE_FAILRESTART, /* failed to restart the read */ + CURLIOE_LAST /* never use */ +} curlioerr; + +typedef enum { + CURLIOCMD_NOP, /* no operation */ + CURLIOCMD_RESTARTREAD, /* restart the read stream from start */ + CURLIOCMD_LAST /* never use */ +} curliocmd; + +typedef curlioerr (*curl_ioctl_callback)(CURL *handle, + int cmd, + void *clientp); + +/* + * The following typedef's are signatures of malloc, free, realloc, strdup and + * calloc respectively. Function pointers of these types can be passed to the + * curl_global_init_mem() function to set user defined memory management + * callback routines. + */ +typedef void *(*curl_malloc_callback)(size_t size); +typedef void (*curl_free_callback)(void *ptr); +typedef void *(*curl_realloc_callback)(void *ptr, size_t size); +typedef char *(*curl_strdup_callback)(const char *str); +typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); + +/* the kind of data that is passed to information_callback*/ +typedef enum { + CURLINFO_TEXT = 0, + CURLINFO_HEADER_IN, /* 1 */ + CURLINFO_HEADER_OUT, /* 2 */ + CURLINFO_DATA_IN, /* 3 */ + CURLINFO_DATA_OUT, /* 4 */ + CURLINFO_SSL_DATA_IN, /* 5 */ + CURLINFO_SSL_DATA_OUT, /* 6 */ + CURLINFO_END +} curl_infotype; + +typedef int (*curl_debug_callback) + (CURL *handle, /* the handle/transfer this concerns */ + curl_infotype type, /* what kind of data */ + char *data, /* points to the data */ + size_t size, /* size of the data pointed to */ + void *userptr); /* whatever the user please */ + +/* All possible error codes from all sorts of curl functions. Future versions + may return other values, stay prepared. + + Always add new return codes last. Never *EVER* remove any. The return + codes must remain the same! + */ + +typedef enum { + CURLE_OK = 0, + CURLE_UNSUPPORTED_PROTOCOL, /* 1 */ + CURLE_FAILED_INIT, /* 2 */ + CURLE_URL_MALFORMAT, /* 3 */ + CURLE_NOT_BUILT_IN, /* 4 - [was obsoleted in August 2007 for + 7.17.0, reused in April 2011 for 7.21.5] */ + CURLE_COULDNT_RESOLVE_PROXY, /* 5 */ + CURLE_COULDNT_RESOLVE_HOST, /* 6 */ + CURLE_COULDNT_CONNECT, /* 7 */ + CURLE_FTP_WEIRD_SERVER_REPLY, /* 8 */ + CURLE_REMOTE_ACCESS_DENIED, /* 9 a service was denied by the server + due to lack of access - when login fails + this is not returned. */ + CURLE_FTP_ACCEPT_FAILED, /* 10 - [was obsoleted in April 2006 for + 7.15.4, reused in Dec 2011 for 7.24.0]*/ + CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */ + CURLE_FTP_ACCEPT_TIMEOUT, /* 12 - timeout occurred accepting server + [was obsoleted in August 2007 for 7.17.0, + reused in Dec 2011 for 7.24.0]*/ + CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */ + CURLE_FTP_WEIRD_227_FORMAT, /* 14 */ + CURLE_FTP_CANT_GET_HOST, /* 15 */ + CURLE_HTTP2, /* 16 - A problem in the http2 framing layer. + [was obsoleted in August 2007 for 7.17.0, + reused in July 2014 for 7.38.0] */ + CURLE_FTP_COULDNT_SET_TYPE, /* 17 */ + CURLE_PARTIAL_FILE, /* 18 */ + CURLE_FTP_COULDNT_RETR_FILE, /* 19 */ + CURLE_OBSOLETE20, /* 20 - NOT USED */ + CURLE_QUOTE_ERROR, /* 21 - quote command failure */ + CURLE_HTTP_RETURNED_ERROR, /* 22 */ + CURLE_WRITE_ERROR, /* 23 */ + CURLE_OBSOLETE24, /* 24 - NOT USED */ + CURLE_UPLOAD_FAILED, /* 25 - failed upload "command" */ + CURLE_READ_ERROR, /* 26 - couldn't open/read from file */ + CURLE_OUT_OF_MEMORY, /* 27 */ + /* Note: CURLE_OUT_OF_MEMORY may sometimes indicate a conversion error + instead of a memory allocation error if CURL_DOES_CONVERSIONS + is defined + */ + CURLE_OPERATION_TIMEDOUT, /* 28 - the timeout time was reached */ + CURLE_OBSOLETE29, /* 29 - NOT USED */ + CURLE_FTP_PORT_FAILED, /* 30 - FTP PORT operation failed */ + CURLE_FTP_COULDNT_USE_REST, /* 31 - the REST command failed */ + CURLE_OBSOLETE32, /* 32 - NOT USED */ + CURLE_RANGE_ERROR, /* 33 - RANGE "command" didn't work */ + CURLE_HTTP_POST_ERROR, /* 34 */ + CURLE_SSL_CONNECT_ERROR, /* 35 - wrong when connecting with SSL */ + CURLE_BAD_DOWNLOAD_RESUME, /* 36 - couldn't resume download */ + CURLE_FILE_COULDNT_READ_FILE, /* 37 */ + CURLE_LDAP_CANNOT_BIND, /* 38 */ + CURLE_LDAP_SEARCH_FAILED, /* 39 */ + CURLE_OBSOLETE40, /* 40 - NOT USED */ + CURLE_FUNCTION_NOT_FOUND, /* 41 */ + CURLE_ABORTED_BY_CALLBACK, /* 42 */ + CURLE_BAD_FUNCTION_ARGUMENT, /* 43 */ + CURLE_OBSOLETE44, /* 44 - NOT USED */ + CURLE_INTERFACE_FAILED, /* 45 - CURLOPT_INTERFACE failed */ + CURLE_OBSOLETE46, /* 46 - NOT USED */ + CURLE_TOO_MANY_REDIRECTS , /* 47 - catch endless re-direct loops */ + CURLE_UNKNOWN_OPTION, /* 48 - User specified an unknown option */ + CURLE_TELNET_OPTION_SYNTAX , /* 49 - Malformed telnet option */ + CURLE_OBSOLETE50, /* 50 - NOT USED */ + CURLE_PEER_FAILED_VERIFICATION, /* 51 - peer's certificate or fingerprint + wasn't verified fine */ + CURLE_GOT_NOTHING, /* 52 - when this is a specific error */ + CURLE_SSL_ENGINE_NOTFOUND, /* 53 - SSL crypto engine not found */ + CURLE_SSL_ENGINE_SETFAILED, /* 54 - can not set SSL crypto engine as + default */ + CURLE_SEND_ERROR, /* 55 - failed sending network data */ + CURLE_RECV_ERROR, /* 56 - failure in receiving network data */ + CURLE_OBSOLETE57, /* 57 - NOT IN USE */ + CURLE_SSL_CERTPROBLEM, /* 58 - problem with the local certificate */ + CURLE_SSL_CIPHER, /* 59 - couldn't use specified cipher */ + CURLE_SSL_CACERT, /* 60 - problem with the CA cert (path?) */ + CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized/bad encoding */ + CURLE_LDAP_INVALID_URL, /* 62 - Invalid LDAP URL */ + CURLE_FILESIZE_EXCEEDED, /* 63 - Maximum file size exceeded */ + CURLE_USE_SSL_FAILED, /* 64 - Requested FTP SSL level failed */ + CURLE_SEND_FAIL_REWIND, /* 65 - Sending the data requires a rewind + that failed */ + CURLE_SSL_ENGINE_INITFAILED, /* 66 - failed to initialise ENGINE */ + CURLE_LOGIN_DENIED, /* 67 - user, password or similar was not + accepted and we failed to login */ + CURLE_TFTP_NOTFOUND, /* 68 - file not found on server */ + CURLE_TFTP_PERM, /* 69 - permission problem on server */ + CURLE_REMOTE_DISK_FULL, /* 70 - out of disk space on server */ + CURLE_TFTP_ILLEGAL, /* 71 - Illegal TFTP operation */ + CURLE_TFTP_UNKNOWNID, /* 72 - Unknown transfer ID */ + CURLE_REMOTE_FILE_EXISTS, /* 73 - File already exists */ + CURLE_TFTP_NOSUCHUSER, /* 74 - No such user */ + CURLE_CONV_FAILED, /* 75 - conversion failed */ + CURLE_CONV_REQD, /* 76 - caller must register conversion + callbacks using curl_easy_setopt options + CURLOPT_CONV_FROM_NETWORK_FUNCTION, + CURLOPT_CONV_TO_NETWORK_FUNCTION, and + CURLOPT_CONV_FROM_UTF8_FUNCTION */ + CURLE_SSL_CACERT_BADFILE, /* 77 - could not load CACERT file, missing + or wrong format */ + CURLE_REMOTE_FILE_NOT_FOUND, /* 78 - remote file not found */ + CURLE_SSH, /* 79 - error from the SSH layer, somewhat + generic so the error message will be of + interest when this has happened */ + + CURLE_SSL_SHUTDOWN_FAILED, /* 80 - Failed to shut down the SSL + connection */ + CURLE_AGAIN, /* 81 - socket is not ready for send/recv, + wait till it's ready and try again (Added + in 7.18.2) */ + CURLE_SSL_CRL_BADFILE, /* 82 - could not load CRL file, missing or + wrong format (Added in 7.19.0) */ + CURLE_SSL_ISSUER_ERROR, /* 83 - Issuer check failed. (Added in + 7.19.0) */ + CURLE_FTP_PRET_FAILED, /* 84 - a PRET command failed */ + CURLE_RTSP_CSEQ_ERROR, /* 85 - mismatch of RTSP CSeq numbers */ + CURLE_RTSP_SESSION_ERROR, /* 86 - mismatch of RTSP Session Ids */ + CURLE_FTP_BAD_FILE_LIST, /* 87 - unable to parse FTP file list */ + CURLE_CHUNK_FAILED, /* 88 - chunk callback reported error */ + CURLE_NO_CONNECTION_AVAILABLE, /* 89 - No connection available, the + session will be queued */ + CURLE_SSL_PINNEDPUBKEYNOTMATCH, /* 90 - specified pinned public key did not + match */ + CURLE_SSL_INVALIDCERTSTATUS, /* 91 - invalid certificate status */ + CURL_LAST /* never use! */ +} CURLcode; + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Previously obsolete error code re-used in 7.38.0 */ +#define CURLE_OBSOLETE16 CURLE_HTTP2 + +/* Previously obsolete error codes re-used in 7.24.0 */ +#define CURLE_OBSOLETE10 CURLE_FTP_ACCEPT_FAILED +#define CURLE_OBSOLETE12 CURLE_FTP_ACCEPT_TIMEOUT + +/* compatibility with older names */ +#define CURLOPT_ENCODING CURLOPT_ACCEPT_ENCODING + +/* The following were added in 7.21.5, April 2011 */ +#define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION + +/* The following were added in 7.17.1 */ +/* These are scheduled to disappear by 2009 */ +#define CURLE_SSL_PEER_CERTIFICATE CURLE_PEER_FAILED_VERIFICATION + +/* The following were added in 7.17.0 */ +/* These are scheduled to disappear by 2009 */ +#define CURLE_OBSOLETE CURLE_OBSOLETE50 /* no one should be using this! */ +#define CURLE_BAD_PASSWORD_ENTERED CURLE_OBSOLETE46 +#define CURLE_BAD_CALLING_ORDER CURLE_OBSOLETE44 +#define CURLE_FTP_USER_PASSWORD_INCORRECT CURLE_OBSOLETE10 +#define CURLE_FTP_CANT_RECONNECT CURLE_OBSOLETE16 +#define CURLE_FTP_COULDNT_GET_SIZE CURLE_OBSOLETE32 +#define CURLE_FTP_COULDNT_SET_ASCII CURLE_OBSOLETE29 +#define CURLE_FTP_WEIRD_USER_REPLY CURLE_OBSOLETE12 +#define CURLE_FTP_WRITE_ERROR CURLE_OBSOLETE20 +#define CURLE_LIBRARY_NOT_FOUND CURLE_OBSOLETE40 +#define CURLE_MALFORMAT_USER CURLE_OBSOLETE24 +#define CURLE_SHARE_IN_USE CURLE_OBSOLETE57 +#define CURLE_URL_MALFORMAT_USER CURLE_NOT_BUILT_IN + +#define CURLE_FTP_ACCESS_DENIED CURLE_REMOTE_ACCESS_DENIED +#define CURLE_FTP_COULDNT_SET_BINARY CURLE_FTP_COULDNT_SET_TYPE +#define CURLE_FTP_QUOTE_ERROR CURLE_QUOTE_ERROR +#define CURLE_TFTP_DISKFULL CURLE_REMOTE_DISK_FULL +#define CURLE_TFTP_EXISTS CURLE_REMOTE_FILE_EXISTS +#define CURLE_HTTP_RANGE_ERROR CURLE_RANGE_ERROR +#define CURLE_FTP_SSL_FAILED CURLE_USE_SSL_FAILED + +/* The following were added earlier */ + +#define CURLE_OPERATION_TIMEOUTED CURLE_OPERATION_TIMEDOUT + +#define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR +#define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED +#define CURLE_FTP_COULDNT_STOR_FILE CURLE_UPLOAD_FAILED + +#define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE +#define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME + +/* This was the error code 50 in 7.7.3 and a few earlier versions, this + is no longer used by libcurl but is instead #defined here only to not + make programs break */ +#define CURLE_ALREADY_COMPLETE 99999 + +/* Provide defines for really old option names */ +#define CURLOPT_FILE CURLOPT_WRITEDATA /* name changed in 7.9.7 */ +#define CURLOPT_INFILE CURLOPT_READDATA /* name changed in 7.9.7 */ +#define CURLOPT_WRITEHEADER CURLOPT_HEADERDATA + +/* Since long deprecated options with no code in the lib that does anything + with them. */ +#define CURLOPT_WRITEINFO CURLOPT_OBSOLETE40 +#define CURLOPT_CLOSEPOLICY CURLOPT_OBSOLETE72 + +#endif /*!CURL_NO_OLDIES*/ + +/* This prototype applies to all conversion callbacks */ +typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length); + +typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl, /* easy handle */ + void *ssl_ctx, /* actually an + OpenSSL SSL_CTX */ + void *userptr); + +typedef enum { + CURLPROXY_HTTP = 0, /* added in 7.10, new in 7.19.4 default is to use + CONNECT HTTP/1.1 */ + CURLPROXY_HTTP_1_0 = 1, /* added in 7.19.4, force to use CONNECT + HTTP/1.0 */ + CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already + in 7.10 */ + CURLPROXY_SOCKS5 = 5, /* added in 7.10 */ + CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */ + CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the + host name rather than the IP address. added + in 7.18.0 */ +} curl_proxytype; /* this enum was added in 7.10 */ + +/* + * Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options: + * + * CURLAUTH_NONE - No HTTP authentication + * CURLAUTH_BASIC - HTTP Basic authentication (default) + * CURLAUTH_DIGEST - HTTP Digest authentication + * CURLAUTH_NEGOTIATE - HTTP Negotiate (SPNEGO) authentication + * CURLAUTH_GSSNEGOTIATE - Alias for CURLAUTH_NEGOTIATE (deprecated) + * CURLAUTH_NTLM - HTTP NTLM authentication + * CURLAUTH_DIGEST_IE - HTTP Digest authentication with IE flavour + * CURLAUTH_NTLM_WB - HTTP NTLM authentication delegated to winbind helper + * CURLAUTH_ONLY - Use together with a single other type to force no + * authentication or just that single type + * CURLAUTH_ANY - All fine types set + * CURLAUTH_ANYSAFE - All fine types except Basic + */ + +#define CURLAUTH_NONE ((unsigned long)0) +#define CURLAUTH_BASIC (((unsigned long)1)<<0) +#define CURLAUTH_DIGEST (((unsigned long)1)<<1) +#define CURLAUTH_NEGOTIATE (((unsigned long)1)<<2) +/* Deprecated since the advent of CURLAUTH_NEGOTIATE */ +#define CURLAUTH_GSSNEGOTIATE CURLAUTH_NEGOTIATE +#define CURLAUTH_NTLM (((unsigned long)1)<<3) +#define CURLAUTH_DIGEST_IE (((unsigned long)1)<<4) +#define CURLAUTH_NTLM_WB (((unsigned long)1)<<5) +#define CURLAUTH_ONLY (((unsigned long)1)<<31) +#define CURLAUTH_ANY (~CURLAUTH_DIGEST_IE) +#define CURLAUTH_ANYSAFE (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE)) + +#define CURLSSH_AUTH_ANY ~0 /* all types supported by the server */ +#define CURLSSH_AUTH_NONE 0 /* none allowed, silly but complete */ +#define CURLSSH_AUTH_PUBLICKEY (1<<0) /* public/private key files */ +#define CURLSSH_AUTH_PASSWORD (1<<1) /* password */ +#define CURLSSH_AUTH_HOST (1<<2) /* host key files */ +#define CURLSSH_AUTH_KEYBOARD (1<<3) /* keyboard interactive */ +#define CURLSSH_AUTH_AGENT (1<<4) /* agent (ssh-agent, pageant...) */ +#define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY + +#define CURLGSSAPI_DELEGATION_NONE 0 /* no delegation (default) */ +#define CURLGSSAPI_DELEGATION_POLICY_FLAG (1<<0) /* if permitted by policy */ +#define CURLGSSAPI_DELEGATION_FLAG (1<<1) /* delegate always */ + +#define CURL_ERROR_SIZE 256 + +enum curl_khtype { + CURLKHTYPE_UNKNOWN, + CURLKHTYPE_RSA1, + CURLKHTYPE_RSA, + CURLKHTYPE_DSS +}; + +struct curl_khkey { + const char *key; /* points to a zero-terminated string encoded with base64 + if len is zero, otherwise to the "raw" data */ + size_t len; + enum curl_khtype keytype; +}; + +/* this is the set of return values expected from the curl_sshkeycallback + callback */ +enum curl_khstat { + CURLKHSTAT_FINE_ADD_TO_FILE, + CURLKHSTAT_FINE, + CURLKHSTAT_REJECT, /* reject the connection, return an error */ + CURLKHSTAT_DEFER, /* do not accept it, but we can't answer right now so + this causes a CURLE_DEFER error but otherwise the + connection will be left intact etc */ + CURLKHSTAT_LAST /* not for use, only a marker for last-in-list */ +}; + +/* this is the set of status codes pass in to the callback */ +enum curl_khmatch { + CURLKHMATCH_OK, /* match */ + CURLKHMATCH_MISMATCH, /* host found, key mismatch! */ + CURLKHMATCH_MISSING, /* no matching host/key found */ + CURLKHMATCH_LAST /* not for use, only a marker for last-in-list */ +}; + +typedef int + (*curl_sshkeycallback) (CURL *easy, /* easy handle */ + const struct curl_khkey *knownkey, /* known */ + const struct curl_khkey *foundkey, /* found */ + enum curl_khmatch, /* libcurl's view on the keys */ + void *clientp); /* custom pointer passed from app */ + +/* parameter for the CURLOPT_USE_SSL option */ +typedef enum { + CURLUSESSL_NONE, /* do not attempt to use SSL */ + CURLUSESSL_TRY, /* try using SSL, proceed anyway otherwise */ + CURLUSESSL_CONTROL, /* SSL for the control connection or fail */ + CURLUSESSL_ALL, /* SSL for all communication or fail */ + CURLUSESSL_LAST /* not an option, never use */ +} curl_usessl; + +/* Definition of bits for the CURLOPT_SSL_OPTIONS argument: */ + +/* - ALLOW_BEAST tells libcurl to allow the BEAST SSL vulnerability in the + name of improving interoperability with older servers. Some SSL libraries + have introduced work-arounds for this flaw but those work-arounds sometimes + make the SSL communication fail. To regain functionality with those broken + servers, a user can this way allow the vulnerability back. */ +#define CURLSSLOPT_ALLOW_BEAST (1<<0) + +/* - NO_REVOKE tells libcurl to disable certificate revocation checks for those + SSL backends where such behavior is present. */ +#define CURLSSLOPT_NO_REVOKE (1<<1) + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Backwards compatibility with older names */ +/* These are scheduled to disappear by 2009 */ + +#define CURLFTPSSL_NONE CURLUSESSL_NONE +#define CURLFTPSSL_TRY CURLUSESSL_TRY +#define CURLFTPSSL_CONTROL CURLUSESSL_CONTROL +#define CURLFTPSSL_ALL CURLUSESSL_ALL +#define CURLFTPSSL_LAST CURLUSESSL_LAST +#define curl_ftpssl curl_usessl +#endif /*!CURL_NO_OLDIES*/ + +/* parameter for the CURLOPT_FTP_SSL_CCC option */ +typedef enum { + CURLFTPSSL_CCC_NONE, /* do not send CCC */ + CURLFTPSSL_CCC_PASSIVE, /* Let the server initiate the shutdown */ + CURLFTPSSL_CCC_ACTIVE, /* Initiate the shutdown */ + CURLFTPSSL_CCC_LAST /* not an option, never use */ +} curl_ftpccc; + +/* parameter for the CURLOPT_FTPSSLAUTH option */ +typedef enum { + CURLFTPAUTH_DEFAULT, /* let libcurl decide */ + CURLFTPAUTH_SSL, /* use "AUTH SSL" */ + CURLFTPAUTH_TLS, /* use "AUTH TLS" */ + CURLFTPAUTH_LAST /* not an option, never use */ +} curl_ftpauth; + +/* parameter for the CURLOPT_FTP_CREATE_MISSING_DIRS option */ +typedef enum { + CURLFTP_CREATE_DIR_NONE, /* do NOT create missing dirs! */ + CURLFTP_CREATE_DIR, /* (FTP/SFTP) if CWD fails, try MKD and then CWD + again if MKD succeeded, for SFTP this does + similar magic */ + CURLFTP_CREATE_DIR_RETRY, /* (FTP only) if CWD fails, try MKD and then CWD + again even if MKD failed! */ + CURLFTP_CREATE_DIR_LAST /* not an option, never use */ +} curl_ftpcreatedir; + +/* parameter for the CURLOPT_FTP_FILEMETHOD option */ +typedef enum { + CURLFTPMETHOD_DEFAULT, /* let libcurl pick */ + CURLFTPMETHOD_MULTICWD, /* single CWD operation for each path part */ + CURLFTPMETHOD_NOCWD, /* no CWD at all */ + CURLFTPMETHOD_SINGLECWD, /* one CWD to full dir, then work on file */ + CURLFTPMETHOD_LAST /* not an option, never use */ +} curl_ftpmethod; + +/* bitmask defines for CURLOPT_HEADEROPT */ +#define CURLHEADER_UNIFIED 0 +#define CURLHEADER_SEPARATE (1<<0) + +/* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */ +#define CURLPROTO_HTTP (1<<0) +#define CURLPROTO_HTTPS (1<<1) +#define CURLPROTO_FTP (1<<2) +#define CURLPROTO_FTPS (1<<3) +#define CURLPROTO_SCP (1<<4) +#define CURLPROTO_SFTP (1<<5) +#define CURLPROTO_TELNET (1<<6) +#define CURLPROTO_LDAP (1<<7) +#define CURLPROTO_LDAPS (1<<8) +#define CURLPROTO_DICT (1<<9) +#define CURLPROTO_FILE (1<<10) +#define CURLPROTO_TFTP (1<<11) +#define CURLPROTO_IMAP (1<<12) +#define CURLPROTO_IMAPS (1<<13) +#define CURLPROTO_POP3 (1<<14) +#define CURLPROTO_POP3S (1<<15) +#define CURLPROTO_SMTP (1<<16) +#define CURLPROTO_SMTPS (1<<17) +#define CURLPROTO_RTSP (1<<18) +#define CURLPROTO_RTMP (1<<19) +#define CURLPROTO_RTMPT (1<<20) +#define CURLPROTO_RTMPE (1<<21) +#define CURLPROTO_RTMPTE (1<<22) +#define CURLPROTO_RTMPS (1<<23) +#define CURLPROTO_RTMPTS (1<<24) +#define CURLPROTO_GOPHER (1<<25) +#define CURLPROTO_SMB (1<<26) +#define CURLPROTO_SMBS (1<<27) +#define CURLPROTO_ALL (~0) /* enable everything */ + +/* long may be 32 or 64 bits, but we should never depend on anything else + but 32 */ +#define CURLOPTTYPE_LONG 0 +#define CURLOPTTYPE_OBJECTPOINT 10000 +#define CURLOPTTYPE_STRINGPOINT 10000 +#define CURLOPTTYPE_FUNCTIONPOINT 20000 +#define CURLOPTTYPE_OFF_T 30000 + +/* *STRINGPOINT is an alias for OBJECTPOINT to allow tools to extract the + string options from the header file */ + +/* name is uppercase CURLOPT_, + type is one of the defined CURLOPTTYPE_ + number is unique identifier */ +#ifdef CINIT +#undef CINIT +#endif + +#ifdef CURL_ISOCPP +#define CINIT(na,t,nu) CURLOPT_ ## na = CURLOPTTYPE_ ## t + nu +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define LONG CURLOPTTYPE_LONG +#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT +#define STRINGPOINT CURLOPTTYPE_OBJECTPOINT +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT +#define OFF_T CURLOPTTYPE_OFF_T +#define CINIT(name,type,number) CURLOPT_/**/name = type + number +#endif + +/* + * This macro-mania below setups the CURLOPT_[what] enum, to be used with + * curl_easy_setopt(). The first argument in the CINIT() macro is the [what] + * word. + */ + +typedef enum { + /* This is the FILE * or void * the regular output should be written to. */ + CINIT(WRITEDATA, OBJECTPOINT, 1), + + /* The full URL to get/put */ + CINIT(URL, STRINGPOINT, 2), + + /* Port number to connect to, if other than default. */ + CINIT(PORT, LONG, 3), + + /* Name of proxy to use. */ + CINIT(PROXY, STRINGPOINT, 4), + + /* "user:password;options" to use when fetching. */ + CINIT(USERPWD, STRINGPOINT, 5), + + /* "user:password" to use with proxy. */ + CINIT(PROXYUSERPWD, STRINGPOINT, 6), + + /* Range to get, specified as an ASCII string. */ + CINIT(RANGE, STRINGPOINT, 7), + + /* not used */ + + /* Specified file stream to upload from (use as input): */ + CINIT(READDATA, OBJECTPOINT, 9), + + /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE + * bytes big. If this is not used, error messages go to stderr instead: */ + CINIT(ERRORBUFFER, OBJECTPOINT, 10), + + /* Function that will be called to store the output (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(WRITEFUNCTION, FUNCTIONPOINT, 11), + + /* Function that will be called to read the input (instead of fread). The + * parameters will use fread() syntax, make sure to follow them. */ + CINIT(READFUNCTION, FUNCTIONPOINT, 12), + + /* Time-out the read operation after this amount of seconds */ + CINIT(TIMEOUT, LONG, 13), + + /* If the CURLOPT_INFILE is used, this can be used to inform libcurl about + * how large the file being sent really is. That allows better error + * checking and better verifies that the upload was successful. -1 means + * unknown size. + * + * For large file support, there is also a _LARGE version of the key + * which takes an off_t type, allowing platforms with larger off_t + * sizes to handle larger files. See below for INFILESIZE_LARGE. + */ + CINIT(INFILESIZE, LONG, 14), + + /* POST static input fields. */ + CINIT(POSTFIELDS, OBJECTPOINT, 15), + + /* Set the referrer page (needed by some CGIs) */ + CINIT(REFERER, STRINGPOINT, 16), + + /* Set the FTP PORT string (interface name, named or numerical IP address) + Use i.e '-' to use default address. */ + CINIT(FTPPORT, STRINGPOINT, 17), + + /* Set the User-Agent string (examined by some CGIs) */ + CINIT(USERAGENT, STRINGPOINT, 18), + + /* If the download receives less than "low speed limit" bytes/second + * during "low speed time" seconds, the operations is aborted. + * You could i.e if you have a pretty high speed connection, abort if + * it is less than 2000 bytes/sec during 20 seconds. + */ + + /* Set the "low speed limit" */ + CINIT(LOW_SPEED_LIMIT, LONG, 19), + + /* Set the "low speed time" */ + CINIT(LOW_SPEED_TIME, LONG, 20), + + /* Set the continuation offset. + * + * Note there is also a _LARGE version of this key which uses + * off_t types, allowing for large file offsets on platforms which + * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE. + */ + CINIT(RESUME_FROM, LONG, 21), + + /* Set cookie in request: */ + CINIT(COOKIE, STRINGPOINT, 22), + + /* This points to a linked list of headers, struct curl_slist kind. This + list is also used for RTSP (in spite of its name) */ + CINIT(HTTPHEADER, OBJECTPOINT, 23), + + /* This points to a linked list of post entries, struct curl_httppost */ + CINIT(HTTPPOST, OBJECTPOINT, 24), + + /* name of the file keeping your private SSL-certificate */ + CINIT(SSLCERT, STRINGPOINT, 25), + + /* password for the SSL or SSH private key */ + CINIT(KEYPASSWD, STRINGPOINT, 26), + + /* send TYPE parameter? */ + CINIT(CRLF, LONG, 27), + + /* send linked-list of QUOTE commands */ + CINIT(QUOTE, OBJECTPOINT, 28), + + /* send FILE * or void * to store headers to, if you use a callback it + is simply passed to the callback unmodified */ + CINIT(HEADERDATA, OBJECTPOINT, 29), + + /* point to a file to read the initial cookies from, also enables + "cookie awareness" */ + CINIT(COOKIEFILE, STRINGPOINT, 31), + + /* What version to specifically try to use. + See CURL_SSLVERSION defines below. */ + CINIT(SSLVERSION, LONG, 32), + + /* What kind of HTTP time condition to use, see defines */ + CINIT(TIMECONDITION, LONG, 33), + + /* Time to use with the above condition. Specified in number of seconds + since 1 Jan 1970 */ + CINIT(TIMEVALUE, LONG, 34), + + /* 35 = OBSOLETE */ + + /* Custom request, for customizing the get command like + HTTP: DELETE, TRACE and others + FTP: to use a different list command + */ + CINIT(CUSTOMREQUEST, STRINGPOINT, 36), + + /* FILE handle to use instead of stderr */ + CINIT(STDERR, OBJECTPOINT, 37), + + /* 38 is not used */ + + /* send linked-list of post-transfer QUOTE commands */ + CINIT(POSTQUOTE, OBJECTPOINT, 39), + + CINIT(OBSOLETE40, OBJECTPOINT, 40), /* OBSOLETE, do not use! */ + + CINIT(VERBOSE, LONG, 41), /* talk a lot */ + CINIT(HEADER, LONG, 42), /* throw the header out too */ + CINIT(NOPROGRESS, LONG, 43), /* shut off the progress meter */ + CINIT(NOBODY, LONG, 44), /* use HEAD to get http document */ + CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 400 */ + CINIT(UPLOAD, LONG, 46), /* this is an upload */ + CINIT(POST, LONG, 47), /* HTTP POST method */ + CINIT(DIRLISTONLY, LONG, 48), /* bare names when listing directories */ + + CINIT(APPEND, LONG, 50), /* Append instead of overwrite on upload! */ + + /* Specify whether to read the user+password from the .netrc or the URL. + * This must be one of the CURL_NETRC_* enums below. */ + CINIT(NETRC, LONG, 51), + + CINIT(FOLLOWLOCATION, LONG, 52), /* use Location: Luke! */ + + CINIT(TRANSFERTEXT, LONG, 53), /* transfer data in text/ASCII format */ + CINIT(PUT, LONG, 54), /* HTTP PUT */ + + /* 55 = OBSOLETE */ + + /* DEPRECATED + * Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_progress_callback + * prototype defines. */ + CINIT(PROGRESSFUNCTION, FUNCTIONPOINT, 56), + + /* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION + callbacks */ + CINIT(PROGRESSDATA, OBJECTPOINT, 57), +#define CURLOPT_XFERINFODATA CURLOPT_PROGRESSDATA + + /* We want the referrer field set automatically when following locations */ + CINIT(AUTOREFERER, LONG, 58), + + /* Port of the proxy, can be set in the proxy string as well with: + "[host]:[port]" */ + CINIT(PROXYPORT, LONG, 59), + + /* size of the POST input data, if strlen() is not good to use */ + CINIT(POSTFIELDSIZE, LONG, 60), + + /* tunnel non-http operations through a HTTP proxy */ + CINIT(HTTPPROXYTUNNEL, LONG, 61), + + /* Set the interface string to use as outgoing network interface */ + CINIT(INTERFACE, STRINGPOINT, 62), + + /* Set the krb4/5 security level, this also enables krb4/5 awareness. This + * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string + * is set but doesn't match one of these, 'private' will be used. */ + CINIT(KRBLEVEL, STRINGPOINT, 63), + + /* Set if we should verify the peer in ssl handshake, set 1 to verify. */ + CINIT(SSL_VERIFYPEER, LONG, 64), + + /* The CApath or CAfile used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ + CINIT(CAINFO, STRINGPOINT, 65), + + /* 66 = OBSOLETE */ + /* 67 = OBSOLETE */ + + /* Maximum number of http redirects to follow */ + CINIT(MAXREDIRS, LONG, 68), + + /* Pass a long set to 1 to get the date of the requested document (if + possible)! Pass a zero to shut it off. */ + CINIT(FILETIME, LONG, 69), + + /* This points to a linked list of telnet options */ + CINIT(TELNETOPTIONS, OBJECTPOINT, 70), + + /* Max amount of cached alive connections */ + CINIT(MAXCONNECTS, LONG, 71), + + CINIT(OBSOLETE72, LONG, 72), /* OBSOLETE, do not use! */ + + /* 73 = OBSOLETE */ + + /* Set to explicitly use a new connection for the upcoming transfer. + Do not use this unless you're absolutely sure of this, as it makes the + operation slower and is less friendly for the network. */ + CINIT(FRESH_CONNECT, LONG, 74), + + /* Set to explicitly forbid the upcoming transfer's connection to be re-used + when done. Do not use this unless you're absolutely sure of this, as it + makes the operation slower and is less friendly for the network. */ + CINIT(FORBID_REUSE, LONG, 75), + + /* Set to a file name that contains random data for libcurl to use to + seed the random engine when doing SSL connects. */ + CINIT(RANDOM_FILE, STRINGPOINT, 76), + + /* Set to the Entropy Gathering Daemon socket pathname */ + CINIT(EGDSOCKET, STRINGPOINT, 77), + + /* Time-out connect operations after this amount of seconds, if connects are + OK within this time, then fine... This only aborts the connect phase. */ + CINIT(CONNECTTIMEOUT, LONG, 78), + + /* Function that will be called to store headers (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(HEADERFUNCTION, FUNCTIONPOINT, 79), + + /* Set this to force the HTTP request to get back to GET. Only really usable + if POST, PUT or a custom request have been used first. + */ + CINIT(HTTPGET, LONG, 80), + + /* Set if we should verify the Common name from the peer certificate in ssl + * handshake, set 1 to check existence, 2 to ensure that it matches the + * provided hostname. */ + CINIT(SSL_VERIFYHOST, LONG, 81), + + /* Specify which file name to write all known cookies in after completed + operation. Set file name to "-" (dash) to make it go to stdout. */ + CINIT(COOKIEJAR, STRINGPOINT, 82), + + /* Specify which SSL ciphers to use */ + CINIT(SSL_CIPHER_LIST, STRINGPOINT, 83), + + /* Specify which HTTP version to use! This must be set to one of the + CURL_HTTP_VERSION* enums set below. */ + CINIT(HTTP_VERSION, LONG, 84), + + /* Specifically switch on or off the FTP engine's use of the EPSV command. By + default, that one will always be attempted before the more traditional + PASV command. */ + CINIT(FTP_USE_EPSV, LONG, 85), + + /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */ + CINIT(SSLCERTTYPE, STRINGPOINT, 86), + + /* name of the file keeping your private SSL-key */ + CINIT(SSLKEY, STRINGPOINT, 87), + + /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */ + CINIT(SSLKEYTYPE, STRINGPOINT, 88), + + /* crypto engine for the SSL-sub system */ + CINIT(SSLENGINE, STRINGPOINT, 89), + + /* set the crypto engine for the SSL-sub system as default + the param has no meaning... + */ + CINIT(SSLENGINE_DEFAULT, LONG, 90), + + /* Non-zero value means to use the global dns cache */ + CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* DEPRECATED, do not use! */ + + /* DNS cache timeout */ + CINIT(DNS_CACHE_TIMEOUT, LONG, 92), + + /* send linked-list of pre-transfer QUOTE commands */ + CINIT(PREQUOTE, OBJECTPOINT, 93), + + /* set the debug function */ + CINIT(DEBUGFUNCTION, FUNCTIONPOINT, 94), + + /* set the data for the debug function */ + CINIT(DEBUGDATA, OBJECTPOINT, 95), + + /* mark this as start of a cookie session */ + CINIT(COOKIESESSION, LONG, 96), + + /* The CApath directory used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ + CINIT(CAPATH, STRINGPOINT, 97), + + /* Instruct libcurl to use a smaller receive buffer */ + CINIT(BUFFERSIZE, LONG, 98), + + /* Instruct libcurl to not use any signal/alarm handlers, even when using + timeouts. This option is useful for multi-threaded applications. + See libcurl-the-guide for more background information. */ + CINIT(NOSIGNAL, LONG, 99), + + /* Provide a CURLShare for mutexing non-ts data */ + CINIT(SHARE, OBJECTPOINT, 100), + + /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default), + CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and CURLPROXY_SOCKS5. */ + CINIT(PROXYTYPE, LONG, 101), + + /* Set the Accept-Encoding string. Use this to tell a server you would like + the response to be compressed. Before 7.21.6, this was known as + CURLOPT_ENCODING */ + CINIT(ACCEPT_ENCODING, STRINGPOINT, 102), + + /* Set pointer to private data */ + CINIT(PRIVATE, OBJECTPOINT, 103), + + /* Set aliases for HTTP 200 in the HTTP Response header */ + CINIT(HTTP200ALIASES, OBJECTPOINT, 104), + + /* Continue to send authentication (user+password) when following locations, + even when hostname changed. This can potentially send off the name + and password to whatever host the server decides. */ + CINIT(UNRESTRICTED_AUTH, LONG, 105), + + /* Specifically switch on or off the FTP engine's use of the EPRT command ( + it also disables the LPRT attempt). By default, those ones will always be + attempted before the good old traditional PORT command. */ + CINIT(FTP_USE_EPRT, LONG, 106), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_USERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(HTTPAUTH, LONG, 107), + + /* Set the ssl context callback function, currently only for OpenSSL ssl_ctx + in second argument. The function must be matching the + curl_ssl_ctx_callback proto. */ + CINIT(SSL_CTX_FUNCTION, FUNCTIONPOINT, 108), + + /* Set the userdata for the ssl context callback function's third + argument */ + CINIT(SSL_CTX_DATA, OBJECTPOINT, 109), + + /* FTP Option that causes missing dirs to be created on the remote server. + In 7.19.4 we introduced the convenience enums for this option using the + CURLFTP_CREATE_DIR prefix. + */ + CINIT(FTP_CREATE_MISSING_DIRS, LONG, 110), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_PROXYUSERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(PROXYAUTH, LONG, 111), + + /* FTP option that changes the timeout, in seconds, associated with + getting a response. This is different from transfer timeout time and + essentially places a demand on the FTP server to acknowledge commands + in a timely manner. */ + CINIT(FTP_RESPONSE_TIMEOUT, LONG, 112), +#define CURLOPT_SERVER_RESPONSE_TIMEOUT CURLOPT_FTP_RESPONSE_TIMEOUT + + /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to + tell libcurl to resolve names to those IP versions only. This only has + affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */ + CINIT(IPRESOLVE, LONG, 113), + + /* Set this option to limit the size of a file that will be downloaded from + an HTTP or FTP server. + + Note there is also _LARGE version which adds large file support for + platforms which have larger off_t sizes. See MAXFILESIZE_LARGE below. */ + CINIT(MAXFILESIZE, LONG, 114), + + /* See the comment for INFILESIZE above, but in short, specifies + * the size of the file being uploaded. -1 means unknown. + */ + CINIT(INFILESIZE_LARGE, OFF_T, 115), + + /* Sets the continuation offset. There is also a LONG version of this; + * look above for RESUME_FROM. + */ + CINIT(RESUME_FROM_LARGE, OFF_T, 116), + + /* Sets the maximum size of data that will be downloaded from + * an HTTP or FTP server. See MAXFILESIZE above for the LONG version. + */ + CINIT(MAXFILESIZE_LARGE, OFF_T, 117), + + /* Set this option to the file name of your .netrc file you want libcurl + to parse (using the CURLOPT_NETRC option). If not set, libcurl will do + a poor attempt to find the user's home directory and check for a .netrc + file in there. */ + CINIT(NETRC_FILE, STRINGPOINT, 118), + + /* Enable SSL/TLS for FTP, pick one of: + CURLUSESSL_TRY - try using SSL, proceed anyway otherwise + CURLUSESSL_CONTROL - SSL for the control connection or fail + CURLUSESSL_ALL - SSL for all communication or fail + */ + CINIT(USE_SSL, LONG, 119), + + /* The _LARGE version of the standard POSTFIELDSIZE option */ + CINIT(POSTFIELDSIZE_LARGE, OFF_T, 120), + + /* Enable/disable the TCP Nagle algorithm */ + CINIT(TCP_NODELAY, LONG, 121), + + /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 123 OBSOLETE. Gone in 7.16.0 */ + /* 124 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 125 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 126 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 127 OBSOLETE. Gone in 7.16.0 */ + /* 128 OBSOLETE. Gone in 7.16.0 */ + + /* When FTP over SSL/TLS is selected (with CURLOPT_USE_SSL), this option + can be used to change libcurl's default action which is to first try + "AUTH SSL" and then "AUTH TLS" in this order, and proceed when a OK + response has been received. + + Available parameters are: + CURLFTPAUTH_DEFAULT - let libcurl decide + CURLFTPAUTH_SSL - try "AUTH SSL" first, then TLS + CURLFTPAUTH_TLS - try "AUTH TLS" first, then SSL + */ + CINIT(FTPSSLAUTH, LONG, 129), + + CINIT(IOCTLFUNCTION, FUNCTIONPOINT, 130), + CINIT(IOCTLDATA, OBJECTPOINT, 131), + + /* 132 OBSOLETE. Gone in 7.16.0 */ + /* 133 OBSOLETE. Gone in 7.16.0 */ + + /* zero terminated string for pass on to the FTP server when asked for + "account" info */ + CINIT(FTP_ACCOUNT, STRINGPOINT, 134), + + /* feed cookie into cookie engine */ + CINIT(COOKIELIST, STRINGPOINT, 135), + + /* ignore Content-Length */ + CINIT(IGNORE_CONTENT_LENGTH, LONG, 136), + + /* Set to non-zero to skip the IP address received in a 227 PASV FTP server + response. Typically used for FTP-SSL purposes but is not restricted to + that. libcurl will then instead use the same IP address it used for the + control connection. */ + CINIT(FTP_SKIP_PASV_IP, LONG, 137), + + /* Select "file method" to use when doing FTP, see the curl_ftpmethod + above. */ + CINIT(FTP_FILEMETHOD, LONG, 138), + + /* Local port number to bind the socket to */ + CINIT(LOCALPORT, LONG, 139), + + /* Number of ports to try, including the first one set with LOCALPORT. + Thus, setting it to 1 will make no additional attempts but the first. + */ + CINIT(LOCALPORTRANGE, LONG, 140), + + /* no transfer, set up connection and let application use the socket by + extracting it with CURLINFO_LASTSOCKET */ + CINIT(CONNECT_ONLY, LONG, 141), + + /* Function that will be called to convert from the + network encoding (instead of using the iconv calls in libcurl) */ + CINIT(CONV_FROM_NETWORK_FUNCTION, FUNCTIONPOINT, 142), + + /* Function that will be called to convert to the + network encoding (instead of using the iconv calls in libcurl) */ + CINIT(CONV_TO_NETWORK_FUNCTION, FUNCTIONPOINT, 143), + + /* Function that will be called to convert from UTF8 + (instead of using the iconv calls in libcurl) + Note that this is used only for SSL certificate processing */ + CINIT(CONV_FROM_UTF8_FUNCTION, FUNCTIONPOINT, 144), + + /* if the connection proceeds too quickly then need to slow it down */ + /* limit-rate: maximum number of bytes per second to send or receive */ + CINIT(MAX_SEND_SPEED_LARGE, OFF_T, 145), + CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146), + + /* Pointer to command string to send if USER/PASS fails. */ + CINIT(FTP_ALTERNATIVE_TO_USER, STRINGPOINT, 147), + + /* callback function for setting socket options */ + CINIT(SOCKOPTFUNCTION, FUNCTIONPOINT, 148), + CINIT(SOCKOPTDATA, OBJECTPOINT, 149), + + /* set to 0 to disable session ID re-use for this transfer, default is + enabled (== 1) */ + CINIT(SSL_SESSIONID_CACHE, LONG, 150), + + /* allowed SSH authentication methods */ + CINIT(SSH_AUTH_TYPES, LONG, 151), + + /* Used by scp/sftp to do public/private key authentication */ + CINIT(SSH_PUBLIC_KEYFILE, STRINGPOINT, 152), + CINIT(SSH_PRIVATE_KEYFILE, STRINGPOINT, 153), + + /* Send CCC (Clear Command Channel) after authentication */ + CINIT(FTP_SSL_CCC, LONG, 154), + + /* Same as TIMEOUT and CONNECTTIMEOUT, but with ms resolution */ + CINIT(TIMEOUT_MS, LONG, 155), + CINIT(CONNECTTIMEOUT_MS, LONG, 156), + + /* set to zero to disable the libcurl's decoding and thus pass the raw body + data to the application even when it is encoded/compressed */ + CINIT(HTTP_TRANSFER_DECODING, LONG, 157), + CINIT(HTTP_CONTENT_DECODING, LONG, 158), + + /* Permission used when creating new files and directories on the remote + server for protocols that support it, SFTP/SCP/FILE */ + CINIT(NEW_FILE_PERMS, LONG, 159), + CINIT(NEW_DIRECTORY_PERMS, LONG, 160), + + /* Set the behaviour of POST when redirecting. Values must be set to one + of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */ + CINIT(POSTREDIR, LONG, 161), + + /* used by scp/sftp to verify the host's public key */ + CINIT(SSH_HOST_PUBLIC_KEY_MD5, STRINGPOINT, 162), + + /* Callback function for opening socket (instead of socket(2)). Optionally, + callback is able change the address or refuse to connect returning + CURL_SOCKET_BAD. The callback should have type + curl_opensocket_callback */ + CINIT(OPENSOCKETFUNCTION, FUNCTIONPOINT, 163), + CINIT(OPENSOCKETDATA, OBJECTPOINT, 164), + + /* POST volatile input fields. */ + CINIT(COPYPOSTFIELDS, OBJECTPOINT, 165), + + /* set transfer mode (;type=) when doing FTP via an HTTP proxy */ + CINIT(PROXY_TRANSFER_MODE, LONG, 166), + + /* Callback function for seeking in the input stream */ + CINIT(SEEKFUNCTION, FUNCTIONPOINT, 167), + CINIT(SEEKDATA, OBJECTPOINT, 168), + + /* CRL file */ + CINIT(CRLFILE, STRINGPOINT, 169), + + /* Issuer certificate */ + CINIT(ISSUERCERT, STRINGPOINT, 170), + + /* (IPv6) Address scope */ + CINIT(ADDRESS_SCOPE, LONG, 171), + + /* Collect certificate chain info and allow it to get retrievable with + CURLINFO_CERTINFO after the transfer is complete. */ + CINIT(CERTINFO, LONG, 172), + + /* "name" and "pwd" to use when fetching. */ + CINIT(USERNAME, STRINGPOINT, 173), + CINIT(PASSWORD, STRINGPOINT, 174), + + /* "name" and "pwd" to use with Proxy when fetching. */ + CINIT(PROXYUSERNAME, STRINGPOINT, 175), + CINIT(PROXYPASSWORD, STRINGPOINT, 176), + + /* Comma separated list of hostnames defining no-proxy zones. These should + match both hostnames directly, and hostnames within a domain. For + example, local.com will match local.com and www.local.com, but NOT + notlocal.com or www.notlocal.com. For compatibility with other + implementations of this, .local.com will be considered to be the same as + local.com. A single * is the only valid wildcard, and effectively + disables the use of proxy. */ + CINIT(NOPROXY, STRINGPOINT, 177), + + /* block size for TFTP transfers */ + CINIT(TFTP_BLKSIZE, LONG, 178), + + /* Socks Service */ + CINIT(SOCKS5_GSSAPI_SERVICE, STRINGPOINT, 179), + + /* Socks Service */ + CINIT(SOCKS5_GSSAPI_NEC, LONG, 180), + + /* set the bitmask for the protocols that are allowed to be used for the + transfer, which thus helps the app which takes URLs from users or other + external inputs and want to restrict what protocol(s) to deal + with. Defaults to CURLPROTO_ALL. */ + CINIT(PROTOCOLS, LONG, 181), + + /* set the bitmask for the protocols that libcurl is allowed to follow to, + as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs + to be set in both bitmasks to be allowed to get redirected to. Defaults + to all protocols except FILE and SCP. */ + CINIT(REDIR_PROTOCOLS, LONG, 182), + + /* set the SSH knownhost file name to use */ + CINIT(SSH_KNOWNHOSTS, STRINGPOINT, 183), + + /* set the SSH host key callback, must point to a curl_sshkeycallback + function */ + CINIT(SSH_KEYFUNCTION, FUNCTIONPOINT, 184), + + /* set the SSH host key callback custom pointer */ + CINIT(SSH_KEYDATA, OBJECTPOINT, 185), + + /* set the SMTP mail originator */ + CINIT(MAIL_FROM, STRINGPOINT, 186), + + /* set the list of SMTP mail receiver(s) */ + CINIT(MAIL_RCPT, OBJECTPOINT, 187), + + /* FTP: send PRET before PASV */ + CINIT(FTP_USE_PRET, LONG, 188), + + /* RTSP request method (OPTIONS, SETUP, PLAY, etc...) */ + CINIT(RTSP_REQUEST, LONG, 189), + + /* The RTSP session identifier */ + CINIT(RTSP_SESSION_ID, STRINGPOINT, 190), + + /* The RTSP stream URI */ + CINIT(RTSP_STREAM_URI, STRINGPOINT, 191), + + /* The Transport: header to use in RTSP requests */ + CINIT(RTSP_TRANSPORT, STRINGPOINT, 192), + + /* Manually initialize the client RTSP CSeq for this handle */ + CINIT(RTSP_CLIENT_CSEQ, LONG, 193), + + /* Manually initialize the server RTSP CSeq for this handle */ + CINIT(RTSP_SERVER_CSEQ, LONG, 194), + + /* The stream to pass to INTERLEAVEFUNCTION. */ + CINIT(INTERLEAVEDATA, OBJECTPOINT, 195), + + /* Let the application define a custom write method for RTP data */ + CINIT(INTERLEAVEFUNCTION, FUNCTIONPOINT, 196), + + /* Turn on wildcard matching */ + CINIT(WILDCARDMATCH, LONG, 197), + + /* Directory matching callback called before downloading of an + individual file (chunk) started */ + CINIT(CHUNK_BGN_FUNCTION, FUNCTIONPOINT, 198), + + /* Directory matching callback called after the file (chunk) + was downloaded, or skipped */ + CINIT(CHUNK_END_FUNCTION, FUNCTIONPOINT, 199), + + /* Change match (fnmatch-like) callback for wildcard matching */ + CINIT(FNMATCH_FUNCTION, FUNCTIONPOINT, 200), + + /* Let the application define custom chunk data pointer */ + CINIT(CHUNK_DATA, OBJECTPOINT, 201), + + /* FNMATCH_FUNCTION user pointer */ + CINIT(FNMATCH_DATA, OBJECTPOINT, 202), + + /* send linked-list of name:port:address sets */ + CINIT(RESOLVE, OBJECTPOINT, 203), + + /* Set a username for authenticated TLS */ + CINIT(TLSAUTH_USERNAME, STRINGPOINT, 204), + + /* Set a password for authenticated TLS */ + CINIT(TLSAUTH_PASSWORD, STRINGPOINT, 205), + + /* Set authentication type for authenticated TLS */ + CINIT(TLSAUTH_TYPE, STRINGPOINT, 206), + + /* Set to 1 to enable the "TE:" header in HTTP requests to ask for + compressed transfer-encoded responses. Set to 0 to disable the use of TE: + in outgoing requests. The current default is 0, but it might change in a + future libcurl release. + + libcurl will ask for the compressed methods it knows of, and if that + isn't any, it will not ask for transfer-encoding at all even if this + option is set to 1. + + */ + CINIT(TRANSFER_ENCODING, LONG, 207), + + /* Callback function for closing socket (instead of close(2)). The callback + should have type curl_closesocket_callback */ + CINIT(CLOSESOCKETFUNCTION, FUNCTIONPOINT, 208), + CINIT(CLOSESOCKETDATA, OBJECTPOINT, 209), + + /* allow GSSAPI credential delegation */ + CINIT(GSSAPI_DELEGATION, LONG, 210), + + /* Set the name servers to use for DNS resolution */ + CINIT(DNS_SERVERS, STRINGPOINT, 211), + + /* Time-out accept operations (currently for FTP only) after this amount + of miliseconds. */ + CINIT(ACCEPTTIMEOUT_MS, LONG, 212), + + /* Set TCP keepalive */ + CINIT(TCP_KEEPALIVE, LONG, 213), + + /* non-universal keepalive knobs (Linux, AIX, HP-UX, more) */ + CINIT(TCP_KEEPIDLE, LONG, 214), + CINIT(TCP_KEEPINTVL, LONG, 215), + + /* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */ + CINIT(SSL_OPTIONS, LONG, 216), + + /* Set the SMTP auth originator */ + CINIT(MAIL_AUTH, STRINGPOINT, 217), + + /* Enable/disable SASL initial response */ + CINIT(SASL_IR, LONG, 218), + + /* Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_xferinfo_callback + * prototype defines. (Deprecates CURLOPT_PROGRESSFUNCTION) */ + CINIT(XFERINFOFUNCTION, FUNCTIONPOINT, 219), + + /* The XOAUTH2 bearer token */ + CINIT(XOAUTH2_BEARER, STRINGPOINT, 220), + + /* Set the interface string to use as outgoing network + * interface for DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_INTERFACE, STRINGPOINT, 221), + + /* Set the local IPv4 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_LOCAL_IP4, STRINGPOINT, 222), + + /* Set the local IPv4 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_LOCAL_IP6, STRINGPOINT, 223), + + /* Set authentication options directly */ + CINIT(LOGIN_OPTIONS, STRINGPOINT, 224), + + /* Enable/disable TLS NPN extension (http2 over ssl might fail without) */ + CINIT(SSL_ENABLE_NPN, LONG, 225), + + /* Enable/disable TLS ALPN extension (http2 over ssl might fail without) */ + CINIT(SSL_ENABLE_ALPN, LONG, 226), + + /* Time to wait for a response to a HTTP request containing an + * Expect: 100-continue header before sending the data anyway. */ + CINIT(EXPECT_100_TIMEOUT_MS, LONG, 227), + + /* This points to a linked list of headers used for proxy requests only, + struct curl_slist kind */ + CINIT(PROXYHEADER, OBJECTPOINT, 228), + + /* Pass in a bitmask of "header options" */ + CINIT(HEADEROPT, LONG, 229), + + /* The public key in DER form used to validate the peer public key + this option is used only if SSL_VERIFYPEER is true */ + CINIT(PINNEDPUBLICKEY, STRINGPOINT, 230), + + /* Path to Unix domain socket */ + CINIT(UNIX_SOCKET_PATH, STRINGPOINT, 231), + + /* Set if we should verify the certificate status. */ + CINIT(SSL_VERIFYSTATUS, LONG, 232), + + /* Set if we should enable TLS false start. */ + CINIT(SSL_FALSESTART, LONG, 233), + + /* Do not squash dot-dot sequences */ + CINIT(PATH_AS_IS, LONG, 234), + + /* Proxy Service Name */ + CINIT(PROXY_SERVICE_NAME, STRINGPOINT, 235), + + /* Service Name */ + CINIT(SERVICE_NAME, STRINGPOINT, 236), + + /* Wait/don't wait for pipe/mutex to clarify */ + CINIT(PIPEWAIT, LONG, 237), + + /* Set the protocol used when curl is given a URL without a protocol */ + CINIT(DEFAULT_PROTOCOL, STRINGPOINT, 238), + + /* Set stream weight, 1 - 256 (default is 16) */ + CINIT(STREAM_WEIGHT, LONG, 239), + + /* Set stream dependency on another CURL handle */ + CINIT(STREAM_DEPENDS, OBJECTPOINT, 240), + + /* Set E-xclusive stream dependency on another CURL handle */ + CINIT(STREAM_DEPENDS_E, OBJECTPOINT, 241), + + CURLOPT_LASTENTRY /* the last unused */ +} CURLoption; + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Backwards compatibility with older names */ +/* These are scheduled to disappear by 2011 */ + +/* This was added in version 7.19.1 */ +#define CURLOPT_POST301 CURLOPT_POSTREDIR + +/* These are scheduled to disappear by 2009 */ + +/* The following were added in 7.17.0 */ +#define CURLOPT_SSLKEYPASSWD CURLOPT_KEYPASSWD +#define CURLOPT_FTPAPPEND CURLOPT_APPEND +#define CURLOPT_FTPLISTONLY CURLOPT_DIRLISTONLY +#define CURLOPT_FTP_SSL CURLOPT_USE_SSL + +/* The following were added earlier */ + +#define CURLOPT_SSLCERTPASSWD CURLOPT_KEYPASSWD +#define CURLOPT_KRB4LEVEL CURLOPT_KRBLEVEL + +#else +/* This is set if CURL_NO_OLDIES is defined at compile-time */ +#undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */ +#endif + + + /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host + name resolves addresses using more than one IP protocol version, this + option might be handy to force libcurl to use a specific IP version. */ +#define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP + versions that your system allows */ +#define CURL_IPRESOLVE_V4 1 /* resolve to IPv4 addresses */ +#define CURL_IPRESOLVE_V6 2 /* resolve to IPv6 addresses */ + + /* three convenient "aliases" that follow the name scheme better */ +#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER + + /* These enums are for use with the CURLOPT_HTTP_VERSION option. */ +enum { + CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd + like the library to choose the best possible + for us! */ + CURL_HTTP_VERSION_1_0, /* please use HTTP 1.0 in the request */ + CURL_HTTP_VERSION_1_1, /* please use HTTP 1.1 in the request */ + CURL_HTTP_VERSION_2_0, /* please use HTTP 2 in the request */ + CURL_HTTP_VERSION_2TLS, /* use version 2 for HTTPS, version 1.1 for HTTP */ + + CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */ +}; + +/* Convenience definition simple because the name of the version is HTTP/2 and + not 2.0. The 2_0 version of the enum name was set while the version was + still planned to be 2.0 and we stick to it for compatibility. */ +#define CURL_HTTP_VERSION_2 CURL_HTTP_VERSION_2_0 + +/* + * Public API enums for RTSP requests + */ +enum { + CURL_RTSPREQ_NONE, /* first in list */ + CURL_RTSPREQ_OPTIONS, + CURL_RTSPREQ_DESCRIBE, + CURL_RTSPREQ_ANNOUNCE, + CURL_RTSPREQ_SETUP, + CURL_RTSPREQ_PLAY, + CURL_RTSPREQ_PAUSE, + CURL_RTSPREQ_TEARDOWN, + CURL_RTSPREQ_GET_PARAMETER, + CURL_RTSPREQ_SET_PARAMETER, + CURL_RTSPREQ_RECORD, + CURL_RTSPREQ_RECEIVE, + CURL_RTSPREQ_LAST /* last in list */ +}; + + /* These enums are for use with the CURLOPT_NETRC option. */ +enum CURL_NETRC_OPTION { + CURL_NETRC_IGNORED, /* The .netrc will never be read. + * This is the default. */ + CURL_NETRC_OPTIONAL, /* A user:password in the URL will be preferred + * to one in the .netrc. */ + CURL_NETRC_REQUIRED, /* A user:password in the URL will be ignored. + * Unless one is set programmatically, the .netrc + * will be queried. */ + CURL_NETRC_LAST +}; + +enum { + CURL_SSLVERSION_DEFAULT, + CURL_SSLVERSION_TLSv1, /* TLS 1.x */ + CURL_SSLVERSION_SSLv2, + CURL_SSLVERSION_SSLv3, + CURL_SSLVERSION_TLSv1_0, + CURL_SSLVERSION_TLSv1_1, + CURL_SSLVERSION_TLSv1_2, + + CURL_SSLVERSION_LAST /* never use, keep last */ +}; + +enum CURL_TLSAUTH { + CURL_TLSAUTH_NONE, + CURL_TLSAUTH_SRP, + CURL_TLSAUTH_LAST /* never use, keep last */ +}; + +/* symbols to use with CURLOPT_POSTREDIR. + CURL_REDIR_POST_301, CURL_REDIR_POST_302 and CURL_REDIR_POST_303 + can be bitwise ORed so that CURL_REDIR_POST_301 | CURL_REDIR_POST_302 + | CURL_REDIR_POST_303 == CURL_REDIR_POST_ALL */ + +#define CURL_REDIR_GET_ALL 0 +#define CURL_REDIR_POST_301 1 +#define CURL_REDIR_POST_302 2 +#define CURL_REDIR_POST_303 4 +#define CURL_REDIR_POST_ALL \ + (CURL_REDIR_POST_301|CURL_REDIR_POST_302|CURL_REDIR_POST_303) + +typedef enum { + CURL_TIMECOND_NONE, + + CURL_TIMECOND_IFMODSINCE, + CURL_TIMECOND_IFUNMODSINCE, + CURL_TIMECOND_LASTMOD, + + CURL_TIMECOND_LAST +} curl_TimeCond; + + +/* curl_strequal() and curl_strnequal() are subject for removal in a future + libcurl, see lib/README.curlx for details */ +CURL_EXTERN int (curl_strequal)(const char *s1, const char *s2); +CURL_EXTERN int (curl_strnequal)(const char *s1, const char *s2, size_t n); + +/* name is uppercase CURLFORM_ */ +#ifdef CFINIT +#undef CFINIT +#endif + +#ifdef CURL_ISOCPP +#define CFINIT(name) CURLFORM_ ## name +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define CFINIT(name) CURLFORM_/**/name +#endif + +typedef enum { + CFINIT(NOTHING), /********* the first one is unused ************/ + + /* */ + CFINIT(COPYNAME), + CFINIT(PTRNAME), + CFINIT(NAMELENGTH), + CFINIT(COPYCONTENTS), + CFINIT(PTRCONTENTS), + CFINIT(CONTENTSLENGTH), + CFINIT(FILECONTENT), + CFINIT(ARRAY), + CFINIT(OBSOLETE), + CFINIT(FILE), + + CFINIT(BUFFER), + CFINIT(BUFFERPTR), + CFINIT(BUFFERLENGTH), + + CFINIT(CONTENTTYPE), + CFINIT(CONTENTHEADER), + CFINIT(FILENAME), + CFINIT(END), + CFINIT(OBSOLETE2), + + CFINIT(STREAM), + CFINIT(CONTENTLEN), /* added in 7.46.0, provide a curl_off_t length */ + + CURLFORM_LASTENTRY /* the last unused */ +} CURLformoption; + +#undef CFINIT /* done */ + +/* structure to be used as parameter for CURLFORM_ARRAY */ +struct curl_forms { + CURLformoption option; + const char *value; +}; + +/* use this for multipart formpost building */ +/* Returns code for curl_formadd() + * + * Returns: + * CURL_FORMADD_OK on success + * CURL_FORMADD_MEMORY if the FormInfo allocation fails + * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form + * CURL_FORMADD_NULL if a null pointer was given for a char + * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed + * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used + * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error) + * CURL_FORMADD_MEMORY if a curl_httppost struct cannot be allocated + * CURL_FORMADD_MEMORY if some allocation for string copying failed. + * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array + * + ***************************************************************************/ +typedef enum { + CURL_FORMADD_OK, /* first, no error */ + + CURL_FORMADD_MEMORY, + CURL_FORMADD_OPTION_TWICE, + CURL_FORMADD_NULL, + CURL_FORMADD_UNKNOWN_OPTION, + CURL_FORMADD_INCOMPLETE, + CURL_FORMADD_ILLEGAL_ARRAY, + CURL_FORMADD_DISABLED, /* libcurl was built with this disabled */ + + CURL_FORMADD_LAST /* last */ +} CURLFORMcode; + +/* + * NAME curl_formadd() + * + * DESCRIPTION + * + * Pretty advanced function for building multi-part formposts. Each invoke + * adds one part that together construct a full post. Then use + * CURLOPT_HTTPPOST to send it off to libcurl. + */ +CURL_EXTERN CURLFORMcode curl_formadd(struct curl_httppost **httppost, + struct curl_httppost **last_post, + ...); + +/* + * callback function for curl_formget() + * The void *arg pointer will be the one passed as second argument to + * curl_formget(). + * The character buffer passed to it must not be freed. + * Should return the buffer length passed to it as the argument "len" on + * success. + */ +typedef size_t (*curl_formget_callback)(void *arg, const char *buf, + size_t len); + +/* + * NAME curl_formget() + * + * DESCRIPTION + * + * Serialize a curl_httppost struct built with curl_formadd(). + * Accepts a void pointer as second argument which will be passed to + * the curl_formget_callback function. + * Returns 0 on success. + */ +CURL_EXTERN int curl_formget(struct curl_httppost *form, void *arg, + curl_formget_callback append); +/* + * NAME curl_formfree() + * + * DESCRIPTION + * + * Free a multipart formpost previously built with curl_formadd(). + */ +CURL_EXTERN void curl_formfree(struct curl_httppost *form); + +/* + * NAME curl_getenv() + * + * DESCRIPTION + * + * Returns a malloc()'ed string that MUST be curl_free()ed after usage is + * complete. DEPRECATED - see lib/README.curlx + */ +CURL_EXTERN char *curl_getenv(const char *variable); + +/* + * NAME curl_version() + * + * DESCRIPTION + * + * Returns a static ascii string of the libcurl version. + */ +CURL_EXTERN char *curl_version(void); + +/* + * NAME curl_easy_escape() + * + * DESCRIPTION + * + * Escapes URL strings (converts all letters consider illegal in URLs to their + * %XX versions). This function returns a new allocated string or NULL if an + * error occurred. + */ +CURL_EXTERN char *curl_easy_escape(CURL *handle, + const char *string, + int length); + +/* the previous version: */ +CURL_EXTERN char *curl_escape(const char *string, + int length); + + +/* + * NAME curl_easy_unescape() + * + * DESCRIPTION + * + * Unescapes URL encoding in strings (converts all %XX codes to their 8bit + * versions). This function returns a new allocated string or NULL if an error + * occurred. + * Conversion Note: On non-ASCII platforms the ASCII %XX codes are + * converted into the host encoding. + */ +CURL_EXTERN char *curl_easy_unescape(CURL *handle, + const char *string, + int length, + int *outlength); + +/* the previous version */ +CURL_EXTERN char *curl_unescape(const char *string, + int length); + +/* + * NAME curl_free() + * + * DESCRIPTION + * + * Provided for de-allocation in the same translation unit that did the + * allocation. Added in libcurl 7.10 + */ +CURL_EXTERN void curl_free(void *p); + +/* + * NAME curl_global_init() + * + * DESCRIPTION + * + * curl_global_init() should be invoked exactly once for each application that + * uses libcurl and before any call of other libcurl functions. + * + * This function is not thread-safe! + */ +CURL_EXTERN CURLcode curl_global_init(long flags); + +/* + * NAME curl_global_init_mem() + * + * DESCRIPTION + * + * curl_global_init() or curl_global_init_mem() should be invoked exactly once + * for each application that uses libcurl. This function can be used to + * initialize libcurl and set user defined memory management callback + * functions. Users can implement memory management routines to check for + * memory leaks, check for mis-use of the curl library etc. User registered + * callback routines with be invoked by this library instead of the system + * memory management routines like malloc, free etc. + */ +CURL_EXTERN CURLcode curl_global_init_mem(long flags, + curl_malloc_callback m, + curl_free_callback f, + curl_realloc_callback r, + curl_strdup_callback s, + curl_calloc_callback c); + +/* + * NAME curl_global_cleanup() + * + * DESCRIPTION + * + * curl_global_cleanup() should be invoked exactly once for each application + * that uses libcurl + */ +CURL_EXTERN void curl_global_cleanup(void); + +/* linked-list structure for the CURLOPT_QUOTE option (and other) */ +struct curl_slist { + char *data; + struct curl_slist *next; +}; + +/* + * NAME curl_slist_append() + * + * DESCRIPTION + * + * Appends a string to a linked list. If no list exists, it will be created + * first. Returns the new list, after appending. + */ +CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *, + const char *); + +/* + * NAME curl_slist_free_all() + * + * DESCRIPTION + * + * free a previously built curl_slist. + */ +CURL_EXTERN void curl_slist_free_all(struct curl_slist *); + +/* + * NAME curl_getdate() + * + * DESCRIPTION + * + * Returns the time, in seconds since 1 Jan 1970 of the time string given in + * the first argument. The time argument in the second parameter is unused + * and should be set to NULL. + */ +CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused); + +/* info about the certificate chain, only for OpenSSL builds. Asked + for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */ +struct curl_certinfo { + int num_of_certs; /* number of certificates with information */ + struct curl_slist **certinfo; /* for each index in this array, there's a + linked list with textual information in the + format "name: value" */ +}; + +/* enum for the different supported SSL backends */ +typedef enum { + CURLSSLBACKEND_NONE = 0, + CURLSSLBACKEND_OPENSSL = 1, + CURLSSLBACKEND_GNUTLS = 2, + CURLSSLBACKEND_NSS = 3, + CURLSSLBACKEND_OBSOLETE4 = 4, /* Was QSOSSL. */ + CURLSSLBACKEND_GSKIT = 5, + CURLSSLBACKEND_POLARSSL = 6, + CURLSSLBACKEND_CYASSL = 7, + CURLSSLBACKEND_SCHANNEL = 8, + CURLSSLBACKEND_DARWINSSL = 9, + CURLSSLBACKEND_AXTLS = 10, + CURLSSLBACKEND_MBEDTLS = 11 +} curl_sslbackend; + +/* Information about the SSL library used and the respective internal SSL + handle, which can be used to obtain further information regarding the + connection. Asked for with CURLINFO_TLS_SESSION. */ +struct curl_tlssessioninfo { + curl_sslbackend backend; + void *internals; +}; + +#define CURLINFO_STRING 0x100000 +#define CURLINFO_LONG 0x200000 +#define CURLINFO_DOUBLE 0x300000 +#define CURLINFO_SLIST 0x400000 +#define CURLINFO_SOCKET 0x500000 +#define CURLINFO_MASK 0x0fffff +#define CURLINFO_TYPEMASK 0xf00000 + +typedef enum { + CURLINFO_NONE, /* first, never use this */ + CURLINFO_EFFECTIVE_URL = CURLINFO_STRING + 1, + CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2, + CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3, + CURLINFO_NAMELOOKUP_TIME = CURLINFO_DOUBLE + 4, + CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5, + CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6, + CURLINFO_SIZE_UPLOAD = CURLINFO_DOUBLE + 7, + CURLINFO_SIZE_DOWNLOAD = CURLINFO_DOUBLE + 8, + CURLINFO_SPEED_DOWNLOAD = CURLINFO_DOUBLE + 9, + CURLINFO_SPEED_UPLOAD = CURLINFO_DOUBLE + 10, + CURLINFO_HEADER_SIZE = CURLINFO_LONG + 11, + CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12, + CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13, + CURLINFO_FILETIME = CURLINFO_LONG + 14, + CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15, + CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16, + CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17, + CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18, + CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19, + CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20, + CURLINFO_PRIVATE = CURLINFO_STRING + 21, + CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG + 22, + CURLINFO_HTTPAUTH_AVAIL = CURLINFO_LONG + 23, + CURLINFO_PROXYAUTH_AVAIL = CURLINFO_LONG + 24, + CURLINFO_OS_ERRNO = CURLINFO_LONG + 25, + CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26, + CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27, + CURLINFO_COOKIELIST = CURLINFO_SLIST + 28, + CURLINFO_LASTSOCKET = CURLINFO_LONG + 29, + CURLINFO_FTP_ENTRY_PATH = CURLINFO_STRING + 30, + CURLINFO_REDIRECT_URL = CURLINFO_STRING + 31, + CURLINFO_PRIMARY_IP = CURLINFO_STRING + 32, + CURLINFO_APPCONNECT_TIME = CURLINFO_DOUBLE + 33, + CURLINFO_CERTINFO = CURLINFO_SLIST + 34, + CURLINFO_CONDITION_UNMET = CURLINFO_LONG + 35, + CURLINFO_RTSP_SESSION_ID = CURLINFO_STRING + 36, + CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG + 37, + CURLINFO_RTSP_SERVER_CSEQ = CURLINFO_LONG + 38, + CURLINFO_RTSP_CSEQ_RECV = CURLINFO_LONG + 39, + CURLINFO_PRIMARY_PORT = CURLINFO_LONG + 40, + CURLINFO_LOCAL_IP = CURLINFO_STRING + 41, + CURLINFO_LOCAL_PORT = CURLINFO_LONG + 42, + CURLINFO_TLS_SESSION = CURLINFO_SLIST + 43, + CURLINFO_ACTIVESOCKET = CURLINFO_SOCKET + 44, + /* Fill in new entries below here! */ + + CURLINFO_LASTONE = 44 +} CURLINFO; + +/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as + CURLINFO_HTTP_CODE */ +#define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE + +typedef enum { + CURLCLOSEPOLICY_NONE, /* first, never use this */ + + CURLCLOSEPOLICY_OLDEST, + CURLCLOSEPOLICY_LEAST_RECENTLY_USED, + CURLCLOSEPOLICY_LEAST_TRAFFIC, + CURLCLOSEPOLICY_SLOWEST, + CURLCLOSEPOLICY_CALLBACK, + + CURLCLOSEPOLICY_LAST /* last, never use this */ +} curl_closepolicy; + +#define CURL_GLOBAL_SSL (1<<0) +#define CURL_GLOBAL_WIN32 (1<<1) +#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) +#define CURL_GLOBAL_NOTHING 0 +#define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL +#define CURL_GLOBAL_ACK_EINTR (1<<2) + + +/***************************************************************************** + * Setup defines, protos etc for the sharing stuff. + */ + +/* Different data locks for a single share */ +typedef enum { + CURL_LOCK_DATA_NONE = 0, + /* CURL_LOCK_DATA_SHARE is used internally to say that + * the locking is just made to change the internal state of the share + * itself. + */ + CURL_LOCK_DATA_SHARE, + CURL_LOCK_DATA_COOKIE, + CURL_LOCK_DATA_DNS, + CURL_LOCK_DATA_SSL_SESSION, + CURL_LOCK_DATA_CONNECT, + CURL_LOCK_DATA_LAST +} curl_lock_data; + +/* Different lock access types */ +typedef enum { + CURL_LOCK_ACCESS_NONE = 0, /* unspecified action */ + CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */ + CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */ + CURL_LOCK_ACCESS_LAST /* never use */ +} curl_lock_access; + +typedef void (*curl_lock_function)(CURL *handle, + curl_lock_data data, + curl_lock_access locktype, + void *userptr); +typedef void (*curl_unlock_function)(CURL *handle, + curl_lock_data data, + void *userptr); + +typedef void CURLSH; + +typedef enum { + CURLSHE_OK, /* all is fine */ + CURLSHE_BAD_OPTION, /* 1 */ + CURLSHE_IN_USE, /* 2 */ + CURLSHE_INVALID, /* 3 */ + CURLSHE_NOMEM, /* 4 out of memory */ + CURLSHE_NOT_BUILT_IN, /* 5 feature not present in lib */ + CURLSHE_LAST /* never use */ +} CURLSHcode; + +typedef enum { + CURLSHOPT_NONE, /* don't use */ + CURLSHOPT_SHARE, /* specify a data type to share */ + CURLSHOPT_UNSHARE, /* specify which data type to stop sharing */ + CURLSHOPT_LOCKFUNC, /* pass in a 'curl_lock_function' pointer */ + CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */ + CURLSHOPT_USERDATA, /* pass in a user data pointer used in the lock/unlock + callback functions */ + CURLSHOPT_LAST /* never use */ +} CURLSHoption; + +CURL_EXTERN CURLSH *curl_share_init(void); +CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...); +CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *); + +/**************************************************************************** + * Structures for querying information about the curl library at runtime. + */ + +typedef enum { + CURLVERSION_FIRST, + CURLVERSION_SECOND, + CURLVERSION_THIRD, + CURLVERSION_FOURTH, + CURLVERSION_LAST /* never actually use this */ +} CURLversion; + +/* The 'CURLVERSION_NOW' is the symbolic name meant to be used by + basically all programs ever that want to get version information. It is + meant to be a built-in version number for what kind of struct the caller + expects. If the struct ever changes, we redefine the NOW to another enum + from above. */ +#define CURLVERSION_NOW CURLVERSION_FOURTH + +typedef struct { + CURLversion age; /* age of the returned struct */ + const char *version; /* LIBCURL_VERSION */ + unsigned int version_num; /* LIBCURL_VERSION_NUM */ + const char *host; /* OS/host/cpu/machine when configured */ + int features; /* bitmask, see defines below */ + const char *ssl_version; /* human readable string */ + long ssl_version_num; /* not used anymore, always 0 */ + const char *libz_version; /* human readable string */ + /* protocols is terminated by an entry with a NULL protoname */ + const char * const *protocols; + + /* The fields below this were added in CURLVERSION_SECOND */ + const char *ares; + int ares_num; + + /* This field was added in CURLVERSION_THIRD */ + const char *libidn; + + /* These field were added in CURLVERSION_FOURTH */ + + /* Same as '_libiconv_version' if built with HAVE_ICONV */ + int iconv_ver_num; + + const char *libssh_version; /* human readable string */ + +} curl_version_info_data; + +#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */ +#define CURL_VERSION_KERBEROS4 (1<<1) /* Kerberos V4 auth is supported + (deprecated) */ +#define CURL_VERSION_SSL (1<<2) /* SSL options are present */ +#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */ +#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */ +#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth is supported + (deprecated) */ +#define CURL_VERSION_DEBUG (1<<6) /* Built with debug capabilities */ +#define CURL_VERSION_ASYNCHDNS (1<<7) /* Asynchronous DNS resolves */ +#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth is supported */ +#define CURL_VERSION_LARGEFILE (1<<9) /* Supports files larger than 2GB */ +#define CURL_VERSION_IDN (1<<10) /* Internationized Domain Names are + supported */ +#define CURL_VERSION_SSPI (1<<11) /* Built against Windows SSPI */ +#define CURL_VERSION_CONV (1<<12) /* Character conversions supported */ +#define CURL_VERSION_CURLDEBUG (1<<13) /* Debug memory tracking supported */ +#define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */ +#define CURL_VERSION_NTLM_WB (1<<15) /* NTLM delegation to winbind helper + is suported */ +#define CURL_VERSION_HTTP2 (1<<16) /* HTTP2 support built-in */ +#define CURL_VERSION_GSSAPI (1<<17) /* Built against a GSS-API library */ +#define CURL_VERSION_KERBEROS5 (1<<18) /* Kerberos V5 auth is supported */ +#define CURL_VERSION_UNIX_SOCKETS (1<<19) /* Unix domain sockets support */ +#define CURL_VERSION_PSL (1<<20) /* Mozilla's Public Suffix List, used + for cookie domain verification */ + + /* + * NAME curl_version_info() + * + * DESCRIPTION + * + * This function returns a pointer to a static copy of the version info + * struct. See above. + */ +CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion); + +/* + * NAME curl_easy_strerror() + * + * DESCRIPTION + * + * The curl_easy_strerror function may be used to turn a CURLcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_easy_strerror(CURLcode); + +/* + * NAME curl_share_strerror() + * + * DESCRIPTION + * + * The curl_share_strerror function may be used to turn a CURLSHcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_share_strerror(CURLSHcode); + +/* + * NAME curl_easy_pause() + * + * DESCRIPTION + * + * The curl_easy_pause function pauses or unpauses transfers. Select the new + * state by setting the bitmask, use the convenience defines below. + * + */ +CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask); + +#define CURLPAUSE_RECV (1<<0) +#define CURLPAUSE_RECV_CONT (0) + +#define CURLPAUSE_SEND (1<<2) +#define CURLPAUSE_SEND_CONT (0) + +#define CURLPAUSE_ALL (CURLPAUSE_RECV|CURLPAUSE_SEND) +#define CURLPAUSE_CONT (CURLPAUSE_RECV_CONT|CURLPAUSE_SEND_CONT) + +#ifdef __cplusplus +} +#endif + +/* unfortunately, the easy.h and multi.h include files need options and info + stuff before they can be included! */ +#include "easy.h" /* nothing in curl is fun without the easy stuff */ +#include "multi.h" + +/* the typechecker doesn't work in C++ (yet) */ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \ + ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \ + !defined(__cplusplus) && !defined(CURL_DISABLE_TYPECHECK) +#include "typecheck-gcc.h" +#else +#if defined(__STDC__) && (__STDC__ >= 1) +/* This preprocessor magic that replaces a call with the exact same call is + only done to make sure application authors pass exactly three arguments + to these functions. */ +#define curl_easy_setopt(handle,opt,param) curl_easy_setopt(handle,opt,param) +#define curl_easy_getinfo(handle,info,arg) curl_easy_getinfo(handle,info,arg) +#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) +#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) +#endif /* __STDC__ >= 1 */ +#endif /* gcc >= 4.3 && !__cplusplus */ + +#endif /* __CURL_CURL_H */ diff --git a/deps/libcurl/include/curl/curlbuild.h b/deps/libcurl/include/curl/curlbuild.h new file mode 100644 index 0000000000..bdca52b535 --- /dev/null +++ b/deps/libcurl/include/curl/curlbuild.h @@ -0,0 +1,198 @@ +/* include/curl/curlbuild.h. Generated from curlbuild.h.in by configure. */ +#ifndef __CURL_CURLBUILD_H +#define __CURL_CURLBUILD_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* ================================================================ */ +/* NOTES FOR CONFIGURE CAPABLE SYSTEMS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * Nothing in this file is intended to be modified or adjusted by the + * curl library user nor by the curl library builder. + * + * If you think that something actually needs to be changed, adjusted + * or fixed in this file, then, report it on the libcurl development + * mailing list: http://cool.haxx.se/mailman/listinfo/curl-library/ + * + * This header file shall only export symbols which are 'curl' or 'CURL' + * prefixed, otherwise public name space would be polluted. + * + * NOTE 2: + * ------- + * + * Right now you might be staring at file include/curl/curlbuild.h.in or + * at file include/curl/curlbuild.h, this is due to the following reason: + * + * On systems capable of running the configure script, the configure process + * will overwrite the distributed include/curl/curlbuild.h file with one that + * is suitable and specific to the library being configured and built, which + * is generated from the include/curl/curlbuild.h.in template file. + * + */ + +/* ================================================================ */ +/* DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE */ +/* ================================================================ */ + +#ifdef CURL_SIZEOF_LONG +#error "CURL_SIZEOF_LONG shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_LONG_already_defined +#endif + +#ifdef CURL_TYPEOF_CURL_SOCKLEN_T +#error "CURL_TYPEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_already_defined +#endif + +#ifdef CURL_SIZEOF_CURL_SOCKLEN_T +#error "CURL_SIZEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_already_defined +#endif + +#ifdef CURL_TYPEOF_CURL_OFF_T +#error "CURL_TYPEOF_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_FORMAT_CURL_OFF_T +#error "CURL_FORMAT_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_FORMAT_CURL_OFF_TU +#error "CURL_FORMAT_CURL_OFF_TU shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_already_defined +#endif + +#ifdef CURL_FORMAT_OFF_T +#error "CURL_FORMAT_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_OFF_T_already_defined +#endif + +#ifdef CURL_SIZEOF_CURL_OFF_T +#error "CURL_SIZEOF_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_SUFFIX_CURL_OFF_T +#error "CURL_SUFFIX_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_SUFFIX_CURL_OFF_TU +#error "CURL_SUFFIX_CURL_OFF_TU shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_already_defined +#endif + +/* ================================================================ */ +/* EXTERNAL INTERFACE SETTINGS FOR CONFIGURE CAPABLE SYSTEMS ONLY */ +/* ================================================================ */ + +/* Configure process defines this to 1 when it finds out that system */ +/* header file ws2tcpip.h must be included by the external interface. */ +/* #undef CURL_PULL_WS2TCPIP_H */ +#ifdef CURL_PULL_WS2TCPIP_H +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# include +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/types.h must be included by the external interface. */ +#define CURL_PULL_SYS_TYPES_H 1 +#ifdef CURL_PULL_SYS_TYPES_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file stdint.h must be included by the external interface. */ +/* #undef CURL_PULL_STDINT_H */ +#ifdef CURL_PULL_STDINT_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file inttypes.h must be included by the external interface. */ +/* #undef CURL_PULL_INTTYPES_H */ +#ifdef CURL_PULL_INTTYPES_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/socket.h must be included by the external interface. */ +#define CURL_PULL_SYS_SOCKET_H 1 +#ifdef CURL_PULL_SYS_SOCKET_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/poll.h must be included by the external interface. */ +/* #undef CURL_PULL_SYS_POLL_H */ +#ifdef CURL_PULL_SYS_POLL_H +# include +#endif + +/* The size of `long', as computed by sizeof. */ +#define CURL_SIZEOF_LONG 8 + +/* Integral data type used for curl_socklen_t. */ +#define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t + +/* The size of `curl_socklen_t', as computed by sizeof. */ +#define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +/* Data type definition of curl_socklen_t. */ +typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; + +/* Signed integral data type used for curl_off_t. */ +#define CURL_TYPEOF_CURL_OFF_T long + +/* Data type definition of curl_off_t. */ +typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; + +/* curl_off_t formatting string directive without "%" conversion specifier. */ +#define CURL_FORMAT_CURL_OFF_T "ld" + +/* unsigned curl_off_t formatting string without "%" conversion specifier. */ +#define CURL_FORMAT_CURL_OFF_TU "lu" + +/* curl_off_t formatting string directive with "%" conversion specifier. */ +#define CURL_FORMAT_OFF_T "%ld" + +/* The size of `curl_off_t', as computed by sizeof. */ +#define CURL_SIZEOF_CURL_OFF_T 8 + +/* curl_off_t constant suffix. */ +#define CURL_SUFFIX_CURL_OFF_T L + +/* unsigned curl_off_t constant suffix. */ +#define CURL_SUFFIX_CURL_OFF_TU UL + +#endif /* __CURL_CURLBUILD_H */ diff --git a/deps/libcurl/include/curl/curlrules.h b/deps/libcurl/include/curl/curlrules.h new file mode 100644 index 0000000000..7c2ede35b6 --- /dev/null +++ b/deps/libcurl/include/curl/curlrules.h @@ -0,0 +1,262 @@ +#ifndef __CURL_CURLRULES_H +#define __CURL_CURLRULES_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* ================================================================ */ +/* COMPILE TIME SANITY CHECKS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * All checks done in this file are intentionally placed in a public + * header file which is pulled by curl/curl.h when an application is + * being built using an already built libcurl library. Additionally + * this file is also included and used when building the library. + * + * If compilation fails on this file it is certainly sure that the + * problem is elsewhere. It could be a problem in the curlbuild.h + * header file, or simply that you are using different compilation + * settings than those used to build the library. + * + * Nothing in this file is intended to be modified or adjusted by the + * curl library user nor by the curl library builder. + * + * Do not deactivate any check, these are done to make sure that the + * library is properly built and used. + * + * You can find further help on the libcurl development mailing list: + * http://cool.haxx.se/mailman/listinfo/curl-library/ + * + * NOTE 2 + * ------ + * + * Some of the following compile time checks are based on the fact + * that the dimension of a constant array can not be a negative one. + * In this way if the compile time verification fails, the compilation + * will fail issuing an error. The error description wording is compiler + * dependent but it will be quite similar to one of the following: + * + * "negative subscript or subscript is too large" + * "array must have at least one element" + * "-1 is an illegal array size" + * "size of array is negative" + * + * If you are building an application which tries to use an already + * built libcurl library and you are getting this kind of errors on + * this file, it is a clear indication that there is a mismatch between + * how the library was built and how you are trying to use it for your + * application. Your already compiled or binary library provider is the + * only one who can give you the details you need to properly use it. + */ + +/* + * Verify that some macros are actually defined. + */ + +#ifndef CURL_SIZEOF_LONG +# error "CURL_SIZEOF_LONG definition is missing!" + Error Compilation_aborted_CURL_SIZEOF_LONG_is_missing +#endif + +#ifndef CURL_TYPEOF_CURL_SOCKLEN_T +# error "CURL_TYPEOF_CURL_SOCKLEN_T definition is missing!" + Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_is_missing +#endif + +#ifndef CURL_SIZEOF_CURL_SOCKLEN_T +# error "CURL_SIZEOF_CURL_SOCKLEN_T definition is missing!" + Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_is_missing +#endif + +#ifndef CURL_TYPEOF_CURL_OFF_T +# error "CURL_TYPEOF_CURL_OFF_T definition is missing!" + Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_is_missing +#endif + +#ifndef CURL_FORMAT_CURL_OFF_T +# error "CURL_FORMAT_CURL_OFF_T definition is missing!" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_is_missing +#endif + +#ifndef CURL_FORMAT_CURL_OFF_TU +# error "CURL_FORMAT_CURL_OFF_TU definition is missing!" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_is_missing +#endif + +#ifndef CURL_FORMAT_OFF_T +# error "CURL_FORMAT_OFF_T definition is missing!" + Error Compilation_aborted_CURL_FORMAT_OFF_T_is_missing +#endif + +#ifndef CURL_SIZEOF_CURL_OFF_T +# error "CURL_SIZEOF_CURL_OFF_T definition is missing!" + Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_is_missing +#endif + +#ifndef CURL_SUFFIX_CURL_OFF_T +# error "CURL_SUFFIX_CURL_OFF_T definition is missing!" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_is_missing +#endif + +#ifndef CURL_SUFFIX_CURL_OFF_TU +# error "CURL_SUFFIX_CURL_OFF_TU definition is missing!" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_is_missing +#endif + +/* + * Macros private to this header file. + */ + +#define CurlchkszEQ(t, s) sizeof(t) == s ? 1 : -1 + +#define CurlchkszGE(t1, t2) sizeof(t1) >= sizeof(t2) ? 1 : -1 + +/* + * Verify that the size previously defined and expected for long + * is the same as the one reported by sizeof() at compile time. + */ + +typedef char + __curl_rule_01__ + [CurlchkszEQ(long, CURL_SIZEOF_LONG)]; + +/* + * Verify that the size previously defined and expected for + * curl_off_t is actually the the same as the one reported + * by sizeof() at compile time. + */ + +typedef char + __curl_rule_02__ + [CurlchkszEQ(curl_off_t, CURL_SIZEOF_CURL_OFF_T)]; + +/* + * Verify at compile time that the size of curl_off_t as reported + * by sizeof() is greater or equal than the one reported for long + * for the current compilation. + */ + +typedef char + __curl_rule_03__ + [CurlchkszGE(curl_off_t, long)]; + +/* + * Verify that the size previously defined and expected for + * curl_socklen_t is actually the the same as the one reported + * by sizeof() at compile time. + */ + +typedef char + __curl_rule_04__ + [CurlchkszEQ(curl_socklen_t, CURL_SIZEOF_CURL_SOCKLEN_T)]; + +/* + * Verify at compile time that the size of curl_socklen_t as reported + * by sizeof() is greater or equal than the one reported for int for + * the current compilation. + */ + +typedef char + __curl_rule_05__ + [CurlchkszGE(curl_socklen_t, int)]; + +/* ================================================================ */ +/* EXTERNALLY AND INTERNALLY VISIBLE DEFINITIONS */ +/* ================================================================ */ + +/* + * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow + * these to be visible and exported by the external libcurl interface API, + * while also making them visible to the library internals, simply including + * curl_setup.h, without actually needing to include curl.h internally. + * If some day this section would grow big enough, all this should be moved + * to its own header file. + */ + +/* + * Figure out if we can use the ## preprocessor operator, which is supported + * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__ + * or __cplusplus so we need to carefully check for them too. + */ + +#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \ + defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \ + defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \ + defined(__ILEC400__) + /* This compiler is believed to have an ISO compatible preprocessor */ +#define CURL_ISOCPP +#else + /* This compiler is believed NOT to have an ISO compatible preprocessor */ +#undef CURL_ISOCPP +#endif + +/* + * Macros for minimum-width signed and unsigned curl_off_t integer constants. + */ + +#if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551) +# define __CURL_OFF_T_C_HLPR2(x) x +# define __CURL_OFF_T_C_HLPR1(x) __CURL_OFF_T_C_HLPR2(x) +# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ + __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T) +# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ + __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU) +#else +# ifdef CURL_ISOCPP +# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix +# else +# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix +# endif +# define __CURL_OFF_T_C_HLPR1(Val,Suffix) __CURL_OFF_T_C_HLPR2(Val,Suffix) +# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T) +# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU) +#endif + +/* + * Get rid of macros private to this header file. + */ + +#undef CurlchkszEQ +#undef CurlchkszGE + +/* + * Get rid of macros not intended to exist beyond this point. + */ + +#undef CURL_PULL_WS2TCPIP_H +#undef CURL_PULL_SYS_TYPES_H +#undef CURL_PULL_SYS_SOCKET_H +#undef CURL_PULL_SYS_POLL_H +#undef CURL_PULL_STDINT_H +#undef CURL_PULL_INTTYPES_H + +#undef CURL_TYPEOF_CURL_SOCKLEN_T +#undef CURL_TYPEOF_CURL_OFF_T + +#ifdef CURL_NO_OLDIES +#undef CURL_FORMAT_OFF_T /* not required since 7.19.0 - obsoleted in 7.20.0 */ +#endif + +#endif /* __CURL_CURLRULES_H */ diff --git a/deps/libcurl/include/curl/curlver.h b/deps/libcurl/include/curl/curlver.h new file mode 100644 index 0000000000..17906764c8 --- /dev/null +++ b/deps/libcurl/include/curl/curlver.h @@ -0,0 +1,77 @@ +#ifndef __CURL_CURLVER_H +#define __CURL_CURLVER_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* This header file contains nothing but libcurl version info, generated by + a script at release-time. This was made its own header file in 7.11.2 */ + +/* This is the global package copyright */ +#define LIBCURL_COPYRIGHT "1996 - 2015 Daniel Stenberg, ." + +/* This is the version number of the libcurl package from which this header + file origins: */ +#define LIBCURL_VERSION "7.47.0" + +/* The numeric version number is also available "in parts" by using these + defines: */ +#define LIBCURL_VERSION_MAJOR 7 +#define LIBCURL_VERSION_MINOR 47 +#define LIBCURL_VERSION_PATCH 0 + +/* This is the numeric version of the libcurl version number, meant for easier + parsing and comparions by programs. The LIBCURL_VERSION_NUM define will + always follow this syntax: + + 0xXXYYZZ + + Where XX, YY and ZZ are the main version, release and patch numbers in + hexadecimal (using 8 bits each). All three numbers are always represented + using two digits. 1.2 would appear as "0x010200" while version 9.11.7 + appears as "0x090b07". + + This 6-digit (24 bits) hexadecimal number does not show pre-release number, + and it is always a greater number in a more recent release. It makes + comparisons with greater than and less than work. + + Note: This define is the full hex number and _does not_ use the + CURL_VERSION_BITS() macro since curl's own configure script greps for it + and needs it to contain the full number. +*/ +#define LIBCURL_VERSION_NUM 0x072f00 + +/* + * This is the date and time when the full source package was created. The + * timestamp is not stored in git, as the timestamp is properly set in the + * tarballs by the maketgz script. + * + * The format of the date should follow this template: + * + * "Mon Feb 12 11:35:33 UTC 2007" + */ +#define LIBCURL_TIMESTAMP "Wed Jan 27 07:32:44 UTC 2016" + +#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|z) +#define CURL_AT_LEAST_VERSION(x,y,z) \ + (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z)) + +#endif /* __CURL_CURLVER_H */ diff --git a/deps/libcurl/include/curl/easy.h b/deps/libcurl/include/curl/easy.h new file mode 100644 index 0000000000..c1e3e76096 --- /dev/null +++ b/deps/libcurl/include/curl/easy.h @@ -0,0 +1,102 @@ +#ifndef __CURL_EASY_H +#define __CURL_EASY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +CURL_EXTERN CURL *curl_easy_init(void); +CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); +CURL_EXTERN CURLcode curl_easy_perform(CURL *curl); +CURL_EXTERN void curl_easy_cleanup(CURL *curl); + +/* + * NAME curl_easy_getinfo() + * + * DESCRIPTION + * + * Request internal information from the curl session with this function. The + * third argument MUST be a pointer to a long, a pointer to a char * or a + * pointer to a double (as the documentation describes elsewhere). The data + * pointed to will be filled in accordingly and can be relied upon only if the + * function returns CURLE_OK. This function is intended to get used *AFTER* a + * performed transfer, all results from this function are undefined until the + * transfer is completed. + */ +CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...); + + +/* + * NAME curl_easy_duphandle() + * + * DESCRIPTION + * + * Creates a new curl session handle with the same options set for the handle + * passed in. Duplicating a handle could only be a matter of cloning data and + * options, internal state info and things like persistent connections cannot + * be transferred. It is useful in multithreaded applications when you can run + * curl_easy_duphandle() for each new thread to avoid a series of identical + * curl_easy_setopt() invokes in every thread. + */ +CURL_EXTERN CURL* curl_easy_duphandle(CURL *curl); + +/* + * NAME curl_easy_reset() + * + * DESCRIPTION + * + * Re-initializes a CURL handle to the default values. This puts back the + * handle to the same state as it was in when it was just created. + * + * It does keep: live connections, the Session ID cache, the DNS cache and the + * cookies. + */ +CURL_EXTERN void curl_easy_reset(CURL *curl); + +/* + * NAME curl_easy_recv() + * + * DESCRIPTION + * + * Receives data from the connected socket. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURL_EXTERN CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, + size_t *n); + +/* + * NAME curl_easy_send() + * + * DESCRIPTION + * + * Sends data over the connected socket. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer, + size_t buflen, size_t *n); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/deps/libcurl/include/curl/mprintf.h b/deps/libcurl/include/curl/mprintf.h new file mode 100644 index 0000000000..c6b0d7679a --- /dev/null +++ b/deps/libcurl/include/curl/mprintf.h @@ -0,0 +1,74 @@ +#ifndef __CURL_MPRINTF_H +#define __CURL_MPRINTF_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include +#include /* needed for FILE */ + +#include "curl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +CURL_EXTERN int curl_mprintf(const char *format, ...); +CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...); +CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...); +CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength, + const char *format, ...); +CURL_EXTERN int curl_mvprintf(const char *format, va_list args); +CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args); +CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args); +CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength, + const char *format, va_list args); +CURL_EXTERN char *curl_maprintf(const char *format, ...); +CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args); + +#ifdef _MPRINTF_REPLACE +# undef printf +# undef fprintf +# undef sprintf +# undef vsprintf +# undef snprintf +# undef vprintf +# undef vfprintf +# undef vsnprintf +# undef aprintf +# undef vaprintf +# define printf curl_mprintf +# define fprintf curl_mfprintf +# define sprintf curl_msprintf +# define vsprintf curl_mvsprintf +# define snprintf curl_msnprintf +# define vprintf curl_mvprintf +# define vfprintf curl_mvfprintf +# define vsnprintf curl_mvsnprintf +# define aprintf curl_maprintf +# define vaprintf curl_mvaprintf +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __CURL_MPRINTF_H */ diff --git a/deps/libcurl/include/curl/multi.h b/deps/libcurl/include/curl/multi.h new file mode 100644 index 0000000000..36e2e940ec --- /dev/null +++ b/deps/libcurl/include/curl/multi.h @@ -0,0 +1,435 @@ +#ifndef __CURL_MULTI_H +#define __CURL_MULTI_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +/* + This is an "external" header file. Don't give away any internals here! + + GOALS + + o Enable a "pull" interface. The application that uses libcurl decides where + and when to ask libcurl to get/send data. + + o Enable multiple simultaneous transfers in the same thread without making it + complicated for the application. + + o Enable the application to select() on its own file descriptors and curl's + file descriptors simultaneous easily. + +*/ + +/* + * This header file should not really need to include "curl.h" since curl.h + * itself includes this file and we expect user applications to do #include + * without the need for especially including multi.h. + * + * For some reason we added this include here at one point, and rather than to + * break existing (wrongly written) libcurl applications, we leave it as-is + * but with this warning attached. + */ +#include "curl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void CURLM; + +typedef enum { + CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or + curl_multi_socket*() soon */ + CURLM_OK, + CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */ + CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */ + CURLM_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */ + CURLM_INTERNAL_ERROR, /* this is a libcurl bug */ + CURLM_BAD_SOCKET, /* the passed in socket argument did not match */ + CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */ + CURLM_ADDED_ALREADY, /* an easy handle already added to a multi handle was + attempted to get added - again */ + CURLM_LAST +} CURLMcode; + +/* just to make code nicer when using curl_multi_socket() you can now check + for CURLM_CALL_MULTI_SOCKET too in the same style it works for + curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */ +#define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM + +/* bitmask bits for CURLMOPT_PIPELINING */ +#define CURLPIPE_NOTHING 0L +#define CURLPIPE_HTTP1 1L +#define CURLPIPE_MULTIPLEX 2L + +typedef enum { + CURLMSG_NONE, /* first, not used */ + CURLMSG_DONE, /* This easy handle has completed. 'result' contains + the CURLcode of the transfer */ + CURLMSG_LAST /* last, not used */ +} CURLMSG; + +struct CURLMsg { + CURLMSG msg; /* what this message means */ + CURL *easy_handle; /* the handle it concerns */ + union { + void *whatever; /* message-specific data */ + CURLcode result; /* return code for transfer */ + } data; +}; +typedef struct CURLMsg CURLMsg; + +/* Based on poll(2) structure and values. + * We don't use pollfd and POLL* constants explicitly + * to cover platforms without poll(). */ +#define CURL_WAIT_POLLIN 0x0001 +#define CURL_WAIT_POLLPRI 0x0002 +#define CURL_WAIT_POLLOUT 0x0004 + +struct curl_waitfd { + curl_socket_t fd; + short events; + short revents; /* not supported yet */ +}; + +/* + * Name: curl_multi_init() + * + * Desc: inititalize multi-style curl usage + * + * Returns: a new CURLM handle to use in all 'curl_multi' functions. + */ +CURL_EXTERN CURLM *curl_multi_init(void); + +/* + * Name: curl_multi_add_handle() + * + * Desc: add a standard curl handle to the multi stack + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_remove_handle() + * + * Desc: removes a curl handle from the multi stack again + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_fdset() + * + * Desc: Ask curl for its fd_set sets. The app can use these to select() or + * poll() on. We want curl_multi_perform() called as soon as one of + * them are ready. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle, + fd_set *read_fd_set, + fd_set *write_fd_set, + fd_set *exc_fd_set, + int *max_fd); + +/* + * Name: curl_multi_wait() + * + * Desc: Poll on all fds within a CURLM set as well as any + * additional fds passed to the function. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle, + struct curl_waitfd extra_fds[], + unsigned int extra_nfds, + int timeout_ms, + int *ret); + + /* + * Name: curl_multi_perform() + * + * Desc: When the app thinks there's data available for curl it calls this + * function to read/write whatever there is right now. This returns + * as soon as the reads and writes are done. This function does not + * require that there actually is data available for reading or that + * data can be written, it can be called just in case. It returns + * the number of handles that still transfer data in the second + * argument's integer-pointer. + * + * Returns: CURLMcode type, general multi error code. *NOTE* that this only + * returns errors etc regarding the whole multi stack. There might + * still have occurred problems on invidual transfers even when this + * returns OK. + */ +CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle, + int *running_handles); + + /* + * Name: curl_multi_cleanup() + * + * Desc: Cleans up and removes a whole multi stack. It does not free or + * touch any individual easy handles in any way. We need to define + * in what state those handles will be if this function is called + * in the middle of a transfer. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle); + +/* + * Name: curl_multi_info_read() + * + * Desc: Ask the multi handle if there's any messages/informationals from + * the individual transfers. Messages include informationals such as + * error code from the transfer or just the fact that a transfer is + * completed. More details on these should be written down as well. + * + * Repeated calls to this function will return a new struct each + * time, until a special "end of msgs" struct is returned as a signal + * that there is no more to get at this point. + * + * The data the returned pointer points to will not survive calling + * curl_multi_cleanup(). + * + * The 'CURLMsg' struct is meant to be very simple and only contain + * very basic informations. If more involved information is wanted, + * we will provide the particular "transfer handle" in that struct + * and that should/could/would be used in subsequent + * curl_easy_getinfo() calls (or similar). The point being that we + * must never expose complex structs to applications, as then we'll + * undoubtably get backwards compatibility problems in the future. + * + * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out + * of structs. It also writes the number of messages left in the + * queue (after this read) in the integer the second argument points + * to. + */ +CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle, + int *msgs_in_queue); + +/* + * Name: curl_multi_strerror() + * + * Desc: The curl_multi_strerror function may be used to turn a CURLMcode + * value into the equivalent human readable error string. This is + * useful for printing meaningful error messages. + * + * Returns: A pointer to a zero-terminated error message. + */ +CURL_EXTERN const char *curl_multi_strerror(CURLMcode); + +/* + * Name: curl_multi_socket() and + * curl_multi_socket_all() + * + * Desc: An alternative version of curl_multi_perform() that allows the + * application to pass in one of the file descriptors that have been + * detected to have "action" on them and let libcurl perform. + * See man page for details. + */ +#define CURL_POLL_NONE 0 +#define CURL_POLL_IN 1 +#define CURL_POLL_OUT 2 +#define CURL_POLL_INOUT 3 +#define CURL_POLL_REMOVE 4 + +#define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD + +#define CURL_CSELECT_IN 0x01 +#define CURL_CSELECT_OUT 0x02 +#define CURL_CSELECT_ERR 0x04 + +typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */ + curl_socket_t s, /* socket */ + int what, /* see above */ + void *userp, /* private callback + pointer */ + void *socketp); /* private socket + pointer */ +/* + * Name: curl_multi_timer_callback + * + * Desc: Called by libcurl whenever the library detects a change in the + * maximum number of milliseconds the app is allowed to wait before + * curl_multi_socket() or curl_multi_perform() must be called + * (to allow libcurl's timed events to take place). + * + * Returns: The callback should return zero. + */ +typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */ + long timeout_ms, /* see above */ + void *userp); /* private callback + pointer */ + +CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, + int *running_handles); + +CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *multi_handle, + curl_socket_t s, + int ev_bitmask, + int *running_handles); + +CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle, + int *running_handles); + +#ifndef CURL_ALLOW_OLD_MULTI_SOCKET +/* This macro below was added in 7.16.3 to push users who recompile to use + the new curl_multi_socket_action() instead of the old curl_multi_socket() +*/ +#define curl_multi_socket(x,y,z) curl_multi_socket_action(x,y,0,z) +#endif + +/* + * Name: curl_multi_timeout() + * + * Desc: Returns the maximum number of milliseconds the app is allowed to + * wait before curl_multi_socket() or curl_multi_perform() must be + * called (to allow libcurl's timed events to take place). + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle, + long *milliseconds); + +#undef CINIT /* re-using the same name as in curl.h */ + +#ifdef CURL_ISOCPP +#define CINIT(name,type,num) CURLMOPT_ ## name = CURLOPTTYPE_ ## type + num +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define LONG CURLOPTTYPE_LONG +#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT +#define OFF_T CURLOPTTYPE_OFF_T +#define CINIT(name,type,number) CURLMOPT_/**/name = type + number +#endif + +typedef enum { + /* This is the socket callback function pointer */ + CINIT(SOCKETFUNCTION, FUNCTIONPOINT, 1), + + /* This is the argument passed to the socket callback */ + CINIT(SOCKETDATA, OBJECTPOINT, 2), + + /* set to 1 to enable pipelining for this multi handle */ + CINIT(PIPELINING, LONG, 3), + + /* This is the timer callback function pointer */ + CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4), + + /* This is the argument passed to the timer callback */ + CINIT(TIMERDATA, OBJECTPOINT, 5), + + /* maximum number of entries in the connection cache */ + CINIT(MAXCONNECTS, LONG, 6), + + /* maximum number of (pipelining) connections to one host */ + CINIT(MAX_HOST_CONNECTIONS, LONG, 7), + + /* maximum number of requests in a pipeline */ + CINIT(MAX_PIPELINE_LENGTH, LONG, 8), + + /* a connection with a content-length longer than this + will not be considered for pipelining */ + CINIT(CONTENT_LENGTH_PENALTY_SIZE, OFF_T, 9), + + /* a connection with a chunk length longer than this + will not be considered for pipelining */ + CINIT(CHUNK_LENGTH_PENALTY_SIZE, OFF_T, 10), + + /* a list of site names(+port) that are blacklisted from + pipelining */ + CINIT(PIPELINING_SITE_BL, OBJECTPOINT, 11), + + /* a list of server types that are blacklisted from + pipelining */ + CINIT(PIPELINING_SERVER_BL, OBJECTPOINT, 12), + + /* maximum number of open connections in total */ + CINIT(MAX_TOTAL_CONNECTIONS, LONG, 13), + + /* This is the server push callback function pointer */ + CINIT(PUSHFUNCTION, FUNCTIONPOINT, 14), + + /* This is the argument passed to the server push callback */ + CINIT(PUSHDATA, OBJECTPOINT, 15), + + CURLMOPT_LASTENTRY /* the last unused */ +} CURLMoption; + + +/* + * Name: curl_multi_setopt() + * + * Desc: Sets options for the multi handle. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle, + CURLMoption option, ...); + + +/* + * Name: curl_multi_assign() + * + * Desc: This function sets an association in the multi handle between the + * given socket and a private pointer of the application. This is + * (only) useful for curl_multi_socket uses. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle, + curl_socket_t sockfd, void *sockp); + + +/* + * Name: curl_push_callback + * + * Desc: This callback gets called when a new stream is being pushed by the + * server. It approves or denies the new stream. + * + * Returns: CURL_PUSH_OK or CURL_PUSH_DENY. + */ +#define CURL_PUSH_OK 0 +#define CURL_PUSH_DENY 1 + +struct curl_pushheaders; /* forward declaration only */ + +CURL_EXTERN char *curl_pushheader_bynum(struct curl_pushheaders *h, + size_t num); +CURL_EXTERN char *curl_pushheader_byname(struct curl_pushheaders *h, + const char *name); + +typedef int (*curl_push_callback)(CURL *parent, + CURL *easy, + size_t num_headers, + struct curl_pushheaders *headers, + void *userp); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif diff --git a/deps/libcurl/include/curl/stdcheaders.h b/deps/libcurl/include/curl/stdcheaders.h new file mode 100644 index 0000000000..ad82ef6335 --- /dev/null +++ b/deps/libcurl/include/curl/stdcheaders.h @@ -0,0 +1,33 @@ +#ifndef __STDC_HEADERS_H +#define __STDC_HEADERS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include + +size_t fread (void *, size_t, size_t, FILE *); +size_t fwrite (const void *, size_t, size_t, FILE *); + +int strcasecmp(const char *, const char *); +int strncasecmp(const char *, const char *, size_t); + +#endif /* __STDC_HEADERS_H */ diff --git a/deps/libcurl/include/curl/typecheck-gcc.h b/deps/libcurl/include/curl/typecheck-gcc.h new file mode 100644 index 0000000000..2e24db0ff5 --- /dev/null +++ b/deps/libcurl/include/curl/typecheck-gcc.h @@ -0,0 +1,622 @@ +#ifndef __CURL_TYPECHECK_GCC_H +#define __CURL_TYPECHECK_GCC_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* wraps curl_easy_setopt() with typechecking */ + +/* To add a new kind of warning, add an + * if(_curl_is_sometype_option(_curl_opt)) + * if(!_curl_is_sometype(value)) + * _curl_easy_setopt_err_sometype(); + * block and define _curl_is_sometype_option, _curl_is_sometype and + * _curl_easy_setopt_err_sometype below + * + * NOTE: We use two nested 'if' statements here instead of the && operator, in + * order to work around gcc bug #32061. It affects only gcc 4.3.x/4.4.x + * when compiling with -Wlogical-op. + * + * To add an option that uses the same type as an existing option, you'll just + * need to extend the appropriate _curl_*_option macro + */ +#define curl_easy_setopt(handle, option, value) \ +__extension__ ({ \ + __typeof__ (option) _curl_opt = option; \ + if(__builtin_constant_p(_curl_opt)) { \ + if(_curl_is_long_option(_curl_opt)) \ + if(!_curl_is_long(value)) \ + _curl_easy_setopt_err_long(); \ + if(_curl_is_off_t_option(_curl_opt)) \ + if(!_curl_is_off_t(value)) \ + _curl_easy_setopt_err_curl_off_t(); \ + if(_curl_is_string_option(_curl_opt)) \ + if(!_curl_is_string(value)) \ + _curl_easy_setopt_err_string(); \ + if(_curl_is_write_cb_option(_curl_opt)) \ + if(!_curl_is_write_cb(value)) \ + _curl_easy_setopt_err_write_callback(); \ + if((_curl_opt) == CURLOPT_READFUNCTION) \ + if(!_curl_is_read_cb(value)) \ + _curl_easy_setopt_err_read_cb(); \ + if((_curl_opt) == CURLOPT_IOCTLFUNCTION) \ + if(!_curl_is_ioctl_cb(value)) \ + _curl_easy_setopt_err_ioctl_cb(); \ + if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION) \ + if(!_curl_is_sockopt_cb(value)) \ + _curl_easy_setopt_err_sockopt_cb(); \ + if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION) \ + if(!_curl_is_opensocket_cb(value)) \ + _curl_easy_setopt_err_opensocket_cb(); \ + if((_curl_opt) == CURLOPT_PROGRESSFUNCTION) \ + if(!_curl_is_progress_cb(value)) \ + _curl_easy_setopt_err_progress_cb(); \ + if((_curl_opt) == CURLOPT_DEBUGFUNCTION) \ + if(!_curl_is_debug_cb(value)) \ + _curl_easy_setopt_err_debug_cb(); \ + if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION) \ + if(!_curl_is_ssl_ctx_cb(value)) \ + _curl_easy_setopt_err_ssl_ctx_cb(); \ + if(_curl_is_conv_cb_option(_curl_opt)) \ + if(!_curl_is_conv_cb(value)) \ + _curl_easy_setopt_err_conv_cb(); \ + if((_curl_opt) == CURLOPT_SEEKFUNCTION) \ + if(!_curl_is_seek_cb(value)) \ + _curl_easy_setopt_err_seek_cb(); \ + if(_curl_is_cb_data_option(_curl_opt)) \ + if(!_curl_is_cb_data(value)) \ + _curl_easy_setopt_err_cb_data(); \ + if((_curl_opt) == CURLOPT_ERRORBUFFER) \ + if(!_curl_is_error_buffer(value)) \ + _curl_easy_setopt_err_error_buffer(); \ + if((_curl_opt) == CURLOPT_STDERR) \ + if(!_curl_is_FILE(value)) \ + _curl_easy_setopt_err_FILE(); \ + if(_curl_is_postfields_option(_curl_opt)) \ + if(!_curl_is_postfields(value)) \ + _curl_easy_setopt_err_postfields(); \ + if((_curl_opt) == CURLOPT_HTTPPOST) \ + if(!_curl_is_arr((value), struct curl_httppost)) \ + _curl_easy_setopt_err_curl_httpost(); \ + if(_curl_is_slist_option(_curl_opt)) \ + if(!_curl_is_arr((value), struct curl_slist)) \ + _curl_easy_setopt_err_curl_slist(); \ + if((_curl_opt) == CURLOPT_SHARE) \ + if(!_curl_is_ptr((value), CURLSH)) \ + _curl_easy_setopt_err_CURLSH(); \ + } \ + curl_easy_setopt(handle, _curl_opt, value); \ +}) + +/* wraps curl_easy_getinfo() with typechecking */ +/* FIXME: don't allow const pointers */ +#define curl_easy_getinfo(handle, info, arg) \ +__extension__ ({ \ + __typeof__ (info) _curl_info = info; \ + if(__builtin_constant_p(_curl_info)) { \ + if(_curl_is_string_info(_curl_info)) \ + if(!_curl_is_arr((arg), char *)) \ + _curl_easy_getinfo_err_string(); \ + if(_curl_is_long_info(_curl_info)) \ + if(!_curl_is_arr((arg), long)) \ + _curl_easy_getinfo_err_long(); \ + if(_curl_is_double_info(_curl_info)) \ + if(!_curl_is_arr((arg), double)) \ + _curl_easy_getinfo_err_double(); \ + if(_curl_is_slist_info(_curl_info)) \ + if(!_curl_is_arr((arg), struct curl_slist *)) \ + _curl_easy_getinfo_err_curl_slist(); \ + } \ + curl_easy_getinfo(handle, _curl_info, arg); \ +}) + +/* TODO: typechecking for curl_share_setopt() and curl_multi_setopt(), + * for now just make sure that the functions are called with three + * arguments + */ +#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) +#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) + + +/* the actual warnings, triggered by calling the _curl_easy_setopt_err* + * functions */ + +/* To define a new warning, use _CURL_WARNING(identifier, "message") */ +#define _CURL_WARNING(id, message) \ + static void __attribute__((__warning__(message))) \ + __attribute__((__unused__)) __attribute__((__noinline__)) \ + id(void) { __asm__(""); } + +_CURL_WARNING(_curl_easy_setopt_err_long, + "curl_easy_setopt expects a long argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_off_t, + "curl_easy_setopt expects a curl_off_t argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_string, + "curl_easy_setopt expects a " + "string (char* or char[]) argument for this option" + ) +_CURL_WARNING(_curl_easy_setopt_err_write_callback, + "curl_easy_setopt expects a curl_write_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_read_cb, + "curl_easy_setopt expects a curl_read_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_ioctl_cb, + "curl_easy_setopt expects a curl_ioctl_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_sockopt_cb, + "curl_easy_setopt expects a curl_sockopt_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_opensocket_cb, + "curl_easy_setopt expects a " + "curl_opensocket_callback argument for this option" + ) +_CURL_WARNING(_curl_easy_setopt_err_progress_cb, + "curl_easy_setopt expects a curl_progress_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_debug_cb, + "curl_easy_setopt expects a curl_debug_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_ssl_ctx_cb, + "curl_easy_setopt expects a curl_ssl_ctx_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_conv_cb, + "curl_easy_setopt expects a curl_conv_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_seek_cb, + "curl_easy_setopt expects a curl_seek_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_cb_data, + "curl_easy_setopt expects a " + "private data pointer as argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_error_buffer, + "curl_easy_setopt expects a " + "char buffer of CURL_ERROR_SIZE as argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_FILE, + "curl_easy_setopt expects a FILE* argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_postfields, + "curl_easy_setopt expects a void* or char* argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_httpost, + "curl_easy_setopt expects a struct curl_httppost* argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_slist, + "curl_easy_setopt expects a struct curl_slist* argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_CURLSH, + "curl_easy_setopt expects a CURLSH* argument for this option") + +_CURL_WARNING(_curl_easy_getinfo_err_string, + "curl_easy_getinfo expects a pointer to char * for this info") +_CURL_WARNING(_curl_easy_getinfo_err_long, + "curl_easy_getinfo expects a pointer to long for this info") +_CURL_WARNING(_curl_easy_getinfo_err_double, + "curl_easy_getinfo expects a pointer to double for this info") +_CURL_WARNING(_curl_easy_getinfo_err_curl_slist, + "curl_easy_getinfo expects a pointer to struct curl_slist * for this info") + +/* groups of curl_easy_setops options that take the same type of argument */ + +/* To add a new option to one of the groups, just add + * (option) == CURLOPT_SOMETHING + * to the or-expression. If the option takes a long or curl_off_t, you don't + * have to do anything + */ + +/* evaluates to true if option takes a long argument */ +#define _curl_is_long_option(option) \ + (0 < (option) && (option) < CURLOPTTYPE_OBJECTPOINT) + +#define _curl_is_off_t_option(option) \ + ((option) > CURLOPTTYPE_OFF_T) + +/* evaluates to true if option takes a char* argument */ +#define _curl_is_string_option(option) \ + ((option) == CURLOPT_ACCEPT_ENCODING || \ + (option) == CURLOPT_CAINFO || \ + (option) == CURLOPT_CAPATH || \ + (option) == CURLOPT_COOKIE || \ + (option) == CURLOPT_COOKIEFILE || \ + (option) == CURLOPT_COOKIEJAR || \ + (option) == CURLOPT_COOKIELIST || \ + (option) == CURLOPT_CRLFILE || \ + (option) == CURLOPT_CUSTOMREQUEST || \ + (option) == CURLOPT_DEFAULT_PROTOCOL || \ + (option) == CURLOPT_DNS_INTERFACE || \ + (option) == CURLOPT_DNS_LOCAL_IP4 || \ + (option) == CURLOPT_DNS_LOCAL_IP6 || \ + (option) == CURLOPT_DNS_SERVERS || \ + (option) == CURLOPT_EGDSOCKET || \ + (option) == CURLOPT_FTPPORT || \ + (option) == CURLOPT_FTP_ACCOUNT || \ + (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \ + (option) == CURLOPT_INTERFACE || \ + (option) == CURLOPT_ISSUERCERT || \ + (option) == CURLOPT_KEYPASSWD || \ + (option) == CURLOPT_KRBLEVEL || \ + (option) == CURLOPT_LOGIN_OPTIONS || \ + (option) == CURLOPT_MAIL_AUTH || \ + (option) == CURLOPT_MAIL_FROM || \ + (option) == CURLOPT_NETRC_FILE || \ + (option) == CURLOPT_NOPROXY || \ + (option) == CURLOPT_PASSWORD || \ + (option) == CURLOPT_PINNEDPUBLICKEY || \ + (option) == CURLOPT_PROXY || \ + (option) == CURLOPT_PROXYPASSWORD || \ + (option) == CURLOPT_PROXYUSERNAME || \ + (option) == CURLOPT_PROXYUSERPWD || \ + (option) == CURLOPT_PROXY_SERVICE_NAME || \ + (option) == CURLOPT_RANDOM_FILE || \ + (option) == CURLOPT_RANGE || \ + (option) == CURLOPT_REFERER || \ + (option) == CURLOPT_RTSP_SESSION_ID || \ + (option) == CURLOPT_RTSP_STREAM_URI || \ + (option) == CURLOPT_RTSP_TRANSPORT || \ + (option) == CURLOPT_SERVICE_NAME || \ + (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \ + (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \ + (option) == CURLOPT_SSH_KNOWNHOSTS || \ + (option) == CURLOPT_SSH_PRIVATE_KEYFILE || \ + (option) == CURLOPT_SSH_PUBLIC_KEYFILE || \ + (option) == CURLOPT_SSLCERT || \ + (option) == CURLOPT_SSLCERTTYPE || \ + (option) == CURLOPT_SSLENGINE || \ + (option) == CURLOPT_SSLKEY || \ + (option) == CURLOPT_SSLKEYTYPE || \ + (option) == CURLOPT_SSL_CIPHER_LIST || \ + (option) == CURLOPT_TLSAUTH_PASSWORD || \ + (option) == CURLOPT_TLSAUTH_TYPE || \ + (option) == CURLOPT_TLSAUTH_USERNAME || \ + (option) == CURLOPT_UNIX_SOCKET_PATH || \ + (option) == CURLOPT_URL || \ + (option) == CURLOPT_USERAGENT || \ + (option) == CURLOPT_USERNAME || \ + (option) == CURLOPT_USERPWD || \ + (option) == CURLOPT_XOAUTH2_BEARER || \ + 0) + +/* evaluates to true if option takes a curl_write_callback argument */ +#define _curl_is_write_cb_option(option) \ + ((option) == CURLOPT_HEADERFUNCTION || \ + (option) == CURLOPT_WRITEFUNCTION) + +/* evaluates to true if option takes a curl_conv_callback argument */ +#define _curl_is_conv_cb_option(option) \ + ((option) == CURLOPT_CONV_TO_NETWORK_FUNCTION || \ + (option) == CURLOPT_CONV_FROM_NETWORK_FUNCTION || \ + (option) == CURLOPT_CONV_FROM_UTF8_FUNCTION) + +/* evaluates to true if option takes a data argument to pass to a callback */ +#define _curl_is_cb_data_option(option) \ + ((option) == CURLOPT_CHUNK_DATA || \ + (option) == CURLOPT_CLOSESOCKETDATA || \ + (option) == CURLOPT_DEBUGDATA || \ + (option) == CURLOPT_FNMATCH_DATA || \ + (option) == CURLOPT_HEADERDATA || \ + (option) == CURLOPT_INTERLEAVEDATA || \ + (option) == CURLOPT_IOCTLDATA || \ + (option) == CURLOPT_OPENSOCKETDATA || \ + (option) == CURLOPT_PRIVATE || \ + (option) == CURLOPT_PROGRESSDATA || \ + (option) == CURLOPT_READDATA || \ + (option) == CURLOPT_SEEKDATA || \ + (option) == CURLOPT_SOCKOPTDATA || \ + (option) == CURLOPT_SSH_KEYDATA || \ + (option) == CURLOPT_SSL_CTX_DATA || \ + (option) == CURLOPT_WRITEDATA || \ + 0) + +/* evaluates to true if option takes a POST data argument (void* or char*) */ +#define _curl_is_postfields_option(option) \ + ((option) == CURLOPT_POSTFIELDS || \ + (option) == CURLOPT_COPYPOSTFIELDS || \ + 0) + +/* evaluates to true if option takes a struct curl_slist * argument */ +#define _curl_is_slist_option(option) \ + ((option) == CURLOPT_HTTP200ALIASES || \ + (option) == CURLOPT_HTTPHEADER || \ + (option) == CURLOPT_MAIL_RCPT || \ + (option) == CURLOPT_POSTQUOTE || \ + (option) == CURLOPT_PREQUOTE || \ + (option) == CURLOPT_PROXYHEADER || \ + (option) == CURLOPT_QUOTE || \ + (option) == CURLOPT_RESOLVE || \ + (option) == CURLOPT_TELNETOPTIONS || \ + 0) + +/* groups of curl_easy_getinfo infos that take the same type of argument */ + +/* evaluates to true if info expects a pointer to char * argument */ +#define _curl_is_string_info(info) \ + (CURLINFO_STRING < (info) && (info) < CURLINFO_LONG) + +/* evaluates to true if info expects a pointer to long argument */ +#define _curl_is_long_info(info) \ + (CURLINFO_LONG < (info) && (info) < CURLINFO_DOUBLE) + +/* evaluates to true if info expects a pointer to double argument */ +#define _curl_is_double_info(info) \ + (CURLINFO_DOUBLE < (info) && (info) < CURLINFO_SLIST) + +/* true if info expects a pointer to struct curl_slist * argument */ +#define _curl_is_slist_info(info) \ + (CURLINFO_SLIST < (info)) + + +/* typecheck helpers -- check whether given expression has requested type*/ + +/* For pointers, you can use the _curl_is_ptr/_curl_is_arr macros, + * otherwise define a new macro. Search for __builtin_types_compatible_p + * in the GCC manual. + * NOTE: these macros MUST NOT EVALUATE their arguments! The argument is + * the actual expression passed to the curl_easy_setopt macro. This + * means that you can only apply the sizeof and __typeof__ operators, no + * == or whatsoever. + */ + +/* XXX: should evaluate to true iff expr is a pointer */ +#define _curl_is_any_ptr(expr) \ + (sizeof(expr) == sizeof(void*)) + +/* evaluates to true if expr is NULL */ +/* XXX: must not evaluate expr, so this check is not accurate */ +#define _curl_is_NULL(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), __typeof__(NULL))) + +/* evaluates to true if expr is type*, const type* or NULL */ +#define _curl_is_ptr(expr, type) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), type *) || \ + __builtin_types_compatible_p(__typeof__(expr), const type *)) + +/* evaluates to true if expr is one of type[], type*, NULL or const type* */ +#define _curl_is_arr(expr, type) \ + (_curl_is_ptr((expr), type) || \ + __builtin_types_compatible_p(__typeof__(expr), type [])) + +/* evaluates to true if expr is a string */ +#define _curl_is_string(expr) \ + (_curl_is_arr((expr), char) || \ + _curl_is_arr((expr), signed char) || \ + _curl_is_arr((expr), unsigned char)) + +/* evaluates to true if expr is a long (no matter the signedness) + * XXX: for now, int is also accepted (and therefore short and char, which + * are promoted to int when passed to a variadic function) */ +#define _curl_is_long(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), long) || \ + __builtin_types_compatible_p(__typeof__(expr), signed long) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned long) || \ + __builtin_types_compatible_p(__typeof__(expr), int) || \ + __builtin_types_compatible_p(__typeof__(expr), signed int) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned int) || \ + __builtin_types_compatible_p(__typeof__(expr), short) || \ + __builtin_types_compatible_p(__typeof__(expr), signed short) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned short) || \ + __builtin_types_compatible_p(__typeof__(expr), char) || \ + __builtin_types_compatible_p(__typeof__(expr), signed char) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned char)) + +/* evaluates to true if expr is of type curl_off_t */ +#define _curl_is_off_t(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), curl_off_t)) + +/* evaluates to true if expr is abuffer suitable for CURLOPT_ERRORBUFFER */ +/* XXX: also check size of an char[] array? */ +#define _curl_is_error_buffer(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), char *) || \ + __builtin_types_compatible_p(__typeof__(expr), char[])) + +/* evaluates to true if expr is of type (const) void* or (const) FILE* */ +#if 0 +#define _curl_is_cb_data(expr) \ + (_curl_is_ptr((expr), void) || \ + _curl_is_ptr((expr), FILE)) +#else /* be less strict */ +#define _curl_is_cb_data(expr) \ + _curl_is_any_ptr(expr) +#endif + +/* evaluates to true if expr is of type FILE* */ +#define _curl_is_FILE(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), FILE *)) + +/* evaluates to true if expr can be passed as POST data (void* or char*) */ +#define _curl_is_postfields(expr) \ + (_curl_is_ptr((expr), void) || \ + _curl_is_arr((expr), char)) + +/* FIXME: the whole callback checking is messy... + * The idea is to tolerate char vs. void and const vs. not const + * pointers in arguments at least + */ +/* helper: __builtin_types_compatible_p distinguishes between functions and + * function pointers, hide it */ +#define _curl_callback_compatible(func, type) \ + (__builtin_types_compatible_p(__typeof__(func), type) || \ + __builtin_types_compatible_p(__typeof__(func), type*)) + +/* evaluates to true if expr is of type curl_read_callback or "similar" */ +#define _curl_is_read_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), __typeof__(fread)) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_read_callback) || \ + _curl_callback_compatible((expr), _curl_read_callback1) || \ + _curl_callback_compatible((expr), _curl_read_callback2) || \ + _curl_callback_compatible((expr), _curl_read_callback3) || \ + _curl_callback_compatible((expr), _curl_read_callback4) || \ + _curl_callback_compatible((expr), _curl_read_callback5) || \ + _curl_callback_compatible((expr), _curl_read_callback6)) +typedef size_t (_curl_read_callback1)(char *, size_t, size_t, void*); +typedef size_t (_curl_read_callback2)(char *, size_t, size_t, const void*); +typedef size_t (_curl_read_callback3)(char *, size_t, size_t, FILE*); +typedef size_t (_curl_read_callback4)(void *, size_t, size_t, void*); +typedef size_t (_curl_read_callback5)(void *, size_t, size_t, const void*); +typedef size_t (_curl_read_callback6)(void *, size_t, size_t, FILE*); + +/* evaluates to true if expr is of type curl_write_callback or "similar" */ +#define _curl_is_write_cb(expr) \ + (_curl_is_read_cb(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), __typeof__(fwrite)) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_write_callback) || \ + _curl_callback_compatible((expr), _curl_write_callback1) || \ + _curl_callback_compatible((expr), _curl_write_callback2) || \ + _curl_callback_compatible((expr), _curl_write_callback3) || \ + _curl_callback_compatible((expr), _curl_write_callback4) || \ + _curl_callback_compatible((expr), _curl_write_callback5) || \ + _curl_callback_compatible((expr), _curl_write_callback6)) +typedef size_t (_curl_write_callback1)(const char *, size_t, size_t, void*); +typedef size_t (_curl_write_callback2)(const char *, size_t, size_t, + const void*); +typedef size_t (_curl_write_callback3)(const char *, size_t, size_t, FILE*); +typedef size_t (_curl_write_callback4)(const void *, size_t, size_t, void*); +typedef size_t (_curl_write_callback5)(const void *, size_t, size_t, + const void*); +typedef size_t (_curl_write_callback6)(const void *, size_t, size_t, FILE*); + +/* evaluates to true if expr is of type curl_ioctl_callback or "similar" */ +#define _curl_is_ioctl_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_ioctl_callback) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback1) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback2) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback3) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback4)) +typedef curlioerr (_curl_ioctl_callback1)(CURL *, int, void*); +typedef curlioerr (_curl_ioctl_callback2)(CURL *, int, const void*); +typedef curlioerr (_curl_ioctl_callback3)(CURL *, curliocmd, void*); +typedef curlioerr (_curl_ioctl_callback4)(CURL *, curliocmd, const void*); + +/* evaluates to true if expr is of type curl_sockopt_callback or "similar" */ +#define _curl_is_sockopt_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_sockopt_callback) || \ + _curl_callback_compatible((expr), _curl_sockopt_callback1) || \ + _curl_callback_compatible((expr), _curl_sockopt_callback2)) +typedef int (_curl_sockopt_callback1)(void *, curl_socket_t, curlsocktype); +typedef int (_curl_sockopt_callback2)(const void *, curl_socket_t, + curlsocktype); + +/* evaluates to true if expr is of type curl_opensocket_callback or + "similar" */ +#define _curl_is_opensocket_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_opensocket_callback) ||\ + _curl_callback_compatible((expr), _curl_opensocket_callback1) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback2) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback3) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback4)) +typedef curl_socket_t (_curl_opensocket_callback1) + (void *, curlsocktype, struct curl_sockaddr *); +typedef curl_socket_t (_curl_opensocket_callback2) + (void *, curlsocktype, const struct curl_sockaddr *); +typedef curl_socket_t (_curl_opensocket_callback3) + (const void *, curlsocktype, struct curl_sockaddr *); +typedef curl_socket_t (_curl_opensocket_callback4) + (const void *, curlsocktype, const struct curl_sockaddr *); + +/* evaluates to true if expr is of type curl_progress_callback or "similar" */ +#define _curl_is_progress_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_progress_callback) || \ + _curl_callback_compatible((expr), _curl_progress_callback1) || \ + _curl_callback_compatible((expr), _curl_progress_callback2)) +typedef int (_curl_progress_callback1)(void *, + double, double, double, double); +typedef int (_curl_progress_callback2)(const void *, + double, double, double, double); + +/* evaluates to true if expr is of type curl_debug_callback or "similar" */ +#define _curl_is_debug_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_debug_callback) || \ + _curl_callback_compatible((expr), _curl_debug_callback1) || \ + _curl_callback_compatible((expr), _curl_debug_callback2) || \ + _curl_callback_compatible((expr), _curl_debug_callback3) || \ + _curl_callback_compatible((expr), _curl_debug_callback4) || \ + _curl_callback_compatible((expr), _curl_debug_callback5) || \ + _curl_callback_compatible((expr), _curl_debug_callback6) || \ + _curl_callback_compatible((expr), _curl_debug_callback7) || \ + _curl_callback_compatible((expr), _curl_debug_callback8)) +typedef int (_curl_debug_callback1) (CURL *, + curl_infotype, char *, size_t, void *); +typedef int (_curl_debug_callback2) (CURL *, + curl_infotype, char *, size_t, const void *); +typedef int (_curl_debug_callback3) (CURL *, + curl_infotype, const char *, size_t, void *); +typedef int (_curl_debug_callback4) (CURL *, + curl_infotype, const char *, size_t, const void *); +typedef int (_curl_debug_callback5) (CURL *, + curl_infotype, unsigned char *, size_t, void *); +typedef int (_curl_debug_callback6) (CURL *, + curl_infotype, unsigned char *, size_t, const void *); +typedef int (_curl_debug_callback7) (CURL *, + curl_infotype, const unsigned char *, size_t, void *); +typedef int (_curl_debug_callback8) (CURL *, + curl_infotype, const unsigned char *, size_t, const void *); + +/* evaluates to true if expr is of type curl_ssl_ctx_callback or "similar" */ +/* this is getting even messier... */ +#define _curl_is_ssl_ctx_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_ssl_ctx_callback) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback1) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback2) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback3) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback4) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback5) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback6) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback7) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback8)) +typedef CURLcode (_curl_ssl_ctx_callback1)(CURL *, void *, void *); +typedef CURLcode (_curl_ssl_ctx_callback2)(CURL *, void *, const void *); +typedef CURLcode (_curl_ssl_ctx_callback3)(CURL *, const void *, void *); +typedef CURLcode (_curl_ssl_ctx_callback4)(CURL *, const void *, const void *); +#ifdef HEADER_SSL_H +/* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX + * this will of course break if we're included before OpenSSL headers... + */ +typedef CURLcode (_curl_ssl_ctx_callback5)(CURL *, SSL_CTX, void *); +typedef CURLcode (_curl_ssl_ctx_callback6)(CURL *, SSL_CTX, const void *); +typedef CURLcode (_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX, void *); +typedef CURLcode (_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX, + const void *); +#else +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback5; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback6; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback7; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback8; +#endif + +/* evaluates to true if expr is of type curl_conv_callback or "similar" */ +#define _curl_is_conv_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_conv_callback) || \ + _curl_callback_compatible((expr), _curl_conv_callback1) || \ + _curl_callback_compatible((expr), _curl_conv_callback2) || \ + _curl_callback_compatible((expr), _curl_conv_callback3) || \ + _curl_callback_compatible((expr), _curl_conv_callback4)) +typedef CURLcode (*_curl_conv_callback1)(char *, size_t length); +typedef CURLcode (*_curl_conv_callback2)(const char *, size_t length); +typedef CURLcode (*_curl_conv_callback3)(void *, size_t length); +typedef CURLcode (*_curl_conv_callback4)(const void *, size_t length); + +/* evaluates to true if expr is of type curl_seek_callback or "similar" */ +#define _curl_is_seek_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_seek_callback) || \ + _curl_callback_compatible((expr), _curl_seek_callback1) || \ + _curl_callback_compatible((expr), _curl_seek_callback2)) +typedef CURLcode (*_curl_seek_callback1)(void *, curl_off_t, int); +typedef CURLcode (*_curl_seek_callback2)(const void *, curl_off_t, int); + + +#endif /* __CURL_TYPECHECK_GCC_H */ diff --git a/deps/libcurl/lib/libcurl.a b/deps/libcurl/lib/libcurl.a new file mode 100644 index 0000000000000000000000000000000000000000..c63ac70946dddefb5b3b5c55cf82d693b731cad6 GIT binary patch literal 734534 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%0DG{5m+^rE4)0H+Ku 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

w>7VBN-LHvu!|8uCifk-+C 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

<3Z}35sM>}2X|wq+)i%U-lwl$ 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 N<0od0zgoUY`u_?Ma^nC1 literal 0 HcmV?d00001 diff --git a/src/kit/CMakeLists.txt b/src/kit/CMakeLists.txt index 66e8cf7398..bf52784300 100644 --- a/src/kit/CMakeLists.txt +++ b/src/kit/CMakeLists.txt @@ -3,4 +3,5 @@ PROJECT(TDengine) ADD_SUBDIRECTORY(shell) ADD_SUBDIRECTORY(taosdemo) +ADD_SUBDIRECTORY(taosdemox) ADD_SUBDIRECTORY(taosdump) diff --git a/src/kit/taosdemox/CMakeLists.txt b/src/kit/taosdemox/CMakeLists.txt new file mode 100644 index 0000000000..3f5e725aea --- /dev/null +++ b/src/kit/taosdemox/CMakeLists.txt @@ -0,0 +1,25 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) +PROJECT(TDengine) + +INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/src/client/inc) +INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/libcurl/include) + +IF (TD_LINUX) + AUX_SOURCE_DIRECTORY(. SRC) + ADD_EXECUTABLE(taosdemox ${SRC}) + + #find_program(HAVE_CURL NAMES curl) + IF ((NOT TD_ARM_64) AND (NOT TD_ARM_32)) + ADD_DEFINITIONS(-DTD_LOWA_CURL) + LINK_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/libcurl/lib) + ADD_LIBRARY(curl STATIC IMPORTED) + SET_PROPERTY(TARGET curl PROPERTY IMPORTED_LOCATION ${TD_COMMUNITY_DIR}/deps/libcurl/lib/libcurl.a) + TARGET_LINK_LIBRARIES(taosdemox curl) + ENDIF () + + IF (TD_SOMODE_STATIC) + TARGET_LINK_LIBRARIES(taosdemox taos_static cJson) + ELSE () + TARGET_LINK_LIBRARIES(taosdemox taos cJson) + ENDIF () +ENDIF () diff --git a/src/kit/taosdemox/insert.json b/src/kit/taosdemox/insert.json new file mode 100644 index 0000000000..88416c13a4 --- /dev/null +++ b/src/kit/taosdemox/insert.json @@ -0,0 +1,53 @@ +{ + "filetype": "insert", + "cfgdir": "/etc/taos", + "host": "127.0.0.1", + "port": 6030, + "user": "root", + "password": "taosdata", + "thread_count": 2, + "result_file": "./insert_res.txt", + "databases": [{ + "dbinfo": { + "name": "db", + "drop": "no", + "replica": 1, + "days": 2, + "cache": 16, + "blocks": 8, + "precision": "ms", + "keep": 365, + "minRows": 100, + "maxRows": 4096, + "comp":2, + "walLevel":1, + "quorum":1, + "fsync":3000, + "update": 0 + }, + "super_tables": [{ + "name": "stb", + "child_table_exists":"no", + "childtable_count": 1, + "childtable_prefix": "stb_", + "auto_create_table": "no", + "data_source": "rand", + "insert_mode": "taosc", + "insert_rate": 0, + "insert_rows": 100000, + "multi_thread_write_one_tbl": "no", + "number_of_tbl_in_one_sql": 1, + "rows_per_tbl": 100, + "max_sql_len": 1024000, + "disorder_ratio": 0, + "disorder_range": 1000, + "timestamp_step": 10, + "start_timestamp": "2020-10-01 00:00:00.000", + "sample_format": "csv", + "sample_file": "./sample.csv", + "tags_file": "", + "columns": [{"type": "INT"}, {"type": "DOUBLE", "count":10}, {"type": "BINARY", "len": 16, "count":3}, {"type": "BINARY", "len": 32, "count":6}], + "tags": [{"type": "TINYINT", "count":2}, {"type": "BINARY", "len": 16, "count":5}] + }] + }] +} diff --git a/src/kit/taosdemox/query.json b/src/kit/taosdemox/query.json new file mode 100644 index 0000000000..53d0b31921 --- /dev/null +++ b/src/kit/taosdemox/query.json @@ -0,0 +1,17 @@ +{ + "filetype":"query", + "cfgdir": "/etc/taos", + "host": "127.0.0.1", + "port": 6030, + "user": "root", + "password": "taosdata", + "databases": "db01", + "super_table_query": + {"rate":1, "concurrent":1, + "sqls": [{"sql": "select count(*) from stb01", "result": "./query_res0.txt"}] + }, + "sub_table_query": + {"stblname": "stb01", "rate":1, "threads":1, + "sqls": [{"sql": "select count(*) from xxxx", "result": "./query_res1.txt"}] + } +} diff --git a/src/kit/taosdemox/subscribe.json b/src/kit/taosdemox/subscribe.json new file mode 100644 index 0000000000..6dfacdd6ed --- /dev/null +++ b/src/kit/taosdemox/subscribe.json @@ -0,0 +1,17 @@ +{ + "filetype":"subscribe", + "cfgdir": "/etc/taos", + "host": "127.0.0.1", + "port": 6030, + "user": "root", + "password": "taosdata", + "databases": "db01", + "super_table_query": + {"concurrent":1, "mode":"sync", "interval":5000, "restart":"yes", "keepProgress":"yes", + "sqls": [{"sql": "select avg(c1) from stb01 where col1 > 1;", "result": "./subscribe_res0.txt"}] + }, + "sub_table_query": + {"stblname": "stb01", "threads":1, "mode":"sync", "interval":10000, "restart":"yes", "keepProgress":"yes", + "sqls": [{"sql": "select col1 from xxxx where col1 > 10;", "result": "./subscribe_res1.txt"}] + } +} diff --git a/src/kit/taosdemox/taosdemox.c b/src/kit/taosdemox/taosdemox.c new file mode 100644 index 0000000000..8cf6330cf4 --- /dev/null +++ b/src/kit/taosdemox/taosdemox.c @@ -0,0 +1,4621 @@ +/* + * 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 . + */ + + +/* + when in some thread query return error, thread don't exit, but return, otherwise coredump in other thread. +*/ + +#define _GNU_SOURCE +#define CURL_STATICLIB + +#ifdef TD_LOWA_CURL +#include "curl/curl.h" +#endif + +#ifdef LINUX + #include "os.h" + #include "cJSON.h" + #include + #include + #include + #ifndef _ALPINE + #include + #endif + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include +#else + #include + #include + #include + #include "os.h" + + #pragma comment ( lib, "libcurl.lib" ) + #pragma comment ( lib, "ws2_32.lib" ) + #pragma comment ( lib, "winmm.lib" ) + #pragma comment ( lib, "wldap32.lib" ) +#endif + +#include "taos.h" +#include "tutil.h" + +extern char configDir[]; + +#define INSERT_JSON_NAME "insert.json" +#define QUERY_JSON_NAME "query.json" +#define SUBSCRIBE_JSON_NAME "subscribe.json" + +#define INSERT_MODE 0 +#define QUERY_MODE 1 +#define SUBSCRIBE_MODE 2 + +#define MAX_SQL_SIZE 65536 +#define BUFFER_SIZE (65536*2) +#define MAX_DB_NAME_SIZE 64 +#define MAX_TB_NAME_SIZE 64 +#define MAX_DATA_SIZE 16000 +#define MAX_NUM_DATATYPE 10 +#define OPT_ABORT 1 /* –abort */ +#define STRING_LEN 60000 +#define MAX_PREPARED_RAND 1000000 +//#define MAX_SQL_SIZE 65536 +#define MAX_FILE_NAME_LEN 256 + +#define MAX_SAMPLES_ONCE_FROM_FILE 10000 +#define MAX_NUM_DATATYPE 10 + +#define MAX_DB_COUNT 8 +#define MAX_SUPER_TABLE_COUNT 8 +#define MAX_COLUMN_COUNT 1024 +#define MAX_TAG_COUNT 128 + +#define MAX_QUERY_SQL_COUNT 10 +#define MAX_QUERY_SQL_LENGTH 256 + + +#define MAX_LINE_COUNT_IN_MEM 10000 + +typedef enum CREATE_SUB_TALBE_MOD_EN { + PRE_CREATE_SUBTBL, + AUTO_CREATE_SUBTBL, + NO_CREATE_SUBTBL +} CREATE_SUB_TALBE_MOD_EN; + +typedef enum TALBE_EXISTS_EN { + TBL_ALREADY_EXISTS, + TBL_NO_EXISTS, + TBL_EXISTS_BUTT +} TALBE_EXISTS_EN; + +enum MODE { + SYNC, + ASYNC, + MODE_BUT +}; + +enum QUERY_TYPE { + NO_INSERT_TYPE, + INSERT_TYPE, + QUERY_TYPE_BUT +} ; + +enum _describe_table_index { + TSDB_DESCRIBE_METRIC_FIELD_INDEX, + TSDB_DESCRIBE_METRIC_TYPE_INDEX, + TSDB_DESCRIBE_METRIC_LENGTH_INDEX, + TSDB_DESCRIBE_METRIC_NOTE_INDEX, + TSDB_MAX_DESCRIBE_METRIC +}; + +typedef struct { + char field[TSDB_COL_NAME_LEN + 1]; + char type[16]; + int length; + char note[128]; +} SColDes; + +/* Used by main to communicate with parse_opt. */ +typedef struct SArguments_S { + char * metaFile; + char * host; + uint16_t port; + char * user; + char * password; + char * database; + int replica; + char * tb_prefix; + char * sqlFile; + bool use_metric; + bool insert_only; + char * output_file; + int mode; + char * datatype[MAX_NUM_DATATYPE + 1]; + int len_of_binary; + int num_of_CPR; + int num_of_threads; + int num_of_RPR; + int num_of_tables; + int num_of_DPT; + int abort; + int disorderRatio; + int disorderRange; + int method_of_delete; + char ** arg_list; +} SArguments; + +typedef struct SColumn_S { + char field[TSDB_COL_NAME_LEN + 1]; + char dataType[MAX_TB_NAME_SIZE]; + int dataLen; + char note[128]; +} StrColumn; + +typedef struct SSuperTable_S { + char sTblName[MAX_TB_NAME_SIZE]; + int childTblCount; + bool superTblExists; // 0: no, 1: yes + bool childTblExists; // 0: no, 1: yes + int8_t autoCreateTable; // 0: create sub table, 1: auto create sub table + char childTblPrefix[MAX_TB_NAME_SIZE]; + char dataSource[MAX_TB_NAME_SIZE]; // rand_gen or sample + char insertMode[MAX_TB_NAME_SIZE]; // taosc, restful + int insertRate; // 0: unlimit > 0 rows/s + + int multiThreadWriteOneTbl; // 0: no, 1: yes + int numberOfTblInOneSql; // 0/1: one table, > 1: number of tbl + int rowsPerTbl; // + int disorderRatio; // 0: no disorder, >0: x% + int disorderRange; // ms or us by database precision + int maxSqlLen; // + + int64_t insertRows; // 0: no limit + int timeStampStep; + char startTimestamp[MAX_TB_NAME_SIZE]; // + char sampleFormat[MAX_TB_NAME_SIZE]; // csv, json + char sampleFile[MAX_FILE_NAME_LEN]; + char tagsFile[MAX_FILE_NAME_LEN]; + + int columnCount; + StrColumn columns[MAX_COLUMN_COUNT]; + int tagCount; + StrColumn tags[MAX_TAG_COUNT]; + + char* childTblName; + char* colsOfCreatChildTable; + int lenOfOneRow; + int lenOfTagOfOneRow; + + char* sampleDataBuf; + int sampleDataBufSize; + //int sampleRowCount; + //int sampleUsePos; + + int tagSource; // 0: rand, 1: tag sample + char* tagDataBuf; + int tagSampleCount; + int tagUsePos; + + // statistics + int64_t totalRowsInserted; + int64_t totalAffectedRows; +} SSuperTable; + +typedef struct SDbCfg_S { +// int maxtablesPerVnode; + int minRows; + int maxRows; + int comp; + int walLevel; + int fsync; + int replica; + int update; + int keep; + int days; + int cache; + int blocks; + int quorum; + char precision[MAX_TB_NAME_SIZE]; +} SDbCfg; + +typedef struct SDataBase_S { + char dbName[MAX_DB_NAME_SIZE]; + int drop; // 0: use exists, 1: if exists, drop then new create + SDbCfg dbCfg; + int superTblCount; + SSuperTable superTbls[MAX_SUPER_TABLE_COUNT]; +} SDataBase; + +typedef struct SDbs_S { + char cfgDir[MAX_FILE_NAME_LEN]; + char host[MAX_DB_NAME_SIZE]; + uint16_t port; + char user[MAX_DB_NAME_SIZE]; + char password[MAX_DB_NAME_SIZE]; + char resultFile[MAX_FILE_NAME_LEN]; + bool use_metric; + bool insert_only; + bool do_aggreFunc; + bool queryMode; + + int threadCount; + int dbCount; + SDataBase db[MAX_DB_COUNT]; + + // statistics + int64_t totalRowsInserted; + int64_t totalAffectedRows; +} SDbs; + +typedef struct SuperQueryInfo_S { + int rate; // 0: unlimit > 0 loop/s + int concurrent; + int sqlCount; + int subscribeMode; // 0: sync, 1: async + int subscribeInterval; // ms + int subscribeRestart; + int subscribeKeepProgress; + char sql[MAX_QUERY_SQL_COUNT][MAX_QUERY_SQL_LENGTH]; + char result[MAX_QUERY_SQL_COUNT][MAX_FILE_NAME_LEN]; + TAOS_SUB* tsub[MAX_QUERY_SQL_COUNT]; +} SuperQueryInfo; + +typedef struct SubQueryInfo_S { + char sTblName[MAX_TB_NAME_SIZE]; + int rate; // 0: unlimit > 0 loop/s + int threadCnt; + int subscribeMode; // 0: sync, 1: async + int subscribeInterval; // ms + int subscribeRestart; + int subscribeKeepProgress; + int childTblCount; + char childTblPrefix[MAX_TB_NAME_SIZE]; + int sqlCount; + char sql[MAX_QUERY_SQL_COUNT][MAX_QUERY_SQL_LENGTH]; + char result[MAX_QUERY_SQL_COUNT][MAX_FILE_NAME_LEN]; + TAOS_SUB* tsub[MAX_QUERY_SQL_COUNT]; + + char* childTblName; +} SubQueryInfo; + +typedef struct SQueryMetaInfo_S { + char cfgDir[MAX_FILE_NAME_LEN]; + char host[MAX_DB_NAME_SIZE]; + uint16_t port; + char user[MAX_DB_NAME_SIZE]; + char password[MAX_DB_NAME_SIZE]; + char dbName[MAX_DB_NAME_SIZE]; + char queryMode[MAX_TB_NAME_SIZE]; // taosc, restful + + SuperQueryInfo superQueryInfo; + SubQueryInfo subQueryInfo; +} SQueryMetaInfo; + +typedef struct SThreadInfo_S { + TAOS *taos; + #ifdef TD_LOWA_CURL + CURL *curl_handle; + #endif + int threadID; + char db_name[MAX_DB_NAME_SIZE]; + char fp[4096]; + char tb_prefix[MAX_TB_NAME_SIZE]; + int start_table_id; + int end_table_id; + int data_of_rate; + int64_t start_time; + char* cols; + bool use_metric; + SSuperTable* superTblInfo; + + // for async insert + tsem_t lock_sem; + int64_t counter; + int64_t st; + int64_t et; + int64_t lastTs; + int nrecords_per_request; + + // statistics + int64_t totalRowsInserted; + int64_t totalAffectedRows; +} threadInfo; + +typedef struct curlMemInfo_S { + char *buf; + size_t sizeleft; + } curlMemInfo; + + + +#ifdef LINUX + /* The options we understand. */ + static struct argp_option options[] = { + {0, 'f', "meta file", 0, "The meta data to the execution procedure, if use -f, all others options invalid. Default is NULL.", 0}, + #ifdef _TD_POWER_ + {0, 'c', "config_directory", 0, "Configuration directory. Default is '/etc/power/'.", 1}, + {0, 'P', "password", 0, "The password to use when connecting to the server. Default is 'powerdb'.", 2}, + #else + {0, 'c', "config_directory", 0, "Configuration directory. Default is '/etc/taos/'.", 1}, + {0, 'P', "password", 0, "The password to use when connecting to the server. Default is 'taosdata'.", 2}, + #endif + {0, 'h', "host", 0, "The host to connect to TDengine. Default is localhost.", 2}, + {0, 'p', "port", 0, "The TCP/IP port number to use for the connection. Default is 0.", 2}, + {0, 'u', "user", 0, "The TDengine user name to use when connecting to the server. Default is 'root'.", 2}, + {0, 'd', "database", 0, "Destination database. Default is 'test'.", 3}, + {0, 'a', "replica", 0, "Set the replica parameters of the database, Default 1, min: 1, max: 3.", 4}, + {0, 'm', "table_prefix", 0, "Table prefix name. Default is 't'.", 4}, + {0, 's', "sql file", 0, "The select sql file.", 6}, + {0, 'M', 0, 0, "Use metric flag.", 4}, + {0, 'o', "outputfile", 0, "Direct output to the named file. Default is './output.txt'.", 6}, + {0, 'q', "query_mode", 0, "Query mode--0: SYNC, 1: ASYNC. Default is SYNC.", 4}, + {0, 'b', "type_of_cols", 0, "The data_type of columns, default: TINYINT,SMALLINT,INT,BIGINT,FLOAT,DOUBLE,BINARY,NCHAR,BOOL,TIMESTAMP.", 4}, + {0, 'w', "length_of_chartype", 0, "The length of data_type 'BINARY' or 'NCHAR'. Default is 16", 4}, + {0, 'l', "num_of_cols_per_record", 0, "The number of columns per record. Default is 10.", 4}, + {0, 'T', "num_of_threads", 0, "The number of threads. Default is 10.", 4}, + // {0, 'r', "num_of_records_per_req", 0, "The number of records per request. Default is 100.", 4}, + {0, 't', "num_of_tables", 0, "The number of tables. Default is 10000.", 4}, + {0, 'n', "num_of_records_per_table", 0, "The number of records per table. Default is 10000.", 4}, + {0, 'x', 0, 0, "Not insert only flag.", 4}, + {0, 'O', "disorderRatio", 0, "Insert mode--0: In order, > 0: disorder ratio. Default is in order.", 4}, + {0, 'R', "disorderRang", 0, "Out of order data's range, ms, default is 1000.", 4}, + //{0, 'D', "delete database", 0, "if elete database if exists. 0: no, 1: yes, default is 1", 5}, + {0}}; + +/* Parse a single option. */ +static error_t parse_opt(int key, char *arg, struct argp_state *state) { + // Get the input argument from argp_parse, which we know is a pointer to our arguments structure. + SArguments *arguments = state->input; + wordexp_t full_path; + char **sptr; + switch (key) { + case 'f': + arguments->metaFile = arg; + break; + case 'h': + arguments->host = arg; + break; + case 'p': + arguments->port = atoi(arg); + break; + case 'u': + arguments->user = arg; + break; + case 'P': + arguments->password = arg; + break; + case 'o': + arguments->output_file = arg; + break; + case 's': + arguments->sqlFile = arg; + break; + case 'q': + arguments->mode = atoi(arg); + break; + case 'T': + arguments->num_of_threads = atoi(arg); + break; + //case 'r': + // arguments->num_of_RPR = atoi(arg); + // break; + case 't': + arguments->num_of_tables = atoi(arg); + break; + case 'n': + arguments->num_of_DPT = atoi(arg); + break; + case 'd': + arguments->database = arg; + break; + case 'l': + arguments->num_of_CPR = atoi(arg); + break; + case 'b': + sptr = arguments->datatype; + if (strstr(arg, ",") == NULL) { + if (strcasecmp(arg, "INT") != 0 && strcasecmp(arg, "FLOAT") != 0 && + strcasecmp(arg, "TINYINT") != 0 && strcasecmp(arg, "BOOL") != 0 && + strcasecmp(arg, "SMALLINT") != 0 && strcasecmp(arg, "TIMESTAMP") != 0 && + strcasecmp(arg, "BIGINT") != 0 && strcasecmp(arg, "DOUBLE") != 0 && + strcasecmp(arg, "BINARY") != 0 && strcasecmp(arg, "NCHAR") != 0) { + argp_error(state, "Invalid data_type!"); + } + sptr[0] = arg; + } else { + int index = 0; + char *dupstr = strdup(arg); + char *running = dupstr; + char *token = strsep(&running, ","); + while (token != NULL) { + if (strcasecmp(token, "INT") != 0 && strcasecmp(token, "FLOAT") != 0 && + strcasecmp(token, "TINYINT") != 0 && strcasecmp(token, "BOOL") != 0 && + strcasecmp(token, "SMALLINT") != 0 && strcasecmp(token, "TIMESTAMP") != 0 && + strcasecmp(token, "BIGINT") != 0 && strcasecmp(token, "DOUBLE") != 0 && + strcasecmp(token, "BINARY") != 0 && strcasecmp(token, "NCHAR") != 0) { + argp_error(state, "Invalid data_type!"); + } + sptr[index++] = token; + token = strsep(&running, ","); + if (index >= MAX_NUM_DATATYPE) break; + } + } + break; + case 'w': + arguments->len_of_binary = atoi(arg); + break; + case 'm': + arguments->tb_prefix = arg; + break; + case 'M': + arguments->use_metric = true; + break; + case 'x': + arguments->insert_only = false; + break; + case 'c': + if (wordexp(arg, &full_path, 0) != 0) { + fprintf(stderr, "Invalid path %s\n", arg); + return -1; + } + taos_options(TSDB_OPTION_CONFIGDIR, full_path.we_wordv[0]); + wordfree(&full_path); + break; + case 'O': + arguments->disorderRatio = atoi(arg); + if (arguments->disorderRatio < 0 || arguments->disorderRatio > 100) + { + argp_error(state, "Invalid disorder ratio, should 1 ~ 100!"); + } + break; + case 'R': + arguments->disorderRange = atoi(arg); + break; + case 'a': + arguments->replica = atoi(arg); + if (arguments->replica > 3 || arguments->replica < 1) + { + arguments->replica = 1; + } + break; + //case 'D': + // arguments->method_of_delete = atoi(arg); + // break; + case OPT_ABORT: + arguments->abort = 1; + break; + case ARGP_KEY_ARG: + /*arguments->arg_list = &state->argv[state->next-1]; + state->next = state->argc;*/ + argp_usage(state); + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static struct argp argp = {options, parse_opt, 0, 0}; + +void parse_args(int argc, char *argv[], SArguments *arguments) { + argp_parse(&argp, argc, argv, 0, 0, arguments); + if (arguments->abort) { + #ifndef _ALPINE + error(10, 0, "ABORTED"); + #else + abort(); + #endif + } +} + +#else + void printHelp() { + char indent[10] = " "; + printf("%s%s\n", indent, "-f"); + printf("%s%s%s\n", indent, indent, "The meta file to the execution procedure. Default is './meta.json'."); + printf("%s%s\n", indent, "-c"); + printf("%s%s%s\n", indent, indent, "config_directory, Configuration directory. Default is '/etc/taos/'."); + } + + void parse_args(int argc, char *argv[], SArguments *arguments) { + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "-f") == 0) { + arguments->metaFile = argv[++i]; + } else if (strcmp(argv[i], "-c") == 0) { + strcpy(configDir, argv[++i]); + } else if (strcmp(argv[i], "--help") == 0) { + printHelp(); + exit(EXIT_FAILURE); + } else { + fprintf(stderr, "wrong options\n"); + printHelp(); + exit(EXIT_FAILURE); + } + } + } +#endif + +static bool getInfoFromJsonFile(char* file); +//static int generateOneRowDataForStb(SSuperTable* stbInfo); +//static int getDataIntoMemForStb(SSuperTable* stbInfo); +static void init_rand_data(); +static int createDatabases(); +static void createChildTables(); +static int queryDbExec(TAOS *taos, char *command, int type); + +/* ************ Global variables ************ */ + +int32_t randint[MAX_PREPARED_RAND]; +int64_t randbigint[MAX_PREPARED_RAND]; +float randfloat[MAX_PREPARED_RAND]; +double randdouble[MAX_PREPARED_RAND]; +char *aggreFunc[] = {"*", "count(*)", "avg(col0)", "sum(col0)", "max(col0)", "min(col0)", "first(col0)", "last(col0)"}; + +SArguments g_args = {NULL, + "127.0.0.1", // host + 6030, // port + "root", // user + #ifdef _TD_POWER_ + "powerdb", // password + #else + "taosdata", // password + #endif + "test", // database + 1, // replica + "t", // tb_prefix + NULL, // sqlFile + false, // use_metric + true, // insert_only + "./output.txt", // output_file + 0, // mode : sync or async + { + "TINYINT", // datatype + "SMALLINT", + "INT", + "BIGINT", + "FLOAT", + "DOUBLE", + "BINARY", + "NCHAR", + "BOOL", + "TIMESTAMP" + }, + 16, // len_of_binary + 10, // num_of_CPR + 10, // num_of_connections/thread + 100, // num_of_RPR + 10000, // num_of_tables + 10000, // num_of_DPT + 0, // abort + 0, // disorderRatio + 1000, // disorderRange + 1, // method_of_delete + NULL // arg_list +}; + + +static int g_jsonType = 0; +static SDbs g_Dbs; +static int g_totalChildTables = 0; +static SQueryMetaInfo g_queryInfo; +static FILE * g_fpOfInsertResult = NULL; + + +void tmfclose(FILE *fp) { + if (NULL != fp) { + fclose(fp); + } +} + +void tmfree(char *buf) { + if (NULL != buf) { + free(buf); + } +} + +static int queryDbExec(TAOS *taos, char *command, int type) { + int i; + TAOS_RES *res = NULL; + int32_t code = -1; + + for (i = 0; i < 5; i++) { + if (NULL != res) { + taos_free_result(res); + res = NULL; + } + + res = taos_query(taos, command); + code = taos_errno(res); + if (0 == code) { + break; + } + } + + if (code != 0) { + fprintf(stderr, "Failed to run %s, reason: %s\n", command, taos_errstr(res)); + taos_free_result(res); + //taos_close(taos); + return -1; + } + + if (INSERT_TYPE == type) { + int affectedRows = taos_affected_rows(res); + taos_free_result(res); + return affectedRows; + } + + taos_free_result(res); + return 0; +} + +static void getResult(TAOS_RES *res, char* resultFileName) { + TAOS_ROW row = NULL; + int num_rows = 0; + int num_fields = taos_field_count(res); + TAOS_FIELD *fields = taos_fetch_fields(res); + + FILE *fp = NULL; + if (resultFileName[0] != 0) { + fp = fopen(resultFileName, "at"); + if (fp == NULL) { + fprintf(stderr, "failed to open result file: %s, result will not save to file\n", resultFileName); + } + } + + char* databuf = (char*) calloc(1, 100*1024*1024); + if (databuf == NULL) { + fprintf(stderr, "failed to malloc, warning: save result to file slowly!\n"); + return ; + } + + int totalLen = 0; + char temp[16000]; + + // fetch the records row by row + while ((row = taos_fetch_row(res))) { + if (totalLen >= 100*1024*1024 - 32000) { + if (fp) fprintf(fp, "%s", databuf); + totalLen = 0; + memset(databuf, 0, 100*1024*1024); + } + num_rows++; + int len = taos_print_row(temp, row, fields, num_fields); + len += sprintf(temp + len, "\n"); + //printf("query result:%s\n", temp); + memcpy(databuf + totalLen, temp, len); + totalLen += len; + } + + if (fp) fprintf(fp, "%s", databuf); + tmfclose(fp); + free(databuf); +} + +static void selectAndGetResult(TAOS *taos, char *command, char* resultFileName) { + TAOS_RES *res = taos_query(taos, command); + if (res == NULL || taos_errno(res) != 0) { + printf("failed to sql:%s, reason:%s\n", command, taos_errstr(res)); + taos_free_result(res); + return; + } + + getResult(res, resultFileName); + taos_free_result(res); +} + +double getCurrentTime() { + struct timeval tv; + if (gettimeofday(&tv, NULL) != 0) { + perror("Failed to get current time in ms"); + return 0.0; + } + + return tv.tv_sec + tv.tv_usec / 1E6; +} + +static int32_t rand_bool(){ + static int cursor; + cursor++; + cursor = cursor % MAX_PREPARED_RAND; + return randint[cursor] % 2; +} + +static int32_t rand_tinyint(){ + static int cursor; + cursor++; + cursor = cursor % MAX_PREPARED_RAND; + return randint[cursor] % 128; +} + +static int32_t rand_smallint(){ + static int cursor; + cursor++; + cursor = cursor % MAX_PREPARED_RAND; + return randint[cursor] % 32767; +} + +static int32_t rand_int(){ + static int cursor; + cursor++; + cursor = cursor % MAX_PREPARED_RAND; + return randint[cursor]; +} + +static int64_t rand_bigint(){ + static int cursor; + cursor++; + cursor = cursor % MAX_PREPARED_RAND; + return randbigint[cursor]; + +} + +static float rand_float(){ + static int cursor; + cursor++; + cursor = cursor % MAX_PREPARED_RAND; + return randfloat[cursor]; +} + +static const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; +void rand_string(char *str, int size) { + str[0] = 0; + if (size > 0) { + //--size; + int n; + for (n = 0; n < size; n++) { + int key = rand_tinyint() % (int)(sizeof(charset) - 1); + str[n] = charset[key]; + } + str[n] = 0; + } +} + +static double rand_double() { + static int cursor; + cursor++; + cursor = cursor % MAX_PREPARED_RAND; + return randdouble[cursor]; + +} + +static void init_rand_data() { + for (int i = 0; i < MAX_PREPARED_RAND; i++){ + randint[i] = (int)(rand() % 65535); + randbigint[i] = (int64_t)(rand() % 2147483648); + randfloat[i] = (float)(rand() / 1000.0); + randdouble[i] = (double)(rand() / 1000000.0); + } +} + +static void printfInsertMeta() { + printf("\033[1m\033[40;32m================ insert.json parse result START ================\033[0m\n"); + printf("host: \033[33m%s:%u\033[0m\n", g_Dbs.host, g_Dbs.port); + printf("user: \033[33m%s\033[0m\n", g_Dbs.user); + printf("password: \033[33m%s\033[0m\n", g_Dbs.password); + printf("resultFile: \033[33m%s\033[0m\n", g_Dbs.resultFile); + printf("thread count: \033[33m%d\033[0m\n", g_Dbs.threadCount); + + printf("database count: \033[33m%d\033[0m\n", g_Dbs.dbCount); + for (int i = 0; i < g_Dbs.dbCount; i++) { + printf("database[\033[33m%d\033[0m]:\n", i); + printf(" database name: \033[33m%s\033[0m\n", g_Dbs.db[i].dbName); + if (0 == g_Dbs.db[i].drop) { + printf(" drop: \033[33mno\033[0m\n"); + }else { + printf(" drop: \033[33myes\033[0m\n"); + } + + if (g_Dbs.db[i].dbCfg.blocks > 0) { + printf(" blocks: \033[33m%d\033[0m\n", g_Dbs.db[i].dbCfg.blocks); + } + if (g_Dbs.db[i].dbCfg.cache > 0) { + printf(" cache: \033[33m%d\033[0m\n", g_Dbs.db[i].dbCfg.cache); + } + if (g_Dbs.db[i].dbCfg.days > 0) { + printf(" days: \033[33m%d\033[0m\n", g_Dbs.db[i].dbCfg.days); + } + if (g_Dbs.db[i].dbCfg.keep > 0) { + printf(" keep: \033[33m%d\033[0m\n", g_Dbs.db[i].dbCfg.keep); + } + if (g_Dbs.db[i].dbCfg.replica > 0) { + printf(" replica: \033[33m%d\033[0m\n", g_Dbs.db[i].dbCfg.replica); + } + if (g_Dbs.db[i].dbCfg.update > 0) { + printf(" update: \033[33m%d\033[0m\n", g_Dbs.db[i].dbCfg.update); + } + if (g_Dbs.db[i].dbCfg.minRows > 0) { + printf(" minRows: \033[33m%d\033[0m\n", g_Dbs.db[i].dbCfg.minRows); + } + if (g_Dbs.db[i].dbCfg.maxRows > 0) { + printf(" maxRows: \033[33m%d\033[0m\n", g_Dbs.db[i].dbCfg.maxRows); + } + if (g_Dbs.db[i].dbCfg.comp > 0) { + printf(" comp: \033[33m%d\033[0m\n", g_Dbs.db[i].dbCfg.comp); + } + if (g_Dbs.db[i].dbCfg.walLevel > 0) { + printf(" walLevel: \033[33m%d\033[0m\n", g_Dbs.db[i].dbCfg.walLevel); + } + if (g_Dbs.db[i].dbCfg.fsync > 0) { + printf(" fsync: \033[33m%d\033[0m\n", g_Dbs.db[i].dbCfg.fsync); + } + if (g_Dbs.db[i].dbCfg.quorum > 0) { + printf(" quorum: \033[33m%d\033[0m\n", g_Dbs.db[i].dbCfg.quorum); + } + if (g_Dbs.db[i].dbCfg.precision[0] != 0) { + if ((0 == strncasecmp(g_Dbs.db[i].dbCfg.precision, "ms", 2)) || (0 == strncasecmp(g_Dbs.db[i].dbCfg.precision, "us", 2))) { + printf(" precision: \033[33m%s\033[0m\n", g_Dbs.db[i].dbCfg.precision); + } else { + printf(" precision error: \033[33m%s\033[0m\n", g_Dbs.db[i].dbCfg.precision); + exit(EXIT_FAILURE); + } + } + + printf(" super table count: \033[33m%d\033[0m\n", g_Dbs.db[i].superTblCount); + for (int j = 0; j < g_Dbs.db[i].superTblCount; j++) { + printf(" super table[\033[33m%d\033[0m]:\n", j); + + printf(" stbName: \033[33m%s\033[0m\n", g_Dbs.db[i].superTbls[j].sTblName); + + if (PRE_CREATE_SUBTBL == g_Dbs.db[i].superTbls[j].autoCreateTable) { + printf(" autoCreateTable: \033[33m%s\033[0m\n", "no"); + } else if (AUTO_CREATE_SUBTBL == g_Dbs.db[i].superTbls[j].autoCreateTable) { + printf(" autoCreateTable: \033[33m%s\033[0m\n", "yes"); + } else { + printf(" autoCreateTable: \033[33m%s\033[0m\n", "error"); + } + + if (TBL_NO_EXISTS == g_Dbs.db[i].superTbls[j].childTblExists) { + printf(" childTblExists: \033[33m%s\033[0m\n", "no"); + } else if (TBL_ALREADY_EXISTS == g_Dbs.db[i].superTbls[j].childTblExists) { + printf(" childTblExists: \033[33m%s\033[0m\n", "yes"); + } else { + printf(" childTblExists: \033[33m%s\033[0m\n", "error"); + } + + printf(" childTblCount: \033[33m%d\033[0m\n", g_Dbs.db[i].superTbls[j].childTblCount); + printf(" childTblPrefix: \033[33m%s\033[0m\n", g_Dbs.db[i].superTbls[j].childTblPrefix); + printf(" dataSource: \033[33m%s\033[0m\n", g_Dbs.db[i].superTbls[j].dataSource); + printf(" insertMode: \033[33m%s\033[0m\n", g_Dbs.db[i].superTbls[j].insertMode); + printf(" insertRate: \033[33m%d\033[0m\n", g_Dbs.db[i].superTbls[j].insertRate); + printf(" insertRows: \033[33m%"PRId64"\033[0m\n", g_Dbs.db[i].superTbls[j].insertRows); + + if (0 == g_Dbs.db[i].superTbls[j].multiThreadWriteOneTbl) { + printf(" multiThreadWriteOneTbl: \033[33mno\033[0m\n"); + }else { + printf(" multiThreadWriteOneTbl: \033[33myes\033[0m\n"); + } + printf(" numberOfTblInOneSql: \033[33m%d\033[0m\n", g_Dbs.db[i].superTbls[j].numberOfTblInOneSql); + printf(" rowsPerTbl: \033[33m%d\033[0m\n", g_Dbs.db[i].superTbls[j].rowsPerTbl); + printf(" disorderRange: \033[33m%d\033[0m\n", g_Dbs.db[i].superTbls[j].disorderRange); + printf(" disorderRatio: \033[33m%d\033[0m\n", g_Dbs.db[i].superTbls[j].disorderRatio); + printf(" maxSqlLen: \033[33m%d\033[0m\n", g_Dbs.db[i].superTbls[j].maxSqlLen); + + printf(" timeStampStep: \033[33m%d\033[0m\n", g_Dbs.db[i].superTbls[j].timeStampStep); + printf(" startTimestamp: \033[33m%s\033[0m\n", g_Dbs.db[i].superTbls[j].startTimestamp); + printf(" sampleFormat: \033[33m%s\033[0m\n", g_Dbs.db[i].superTbls[j].sampleFormat); + printf(" sampleFile: \033[33m%s\033[0m\n", g_Dbs.db[i].superTbls[j].sampleFile); + printf(" tagsFile: \033[33m%s\033[0m\n", g_Dbs.db[i].superTbls[j].tagsFile); + + printf(" columnCount: \033[33m%d\033[0m\n ", g_Dbs.db[i].superTbls[j].columnCount); + for (int k = 0; k < g_Dbs.db[i].superTbls[j].columnCount; k++) { + //printf("dataType:%s, dataLen:%d\t", g_Dbs.db[i].superTbls[j].columns[k].dataType, g_Dbs.db[i].superTbls[j].columns[k].dataLen); + if ((0 == strncasecmp(g_Dbs.db[i].superTbls[j].columns[k].dataType, "binary", 6)) || (0 == strncasecmp(g_Dbs.db[i].superTbls[j].columns[k].dataType, "nchar", 5))) { + printf("column[\033[33m%d\033[0m]:\033[33m%s(%d)\033[0m ", k, g_Dbs.db[i].superTbls[j].columns[k].dataType, g_Dbs.db[i].superTbls[j].columns[k].dataLen); + } else { + printf("column[%d]:\033[33m%s\033[0m ", k, g_Dbs.db[i].superTbls[j].columns[k].dataType); + } + } + printf("\n"); + + printf(" tagCount: \033[33m%d\033[0m\n ", g_Dbs.db[i].superTbls[j].tagCount); + for (int k = 0; k < g_Dbs.db[i].superTbls[j].tagCount; k++) { + //printf("dataType:%s, dataLen:%d\t", g_Dbs.db[i].superTbls[j].tags[k].dataType, g_Dbs.db[i].superTbls[j].tags[k].dataLen); + if ((0 == strncasecmp(g_Dbs.db[i].superTbls[j].tags[k].dataType, "binary", 6)) || (0 == strncasecmp(g_Dbs.db[i].superTbls[j].tags[k].dataType, "nchar", 5))) { + printf("tag[%d]:\033[33m%s(%d)\033[0m ", k, g_Dbs.db[i].superTbls[j].tags[k].dataType, g_Dbs.db[i].superTbls[j].tags[k].dataLen); + } else { + printf("tag[%d]:\033[33m%s\033[0m ", k, g_Dbs.db[i].superTbls[j].tags[k].dataType); + } + } + printf("\n"); + } + printf("\n"); + } + printf("\033[1m\033[40;32m================ insert.json parse result END================\033[0m\n"); +} + +static void printfInsertMetaToFile(FILE* fp) { + fprintf(fp, "================ insert.json parse result START================\n"); + fprintf(fp, "host: %s:%u\n", g_Dbs.host, g_Dbs.port); + fprintf(fp, "user: %s\n", g_Dbs.user); + fprintf(fp, "password: %s\n", g_Dbs.password); + fprintf(fp, "resultFile: %s\n", g_Dbs.resultFile); + fprintf(fp, "thread count: %d\n", g_Dbs.threadCount); + + fprintf(fp, "database count: %d\n", g_Dbs.dbCount); + for (int i = 0; i < g_Dbs.dbCount; i++) { + fprintf(fp, "database[%d]:\n", i); + fprintf(fp, " database name: %s\n", g_Dbs.db[i].dbName); + if (0 == g_Dbs.db[i].drop) { + fprintf(fp, " drop: no\n"); + }else { + fprintf(fp, " drop: yes\n"); + } + + if (g_Dbs.db[i].dbCfg.blocks > 0) { + fprintf(fp, " blocks: %d\n", g_Dbs.db[i].dbCfg.blocks); + } + if (g_Dbs.db[i].dbCfg.cache > 0) { + fprintf(fp, " cache: %d\n", g_Dbs.db[i].dbCfg.cache); + } + if (g_Dbs.db[i].dbCfg.days > 0) { + fprintf(fp, " days: %d\n", g_Dbs.db[i].dbCfg.days); + } + if (g_Dbs.db[i].dbCfg.keep > 0) { + fprintf(fp, " keep: %d\n", g_Dbs.db[i].dbCfg.keep); + } + if (g_Dbs.db[i].dbCfg.replica > 0) { + fprintf(fp, " replica: %d\n", g_Dbs.db[i].dbCfg.replica); + } + if (g_Dbs.db[i].dbCfg.update > 0) { + fprintf(fp, " update: %d\n", g_Dbs.db[i].dbCfg.update); + } + if (g_Dbs.db[i].dbCfg.minRows > 0) { + fprintf(fp, " minRows: %d\n", g_Dbs.db[i].dbCfg.minRows); + } + if (g_Dbs.db[i].dbCfg.maxRows > 0) { + fprintf(fp, " maxRows: %d\n", g_Dbs.db[i].dbCfg.maxRows); + } + if (g_Dbs.db[i].dbCfg.comp > 0) { + fprintf(fp, " comp: %d\n", g_Dbs.db[i].dbCfg.comp); + } + if (g_Dbs.db[i].dbCfg.walLevel > 0) { + fprintf(fp, " walLevel: %d\n", g_Dbs.db[i].dbCfg.walLevel); + } + if (g_Dbs.db[i].dbCfg.fsync > 0) { + fprintf(fp, " fsync: %d\n", g_Dbs.db[i].dbCfg.fsync); + } + if (g_Dbs.db[i].dbCfg.quorum > 0) { + fprintf(fp, " quorum: %d\n", g_Dbs.db[i].dbCfg.quorum); + } + if (g_Dbs.db[i].dbCfg.precision[0] != 0) { + if ((0 == strncasecmp(g_Dbs.db[i].dbCfg.precision, "ms", 2)) || (0 == strncasecmp(g_Dbs.db[i].dbCfg.precision, "us", 2))) { + fprintf(fp, " precision: %s\n", g_Dbs.db[i].dbCfg.precision); + } else { + fprintf(fp, " precision error: %s\n", g_Dbs.db[i].dbCfg.precision); + } + } + + fprintf(fp, " super table count: %d\n", g_Dbs.db[i].superTblCount); + for (int j = 0; j < g_Dbs.db[i].superTblCount; j++) { + fprintf(fp, " super table[%d]:\n", j); + + fprintf(fp, " stbName: %s\n", g_Dbs.db[i].superTbls[j].sTblName); + + if (PRE_CREATE_SUBTBL == g_Dbs.db[i].superTbls[j].autoCreateTable) { + fprintf(fp, " autoCreateTable: %s\n", "no"); + } else if (AUTO_CREATE_SUBTBL == g_Dbs.db[i].superTbls[j].autoCreateTable) { + fprintf(fp, " autoCreateTable: %s\n", "yes"); + } else { + fprintf(fp, " autoCreateTable: %s\n", "error"); + } + + if (TBL_NO_EXISTS == g_Dbs.db[i].superTbls[j].childTblExists) { + fprintf(fp, " childTblExists: %s\n", "no"); + } else if (TBL_ALREADY_EXISTS == g_Dbs.db[i].superTbls[j].childTblExists) { + fprintf(fp, " childTblExists: %s\n", "yes"); + } else { + fprintf(fp, " childTblExists: %s\n", "error"); + } + + fprintf(fp, " childTblCount: %d\n", g_Dbs.db[i].superTbls[j].childTblCount); + fprintf(fp, " childTblPrefix: %s\n", g_Dbs.db[i].superTbls[j].childTblPrefix); + fprintf(fp, " dataSource: %s\n", g_Dbs.db[i].superTbls[j].dataSource); + fprintf(fp, " insertMode: %s\n", g_Dbs.db[i].superTbls[j].insertMode); + fprintf(fp, " insertRate: %d\n", g_Dbs.db[i].superTbls[j].insertRate); + fprintf(fp, " insertRows: %"PRId64"\n", g_Dbs.db[i].superTbls[j].insertRows); + + if (0 == g_Dbs.db[i].superTbls[j].multiThreadWriteOneTbl) { + fprintf(fp, " multiThreadWriteOneTbl: no\n"); + }else { + fprintf(fp, " multiThreadWriteOneTbl: yes\n"); + } + fprintf(fp, " numberOfTblInOneSql: %d\n", g_Dbs.db[i].superTbls[j].numberOfTblInOneSql); + fprintf(fp, " rowsPerTbl: %d\n", g_Dbs.db[i].superTbls[j].rowsPerTbl); + fprintf(fp, " disorderRange: %d\n", g_Dbs.db[i].superTbls[j].disorderRange); + fprintf(fp, " disorderRatio: %d\n", g_Dbs.db[i].superTbls[j].disorderRatio); + fprintf(fp, " maxSqlLen: %d\n", g_Dbs.db[i].superTbls[j].maxSqlLen); + + fprintf(fp, " timeStampStep: %d\n", g_Dbs.db[i].superTbls[j].timeStampStep); + fprintf(fp, " startTimestamp: %s\n", g_Dbs.db[i].superTbls[j].startTimestamp); + fprintf(fp, " sampleFormat: %s\n", g_Dbs.db[i].superTbls[j].sampleFormat); + fprintf(fp, " sampleFile: %s\n", g_Dbs.db[i].superTbls[j].sampleFile); + fprintf(fp, " tagsFile: %s\n", g_Dbs.db[i].superTbls[j].tagsFile); + + fprintf(fp, " columnCount: %d\n ", g_Dbs.db[i].superTbls[j].columnCount); + for (int k = 0; k < g_Dbs.db[i].superTbls[j].columnCount; k++) { + //printf("dataType:%s, dataLen:%d\t", g_Dbs.db[i].superTbls[j].columns[k].dataType, g_Dbs.db[i].superTbls[j].columns[k].dataLen); + if ((0 == strncasecmp(g_Dbs.db[i].superTbls[j].columns[k].dataType, "binary", 6)) || (0 == strncasecmp(g_Dbs.db[i].superTbls[j].columns[k].dataType, "nchar", 5))) { + fprintf(fp, "column[%d]:%s(%d) ", k, g_Dbs.db[i].superTbls[j].columns[k].dataType, g_Dbs.db[i].superTbls[j].columns[k].dataLen); + } else { + fprintf(fp, "column[%d]:%s ", k, g_Dbs.db[i].superTbls[j].columns[k].dataType); + } + } + fprintf(fp, "\n"); + + fprintf(fp, " tagCount: %d\n ", g_Dbs.db[i].superTbls[j].tagCount); + for (int k = 0; k < g_Dbs.db[i].superTbls[j].tagCount; k++) { + //printf("dataType:%s, dataLen:%d\t", g_Dbs.db[i].superTbls[j].tags[k].dataType, g_Dbs.db[i].superTbls[j].tags[k].dataLen); + if ((0 == strncasecmp(g_Dbs.db[i].superTbls[j].tags[k].dataType, "binary", 6)) || (0 == strncasecmp(g_Dbs.db[i].superTbls[j].tags[k].dataType, "nchar", 5))) { + fprintf(fp, "tag[%d]:%s(%d) ", k, g_Dbs.db[i].superTbls[j].tags[k].dataType, g_Dbs.db[i].superTbls[j].tags[k].dataLen); + } else { + fprintf(fp, "tag[%d]:%s ", k, g_Dbs.db[i].superTbls[j].tags[k].dataType); + } + } + fprintf(fp, "\n"); + } + fprintf(fp, "\n"); + } + fprintf(fp, "================ insert.json parse result END ================\n\n"); +} + +static void printfQueryMeta() { + printf("\033[1m\033[40;32m================ query.json parse result ================\033[0m\n"); + printf("host: \033[33m%s:%u\033[0m\n", g_queryInfo.host, g_queryInfo.port); + printf("user: \033[33m%s\033[0m\n", g_queryInfo.user); + printf("password: \033[33m%s\033[0m\n", g_queryInfo.password); + printf("database name: \033[33m%s\033[0m\n", g_queryInfo.dbName); + + printf("\n"); + printf("super table query info: \n"); + printf("rate: \033[33m%d\033[0m\n", g_queryInfo.superQueryInfo.rate); + printf("concurrent: \033[33m%d\033[0m\n", g_queryInfo.superQueryInfo.concurrent); + printf("sqlCount: \033[33m%d\033[0m\n", g_queryInfo.superQueryInfo.sqlCount); + + if (SUBSCRIBE_MODE == g_jsonType) { + printf("mod: \033[33m%d\033[0m\n", g_queryInfo.superQueryInfo.subscribeMode); + printf("interval: \033[33m%d\033[0m\n", g_queryInfo.superQueryInfo.subscribeInterval); + printf("restart: \033[33m%d\033[0m\n", g_queryInfo.superQueryInfo.subscribeRestart); + printf("keepProgress: \033[33m%d\033[0m\n", g_queryInfo.superQueryInfo.subscribeKeepProgress); + } + + + for (int i = 0; i < g_queryInfo.superQueryInfo.sqlCount; i++) { + printf(" sql[%d]: \033[33m%s\033[0m\n", i, g_queryInfo.superQueryInfo.sql[i]); + } + printf("\n"); + printf("sub table query info: \n"); + printf("rate: \033[33m%d\033[0m\n", g_queryInfo.subQueryInfo.rate); + printf("threadCnt: \033[33m%d\033[0m\n", g_queryInfo.subQueryInfo.threadCnt); + printf("childTblCount: \033[33m%d\033[0m\n", g_queryInfo.subQueryInfo.childTblCount); + printf("childTblPrefix: \033[33m%s\033[0m\n", g_queryInfo.subQueryInfo.childTblPrefix); + + if (SUBSCRIBE_MODE == g_jsonType) { + printf("mod: \033[33m%d\033[0m\n", g_queryInfo.subQueryInfo.subscribeMode); + printf("interval: \033[33m%d\033[0m\n", g_queryInfo.subQueryInfo.subscribeInterval); + printf("restart: \033[33m%d\033[0m\n", g_queryInfo.subQueryInfo.subscribeRestart); + printf("keepProgress: \033[33m%d\033[0m\n", g_queryInfo.subQueryInfo.subscribeKeepProgress); + } + + printf("sqlCount: \033[33m%d\033[0m\n", g_queryInfo.subQueryInfo.sqlCount); + for (int i = 0; i < g_queryInfo.subQueryInfo.sqlCount; i++) { + printf(" sql[%d]: \033[33m%s\033[0m\n", i, g_queryInfo.subQueryInfo.sql[i]); + } + printf("\n"); + printf("\033[1m\033[40;32m================ query.json parse result ================\033[0m\n"); +} + +#ifdef TD_LOWA_CURL +static size_t responseCallback(void *contents, size_t size, size_t nmemb, void *userp) +{ + size_t realsize = size * nmemb; + curlMemInfo* mem = (curlMemInfo*)userp; + + char *ptr = realloc(mem->buf, mem->sizeleft + realsize + 1); + if(ptr == NULL) { + /* out of memory! */ + printf("not enough memory (realloc returned NULL)\n"); + return 0; + } + + mem->buf = ptr; + memcpy(&(mem->buf[mem->sizeleft]), contents, realsize); + mem->sizeleft += realsize; + mem->buf[mem->sizeleft] = 0; + + //printf("result:%s\n\n", mem->buf); + + return realsize; +} + +void curlProceLogin(void) +{ + CURL *curl_handle; + CURLcode res; + + curlMemInfo chunk; + + chunk.buf = malloc(1); /* will be grown as needed by the realloc above */ + chunk.sizeleft = 0; /* no data at this point */ + + //curl_global_init(CURL_GLOBAL_ALL); + + /* init the curl session */ + curl_handle = curl_easy_init(); + + curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,""); + curl_easy_setopt(curl_handle, CURLOPT_POST, 1); + + char dstUrl[128] = {0}; + snprintf(dstUrl, 128, "http://%s:6041/rest/login/root/taosdata", g_Dbs.host); + + /* specify URL to get */ + curl_easy_setopt(curl_handle, CURLOPT_URL, dstUrl); + + /* send all data to this function */ + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, responseCallback); + + /* we pass our 'chunk' struct to the callback function */ + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk); + + /* do it! */ + res = curl_easy_perform(curl_handle); + + /* check for errors */ + if(res != CURLE_OK) { + fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); + } + else { + //printf("response len:%lu, content: %s \n", (unsigned long)chunk.sizeleft, chunk.buf); + ; + } + + /* cleanup curl stuff */ + curl_easy_cleanup(curl_handle); + + free(chunk.buf); + + /* we're done with libcurl, so clean it up */ + //curl_global_cleanup(); + + return; +} + +int curlProceSql(char* host, uint16_t port, char* sqlstr, CURL *curl_handle) +{ + //curlProceLogin(); + + //CURL *curl_handle; + CURLcode res; + + curlMemInfo chunk; + + chunk.buf = malloc(1); /* will be grown as needed by the realloc above */ + chunk.sizeleft = 0; /* no data at this point */ + + + char dstUrl[128] = {0}; + snprintf(dstUrl, 128, "http://%s:%u/rest/sql", host, port+TSDB_PORT_HTTP); + + //curl_global_init(CURL_GLOBAL_ALL); + + /* init the curl session */ + //curl_handle = curl_easy_init(); + + //curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,""); + curl_easy_setopt(curl_handle, CURLOPT_POST, 1L); + + /* specify URL to get */ + curl_easy_setopt(curl_handle, CURLOPT_URL, dstUrl); + + /* enable TCP keep-alive for this transfer */ + curl_easy_setopt(curl_handle, CURLOPT_TCP_KEEPALIVE, 1L); + /* keep-alive idle time to 120 seconds */ + curl_easy_setopt(curl_handle, CURLOPT_TCP_KEEPIDLE, 120L); + /* interval time between keep-alive probes: 60 seconds */ + curl_easy_setopt(curl_handle, CURLOPT_TCP_KEEPINTVL, 60L); + + /* send all data to this function */ + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, responseCallback); + + /* we pass our 'chunk' struct to the callback function */ + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk); + + struct curl_slist *list = NULL; + list = curl_slist_append(list, "Authorization: Basic cm9vdDp0YW9zZGF0YQ=="); + curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, list); + curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, list); + + /* Set the expected upload size. */ + curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)strlen(sqlstr)); + curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, sqlstr); + + /* get it! */ + res = curl_easy_perform(curl_handle); + + /* check for errors */ + if(res != CURLE_OK) { + fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); + return -1; + } + else { + /* curl_easy_perform() block end and return result */ + //printf("[%32.32s] sql response len:%lu, content: %s \n\n", sqlstr, (unsigned long)chunk.sizeleft, chunk.buf); + ; + } + + curl_slist_free_all(list); /* free the list again */ + + /* cleanup curl stuff */ + //curl_easy_cleanup(curl_handle); + + free(chunk.buf); + + /* we're done with libcurl, so clean it up */ + //curl_global_cleanup(); + + return 0; +} +#endif + +char* getTagValueFromTagSample( SSuperTable* stbInfo, int tagUsePos) { + char* dataBuf = (char*)calloc(TSDB_MAX_SQL_LEN+1, 1); + if (NULL == dataBuf) { + printf("calloc failed! size:%d\n", TSDB_MAX_SQL_LEN+1); + return NULL; + } + + int dataLen = 0; + dataLen += snprintf(dataBuf + dataLen, TSDB_MAX_SQL_LEN - dataLen, "(%s)", stbInfo->tagDataBuf + stbInfo->lenOfTagOfOneRow * tagUsePos); + + return dataBuf; +} + +char* generateTagVaulesForStb(SSuperTable* stbInfo) { + char* dataBuf = (char*)calloc(TSDB_MAX_SQL_LEN+1, 1); + if (NULL == dataBuf) { + printf("calloc failed! size:%d\n", TSDB_MAX_SQL_LEN+1); + return NULL; + } + + int dataLen = 0; + dataLen += snprintf(dataBuf + dataLen, TSDB_MAX_SQL_LEN - dataLen, "("); + for (int i = 0; i < stbInfo->tagCount; i++) { + if ((0 == strncasecmp(stbInfo->tags[i].dataType, "binary", 6)) || (0 == strncasecmp(stbInfo->tags[i].dataType, "nchar", 5))) { + if (stbInfo->tags[i].dataLen > TSDB_MAX_BINARY_LEN) { + printf("binary or nchar length overflow, max size:%u\n", (uint32_t)TSDB_MAX_BINARY_LEN); + tmfree(dataBuf); + return NULL; + } + + char* buf = (char*)calloc(stbInfo->tags[i].dataLen+1, 1); + if (NULL == buf) { + printf("calloc failed! size:%d\n", stbInfo->tags[i].dataLen); + tmfree(dataBuf); + return NULL; + } + rand_string(buf, stbInfo->tags[i].dataLen); + dataLen += snprintf(dataBuf + dataLen, TSDB_MAX_SQL_LEN - dataLen, "\'%s\', ", buf); + tmfree(buf); + } else if (0 == strncasecmp(stbInfo->tags[i].dataType, "int", 3)) { + dataLen += snprintf(dataBuf + dataLen, TSDB_MAX_SQL_LEN - dataLen, "%d, ", rand_int()); + } else if (0 == strncasecmp(stbInfo->tags[i].dataType, "bigint", 6)) { + dataLen += snprintf(dataBuf + dataLen, TSDB_MAX_SQL_LEN - dataLen, "%"PRId64", ", rand_bigint()); + } else if (0 == strncasecmp(stbInfo->tags[i].dataType, "float", 5)) { + dataLen += snprintf(dataBuf + dataLen, TSDB_MAX_SQL_LEN - dataLen, "%f, ", rand_float()); + } else if (0 == strncasecmp(stbInfo->tags[i].dataType, "double", 6)) { + dataLen += snprintf(dataBuf + dataLen, TSDB_MAX_SQL_LEN - dataLen, "%f, ", rand_double()); + } else if (0 == strncasecmp(stbInfo->tags[i].dataType, "smallint", 8)) { + dataLen += snprintf(dataBuf + dataLen, TSDB_MAX_SQL_LEN - dataLen, "%d, ", rand_smallint()); + } else if (0 == strncasecmp(stbInfo->tags[i].dataType, "tinyint", 7)) { + dataLen += snprintf(dataBuf + dataLen, TSDB_MAX_SQL_LEN - dataLen, "%d, ", rand_tinyint()); + } else if (0 == strncasecmp(stbInfo->tags[i].dataType, "bool", 4)) { + dataLen += snprintf(dataBuf + dataLen, TSDB_MAX_SQL_LEN - dataLen, "%d, ", rand_bool()); + } else if (0 == strncasecmp(stbInfo->tags[i].dataType, "timestamp", 4)) { + dataLen += snprintf(dataBuf + dataLen, TSDB_MAX_SQL_LEN - dataLen, "%"PRId64", ", rand_bigint()); + } else { + printf("No support data type: %s\n", stbInfo->tags[i].dataType); + tmfree(dataBuf); + return NULL; + } + } + dataLen -= 2; + dataLen += snprintf(dataBuf + dataLen, TSDB_MAX_SQL_LEN - dataLen, ")"); + return dataBuf; +} + +static int calcRowLen(SSuperTable* superTbls) { + int colIndex; + int lenOfOneRow = 0; + + for (colIndex = 0; colIndex < superTbls->columnCount; colIndex++) { + char* dataType = superTbls->columns[colIndex].dataType; + + if (strcasecmp(dataType, "BINARY") == 0) { + lenOfOneRow += superTbls->columns[colIndex].dataLen + 3; + } else if (strcasecmp(dataType, "NCHAR") == 0) { + lenOfOneRow += superTbls->columns[colIndex].dataLen + 3; + } else if (strcasecmp(dataType, "INT") == 0) { + lenOfOneRow += 11; + } else if (strcasecmp(dataType, "BIGINT") == 0) { + lenOfOneRow += 21; + } else if (strcasecmp(dataType, "SMALLINT") == 0) { + lenOfOneRow += 6; + } else if (strcasecmp(dataType, "TINYINT") == 0) { + lenOfOneRow += 4; + } else if (strcasecmp(dataType, "BOOL") == 0) { + lenOfOneRow += 6; + } else if (strcasecmp(dataType, "FLOAT") == 0) { + lenOfOneRow += 22; + } else if (strcasecmp(dataType, "DOUBLE") == 0) { + lenOfOneRow += 42; + } else if (strcasecmp(dataType, "TIMESTAMP") == 0) { + lenOfOneRow += 21; + } else { + printf("get error data type : %s\n", dataType); + exit(-1); + } + } + + superTbls->lenOfOneRow = lenOfOneRow + 20; // timestamp + + int tagIndex; + int lenOfTagOfOneRow = 0; + for (tagIndex = 0; tagIndex < superTbls->tagCount; tagIndex++) { + char* dataType = superTbls->tags[tagIndex].dataType; + + if (strcasecmp(dataType, "BINARY") == 0) { + lenOfTagOfOneRow += superTbls->tags[tagIndex].dataLen + 3; + } else if (strcasecmp(dataType, "NCHAR") == 0) { + lenOfTagOfOneRow += superTbls->tags[tagIndex].dataLen + 3; + } else if (strcasecmp(dataType, "INT") == 0) { + lenOfTagOfOneRow += superTbls->tags[tagIndex].dataLen + 11; + } else if (strcasecmp(dataType, "BIGINT") == 0) { + lenOfTagOfOneRow += superTbls->tags[tagIndex].dataLen + 21; + } else if (strcasecmp(dataType, "SMALLINT") == 0) { + lenOfTagOfOneRow += superTbls->tags[tagIndex].dataLen + 6; + } else if (strcasecmp(dataType, "TINYINT") == 0) { + lenOfTagOfOneRow += superTbls->tags[tagIndex].dataLen + 4; + } else if (strcasecmp(dataType, "BOOL") == 0) { + lenOfTagOfOneRow += superTbls->tags[tagIndex].dataLen + 6; + } else if (strcasecmp(dataType, "FLOAT") == 0) { + lenOfTagOfOneRow += superTbls->tags[tagIndex].dataLen + 22; + } else if (strcasecmp(dataType, "DOUBLE") == 0) { + lenOfTagOfOneRow += superTbls->tags[tagIndex].dataLen + 42; + } else { + printf("get error tag type : %s\n", dataType); + exit(-1); + } + } + + superTbls->lenOfTagOfOneRow = lenOfTagOfOneRow; + + return 0; +} + + +static int getAllChildNameOfSuperTable(TAOS * taos, char* dbName, char* sTblName, char** childTblNameOfSuperTbl, int* childTblCountOfSuperTbl) { + char command[BUFFER_SIZE] = "\0"; + TAOS_RES * res; + TAOS_ROW row = NULL; + int count = 0; + + char* childTblName = *childTblNameOfSuperTbl; + + //get all child table name use cmd: select tbname from superTblName; + snprintf(command, BUFFER_SIZE, "select tbname from %s.%s", dbName, sTblName); + res = taos_query(taos, command); + int32_t code = taos_errno(res); + if (code != 0) { + printf("failed to run command %s\n", command); + taos_free_result(res); + taos_close(taos); + exit(-1); + } + + int childTblCount = 10000; + count = 0; + childTblName = (char*)calloc(1, childTblCount * TSDB_TABLE_NAME_LEN); + char* pTblName = childTblName; + while ((row = taos_fetch_row(res)) != NULL) { + strncpy(pTblName, (char *)row[0], TSDB_TABLE_NAME_LEN); + //printf("==== sub table name: %s\n", pTblName); + count++; + if (count == childTblCount) { + char *tmp = realloc(childTblName, (size_t)count*1.5*TSDB_TABLE_NAME_LEN); + if (tmp != NULL) { + childTblName = tmp; + memset(childTblName + count*TSDB_TABLE_NAME_LEN, 0, (size_t)(count*0.5*TSDB_TABLE_NAME_LEN)); + } else { + // exit, if allocate more memory failed + printf("realloc fail for save child table name of %s.%s\n", dbName, sTblName); + tmfree(childTblName); + taos_free_result(res); + taos_close(taos); + exit(-1); + } + } + pTblName = childTblName + count * TSDB_TABLE_NAME_LEN; + } + + *childTblCountOfSuperTbl = count; + *childTblNameOfSuperTbl = childTblName; + + taos_free_result(res); + return 0; +} + +static int getSuperTableFromServer(TAOS * taos, char* dbName, SSuperTable* superTbls) { + char command[BUFFER_SIZE] = "\0"; + TAOS_RES * res; + TAOS_ROW row = NULL; + int count = 0; + + //get schema use cmd: describe superTblName; + snprintf(command, BUFFER_SIZE, "describe %s.%s", dbName, superTbls->sTblName); + res = taos_query(taos, command); + int32_t code = taos_errno(res); + if (code != 0) { + printf("failed to run command %s\n", command); + taos_free_result(res); + return -1; + } + + int tagIndex = 0; + int columnIndex = 0; + TAOS_FIELD *fields = taos_fetch_fields(res); + while ((row = taos_fetch_row(res)) != NULL) { + if (0 == count) { + count++; + continue; + } + + if (strcmp((char *)row[TSDB_DESCRIBE_METRIC_NOTE_INDEX], "TAG") == 0) { + strncpy(superTbls->tags[tagIndex].field, (char *)row[TSDB_DESCRIBE_METRIC_FIELD_INDEX], fields[TSDB_DESCRIBE_METRIC_FIELD_INDEX].bytes); + strncpy(superTbls->tags[tagIndex].dataType, (char *)row[TSDB_DESCRIBE_METRIC_TYPE_INDEX], fields[TSDB_DESCRIBE_METRIC_TYPE_INDEX].bytes); + superTbls->tags[tagIndex].dataLen = *((int *)row[TSDB_DESCRIBE_METRIC_LENGTH_INDEX]); + strncpy(superTbls->tags[tagIndex].note, (char *)row[TSDB_DESCRIBE_METRIC_NOTE_INDEX], fields[TSDB_DESCRIBE_METRIC_NOTE_INDEX].bytes); + tagIndex++; + } else { + strncpy(superTbls->columns[columnIndex].field, (char *)row[TSDB_DESCRIBE_METRIC_FIELD_INDEX], fields[TSDB_DESCRIBE_METRIC_FIELD_INDEX].bytes); + strncpy(superTbls->columns[columnIndex].dataType, (char *)row[TSDB_DESCRIBE_METRIC_TYPE_INDEX], fields[TSDB_DESCRIBE_METRIC_TYPE_INDEX].bytes); + superTbls->columns[columnIndex].dataLen = *((int *)row[TSDB_DESCRIBE_METRIC_LENGTH_INDEX]); + strncpy(superTbls->columns[columnIndex].note, (char *)row[TSDB_DESCRIBE_METRIC_NOTE_INDEX], fields[TSDB_DESCRIBE_METRIC_NOTE_INDEX].bytes); + columnIndex++; + } + count++; + } + + superTbls->columnCount = columnIndex; + superTbls->tagCount = tagIndex; + taos_free_result(res); + + calcRowLen(superTbls); + + if (TBL_ALREADY_EXISTS == superTbls->childTblExists) { + //get all child table name use cmd: select tbname from superTblName; + getAllChildNameOfSuperTable(taos, dbName, superTbls->sTblName, &superTbls->childTblName, &superTbls->childTblCount); + } + return 0; +} + +static int createSuperTable(TAOS * taos, char* dbName, SSuperTable* superTbls, bool use_metric) { + char command[BUFFER_SIZE] = "\0"; + + char cols[STRING_LEN] = "\0"; + int colIndex; + int len = 0; + + int lenOfOneRow = 0; + for (colIndex = 0; colIndex < superTbls->columnCount; colIndex++) { + char* dataType = superTbls->columns[colIndex].dataType; + + if (strcasecmp(dataType, "BINARY") == 0) { + len += snprintf(cols + len, STRING_LEN - len, ", col%d %s(%d)", colIndex, "BINARY", superTbls->columns[colIndex].dataLen); + lenOfOneRow += superTbls->columns[colIndex].dataLen + 3; + } else if (strcasecmp(dataType, "NCHAR") == 0) { + len += snprintf(cols + len, STRING_LEN - len, ", col%d %s(%d)", colIndex, "NCHAR", superTbls->columns[colIndex].dataLen); + lenOfOneRow += superTbls->columns[colIndex].dataLen + 3; + } else if (strcasecmp(dataType, "INT") == 0) { + len += snprintf(cols + len, STRING_LEN - len, ", col%d %s", colIndex, "INT"); + lenOfOneRow += 11; + } else if (strcasecmp(dataType, "BIGINT") == 0) { + len += snprintf(cols + len, STRING_LEN - len, ", col%d %s", colIndex, "BIGINT"); + lenOfOneRow += 21; + } else if (strcasecmp(dataType, "SMALLINT") == 0) { + len += snprintf(cols + len, STRING_LEN - len, ", col%d %s", colIndex, "SMALLINT"); + lenOfOneRow += 6; + } else if (strcasecmp(dataType, "TINYINT") == 0) { + len += snprintf(cols + len, STRING_LEN - len, ", col%d %s", colIndex, "TINYINT"); + lenOfOneRow += 4; + } else if (strcasecmp(dataType, "BOOL") == 0) { + len += snprintf(cols + len, STRING_LEN - len, ", col%d %s", colIndex, "BOOL"); + lenOfOneRow += 6; + } else if (strcasecmp(dataType, "FLOAT") == 0) { + len += snprintf(cols + len, STRING_LEN - len, ", col%d %s", colIndex, "FLOAT"); + lenOfOneRow += 22; + } else if (strcasecmp(dataType, "DOUBLE") == 0) { + len += snprintf(cols + len, STRING_LEN - len, ", col%d %s", colIndex, "DOUBLE"); + lenOfOneRow += 42; + } else if (strcasecmp(dataType, "TIMESTAMP") == 0) { + len += snprintf(cols + len, STRING_LEN - len, ", col%d %s", colIndex, "TIMESTAMP"); + lenOfOneRow += 21; + } else { + taos_close(taos); + printf("config error data type : %s\n", dataType); + exit(-1); + } + } + + superTbls->lenOfOneRow = lenOfOneRow + 20; // timestamp + //printf("%s.%s column count:%d, column length:%d\n\n", g_Dbs.db[i].dbName, g_Dbs.db[i].superTbls[j].sTblName, g_Dbs.db[i].superTbls[j].columnCount, lenOfOneRow); + + // save for creating child table + superTbls->colsOfCreatChildTable = (char*)calloc(len+20, 1); + if (NULL == superTbls->colsOfCreatChildTable) { + printf("Failed when calloc, size:%d", len+1); + taos_close(taos); + exit(-1); + } + snprintf(superTbls->colsOfCreatChildTable, len+20, "(ts timestamp%s)", cols); + + if (use_metric) { + char tags[STRING_LEN] = "\0"; + int tagIndex; + len = 0; + + int lenOfTagOfOneRow = 0; + len += snprintf(tags + len, STRING_LEN - len, "("); + for (tagIndex = 0; tagIndex < superTbls->tagCount; tagIndex++) { + char* dataType = superTbls->tags[tagIndex].dataType; + + if (strcasecmp(dataType, "BINARY") == 0) { + len += snprintf(tags + len, STRING_LEN - len, "t%d %s(%d), ", tagIndex, "BINARY", superTbls->tags[tagIndex].dataLen); + lenOfTagOfOneRow += superTbls->tags[tagIndex].dataLen + 3; + } else if (strcasecmp(dataType, "NCHAR") == 0) { + len += snprintf(tags + len, STRING_LEN - len, "t%d %s(%d), ", tagIndex, "NCHAR", superTbls->tags[tagIndex].dataLen); + lenOfTagOfOneRow += superTbls->tags[tagIndex].dataLen + 3; + } else if (strcasecmp(dataType, "INT") == 0) { + len += snprintf(tags + len, STRING_LEN - len, "t%d %s, ", tagIndex, "INT"); + lenOfTagOfOneRow += superTbls->tags[tagIndex].dataLen + 11; + } else if (strcasecmp(dataType, "BIGINT") == 0) { + len += snprintf(tags + len, STRING_LEN - len, "t%d %s, ", tagIndex, "BIGINT"); + lenOfTagOfOneRow += superTbls->tags[tagIndex].dataLen + 21; + } else if (strcasecmp(dataType, "SMALLINT") == 0) { + len += snprintf(tags + len, STRING_LEN - len, "t%d %s, ", tagIndex, "SMALLINT"); + lenOfTagOfOneRow += superTbls->tags[tagIndex].dataLen + 6; + } else if (strcasecmp(dataType, "TINYINT") == 0) { + len += snprintf(tags + len, STRING_LEN - len, "t%d %s, ", tagIndex, "TINYINT"); + lenOfTagOfOneRow += superTbls->tags[tagIndex].dataLen + 4; + } else if (strcasecmp(dataType, "BOOL") == 0) { + len += snprintf(tags + len, STRING_LEN - len, "t%d %s, ", tagIndex, "BOOL"); + lenOfTagOfOneRow += superTbls->tags[tagIndex].dataLen + 6; + } else if (strcasecmp(dataType, "FLOAT") == 0) { + len += snprintf(tags + len, STRING_LEN - len, "t%d %s, ", tagIndex, "FLOAT"); + lenOfTagOfOneRow += superTbls->tags[tagIndex].dataLen + 22; + } else if (strcasecmp(dataType, "DOUBLE") == 0) { + len += snprintf(tags + len, STRING_LEN - len, "t%d %s, ", tagIndex, "DOUBLE"); + lenOfTagOfOneRow += superTbls->tags[tagIndex].dataLen + 42; + } else { + taos_close(taos); + printf("config error tag type : %s\n", dataType); + exit(-1); + } + } + len -= 2; + len += snprintf(tags + len, STRING_LEN - len, ")"); + + superTbls->lenOfTagOfOneRow = lenOfTagOfOneRow; + + snprintf(command, BUFFER_SIZE, "create table if not exists %s.%s (ts timestamp%s) tags %s", dbName, superTbls->sTblName, cols, tags); + if (0 != queryDbExec(taos, command, NO_INSERT_TYPE)) { + return -1; + } + printf("\ncreate supertable %s success!\n\n", superTbls->sTblName); + } + return 0; +} + + +static int createDatabases() { + TAOS * taos = NULL; + int ret = 0; + taos_init(); + taos = taos_connect(g_Dbs.host, g_Dbs.user, g_Dbs.password, NULL, g_Dbs.port); + if (taos == NULL) { + fprintf(stderr, "Failed to connect to TDengine, reason:%s\n", taos_errstr(NULL)); + exit(-1); + } + char command[BUFFER_SIZE] = "\0"; + + + for (int i = 0; i < g_Dbs.dbCount; i++) { + if (g_Dbs.db[i].drop) { + sprintf(command, "drop database if exists %s;", g_Dbs.db[i].dbName); + if (0 != queryDbExec(taos, command, NO_INSERT_TYPE)) { + taos_close(taos); + return -1; + } + } + + int dataLen = 0; + dataLen += snprintf(command + dataLen, BUFFER_SIZE - dataLen, "create database if not exists %s ", g_Dbs.db[i].dbName); + + if (g_Dbs.db[i].dbCfg.blocks > 0) { + dataLen += snprintf(command + dataLen, BUFFER_SIZE - dataLen, "blocks %d ", g_Dbs.db[i].dbCfg.blocks); + } + if (g_Dbs.db[i].dbCfg.cache > 0) { + dataLen += snprintf(command + dataLen, BUFFER_SIZE - dataLen, "cache %d ", g_Dbs.db[i].dbCfg.cache); + } + if (g_Dbs.db[i].dbCfg.days > 0) { + dataLen += snprintf(command + dataLen, BUFFER_SIZE - dataLen, "days %d ", g_Dbs.db[i].dbCfg.days); + } + if (g_Dbs.db[i].dbCfg.keep > 0) { + dataLen += snprintf(command + dataLen, BUFFER_SIZE - dataLen, "keep %d ", g_Dbs.db[i].dbCfg.keep); + } + if (g_Dbs.db[i].dbCfg.replica > 0) { + dataLen += snprintf(command + dataLen, BUFFER_SIZE - dataLen, "replica %d ", g_Dbs.db[i].dbCfg.replica); + } + if (g_Dbs.db[i].dbCfg.update > 0) { + dataLen += snprintf(command + dataLen, BUFFER_SIZE - dataLen, "update %d ", g_Dbs.db[i].dbCfg.update); + } + //if (g_Dbs.db[i].dbCfg.maxtablesPerVnode > 0) { + // dataLen += snprintf(command + dataLen, BUFFER_SIZE - dataLen, "tables %d ", g_Dbs.db[i].dbCfg.maxtablesPerVnode); + //} + if (g_Dbs.db[i].dbCfg.minRows > 0) { + dataLen += snprintf(command + dataLen, BUFFER_SIZE - dataLen, "minrows %d ", g_Dbs.db[i].dbCfg.minRows); + } + if (g_Dbs.db[i].dbCfg.maxRows > 0) { + dataLen += snprintf(command + dataLen, BUFFER_SIZE - dataLen, "maxrows %d ", g_Dbs.db[i].dbCfg.maxRows); + } + if (g_Dbs.db[i].dbCfg.comp > 0) { + dataLen += snprintf(command + dataLen, BUFFER_SIZE - dataLen, "comp %d ", g_Dbs.db[i].dbCfg.comp); + } + if (g_Dbs.db[i].dbCfg.walLevel > 0) { + dataLen += snprintf(command + dataLen, BUFFER_SIZE - dataLen, "wal %d ", g_Dbs.db[i].dbCfg.walLevel); + } + if (g_Dbs.db[i].dbCfg.fsync > 0) { + dataLen += snprintf(command + dataLen, BUFFER_SIZE - dataLen, "fsync %d ", g_Dbs.db[i].dbCfg.fsync); + } + if ((0 == strncasecmp(g_Dbs.db[i].dbCfg.precision, "ms", 2)) || (0 == strncasecmp(g_Dbs.db[i].dbCfg.precision, "us", 2))) { + dataLen += snprintf(command + dataLen, BUFFER_SIZE - dataLen, "precision \'%s\';", g_Dbs.db[i].dbCfg.precision); + } + + if (0 != queryDbExec(taos, command, NO_INSERT_TYPE)) { + taos_close(taos); + return -1; + } + printf("\ncreate database %s success!\n\n", g_Dbs.db[i].dbName); + + for (int j = 0; j < g_Dbs.db[i].superTblCount; j++) { + // describe super table, if exists + sprintf(command, "describe %s.%s;", g_Dbs.db[i].dbName, g_Dbs.db[i].superTbls[j].sTblName); + if (0 != queryDbExec(taos, command, NO_INSERT_TYPE)) { + g_Dbs.db[i].superTbls[j].superTblExists = TBL_NO_EXISTS; + ret = createSuperTable(taos, g_Dbs.db[i].dbName, &g_Dbs.db[i].superTbls[j], g_Dbs.use_metric); + } else { + g_Dbs.db[i].superTbls[j].superTblExists = TBL_ALREADY_EXISTS; + ret = getSuperTableFromServer(taos, g_Dbs.db[i].dbName, &g_Dbs.db[i].superTbls[j]); + } + + if (0 != ret) { + taos_close(taos); + return -1; + } + } + } + + taos_close(taos); + return 0; +} + + +void * createTable(void *sarg) +{ + char command[BUFFER_SIZE] = "\0"; + + threadInfo *winfo = (threadInfo *)sarg; + SSuperTable* superTblInfo = winfo->superTblInfo; + + int64_t lastPrintTime = taosGetTimestampMs(); + + //printf("Creating table from %d to %d\n", winfo->start_table_id, winfo->end_table_id); + for (int i = winfo->start_table_id; i <= winfo->end_table_id; i++) { + if (0 == g_Dbs.use_metric) { + snprintf(command, BUFFER_SIZE, "create table if not exists %s.%s%d %s;", winfo->db_name, superTblInfo->childTblPrefix, i, superTblInfo->colsOfCreatChildTable); + } else { + char* tagsValBuf = NULL; + if (0 == superTblInfo->tagSource) { + tagsValBuf = generateTagVaulesForStb(superTblInfo); + } else { + tagsValBuf = getTagValueFromTagSample(superTblInfo, i % superTblInfo->tagSampleCount); + } + if (NULL == tagsValBuf) { + return NULL; + } + snprintf(command, BUFFER_SIZE, "create table if not exists %s.%s%d using %s.%s tags %s;", winfo->db_name, superTblInfo->childTblPrefix, i, winfo->db_name, superTblInfo->sTblName, tagsValBuf); + free(tagsValBuf); + } + + if (0 != queryDbExec(winfo->taos, command, NO_INSERT_TYPE)){ + return NULL; + } + + int64_t currentPrintTime = taosGetTimestampMs(); + if (currentPrintTime - lastPrintTime > 30*1000) { + printf("thread[%d] already create %d - %d tables\n", winfo->threadID, winfo->start_table_id, i); + lastPrintTime = currentPrintTime; + } + } + + return NULL; +} + +void startMultiThreadCreateChildTable(char* cols, int threads, int ntables, char* db_name, SSuperTable* superTblInfo) { + pthread_t *pids = malloc(threads * sizeof(pthread_t)); + threadInfo *infos = malloc(threads * sizeof(threadInfo)); + + if ((NULL == pids) || (NULL == infos)) { + printf("malloc failed\n"); + exit(-1); + } + + if (threads < 1) { + threads = 1; + } + + int a = ntables / threads; + if (a < 1) { + threads = ntables; + a = 1; + } + + int b = 0; + b = ntables % threads; + + int last = 0; + for (int i = 0; i < threads; i++) { + threadInfo *t_info = infos + i; + t_info->threadID = i; + tstrncpy(t_info->db_name, db_name, MAX_DB_NAME_SIZE); + t_info->superTblInfo = superTblInfo; + t_info->taos = taos_connect(g_Dbs.host, g_Dbs.user, g_Dbs.password, db_name, g_Dbs.port); + t_info->start_table_id = last; + t_info->end_table_id = i < b ? last + a : last + a - 1; + last = t_info->end_table_id + 1; + t_info->use_metric = 1; + t_info->cols = cols; + pthread_create(pids + i, NULL, createTable, t_info); + } + + for (int i = 0; i < threads; i++) { + pthread_join(pids[i], NULL); + } + + for (int i = 0; i < threads; i++) { + threadInfo *t_info = infos + i; + taos_close(t_info->taos); + } + + free(pids); + free(infos); +} + + +static void createChildTables() { + for (int i = 0; i < g_Dbs.dbCount; i++) { + for (int j = 0; j < g_Dbs.db[i].superTblCount; j++) { + if ((AUTO_CREATE_SUBTBL == g_Dbs.db[i].superTbls[j].autoCreateTable) || (TBL_ALREADY_EXISTS == g_Dbs.db[i].superTbls[j].childTblExists)) { + continue; + } + startMultiThreadCreateChildTable(g_Dbs.db[i].superTbls[j].colsOfCreatChildTable, g_Dbs.threadCount, g_Dbs.db[i].superTbls[j].childTblCount, g_Dbs.db[i].dbName, &(g_Dbs.db[i].superTbls[j])); + g_totalChildTables += g_Dbs.db[i].superTbls[j].childTblCount; + } + } +} + +/* + Read 10000 lines at most. If more than 10000 lines, continue to read after using +*/ +int readTagFromCsvFileToMem(SSuperTable * supterTblInfo) { + size_t n = 0; + ssize_t readLen = 0; + char * line = NULL; + + FILE *fp = fopen(supterTblInfo->tagsFile, "r"); + if (fp == NULL) { + printf("Failed to open tags file: %s, reason:%s\n", supterTblInfo->tagsFile, strerror(errno)); + return -1; + } + + if (supterTblInfo->tagDataBuf) { + free(supterTblInfo->tagDataBuf); + supterTblInfo->tagDataBuf = NULL; + } + + supterTblInfo->tagDataBuf = calloc(supterTblInfo->lenOfTagOfOneRow * MAX_LINE_COUNT_IN_MEM, 1); + if (supterTblInfo->tagDataBuf == NULL) { + printf("Failed to calloc, reason:%s\n", strerror(errno)); + fclose(fp); + return -1; + } + + while ((readLen = getline(&line, &n, fp)) != -1) { + if (('\r' == line[readLen - 1]) || ('\n' == line[readLen - 1])) { + line[--readLen] = 0; + } + + if (readLen == 0) { + continue; + } + + memcpy(supterTblInfo->tagDataBuf + supterTblInfo->tagSampleCount * supterTblInfo->lenOfTagOfOneRow, line, readLen); + supterTblInfo->tagSampleCount++; + + if (supterTblInfo->tagSampleCount >= MAX_LINE_COUNT_IN_MEM) { + break; + } + } + + free(line); + fclose(fp); + return 0; +} + +int readSampleFromJsonFileToMem(SSuperTable * supterTblInfo) { + // TODO + return 0; +} + + +/* + Read 10000 lines at most. If more than 10000 lines, continue to read after using +*/ +int readSampleFromCsvFileToMem(FILE *fp, SSuperTable* superTblInfo, char* sampleBuf) { + size_t n = 0; + ssize_t readLen = 0; + char * line = NULL; + int getRows = 0; + + memset(sampleBuf, 0, MAX_SAMPLES_ONCE_FROM_FILE* superTblInfo->lenOfOneRow); + while (1) { + readLen = getline(&line, &n, fp); + if (-1 == readLen) { + if(0 != fseek(fp, 0, SEEK_SET)) { + printf("Failed to fseek file: %s, reason:%s\n", superTblInfo->sampleFile, strerror(errno)); + return -1; + } + continue; + } + + if (('\r' == line[readLen - 1]) || ('\n' == line[readLen - 1])) { + line[--readLen] = 0; + } + + if (readLen == 0) { + continue; + } + + if (readLen > superTblInfo->lenOfOneRow) { + printf("sample row len[%d] overflow define schema len[%d], so discard this row\n", (int32_t)readLen, superTblInfo->lenOfOneRow); + continue; + } + + memcpy(sampleBuf + getRows * superTblInfo->lenOfOneRow, line, readLen); + getRows++; + + if (getRows == MAX_SAMPLES_ONCE_FROM_FILE) { + break; + } + } + + tmfree(line); + return 0; +} + +/* +void readSampleFromFileToMem(SSuperTable * supterTblInfo) { + int ret; + if (0 == strncasecmp(supterTblInfo->sampleFormat, "csv", 3)) { + ret = readSampleFromCsvFileToMem(supterTblInfo); + } else if (0 == strncasecmp(supterTblInfo->sampleFormat, "json", 4)) { + ret = readSampleFromJsonFileToMem(supterTblInfo); + } + + if (0 != ret) { + exit(-1); + } +} +*/ +static bool getColumnAndTagTypeFromInsertJsonFile(cJSON* stbInfo, SSuperTable* superTbls) { + bool ret = false; + + // columns + cJSON *columns = cJSON_GetObjectItem(stbInfo, "columns"); + if (columns && columns->type != cJSON_Array) { + printf("failed to read json, columns not found\n"); + goto PARSE_OVER; + } else if (NULL == columns) { + superTbls->columnCount = 0; + superTbls->tagCount = 0; + return true; + } + + int columnSize = cJSON_GetArraySize(columns); + if (columnSize > MAX_COLUMN_COUNT) { + printf("failed to read json, column size overflow, max column size is %d\n", MAX_COLUMN_COUNT); + goto PARSE_OVER; + } + + int count = 1; + int index = 0; + StrColumn columnCase = {0}; + + //superTbls->columnCount = columnSize; + for (int k = 0; k < columnSize; ++k) { + cJSON* column = cJSON_GetArrayItem(columns, k); + if (column == NULL) continue; + + count = 1; + cJSON* countObj = cJSON_GetObjectItem(column, "count"); + if (countObj && countObj->type == cJSON_Number) { + count = countObj->valueint; + } else if (countObj && countObj->type != cJSON_Number) { + printf("failed to read json, column count not found"); + goto PARSE_OVER; + } else { + count = 1; + } + + // column info + memset(&columnCase, 0, sizeof(StrColumn)); + cJSON *dataType = cJSON_GetObjectItem(column, "type"); + if (!dataType || dataType->type != cJSON_String || dataType->valuestring == NULL) { + printf("failed to read json, column type not found"); + goto PARSE_OVER; + } + //strncpy(superTbls->columns[k].dataType, dataType->valuestring, MAX_TB_NAME_SIZE); + strncpy(columnCase.dataType, dataType->valuestring, MAX_TB_NAME_SIZE); + + cJSON* dataLen = cJSON_GetObjectItem(column, "len"); + if (dataLen && dataLen->type == cJSON_Number) { + columnCase.dataLen = dataLen->valueint; + } else if (dataLen && dataLen->type != cJSON_Number) { + printf("failed to read json, column len not found"); + goto PARSE_OVER; + } else { + columnCase.dataLen = 8; + } + + for (int n = 0; n < count; ++n) { + strncpy(superTbls->columns[index].dataType, columnCase.dataType, MAX_TB_NAME_SIZE); + superTbls->columns[index].dataLen = columnCase.dataLen; + index++; + } + } + superTbls->columnCount = index; + + count = 1; + index = 0; + // tags + cJSON *tags = cJSON_GetObjectItem(stbInfo, "tags"); + if (!tags || tags->type != cJSON_Array) { + printf("failed to read json, tags not found"); + goto PARSE_OVER; + } + + int tagSize = cJSON_GetArraySize(tags); + if (tagSize > MAX_TAG_COUNT) { + printf("failed to read json, tags size overflow, max tag size is %d\n", MAX_TAG_COUNT); + goto PARSE_OVER; + } + + //superTbls->tagCount = tagSize; + for (int k = 0; k < tagSize; ++k) { + cJSON* tag = cJSON_GetArrayItem(tags, k); + if (tag == NULL) continue; + + count = 1; + cJSON* countObj = cJSON_GetObjectItem(tag, "count"); + if (countObj && countObj->type == cJSON_Number) { + count = countObj->valueint; + } else if (countObj && countObj->type != cJSON_Number) { + printf("failed to read json, column count not found"); + goto PARSE_OVER; + } else { + count = 1; + } + + // column info + memset(&columnCase, 0, sizeof(StrColumn)); + cJSON *dataType = cJSON_GetObjectItem(tag, "type"); + if (!dataType || dataType->type != cJSON_String || dataType->valuestring == NULL) { + printf("failed to read json, tag type not found"); + goto PARSE_OVER; + } + strncpy(columnCase.dataType, dataType->valuestring, MAX_TB_NAME_SIZE); + + cJSON* dataLen = cJSON_GetObjectItem(tag, "len"); + if (dataLen && dataLen->type == cJSON_Number) { + columnCase.dataLen = dataLen->valueint; + } else if (dataLen && dataLen->type != cJSON_Number) { + printf("failed to read json, column len not found"); + goto PARSE_OVER; + } else { + columnCase.dataLen = 0; + } + + for (int n = 0; n < count; ++n) { + strncpy(superTbls->tags[index].dataType, columnCase.dataType, MAX_TB_NAME_SIZE); + superTbls->tags[index].dataLen = columnCase.dataLen; + index++; + } + } + superTbls->tagCount = index; + + ret = true; + +PARSE_OVER: + //free(content); + //cJSON_Delete(root); + //fclose(fp); + return ret; +} + +static bool getMetaFromInsertJsonFile(cJSON* root) { + bool ret = false; + + cJSON* cfgdir = cJSON_GetObjectItem(root, "cfgdir"); + if (cfgdir && cfgdir->type == cJSON_String && cfgdir->valuestring != NULL) { + strncpy(g_Dbs.cfgDir, cfgdir->valuestring, MAX_FILE_NAME_LEN); + } + + cJSON* host = cJSON_GetObjectItem(root, "host"); + if (host && host->type == cJSON_String && host->valuestring != NULL) { + strncpy(g_Dbs.host, host->valuestring, MAX_DB_NAME_SIZE); + } else if (!host) { + strncpy(g_Dbs.host, "127.0.0.1", MAX_DB_NAME_SIZE); + } else { + printf("failed to read json, host not found\n"); + goto PARSE_OVER; + } + + cJSON* port = cJSON_GetObjectItem(root, "port"); + if (port && port->type == cJSON_Number) { + g_Dbs.port = port->valueint; + } else if (!port) { + g_Dbs.port = 6030; + } + + cJSON* user = cJSON_GetObjectItem(root, "user"); + if (user && user->type == cJSON_String && user->valuestring != NULL) { + strncpy(g_Dbs.user, user->valuestring, MAX_DB_NAME_SIZE); + } else if (!user) { + strncpy(g_Dbs.user, "root", MAX_DB_NAME_SIZE); + } + + cJSON* password = cJSON_GetObjectItem(root, "password"); + if (password && password->type == cJSON_String && password->valuestring != NULL) { + strncpy(g_Dbs.password, password->valuestring, MAX_DB_NAME_SIZE); + } else if (!password) { + strncpy(g_Dbs.password, "taosdata", MAX_DB_NAME_SIZE); + } + + cJSON* resultfile = cJSON_GetObjectItem(root, "result_file"); + if (resultfile && resultfile->type == cJSON_String && resultfile->valuestring != NULL) { + strncpy(g_Dbs.resultFile, resultfile->valuestring, MAX_FILE_NAME_LEN); + } else if (!resultfile) { + strncpy(g_Dbs.resultFile, "./insert_res.txt", MAX_FILE_NAME_LEN); + } + + cJSON* threads = cJSON_GetObjectItem(root, "thread_count"); + if (threads && threads->type == cJSON_Number) { + g_Dbs.threadCount = threads->valueint; + } else if (!threads) { + g_Dbs.threadCount = 1; + } else { + printf("failed to read json, threads not found"); + goto PARSE_OVER; + } + + cJSON* dbs = cJSON_GetObjectItem(root, "databases"); + if (!dbs || dbs->type != cJSON_Array) { + printf("failed to read json, databases not found\n"); + goto PARSE_OVER; + } + + int dbSize = cJSON_GetArraySize(dbs); + if (dbSize > MAX_DB_COUNT) { + printf("failed to read json, databases size overflow, max database is %d\n", MAX_DB_COUNT); + goto PARSE_OVER; + } + + g_Dbs.dbCount = dbSize; + for (int i = 0; i < dbSize; ++i) { + cJSON* dbinfos = cJSON_GetArrayItem(dbs, i); + if (dbinfos == NULL) continue; + + // dbinfo + cJSON *dbinfo = cJSON_GetObjectItem(dbinfos, "dbinfo"); + if (!dbinfo || dbinfo->type != cJSON_Object) { + printf("failed to read json, dbinfo not found"); + goto PARSE_OVER; + } + + cJSON *dbName = cJSON_GetObjectItem(dbinfo, "name"); + if (!dbName || dbName->type != cJSON_String || dbName->valuestring == NULL) { + printf("failed to read json, db name not found"); + goto PARSE_OVER; + } + strncpy(g_Dbs.db[i].dbName, dbName->valuestring, MAX_DB_NAME_SIZE); + + cJSON *drop = cJSON_GetObjectItem(dbinfo, "drop"); + if (drop && drop->type == cJSON_String && drop->valuestring != NULL) { + if (0 == strncasecmp(drop->valuestring, "yes", 3)) { + g_Dbs.db[i].drop = 1; + } else { + g_Dbs.db[i].drop = 0; + } + } else if (!drop) { + g_Dbs.db[i].drop = 0; + } else { + printf("failed to read json, drop not found"); + goto PARSE_OVER; + } + + cJSON *precision = cJSON_GetObjectItem(dbinfo, "precision"); + if (precision && precision->type == cJSON_String && precision->valuestring != NULL) { + strncpy(g_Dbs.db[i].dbCfg.precision, precision->valuestring, MAX_DB_NAME_SIZE); + } else if (!precision) { + //strncpy(g_Dbs.db[i].dbCfg.precision, "ms", MAX_DB_NAME_SIZE); + memset(g_Dbs.db[i].dbCfg.precision, 0, MAX_DB_NAME_SIZE); + } else { + printf("failed to read json, precision not found"); + goto PARSE_OVER; + } + + cJSON* update = cJSON_GetObjectItem(dbinfo, "update"); + if (update && update->type == cJSON_Number) { + g_Dbs.db[i].dbCfg.update = update->valueint; + } else if (!update) { + g_Dbs.db[i].dbCfg.update = -1; + } else { + printf("failed to read json, update not found"); + goto PARSE_OVER; + } + + cJSON* replica = cJSON_GetObjectItem(dbinfo, "replica"); + if (replica && replica->type == cJSON_Number) { + g_Dbs.db[i].dbCfg.replica = replica->valueint; + } else if (!replica) { + g_Dbs.db[i].dbCfg.replica = -1; + } else { + printf("failed to read json, replica not found"); + goto PARSE_OVER; + } + + cJSON* keep = cJSON_GetObjectItem(dbinfo, "keep"); + if (keep && keep->type == cJSON_Number) { + g_Dbs.db[i].dbCfg.keep = keep->valueint; + } else if (!keep) { + g_Dbs.db[i].dbCfg.keep = -1; + } else { + printf("failed to read json, keep not found"); + goto PARSE_OVER; + } + + cJSON* days = cJSON_GetObjectItem(dbinfo, "days"); + if (days && days->type == cJSON_Number) { + g_Dbs.db[i].dbCfg.days = days->valueint; + } else if (!days) { + g_Dbs.db[i].dbCfg.days = -1; + } else { + printf("failed to read json, days not found"); + goto PARSE_OVER; + } + + cJSON* cache = cJSON_GetObjectItem(dbinfo, "cache"); + if (cache && cache->type == cJSON_Number) { + g_Dbs.db[i].dbCfg.cache = cache->valueint; + } else if (!cache) { + g_Dbs.db[i].dbCfg.cache = -1; + } else { + printf("failed to read json, cache not found"); + goto PARSE_OVER; + } + + cJSON* blocks= cJSON_GetObjectItem(dbinfo, "blocks"); + if (blocks && blocks->type == cJSON_Number) { + g_Dbs.db[i].dbCfg.blocks = blocks->valueint; + } else if (!blocks) { + g_Dbs.db[i].dbCfg.blocks = -1; + } else { + printf("failed to read json, block not found"); + goto PARSE_OVER; + } + + //cJSON* maxtablesPerVnode= cJSON_GetObjectItem(dbinfo, "maxtablesPerVnode"); + //if (maxtablesPerVnode && maxtablesPerVnode->type == cJSON_Number) { + // g_Dbs.db[i].dbCfg.maxtablesPerVnode = maxtablesPerVnode->valueint; + //} else if (!maxtablesPerVnode) { + // g_Dbs.db[i].dbCfg.maxtablesPerVnode = TSDB_DEFAULT_TABLES; + //} else { + // printf("failed to read json, maxtablesPerVnode not found"); + // goto PARSE_OVER; + //} + + cJSON* minRows= cJSON_GetObjectItem(dbinfo, "minRows"); + if (minRows && minRows->type == cJSON_Number) { + g_Dbs.db[i].dbCfg.minRows = minRows->valueint; + } else if (!minRows) { + g_Dbs.db[i].dbCfg.minRows = -1; + } else { + printf("failed to read json, minRows not found"); + goto PARSE_OVER; + } + + cJSON* maxRows= cJSON_GetObjectItem(dbinfo, "maxRows"); + if (maxRows && maxRows->type == cJSON_Number) { + g_Dbs.db[i].dbCfg.maxRows = maxRows->valueint; + } else if (!maxRows) { + g_Dbs.db[i].dbCfg.maxRows = -1; + } else { + printf("failed to read json, maxRows not found"); + goto PARSE_OVER; + } + + cJSON* comp= cJSON_GetObjectItem(dbinfo, "comp"); + if (comp && comp->type == cJSON_Number) { + g_Dbs.db[i].dbCfg.comp = comp->valueint; + } else if (!comp) { + g_Dbs.db[i].dbCfg.comp = -1; + } else { + printf("failed to read json, comp not found"); + goto PARSE_OVER; + } + + cJSON* walLevel= cJSON_GetObjectItem(dbinfo, "walLevel"); + if (walLevel && walLevel->type == cJSON_Number) { + g_Dbs.db[i].dbCfg.walLevel = walLevel->valueint; + } else if (!walLevel) { + g_Dbs.db[i].dbCfg.walLevel = -1; + } else { + printf("failed to read json, walLevel not found"); + goto PARSE_OVER; + } + + cJSON* quorum= cJSON_GetObjectItem(dbinfo, "quorum"); + if (quorum && quorum->type == cJSON_Number) { + g_Dbs.db[i].dbCfg.quorum = quorum->valueint; + } else if (!quorum) { + g_Dbs.db[i].dbCfg.quorum = -1; + } else { + printf("failed to read json, walLevel not found"); + goto PARSE_OVER; + } + + cJSON* fsync= cJSON_GetObjectItem(dbinfo, "fsync"); + if (fsync && fsync->type == cJSON_Number) { + g_Dbs.db[i].dbCfg.fsync = fsync->valueint; + } else if (!fsync) { + g_Dbs.db[i].dbCfg.fsync = -1; + } else { + printf("failed to read json, fsync not found"); + goto PARSE_OVER; + } + + // super_talbes + cJSON *stables = cJSON_GetObjectItem(dbinfos, "super_tables"); + if (!stables || stables->type != cJSON_Array) { + printf("failed to read json, super_tables not found"); + goto PARSE_OVER; + } + + int stbSize = cJSON_GetArraySize(stables); + if (stbSize > MAX_SUPER_TABLE_COUNT) { + printf("failed to read json, databases size overflow, max database is %d\n", MAX_SUPER_TABLE_COUNT); + goto PARSE_OVER; + } + + g_Dbs.db[i].superTblCount = stbSize; + for (int j = 0; j < stbSize; ++j) { + cJSON* stbInfo = cJSON_GetArrayItem(stables, j); + if (stbInfo == NULL) continue; + + // dbinfo + cJSON *stbName = cJSON_GetObjectItem(stbInfo, "name"); + if (!stbName || stbName->type != cJSON_String || stbName->valuestring == NULL) { + printf("failed to read json, stb name not found"); + goto PARSE_OVER; + } + strncpy(g_Dbs.db[i].superTbls[j].sTblName, stbName->valuestring, MAX_TB_NAME_SIZE); + + cJSON *prefix = cJSON_GetObjectItem(stbInfo, "childtable_prefix"); + if (!prefix || prefix->type != cJSON_String || prefix->valuestring == NULL) { + printf("failed to read json, childtable_prefix not found"); + goto PARSE_OVER; + } + strncpy(g_Dbs.db[i].superTbls[j].childTblPrefix, prefix->valuestring, MAX_DB_NAME_SIZE); + + cJSON *autoCreateTbl = cJSON_GetObjectItem(stbInfo, "auto_create_table"); // yes, no, null + if (autoCreateTbl && autoCreateTbl->type == cJSON_String && autoCreateTbl->valuestring != NULL) { + if (0 == strncasecmp(autoCreateTbl->valuestring, "yes", 3)) { + g_Dbs.db[i].superTbls[j].autoCreateTable = AUTO_CREATE_SUBTBL; + } else if (0 == strncasecmp(autoCreateTbl->valuestring, "no", 2)) { + g_Dbs.db[i].superTbls[j].autoCreateTable = PRE_CREATE_SUBTBL; + } else { + g_Dbs.db[i].superTbls[j].autoCreateTable = PRE_CREATE_SUBTBL; + } + } else if (!autoCreateTbl) { + g_Dbs.db[i].superTbls[j].autoCreateTable = PRE_CREATE_SUBTBL; + } else { + printf("failed to read json, auto_create_table not found"); + goto PARSE_OVER; + } + + cJSON *childTblExists = cJSON_GetObjectItem(stbInfo, "child_table_exists"); // yes, no + if (childTblExists && childTblExists->type == cJSON_String && childTblExists->valuestring != NULL) { + if (0 == strncasecmp(childTblExists->valuestring, "yes", 3)) { + g_Dbs.db[i].superTbls[j].childTblExists = TBL_ALREADY_EXISTS; + } else if (0 == strncasecmp(childTblExists->valuestring, "no", 2)) { + g_Dbs.db[i].superTbls[j].childTblExists = TBL_NO_EXISTS; + } else { + g_Dbs.db[i].superTbls[j].childTblExists = TBL_NO_EXISTS; + } + } else if (!childTblExists) { + g_Dbs.db[i].superTbls[j].childTblExists = TBL_NO_EXISTS; + } else { + printf("failed to read json, child_table_exists not found"); + goto PARSE_OVER; + } + + cJSON* count = cJSON_GetObjectItem(stbInfo, "childtable_count"); + if (!count || count->type != cJSON_Number || 0 >= count->valueint) { + printf("failed to read json, childtable_count not found"); + goto PARSE_OVER; + } + g_Dbs.db[i].superTbls[j].childTblCount = count->valueint; + + cJSON *dataSource = cJSON_GetObjectItem(stbInfo, "data_source"); + if (dataSource && dataSource->type == cJSON_String && dataSource->valuestring != NULL) { + strncpy(g_Dbs.db[i].superTbls[j].dataSource, dataSource->valuestring, MAX_DB_NAME_SIZE); + } else if (!dataSource) { + strncpy(g_Dbs.db[i].superTbls[j].dataSource, "rand", MAX_DB_NAME_SIZE); + } else { + printf("failed to read json, data_source not found"); + goto PARSE_OVER; + } + + cJSON *insertMode = cJSON_GetObjectItem(stbInfo, "insert_mode"); // taosc , restful + if (insertMode && insertMode->type == cJSON_String && insertMode->valuestring != NULL) { + strncpy(g_Dbs.db[i].superTbls[j].insertMode, insertMode->valuestring, MAX_DB_NAME_SIZE); + #ifndef TD_LOWA_CURL + if (0 == strncasecmp(g_Dbs.db[i].superTbls[j].insertMode, "restful", 7)) { + printf("There no libcurl, so no support resetful test! please use taosc mode.\n"); + goto PARSE_OVER; + } + #endif + } else if (!insertMode) { + strncpy(g_Dbs.db[i].superTbls[j].insertMode, "taosc", MAX_DB_NAME_SIZE); + } else { + printf("failed to read json, insert_mode not found"); + goto PARSE_OVER; + } + + cJSON *ts = cJSON_GetObjectItem(stbInfo, "start_timestamp"); + if (ts && ts->type == cJSON_String && ts->valuestring != NULL) { + strncpy(g_Dbs.db[i].superTbls[j].startTimestamp, ts->valuestring, MAX_DB_NAME_SIZE); + } else if (!ts) { + strncpy(g_Dbs.db[i].superTbls[j].startTimestamp, "now", MAX_DB_NAME_SIZE); + } else { + printf("failed to read json, start_timestamp not found"); + goto PARSE_OVER; + } + + cJSON* timestampStep = cJSON_GetObjectItem(stbInfo, "timestamp_step"); + if (timestampStep && timestampStep->type == cJSON_Number) { + g_Dbs.db[i].superTbls[j].timeStampStep = timestampStep->valueint; + } else if (!timestampStep) { + g_Dbs.db[i].superTbls[j].timeStampStep = 1000; + } else { + printf("failed to read json, timestamp_step not found"); + goto PARSE_OVER; + } + + cJSON* sampleDataBufSize = cJSON_GetObjectItem(stbInfo, "sample_buf_size"); + if (sampleDataBufSize && sampleDataBufSize->type == cJSON_Number) { + g_Dbs.db[i].superTbls[j].sampleDataBufSize = sampleDataBufSize->valueint; + if (g_Dbs.db[i].superTbls[j].sampleDataBufSize < 1024*1024) { + g_Dbs.db[i].superTbls[j].sampleDataBufSize = 1024*1024 + 1024; + } + } else if (!sampleDataBufSize) { + g_Dbs.db[i].superTbls[j].sampleDataBufSize = 1024*1024 + 1024; + } else { + printf("failed to read json, sample_buf_size not found"); + goto PARSE_OVER; + } + + cJSON *sampleFormat = cJSON_GetObjectItem(stbInfo, "sample_format"); + if (sampleFormat && sampleFormat->type == cJSON_String && sampleFormat->valuestring != NULL) { + strncpy(g_Dbs.db[i].superTbls[j].sampleFormat, sampleFormat->valuestring, MAX_DB_NAME_SIZE); + } else if (!sampleFormat) { + strncpy(g_Dbs.db[i].superTbls[j].sampleFormat, "csv", MAX_DB_NAME_SIZE); + } else { + printf("failed to read json, sample_format not found"); + goto PARSE_OVER; + } + + cJSON *sampleFile = cJSON_GetObjectItem(stbInfo, "sample_file"); + if (sampleFile && sampleFile->type == cJSON_String && sampleFile->valuestring != NULL) { + strncpy(g_Dbs.db[i].superTbls[j].sampleFile, sampleFile->valuestring, MAX_FILE_NAME_LEN); + } else if (!sampleFile) { + memset(g_Dbs.db[i].superTbls[j].sampleFile, 0, MAX_FILE_NAME_LEN); + } else { + printf("failed to read json, sample_file not found"); + goto PARSE_OVER; + } + + cJSON *tagsFile = cJSON_GetObjectItem(stbInfo, "tags_file"); + if (tagsFile && tagsFile->type == cJSON_String && tagsFile->valuestring != NULL) { + strncpy(g_Dbs.db[i].superTbls[j].tagsFile, tagsFile->valuestring, MAX_FILE_NAME_LEN); + if (0 == g_Dbs.db[i].superTbls[j].tagsFile[0]) { + g_Dbs.db[i].superTbls[j].tagSource = 0; + } else { + g_Dbs.db[i].superTbls[j].tagSource = 1; + } + } else if (!tagsFile) { + memset(g_Dbs.db[i].superTbls[j].tagsFile, 0, MAX_FILE_NAME_LEN); + g_Dbs.db[i].superTbls[j].tagSource = 0; + } else { + printf("failed to read json, tags_file not found"); + goto PARSE_OVER; + } + + cJSON* maxSqlLen = cJSON_GetObjectItem(stbInfo, "max_sql_len"); + if (maxSqlLen && maxSqlLen->type == cJSON_Number) { + int32_t len = maxSqlLen->valueint; + if (len > TSDB_MAX_ALLOWED_SQL_LEN) { + len = TSDB_MAX_ALLOWED_SQL_LEN; + } else if (len < TSDB_MAX_SQL_LEN) { + len = TSDB_MAX_SQL_LEN; + } + g_Dbs.db[i].superTbls[j].maxSqlLen = len; + } else if (!maxSqlLen) { + g_Dbs.db[i].superTbls[j].maxSqlLen = TSDB_MAX_SQL_LEN; + } else { + printf("failed to read json, maxSqlLen not found"); + goto PARSE_OVER; + } + + cJSON *multiThreadWriteOneTbl = cJSON_GetObjectItem(stbInfo, "multi_thread_write_one_tbl"); // no , yes + if (multiThreadWriteOneTbl && multiThreadWriteOneTbl->type == cJSON_String && multiThreadWriteOneTbl->valuestring != NULL) { + if (0 == strncasecmp(multiThreadWriteOneTbl->valuestring, "yes", 3)) { + g_Dbs.db[i].superTbls[j].multiThreadWriteOneTbl = 1; + } else { + g_Dbs.db[i].superTbls[j].multiThreadWriteOneTbl = 0; + } + } else if (!multiThreadWriteOneTbl) { + g_Dbs.db[i].superTbls[j].multiThreadWriteOneTbl = 0; + } else { + printf("failed to read json, multiThreadWriteOneTbl not found"); + goto PARSE_OVER; + } + + cJSON* numberOfTblInOneSql = cJSON_GetObjectItem(stbInfo, "number_of_tbl_in_one_sql"); + if (numberOfTblInOneSql && numberOfTblInOneSql->type == cJSON_Number) { + g_Dbs.db[i].superTbls[j].numberOfTblInOneSql = numberOfTblInOneSql->valueint; + } else if (!numberOfTblInOneSql) { + g_Dbs.db[i].superTbls[j].numberOfTblInOneSql = 0; + } else { + printf("failed to read json, numberOfTblInOneSql not found"); + goto PARSE_OVER; + } + + cJSON* rowsPerTbl = cJSON_GetObjectItem(stbInfo, "rows_per_tbl"); + if (rowsPerTbl && rowsPerTbl->type == cJSON_Number) { + g_Dbs.db[i].superTbls[j].rowsPerTbl = rowsPerTbl->valueint; + } else if (!rowsPerTbl) { + g_Dbs.db[i].superTbls[j].rowsPerTbl = 1; + } else { + printf("failed to read json, rowsPerTbl not found"); + goto PARSE_OVER; + } + + cJSON* disorderRatio = cJSON_GetObjectItem(stbInfo, "disorder_ratio"); + if (disorderRatio && disorderRatio->type == cJSON_Number) { + g_Dbs.db[i].superTbls[j].disorderRatio = disorderRatio->valueint; + } else if (!disorderRatio) { + g_Dbs.db[i].superTbls[j].disorderRatio = 0; + } else { + printf("failed to read json, disorderRatio not found"); + goto PARSE_OVER; + } + + cJSON* disorderRange = cJSON_GetObjectItem(stbInfo, "disorder_range"); + if (disorderRange && disorderRange->type == cJSON_Number) { + g_Dbs.db[i].superTbls[j].disorderRange = disorderRange->valueint; + } else if (!disorderRange) { + g_Dbs.db[i].superTbls[j].disorderRange = 1000; + } else { + printf("failed to read json, disorderRange not found"); + goto PARSE_OVER; + } + + cJSON* insertRate = cJSON_GetObjectItem(stbInfo, "insert_rate"); + if (insertRate && insertRate->type == cJSON_Number) { + g_Dbs.db[i].superTbls[j].insertRate = insertRate->valueint; + } else if (!insertRate) { + g_Dbs.db[i].superTbls[j].insertRate = 0; + } else { + printf("failed to read json, insert_rate not found"); + goto PARSE_OVER; + } + + cJSON* insertRows = cJSON_GetObjectItem(stbInfo, "insert_rows"); + if (insertRows && insertRows->type == cJSON_Number) { + g_Dbs.db[i].superTbls[j].insertRows = insertRows->valueint; + if (0 == g_Dbs.db[i].superTbls[j].insertRows) { + g_Dbs.db[i].superTbls[j].insertRows = 0x7FFFFFFFFFFFFFFF; + } + } else if (!insertRows) { + g_Dbs.db[i].superTbls[j].insertRows = 0x7FFFFFFFFFFFFFFF; + } else { + printf("failed to read json, insert_rows not found"); + goto PARSE_OVER; + } + + if (NO_CREATE_SUBTBL == g_Dbs.db[i].superTbls[j].autoCreateTable || (TBL_ALREADY_EXISTS == g_Dbs.db[i].superTbls[j].childTblExists)) { + continue; + } + + int retVal = getColumnAndTagTypeFromInsertJsonFile(stbInfo, &g_Dbs.db[i].superTbls[j]); + if (false == retVal) { + goto PARSE_OVER; + } + } + } + + ret = true; + +PARSE_OVER: + //free(content); + //cJSON_Delete(root); + //fclose(fp); + return ret; +} + +static bool getMetaFromQueryJsonFile(cJSON* root) { + bool ret = false; + + cJSON* cfgdir = cJSON_GetObjectItem(root, "cfgdir"); + if (cfgdir && cfgdir->type == cJSON_String && cfgdir->valuestring != NULL) { + strncpy(g_queryInfo.cfgDir, cfgdir->valuestring, MAX_FILE_NAME_LEN); + } + + cJSON* host = cJSON_GetObjectItem(root, "host"); + if (host && host->type == cJSON_String && host->valuestring != NULL) { + strncpy(g_queryInfo.host, host->valuestring, MAX_DB_NAME_SIZE); + } else if (!host) { + strncpy(g_queryInfo.host, "127.0.0.1", MAX_DB_NAME_SIZE); + } else { + printf("failed to read json, host not found\n"); + goto PARSE_OVER; + } + + cJSON* port = cJSON_GetObjectItem(root, "port"); + if (port && port->type == cJSON_Number) { + g_queryInfo.port = port->valueint; + } else if (!port) { + g_queryInfo.port = 6030; + } + + cJSON* user = cJSON_GetObjectItem(root, "user"); + if (user && user->type == cJSON_String && user->valuestring != NULL) { + strncpy(g_queryInfo.user, user->valuestring, MAX_DB_NAME_SIZE); + } else if (!user) { + strncpy(g_queryInfo.user, "root", MAX_DB_NAME_SIZE); ; + } + + cJSON* password = cJSON_GetObjectItem(root, "password"); + if (password && password->type == cJSON_String && password->valuestring != NULL) { + strncpy(g_queryInfo.password, password->valuestring, MAX_DB_NAME_SIZE); + } else if (!password) { + strncpy(g_queryInfo.password, "taosdata", MAX_DB_NAME_SIZE);; + } + + cJSON* dbs = cJSON_GetObjectItem(root, "databases"); + if (dbs && dbs->type == cJSON_String && dbs->valuestring != NULL) { + strncpy(g_queryInfo.dbName, dbs->valuestring, MAX_DB_NAME_SIZE); + } else if (!dbs) { + printf("failed to read json, databases not found\n"); + goto PARSE_OVER; + } + + cJSON* queryMode = cJSON_GetObjectItem(root, "query_mode"); + if (queryMode && queryMode->type == cJSON_String && queryMode->valuestring != NULL) { + strncpy(g_queryInfo.queryMode, queryMode->valuestring, MAX_TB_NAME_SIZE); + } else if (!queryMode) { + strncpy(g_queryInfo.queryMode, "taosc", MAX_TB_NAME_SIZE); + } else { + printf("failed to read json, query_mode not found\n"); + goto PARSE_OVER; + } + + // super_table_query + cJSON *superQuery = cJSON_GetObjectItem(root, "specified_table_query"); + if (!superQuery) { + g_queryInfo.superQueryInfo.concurrent = 0; + g_queryInfo.superQueryInfo.sqlCount = 0; + } else if (superQuery->type != cJSON_Object) { + printf("failed to read json, super_table_query not found"); + goto PARSE_OVER; + } else { + cJSON* rate = cJSON_GetObjectItem(superQuery, "query_interval"); + if (rate && rate->type == cJSON_Number) { + g_queryInfo.superQueryInfo.rate = rate->valueint; + } else if (!rate) { + g_queryInfo.superQueryInfo.rate = 0; + } + + cJSON* concurrent = cJSON_GetObjectItem(superQuery, "concurrent"); + if (concurrent && concurrent->type == cJSON_Number) { + g_queryInfo.superQueryInfo.concurrent = concurrent->valueint; + } else if (!concurrent) { + g_queryInfo.superQueryInfo.concurrent = 1; + } + + cJSON* mode = cJSON_GetObjectItem(superQuery, "mode"); + if (mode && mode->type == cJSON_String && mode->valuestring != NULL) { + if (0 == strcmp("sync", mode->valuestring)) { + g_queryInfo.superQueryInfo.subscribeMode = 0; + } else if (0 == strcmp("async", mode->valuestring)) { + g_queryInfo.superQueryInfo.subscribeMode = 1; + } else { + printf("failed to read json, subscribe mod error\n"); + goto PARSE_OVER; + } + } else { + g_queryInfo.superQueryInfo.subscribeMode = 0; + } + + cJSON* interval = cJSON_GetObjectItem(superQuery, "interval"); + if (interval && interval->type == cJSON_Number) { + g_queryInfo.superQueryInfo.subscribeInterval = interval->valueint; + } else if (!interval) { + //printf("failed to read json, subscribe interval no found\n"); + //goto PARSE_OVER; + g_queryInfo.superQueryInfo.subscribeInterval = 10000; + } + + cJSON* restart = cJSON_GetObjectItem(superQuery, "restart"); + if (restart && restart->type == cJSON_String && restart->valuestring != NULL) { + if (0 == strcmp("yes", restart->valuestring)) { + g_queryInfo.superQueryInfo.subscribeRestart = 1; + } else if (0 == strcmp("no", restart->valuestring)) { + g_queryInfo.superQueryInfo.subscribeRestart = 0; + } else { + printf("failed to read json, subscribe restart error\n"); + goto PARSE_OVER; + } + } else { + g_queryInfo.superQueryInfo.subscribeRestart = 1; + } + + cJSON* keepProgress = cJSON_GetObjectItem(superQuery, "keepProgress"); + if (keepProgress && keepProgress->type == cJSON_String && keepProgress->valuestring != NULL) { + if (0 == strcmp("yes", keepProgress->valuestring)) { + g_queryInfo.superQueryInfo.subscribeKeepProgress = 1; + } else if (0 == strcmp("no", keepProgress->valuestring)) { + g_queryInfo.superQueryInfo.subscribeKeepProgress = 0; + } else { + printf("failed to read json, subscribe keepProgress error\n"); + goto PARSE_OVER; + } + } else { + g_queryInfo.superQueryInfo.subscribeKeepProgress = 0; + } + + // sqls + cJSON* superSqls = cJSON_GetObjectItem(superQuery, "sqls"); + if (!superSqls) { + g_queryInfo.superQueryInfo.sqlCount = 0; + } else if (superSqls->type != cJSON_Array) { + printf("failed to read json, super sqls not found\n"); + goto PARSE_OVER; + } else { + int superSqlSize = cJSON_GetArraySize(superSqls); + if (superSqlSize > MAX_QUERY_SQL_COUNT) { + printf("failed to read json, query sql size overflow, max is %d\n", MAX_QUERY_SQL_COUNT); + goto PARSE_OVER; + } + + g_queryInfo.superQueryInfo.sqlCount = superSqlSize; + for (int j = 0; j < superSqlSize; ++j) { + cJSON* sql = cJSON_GetArrayItem(superSqls, j); + if (sql == NULL) continue; + + cJSON *sqlStr = cJSON_GetObjectItem(sql, "sql"); + if (!sqlStr || sqlStr->type != cJSON_String || sqlStr->valuestring == NULL) { + printf("failed to read json, sql not found\n"); + goto PARSE_OVER; + } + strncpy(g_queryInfo.superQueryInfo.sql[j], sqlStr->valuestring, MAX_QUERY_SQL_LENGTH); + + cJSON *result = cJSON_GetObjectItem(sql, "result"); + if (NULL != result && result->type == cJSON_String && result->valuestring != NULL) { + strncpy(g_queryInfo.superQueryInfo.result[j], result->valuestring, MAX_FILE_NAME_LEN); + } else if (NULL == result) { + memset(g_queryInfo.superQueryInfo.result[j], 0, MAX_FILE_NAME_LEN); + } else { + printf("failed to read json, super query result file not found\n"); + goto PARSE_OVER; + } + } + } + } + + // sub_table_query + cJSON *subQuery = cJSON_GetObjectItem(root, "super_table_query"); + if (!subQuery) { + g_queryInfo.subQueryInfo.threadCnt = 0; + g_queryInfo.subQueryInfo.sqlCount = 0; + } else if (subQuery->type != cJSON_Object) { + printf("failed to read json, sub_table_query not found"); + ret = true; + goto PARSE_OVER; + } else { + cJSON* subrate = cJSON_GetObjectItem(subQuery, "query_interval"); + if (subrate && subrate->type == cJSON_Number) { + g_queryInfo.subQueryInfo.rate = subrate->valueint; + } else if (!subrate) { + g_queryInfo.subQueryInfo.rate = 0; + } + + cJSON* threads = cJSON_GetObjectItem(subQuery, "threads"); + if (threads && threads->type == cJSON_Number) { + g_queryInfo.subQueryInfo.threadCnt = threads->valueint; + } else if (!threads) { + g_queryInfo.subQueryInfo.threadCnt = 1; + } + + //cJSON* subTblCnt = cJSON_GetObjectItem(subQuery, "childtable_count"); + //if (subTblCnt && subTblCnt->type == cJSON_Number) { + // g_queryInfo.subQueryInfo.childTblCount = subTblCnt->valueint; + //} else if (!subTblCnt) { + // g_queryInfo.subQueryInfo.childTblCount = 0; + //} + + cJSON* stblname = cJSON_GetObjectItem(subQuery, "stblname"); + if (stblname && stblname->type == cJSON_String && stblname->valuestring != NULL) { + strncpy(g_queryInfo.subQueryInfo.sTblName, stblname->valuestring, MAX_TB_NAME_SIZE); + } else { + printf("failed to read json, super table name not found\n"); + goto PARSE_OVER; + } + + cJSON* submode = cJSON_GetObjectItem(subQuery, "mode"); + if (submode && submode->type == cJSON_String && submode->valuestring != NULL) { + if (0 == strcmp("sync", submode->valuestring)) { + g_queryInfo.subQueryInfo.subscribeMode = 0; + } else if (0 == strcmp("async", submode->valuestring)) { + g_queryInfo.subQueryInfo.subscribeMode = 1; + } else { + printf("failed to read json, subscribe mod error\n"); + goto PARSE_OVER; + } + } else { + g_queryInfo.subQueryInfo.subscribeMode = 0; + } + + cJSON* subinterval = cJSON_GetObjectItem(subQuery, "interval"); + if (subinterval && subinterval->type == cJSON_Number) { + g_queryInfo.subQueryInfo.subscribeInterval = subinterval->valueint; + } else if (!subinterval) { + //printf("failed to read json, subscribe interval no found\n"); + //goto PARSE_OVER; + g_queryInfo.subQueryInfo.subscribeInterval = 10000; + } + + cJSON* subrestart = cJSON_GetObjectItem(subQuery, "restart"); + if (subrestart && subrestart->type == cJSON_String && subrestart->valuestring != NULL) { + if (0 == strcmp("yes", subrestart->valuestring)) { + g_queryInfo.subQueryInfo.subscribeRestart = 1; + } else if (0 == strcmp("no", subrestart->valuestring)) { + g_queryInfo.subQueryInfo.subscribeRestart = 0; + } else { + printf("failed to read json, subscribe restart error\n"); + goto PARSE_OVER; + } + } else { + g_queryInfo.subQueryInfo.subscribeRestart = 1; + } + + cJSON* subkeepProgress = cJSON_GetObjectItem(subQuery, "keepProgress"); + if (subkeepProgress && subkeepProgress->type == cJSON_String && subkeepProgress->valuestring != NULL) { + if (0 == strcmp("yes", subkeepProgress->valuestring)) { + g_queryInfo.subQueryInfo.subscribeKeepProgress = 1; + } else if (0 == strcmp("no", subkeepProgress->valuestring)) { + g_queryInfo.subQueryInfo.subscribeKeepProgress = 0; + } else { + printf("failed to read json, subscribe keepProgress error\n"); + goto PARSE_OVER; + } + } else { + g_queryInfo.subQueryInfo.subscribeKeepProgress = 0; + } + + // sqls + cJSON* subsqls = cJSON_GetObjectItem(subQuery, "sqls"); + if (!subsqls) { + g_queryInfo.subQueryInfo.sqlCount = 0; + } else if (subsqls->type != cJSON_Array) { + printf("failed to read json, super sqls not found\n"); + goto PARSE_OVER; + } else { + int superSqlSize = cJSON_GetArraySize(subsqls); + if (superSqlSize > MAX_QUERY_SQL_COUNT) { + printf("failed to read json, query sql size overflow, max is %d\n", MAX_QUERY_SQL_COUNT); + goto PARSE_OVER; + } + + g_queryInfo.subQueryInfo.sqlCount = superSqlSize; + for (int j = 0; j < superSqlSize; ++j) { + cJSON* sql = cJSON_GetArrayItem(subsqls, j); + if (sql == NULL) continue; + + cJSON *sqlStr = cJSON_GetObjectItem(sql, "sql"); + if (!sqlStr || sqlStr->type != cJSON_String || sqlStr->valuestring == NULL) { + printf("failed to read json, sql not found\n"); + goto PARSE_OVER; + } + strncpy(g_queryInfo.subQueryInfo.sql[j], sqlStr->valuestring, MAX_QUERY_SQL_LENGTH); + + cJSON *result = cJSON_GetObjectItem(sql, "result"); + if (result != NULL && result->type == cJSON_String && result->valuestring != NULL){ + strncpy(g_queryInfo.subQueryInfo.result[j], result->valuestring, MAX_FILE_NAME_LEN); + } else if (NULL == result) { + memset(g_queryInfo.subQueryInfo.result[j], 0, MAX_FILE_NAME_LEN); + } else { + printf("failed to read json, sub query result file not found\n"); + goto PARSE_OVER; + } + } + } + } + + ret = true; + +PARSE_OVER: + //free(content); + //cJSON_Delete(root); + //fclose(fp); + return ret; +} + +static bool getInfoFromJsonFile(char* file) { + FILE *fp = fopen(file, "r"); + if (!fp) { + printf("failed to read %s, reason:%s\n", file, strerror(errno)); + return false; + } + + bool ret = false; + int maxLen = 64000; + char *content = calloc(1, maxLen + 1); + int len = fread(content, 1, maxLen, fp); + if (len <= 0) { + free(content); + fclose(fp); + printf("failed to read %s, content is null", file); + return false; + } + + content[len] = 0; + cJSON* root = cJSON_Parse(content); + if (root == NULL) { + printf("failed to cjson parse %s, invalid json format", file); + goto PARSE_OVER; + } + + cJSON* filetype = cJSON_GetObjectItem(root, "filetype"); + if (filetype && filetype->type == cJSON_String && filetype->valuestring != NULL) { + if (0 == strcasecmp("insert", filetype->valuestring)) { + g_jsonType = INSERT_MODE; + } else if (0 == strcasecmp("query", filetype->valuestring)) { + g_jsonType = QUERY_MODE; + } else if (0 == strcasecmp("subscribe", filetype->valuestring)) { + g_jsonType = SUBSCRIBE_MODE; + } else { + printf("failed to read json, filetype not support\n"); + goto PARSE_OVER; + } + } else if (!filetype) { + g_jsonType = INSERT_MODE; + } else { + printf("failed to read json, filetype not found\n"); + goto PARSE_OVER; + } + + if (INSERT_MODE == g_jsonType) { + ret = getMetaFromInsertJsonFile(root); + } else if (QUERY_MODE == g_jsonType) { + ret = getMetaFromQueryJsonFile(root); + } else if (SUBSCRIBE_MODE == g_jsonType) { + ret = getMetaFromQueryJsonFile(root); + } else { + printf("input json file type error! please input correct file type: insert or query or subscribe\n"); + goto PARSE_OVER; + } + +PARSE_OVER: + free(content); + cJSON_Delete(root); + fclose(fp); + return ret; +} + + +void prePareSampleData() { + for (int i = 0; i < g_Dbs.dbCount; i++) { + for (int j = 0; j < g_Dbs.db[i].superTblCount; j++) { + //if (0 == strncasecmp(g_Dbs.db[i].superTbls[j].dataSource, "sample", 6)) { + // readSampleFromFileToMem(&g_Dbs.db[i].superTbls[j]); + //} + + if (g_Dbs.db[i].superTbls[j].tagsFile[0] != 0) { + (void)readTagFromCsvFileToMem(&g_Dbs.db[i].superTbls[j]); + } + + #ifdef TD_LOWA_CURL + if (0 == strncasecmp(g_Dbs.db[i].superTbls[j].insertMode, "restful", 8)) { + curl_global_init(CURL_GLOBAL_ALL); + } + #endif + } + } +} + +void postFreeResource() { + tmfclose(g_fpOfInsertResult); + for (int i = 0; i < g_Dbs.dbCount; i++) { + for (int j = 0; j < g_Dbs.db[i].superTblCount; j++) { + if (0 != g_Dbs.db[i].superTbls[j].colsOfCreatChildTable) { + free(g_Dbs.db[i].superTbls[j].colsOfCreatChildTable); + g_Dbs.db[i].superTbls[j].colsOfCreatChildTable = NULL; + } + if (0 != g_Dbs.db[i].superTbls[j].sampleDataBuf) { + free(g_Dbs.db[i].superTbls[j].sampleDataBuf); + g_Dbs.db[i].superTbls[j].sampleDataBuf = NULL; + } + if (0 != g_Dbs.db[i].superTbls[j].childTblName) { + free(g_Dbs.db[i].superTbls[j].childTblName); + g_Dbs.db[i].superTbls[j].childTblName = NULL; + } + + #ifdef TD_LOWA_CURL + if (0 == strncasecmp(g_Dbs.db[i].superTbls[j].insertMode, "restful", 8)) { + curl_global_cleanup(); + } + #endif + } + } +} + +int getRowDataFromSample(char* dataBuf, int maxLen, int64_t timestamp, SSuperTable* superTblInfo, int* sampleUsePos, FILE *fp, char* sampleBuf) { + if ((*sampleUsePos) == MAX_SAMPLES_ONCE_FROM_FILE) { + int ret = readSampleFromCsvFileToMem(fp, superTblInfo, sampleBuf); + if (0 != ret) { + return -1; + } + *sampleUsePos = 0; + } + + int dataLen = 0; + dataLen += snprintf(dataBuf + dataLen, maxLen - dataLen, "(%" PRId64 ", ", timestamp); + dataLen += snprintf(dataBuf + dataLen, maxLen - dataLen, "%s", sampleBuf + superTblInfo->lenOfOneRow * (*sampleUsePos)); + dataLen += snprintf(dataBuf + dataLen, maxLen - dataLen, ")"); + + (*sampleUsePos)++; + + return dataLen; +} + +int generateRowData(char* dataBuf, int maxLen, int64_t timestamp, SSuperTable* stbInfo) { + int dataLen = 0; + dataLen += snprintf(dataBuf + dataLen, maxLen - dataLen, "(%" PRId64 ", ", timestamp); + for (int i = 0; i < stbInfo->columnCount; i++) { + if ((0 == strncasecmp(stbInfo->columns[i].dataType, "binary", 6)) || (0 == strncasecmp(stbInfo->columns[i].dataType, "nchar", 5))) { + if (stbInfo->columns[i].dataLen > TSDB_MAX_BINARY_LEN) { + printf("binary or nchar length overflow, max size:%u\n", (uint32_t)TSDB_MAX_BINARY_LEN); + return (-1); + } + + char* buf = (char*)calloc(stbInfo->columns[i].dataLen+1, 1); + if (NULL == buf) { + printf("calloc failed! size:%d\n", stbInfo->columns[i].dataLen); + return (-1); + } + rand_string(buf, stbInfo->columns[i].dataLen); + dataLen += snprintf(dataBuf + dataLen, maxLen - dataLen, "\'%s\', ", buf); + tmfree(buf); + } else if (0 == strncasecmp(stbInfo->columns[i].dataType, "int", 3)) { + dataLen += snprintf(dataBuf + dataLen, maxLen - dataLen, "%d, ", rand_int()); + } else if (0 == strncasecmp(stbInfo->columns[i].dataType, "bigint", 6)) { + dataLen += snprintf(dataBuf + dataLen, maxLen - dataLen, "%"PRId64", ", rand_bigint()); + } else if (0 == strncasecmp(stbInfo->columns[i].dataType, "float", 5)) { + dataLen += snprintf(dataBuf + dataLen, maxLen - dataLen, "%f, ", rand_float()); + } else if (0 == strncasecmp(stbInfo->columns[i].dataType, "double", 6)) { + dataLen += snprintf(dataBuf + dataLen, maxLen - dataLen, "%f, ", rand_double()); + } else if (0 == strncasecmp(stbInfo->columns[i].dataType, "smallint", 8)) { + dataLen += snprintf(dataBuf + dataLen, maxLen - dataLen, "%d, ", rand_smallint()); + } else if (0 == strncasecmp(stbInfo->columns[i].dataType, "tinyint", 7)) { + dataLen += snprintf(dataBuf + dataLen, maxLen - dataLen, "%d, ", rand_tinyint()); + } else if (0 == strncasecmp(stbInfo->columns[i].dataType, "bool", 4)) { + dataLen += snprintf(dataBuf + dataLen, maxLen - dataLen, "%d, ", rand_bool()); + } else if (0 == strncasecmp(stbInfo->columns[i].dataType, "timestamp", 9)) { + dataLen += snprintf(dataBuf + dataLen, maxLen - dataLen, "%"PRId64", ", rand_bigint()); + } else { + printf("No support data type: %s\n", stbInfo->columns[i].dataType); + return (-1); + } + } + dataLen -= 2; + dataLen += snprintf(dataBuf + dataLen, maxLen - dataLen, ")"); + + return dataLen; +} + +void syncWriteForNumberOfTblInOneSql(threadInfo *winfo, FILE *fp, char* sampleDataBuf) { + SSuperTable* superTblInfo = winfo->superTblInfo; + + int samplePos = 0; + + //printf("========threadID[%d], table rang: %d - %d \n", winfo->threadID, winfo->start_table_id, winfo->end_table_id); + int64_t totalRowsInserted = 0; + int64_t totalAffectedRows = 0; + int64_t lastPrintTime = taosGetTimestampMs(); + + char* buffer = calloc(superTblInfo->maxSqlLen+1, 1); + if (NULL == buffer) { + printf("========calloc size[ %d ] fail!\n", superTblInfo->maxSqlLen); + return; + } + + int32_t numberOfTblInOneSql = superTblInfo->numberOfTblInOneSql; + int32_t tbls = winfo->end_table_id - winfo->start_table_id + 1; + if (numberOfTblInOneSql > tbls) { + numberOfTblInOneSql = tbls; + } + + int64_t time_counter = winfo->start_time; + int64_t tmp_time; + int sampleUsePos; + + int64_t st = 0; + int64_t et = 0; + for (int i = 0; i < superTblInfo->insertRows;) { + if (superTblInfo->insertRate && (et - st) < 1000) { + taosMsleep(1000 - (et - st)); // ms + //printf("========sleep duration:%"PRId64 "========inserted rows:%d, table range:%d - %d\n", (1000 - (et - st)), i, winfo->start_table_id, winfo->end_table_id); + } + + if (superTblInfo->insertRate) { + st = taosGetTimestampMs(); + } + + int32_t tbl_id = 0; + for (int tID = winfo->start_table_id; tID <= winfo->end_table_id; ) { + int inserted = i; + + int k = 0; + int batchRowsSql = 0; + while (1) + { + int len = 0; + memset(buffer, 0, superTblInfo->maxSqlLen); + char *pstr = buffer; + + int32_t end_tbl_id = tID + numberOfTblInOneSql; + if (end_tbl_id > winfo->end_table_id) { + end_tbl_id = winfo->end_table_id+1; + } + for (tbl_id = tID; tbl_id < end_tbl_id; tbl_id++) { + sampleUsePos = samplePos; + if (AUTO_CREATE_SUBTBL == superTblInfo->autoCreateTable) { + char* tagsValBuf = NULL; + if (0 == superTblInfo->tagSource) { + tagsValBuf = generateTagVaulesForStb(superTblInfo); + } else { + tagsValBuf = getTagValueFromTagSample(superTblInfo, tbl_id % superTblInfo->tagSampleCount); + } + if (NULL == tagsValBuf) { + goto free_and_statistics; + } + + if (0 == len) { + len += snprintf(pstr + len, superTblInfo->maxSqlLen - len, "insert into %s.%s%d using %s.%s tags %s values ", winfo->db_name, superTblInfo->childTblPrefix, tbl_id, winfo->db_name, superTblInfo->sTblName, tagsValBuf); + } else { + len += snprintf(pstr + len, superTblInfo->maxSqlLen - len, " %s.%s%d using %s.%s tags %s values ", winfo->db_name, superTblInfo->childTblPrefix, tbl_id, winfo->db_name, superTblInfo->sTblName, tagsValBuf); + } + tmfree(tagsValBuf); + } else if (TBL_ALREADY_EXISTS == superTblInfo->childTblExists) { + if (0 == len) { + len += snprintf(pstr + len, superTblInfo->maxSqlLen - len, "insert into %s.%s values ", winfo->db_name, superTblInfo->childTblName + tbl_id * TSDB_TABLE_NAME_LEN); + } else { + len += snprintf(pstr + len, superTblInfo->maxSqlLen - len, " %s.%s values ", winfo->db_name, superTblInfo->childTblName + tbl_id * TSDB_TABLE_NAME_LEN); + } + } else { // pre-create child table + if (0 == len) { + len += snprintf(pstr + len, superTblInfo->maxSqlLen - len, "insert into %s.%s%d values ", winfo->db_name, superTblInfo->childTblPrefix, tbl_id); + } else { + len += snprintf(pstr + len, superTblInfo->maxSqlLen - len, " %s.%s%d values ", winfo->db_name, superTblInfo->childTblPrefix, tbl_id); + } + } + + tmp_time = time_counter; + for (k = 0; k < superTblInfo->rowsPerTbl;) { + int retLen = 0; + if (0 == strncasecmp(superTblInfo->dataSource, "sample", 6)) { + retLen = getRowDataFromSample(pstr + len, superTblInfo->maxSqlLen - len, tmp_time += superTblInfo->timeStampStep, superTblInfo, &sampleUsePos, fp, sampleDataBuf); + if (retLen < 0) { + goto free_and_statistics; + } + } else if (0 == strncasecmp(superTblInfo->dataSource, "rand", 8)) { + int rand_num = rand_tinyint() % 100; + if (0 != superTblInfo->disorderRatio && rand_num < superTblInfo->disorderRatio) { + int64_t d = tmp_time - rand() % superTblInfo->disorderRange; + retLen = generateRowData(pstr + len, superTblInfo->maxSqlLen - len, d, superTblInfo); + } else { + retLen = generateRowData(pstr + len, superTblInfo->maxSqlLen - len, tmp_time += superTblInfo->timeStampStep, superTblInfo); + } + if (retLen < 0) { + goto free_and_statistics; + } + } + len += retLen; + //inserted++; + k++; + totalRowsInserted++; + batchRowsSql++; + + if (inserted >= superTblInfo->insertRows || (superTblInfo->maxSqlLen - len) < (superTblInfo->lenOfOneRow + 128) || batchRowsSql >= INT16_MAX - 1) { + tID = tbl_id + 1; + printf("config rowsPerTbl and numberOfTblInOneSql not match with max_sql_lenth, please reconfig![lenOfOneRow:%d]\n", superTblInfo->lenOfOneRow); + goto send_to_server; + } + } + + } + + tID = tbl_id; + inserted += superTblInfo->rowsPerTbl; + + send_to_server: + batchRowsSql = 0; + if (0 == strncasecmp(superTblInfo->insertMode, "taosc", 5)) { + //printf("multi table===== sql: %s \n\n", buffer); + //int64_t t1 = taosGetTimestampMs(); + int affectedRows = queryDbExec(winfo->taos, buffer, INSERT_TYPE); + if (0 > affectedRows) { + goto free_and_statistics; + } + totalAffectedRows += affectedRows; + + int64_t currentPrintTime = taosGetTimestampMs(); + if (currentPrintTime - lastPrintTime > 30*1000) { + printf("thread[%d] has currently inserted rows: %"PRId64 ", affected rows: %"PRId64 "\n", winfo->threadID, totalRowsInserted, totalAffectedRows); + lastPrintTime = currentPrintTime; + } + //int64_t t2 = taosGetTimestampMs(); + //printf("taosc insert sql return, Spent %.4f seconds \n", (double)(t2 - t1)/1000.0); + } else { + #ifdef TD_LOWA_CURL + //int64_t t1 = taosGetTimestampMs(); + int retCode = curlProceSql(g_Dbs.host, g_Dbs.port, buffer, winfo->curl_handle); + //int64_t t2 = taosGetTimestampMs(); + //printf("http insert sql return, Spent %ld ms \n", t2 - t1); + + if (0 != retCode) { + printf("========curl return fail, threadID[%d]\n", winfo->threadID); + goto free_and_statistics; + } + #else + printf("========no use http mode for no curl lib!\n"); + goto free_and_statistics; + #endif + } + + //printf("========tID:%d, k:%d, loop_cnt:%d\n", tID, k, loop_cnt); + break; + } + + if (tID > winfo->end_table_id) { + if (0 == strncasecmp(superTblInfo->dataSource, "sample", 6)) { + samplePos = sampleUsePos; + } + i = inserted; + time_counter = tmp_time; + } + } + + if (superTblInfo->insertRate) { + et = taosGetTimestampMs(); + } + //printf("========loop %d childTables duration:%"PRId64 "========inserted rows:%d\n", winfo->end_table_id - winfo->start_table_id, et - st, i); + } + + free_and_statistics: + tmfree(buffer); + winfo->totalRowsInserted = totalRowsInserted; + winfo->totalAffectedRows = totalAffectedRows; + printf("====thread[%d] completed total inserted rows: %"PRId64 ", affected rows: %"PRId64 "====\n", winfo->threadID, totalRowsInserted, totalAffectedRows); + return; +} + +// sync insertion +/* + 1 thread: 100 tables * 2000 rows/s + 1 thread: 10 tables * 20000 rows/s + 6 thread: 300 tables * 2000 rows/s + + 2 taosinsertdata , 1 thread: 10 tables * 20000 rows/s +*/ +void *syncWrite(void *sarg) { + int64_t totalRowsInserted = 0; + int64_t totalAffectedRows = 0; + int64_t lastPrintTime = taosGetTimestampMs(); + + threadInfo *winfo = (threadInfo *)sarg; + SSuperTable* superTblInfo = winfo->superTblInfo; + + FILE *fp = NULL; + char* sampleDataBuf = NULL; + int samplePos = 0; + + // each thread read sample data from csv file + if (0 == strncasecmp(superTblInfo->dataSource, "sample", 6)) { + sampleDataBuf = calloc(superTblInfo->lenOfOneRow * MAX_SAMPLES_ONCE_FROM_FILE, 1); + if (sampleDataBuf == NULL) { + printf("Failed to calloc %d Bytes, reason:%s\n", superTblInfo->lenOfOneRow * MAX_SAMPLES_ONCE_FROM_FILE, strerror(errno)); + return NULL; + } + + fp = fopen(superTblInfo->sampleFile, "r"); + if (fp == NULL) { + printf("Failed to open sample file: %s, reason:%s\n", superTblInfo->sampleFile, strerror(errno)); + tmfree(sampleDataBuf); + return NULL; + } + int ret = readSampleFromCsvFileToMem(fp, superTblInfo, sampleDataBuf); + if (0 != ret) { + tmfree(sampleDataBuf); + tmfclose(fp); + return NULL; + } + } + + if (superTblInfo->numberOfTblInOneSql > 0) { + syncWriteForNumberOfTblInOneSql(winfo, fp, sampleDataBuf); + tmfree(sampleDataBuf); + tmfclose(fp); + return NULL; + } + + //printf("========threadID[%d], table rang: %d - %d \n", winfo->threadID, winfo->start_table_id, winfo->end_table_id); + + char* buffer = calloc(superTblInfo->maxSqlLen, 1); + + int nrecords_per_request = 0; + if (AUTO_CREATE_SUBTBL == superTblInfo->autoCreateTable) { + nrecords_per_request = (superTblInfo->maxSqlLen - 1280 - superTblInfo->lenOfTagOfOneRow) / superTblInfo->lenOfOneRow; + } else { + nrecords_per_request = (superTblInfo->maxSqlLen - 1280) / superTblInfo->lenOfOneRow; + } + + int nrecords_no_last_req = nrecords_per_request; + int nrecords_last_req = 0; + int loop_cnt = 0; + if (0 != superTblInfo->insertRate) { + if (nrecords_no_last_req >= superTblInfo->insertRate) { + nrecords_no_last_req = superTblInfo->insertRate; + } else { + nrecords_last_req = superTblInfo->insertRate % nrecords_per_request; + loop_cnt = (superTblInfo->insertRate / nrecords_per_request) + (superTblInfo->insertRate % nrecords_per_request ? 1 : 0) ; + } + } + + if (nrecords_no_last_req <= 0) { + nrecords_no_last_req = 1; + } + + if (nrecords_no_last_req >= INT16_MAX) { + nrecords_no_last_req = INT16_MAX - 1; + } + + if (nrecords_last_req >= INT16_MAX) { + nrecords_last_req = INT16_MAX - 1; + } + + int nrecords_cur_req = nrecords_no_last_req; + int loop_cnt_orig = loop_cnt; + + //printf("========nrecords_per_request:%d, nrecords_no_last_req:%d, nrecords_last_req:%d, loop_cnt:%d\n", nrecords_per_request, nrecords_no_last_req, nrecords_last_req, loop_cnt); + + int64_t time_counter = winfo->start_time; + + int64_t st = 0; + int64_t et = 0; + for (int i = 0; i < superTblInfo->insertRows;) { + if (superTblInfo->insertRate && (et - st) < 1000) { + taosMsleep(1000 - (et - st)); // ms + //printf("========sleep duration:%"PRId64 "========inserted rows:%d, table range:%d - %d\n", (1000 - (et - st)), i, winfo->start_table_id, winfo->end_table_id); + } + + if (superTblInfo->insertRate) { + st = taosGetTimestampMs(); + } + + for (int tID = winfo->start_table_id; tID <= winfo->end_table_id; tID++) { + int inserted = i; + int64_t tmp_time = time_counter; + + int sampleUsePos = samplePos; + int k = 0; + while (1) + { + int len = 0; + memset(buffer, 0, superTblInfo->maxSqlLen); + char *pstr = buffer; + + if (AUTO_CREATE_SUBTBL == superTblInfo->autoCreateTable) { + char* tagsValBuf = NULL; + if (0 == superTblInfo->tagSource) { + tagsValBuf = generateTagVaulesForStb(superTblInfo); + } else { + tagsValBuf = getTagValueFromTagSample(superTblInfo, tID % superTblInfo->tagSampleCount); + } + if (NULL == tagsValBuf) { + goto free_and_statistics_2; + } + + len += snprintf(pstr + len, superTblInfo->maxSqlLen - len, "insert into %s.%s%d using %s.%s tags %s values", winfo->db_name, superTblInfo->childTblPrefix, tID, winfo->db_name, superTblInfo->sTblName, tagsValBuf); + tmfree(tagsValBuf); + } else if (TBL_ALREADY_EXISTS == superTblInfo->childTblExists) { + len += snprintf(pstr + len, superTblInfo->maxSqlLen - len, "insert into %s.%s values", winfo->db_name, superTblInfo->childTblName + tID * TSDB_TABLE_NAME_LEN); + } else { + len += snprintf(pstr + len, superTblInfo->maxSqlLen - len, "insert into %s.%s%d values", winfo->db_name, superTblInfo->childTblPrefix, tID); + } + + for (k = 0; k < nrecords_cur_req;) { + int retLen = 0; + if (0 == strncasecmp(superTblInfo->dataSource, "sample", 6)) { + retLen = getRowDataFromSample(pstr + len, superTblInfo->maxSqlLen - len, tmp_time += superTblInfo->timeStampStep, superTblInfo, &sampleUsePos, fp, sampleDataBuf); + if (retLen < 0) { + goto free_and_statistics_2; + } + } else if (0 == strncasecmp(superTblInfo->dataSource, "rand", 8)) { + int rand_num = rand_tinyint() % 100; + if (0 != superTblInfo->disorderRatio && rand_num < superTblInfo->disorderRatio) { + int64_t d = tmp_time - rand() % superTblInfo->disorderRange; + retLen = generateRowData(pstr + len, superTblInfo->maxSqlLen - len, d, superTblInfo); + //printf("disorder rows, rand_num:%d, last ts:%"PRId64" current ts:%"PRId64"\n", rand_num, tmp_time, d); + } else { + retLen = generateRowData(pstr + len, superTblInfo->maxSqlLen - len, tmp_time += superTblInfo->timeStampStep, superTblInfo); + } + if (retLen < 0) { + goto free_and_statistics_2; + } + } + len += retLen; + inserted++; + k++; + totalRowsInserted++; + + if (inserted >= superTblInfo->insertRows || (superTblInfo->maxSqlLen - len) < (superTblInfo->lenOfOneRow + 128)) break; + } + + if (0 == strncasecmp(superTblInfo->insertMode, "taosc", 5)) { + //printf("===== sql: %s \n\n", buffer); + //int64_t t1 = taosGetTimestampMs(); + int affectedRows = queryDbExec(winfo->taos, buffer, INSERT_TYPE); + if (0 > affectedRows){ + goto free_and_statistics_2; + } + totalAffectedRows += affectedRows; + + int64_t currentPrintTime = taosGetTimestampMs(); + if (currentPrintTime - lastPrintTime > 30*1000) { + printf("thread[%d] has currently inserted rows: %"PRId64 ", affected rows: %"PRId64 "\n", winfo->threadID, totalRowsInserted, totalAffectedRows); + lastPrintTime = currentPrintTime; + } + //int64_t t2 = taosGetTimestampMs(); + //printf("taosc insert sql return, Spent %.4f seconds \n", (double)(t2 - t1)/1000.0); + } else { + #ifdef TD_LOWA_CURL + //int64_t t1 = taosGetTimestampMs(); + int retCode = curlProceSql(g_Dbs.host, g_Dbs.port, buffer, winfo->curl_handle); + //int64_t t2 = taosGetTimestampMs(); + //printf("http insert sql return, Spent %ld ms \n", t2 - t1); + + if (0 != retCode) { + printf("========curl return fail, threadID[%d]\n", winfo->threadID); + goto free_and_statistics_2; + } + #else + printf("========no use http mode for no curl lib!\n"); + goto free_and_statistics_2; + #endif + } + + //printf("========tID:%d, k:%d, loop_cnt:%d\n", tID, k, loop_cnt); + + if (loop_cnt) { + loop_cnt--; + if ((1 == loop_cnt) && (0 != nrecords_last_req)) { + nrecords_cur_req = nrecords_last_req; + } else if (0 == loop_cnt){ + nrecords_cur_req = nrecords_no_last_req; + loop_cnt = loop_cnt_orig; + break; + } + } else { + break; + } + } + + if (tID == winfo->end_table_id) { + if (0 == strncasecmp(superTblInfo->dataSource, "sample", 6)) { + samplePos = sampleUsePos; + } + i = inserted; + time_counter = tmp_time; + } + } + + if (superTblInfo->insertRate) { + et = taosGetTimestampMs(); + } + //printf("========loop %d childTables duration:%"PRId64 "========inserted rows:%d\n", winfo->end_table_id - winfo->start_table_id, et - st, i); + } + + free_and_statistics_2: + tmfree(buffer); + tmfree(sampleDataBuf); + tmfclose(fp); + + winfo->totalRowsInserted = totalRowsInserted; + winfo->totalAffectedRows = totalAffectedRows; + + printf("====thread[%d] completed total inserted rows: %"PRId64 ", total affected rows: %"PRId64 "====\n", winfo->threadID, totalRowsInserted, totalAffectedRows); + return NULL; +} + +void callBack(void *param, TAOS_RES *res, int code) { + threadInfo* winfo = (threadInfo*)param; + + if (winfo->superTblInfo->insertRate) { + winfo->et = taosGetTimestampMs(); + if (winfo->et - winfo->st < 1000) { + taosMsleep(1000 - (winfo->et - winfo->st)); // ms + } + } + + char *buffer = calloc(1, winfo->superTblInfo->maxSqlLen); + char *data = calloc(1, MAX_DATA_SIZE); + char *pstr = buffer; + pstr += sprintf(pstr, "insert into %s.%s%d values", winfo->db_name, winfo->tb_prefix, winfo->start_table_id); + if (winfo->counter >= winfo->superTblInfo->insertRows) { + winfo->start_table_id++; + winfo->counter = 0; + } + if (winfo->start_table_id > winfo->end_table_id) { + tsem_post(&winfo->lock_sem); + free(buffer); + free(data); + taos_free_result(res); + return; + } + + for (int i = 0; i < winfo->nrecords_per_request; i++) { + int rand_num = rand() % 100; + if (0 != winfo->superTblInfo->disorderRatio && rand_num < winfo->superTblInfo->disorderRatio) + { + int64_t d = winfo->lastTs - rand() % 1000000 + rand_num; + //generateData(data, datatype, ncols_per_record, d, len_of_binary); + (void)generateRowData(data, MAX_DATA_SIZE, d, winfo->superTblInfo); + } else { + //generateData(data, datatype, ncols_per_record, tmp_time += 1000, len_of_binary); + (void)generateRowData(data, MAX_DATA_SIZE, winfo->lastTs += 1000, winfo->superTblInfo); + } + pstr += sprintf(pstr, "%s", data); + winfo->counter++; + + if (winfo->counter >= winfo->superTblInfo->insertRows) { + break; + } + } + + if (winfo->superTblInfo->insertRate) { + winfo->st = taosGetTimestampMs(); + } + taos_query_a(winfo->taos, buffer, callBack, winfo); + free(buffer); + free(data); + + taos_free_result(res); +} + +void *asyncWrite(void *sarg) { + threadInfo *winfo = (threadInfo *)sarg; + + winfo->nrecords_per_request = 0; + //if (AUTO_CREATE_SUBTBL == winfo->superTblInfo->autoCreateTable) { + winfo->nrecords_per_request = (winfo->superTblInfo->maxSqlLen - 1280 - winfo->superTblInfo->lenOfTagOfOneRow) / winfo->superTblInfo->lenOfOneRow; + //} else { + // winfo->nrecords_per_request = (winfo->superTblInfo->maxSqlLen - 1280) / winfo->superTblInfo->lenOfOneRow; + //} + + if (0 != winfo->superTblInfo->insertRate) { + if (winfo->nrecords_per_request >= winfo->superTblInfo->insertRate) { + winfo->nrecords_per_request = winfo->superTblInfo->insertRate; + } + } + + if (winfo->nrecords_per_request <= 0) { + winfo->nrecords_per_request = 1; + } + + if (winfo->nrecords_per_request >= INT16_MAX) { + winfo->nrecords_per_request = INT16_MAX - 1; + } + + if (winfo->nrecords_per_request >= INT16_MAX) { + winfo->nrecords_per_request = INT16_MAX - 1; + } + + winfo->st = 0; + winfo->et = 0; + winfo->lastTs = winfo->start_time; + + if (winfo->superTblInfo->insertRate) { + winfo->st = taosGetTimestampMs(); + } + taos_query_a(winfo->taos, "show databases", callBack, winfo); + + tsem_wait(&(winfo->lock_sem)); + + return NULL; +} + +void startMultiThreadInsertData(int threads, char* db_name, char* precision, SSuperTable* superTblInfo) { + pthread_t *pids = malloc(threads * sizeof(pthread_t)); + threadInfo *infos = malloc(threads * sizeof(threadInfo)); + memset(pids, 0, threads * sizeof(pthread_t)); + memset(infos, 0, threads * sizeof(threadInfo)); + int ntables = superTblInfo->childTblCount; + + int a = ntables / threads; + if (a < 1) { + threads = ntables; + a = 1; + } + + int b = 0; + if (threads != 0) { + b = ntables % threads; + } + + TAOS* taos; + if (0 == strncasecmp(superTblInfo->insertMode, "taosc", 5)) { + taos = taos_connect(g_Dbs.host, g_Dbs.user, g_Dbs.password, db_name, g_Dbs.port); + if (NULL == taos) { + printf("connect to server fail, reason: %s\n", taos_errstr(NULL)); + exit(-1); + } + } + + int32_t timePrec = TSDB_TIME_PRECISION_MILLI; + if (0 != precision[0]) { + if (0 == strncasecmp(precision, "ms", 2)) { + timePrec = TSDB_TIME_PRECISION_MILLI; + } else if (0 == strncasecmp(precision, "us", 2)) { + timePrec = TSDB_TIME_PRECISION_MICRO; + } else { + printf("No support precision: %s\n", precision); + exit(-1); + } + } + + int64_t start_time; + if (0 == strncasecmp(superTblInfo->startTimestamp, "now", 3)) { + start_time = taosGetTimestamp(timePrec); + } else { + (void)taosParseTime(superTblInfo->startTimestamp, &start_time, strlen(superTblInfo->startTimestamp), timePrec, 0); + } + + double start = getCurrentTime(); + + int last = 0; + for (int i = 0; i < threads; i++) { + threadInfo *t_info = infos + i; + t_info->threadID = i; + tstrncpy(t_info->db_name, db_name, MAX_DB_NAME_SIZE); + t_info->superTblInfo = superTblInfo; + + t_info->start_time = start_time; + + if (0 == strncasecmp(superTblInfo->insertMode, "taosc", 5)) { + t_info->taos = taos; + } else { + t_info->taos = NULL; + #ifdef TD_LOWA_CURL + t_info->curl_handle = curl_easy_init(); + #endif + } + + if (0 == superTblInfo->multiThreadWriteOneTbl) { + t_info->start_table_id = last; + t_info->end_table_id = i < b ? last + a : last + a - 1; + last = t_info->end_table_id + 1; + } else { + t_info->start_table_id = 0; + t_info->end_table_id = superTblInfo->childTblCount - 1; + t_info->start_time = t_info->start_time + rand_int() % 10000 - rand_tinyint(); + } + + tsem_init(&(t_info->lock_sem), 0, 0); + + if (SYNC == g_Dbs.queryMode) { + pthread_create(pids + i, NULL, syncWrite, t_info); + } else { + pthread_create(pids + i, NULL, asyncWrite, t_info); + } + } + + for (int i = 0; i < threads; i++) { + pthread_join(pids[i], NULL); + } + + for (int i = 0; i < threads; i++) { + threadInfo *t_info = infos + i; + + tsem_destroy(&(t_info->lock_sem)); + + superTblInfo->totalAffectedRows += t_info->totalAffectedRows; + superTblInfo->totalRowsInserted += t_info->totalRowsInserted; + #ifdef TD_LOWA_CURL + if (t_info->curl_handle) { + curl_easy_cleanup(t_info->curl_handle); + } + #endif + } + + double end = getCurrentTime(); + + taos_close(taos); + + free(pids); + free(infos); + + printf("Spent %.4f seconds to insert rows: %"PRId64", affected rows: %"PRId64" with %d thread(s) into %s.%s\n\n", + end - start, superTblInfo->totalRowsInserted, superTblInfo->totalAffectedRows, threads, db_name, superTblInfo->sTblName); + fprintf(g_fpOfInsertResult, "Spent %.4f seconds to insert rows: %"PRId64", affected rows: %"PRId64" with %d thread(s) into %s.%s\n\n", + end - start, superTblInfo->totalRowsInserted, superTblInfo->totalAffectedRows, threads, db_name, superTblInfo->sTblName); +} + + +void *readTable(void *sarg) { +#if 1 + threadInfo *rinfo = (threadInfo *)sarg; + TAOS *taos = rinfo->taos; + char command[BUFFER_SIZE] = "\0"; + int64_t sTime = rinfo->start_time; + char *tb_prefix = rinfo->tb_prefix; + FILE *fp = fopen(rinfo->fp, "a"); + if (NULL == fp) { + printf("fopen %s fail, reason:%s.\n", rinfo->fp, strerror(errno)); + return NULL; + } + + int num_of_DPT = rinfo->superTblInfo->insertRows; // nrecords_per_table; + int num_of_tables = rinfo->end_table_id - rinfo->start_table_id + 1; + int totalData = num_of_DPT * num_of_tables; + bool do_aggreFunc = g_Dbs.do_aggreFunc; + + int n = do_aggreFunc ? (sizeof(aggreFunc) / sizeof(aggreFunc[0])) : 2; + if (!do_aggreFunc) { + printf("\nThe first field is either Binary or Bool. Aggregation functions are not supported.\n"); + } + printf("%d records:\n", totalData); + fprintf(fp, "| QFunctions | QRecords | QSpeed(R/s) | QLatency(ms) |\n"); + + for (int j = 0; j < n; j++) { + double totalT = 0; + int count = 0; + for (int i = 0; i < num_of_tables; i++) { + sprintf(command, "select %s from %s%d where ts>= %" PRId64, aggreFunc[j], tb_prefix, i, sTime); + + double t = getCurrentTime(); + TAOS_RES *pSql = taos_query(taos, command); + int32_t code = taos_errno(pSql); + + if (code != 0) { + fprintf(stderr, "Failed to query:%s\n", taos_errstr(pSql)); + taos_free_result(pSql); + taos_close(taos); + return NULL; + } + + while (taos_fetch_row(pSql) != NULL) { + count++; + } + + t = getCurrentTime() - t; + totalT += t; + + taos_free_result(pSql); + } + + fprintf(fp, "|%10s | %10d | %12.2f | %10.2f |\n", + aggreFunc[j][0] == '*' ? " * " : aggreFunc[j], totalData, + (double)(num_of_tables * num_of_DPT) / totalT, totalT * 1000); + printf("select %10s took %.6f second(s)\n", aggreFunc[j], totalT); + } + fprintf(fp, "\n"); + fclose(fp); +#endif + return NULL; +} + +void *readMetric(void *sarg) { +#if 1 + threadInfo *rinfo = (threadInfo *)sarg; + TAOS *taos = rinfo->taos; + char command[BUFFER_SIZE] = "\0"; + FILE *fp = fopen(rinfo->fp, "a"); + if (NULL == fp) { + printf("fopen %s fail, reason:%s.\n", rinfo->fp, strerror(errno)); + return NULL; + } + + int num_of_DPT = rinfo->superTblInfo->insertRows; + int num_of_tables = rinfo->end_table_id - rinfo->start_table_id + 1; + int totalData = num_of_DPT * num_of_tables; + bool do_aggreFunc = g_Dbs.do_aggreFunc; + + int n = do_aggreFunc ? (sizeof(aggreFunc) / sizeof(aggreFunc[0])) : 2; + if (!do_aggreFunc) { + printf("\nThe first field is either Binary or Bool. Aggregation functions are not supported.\n"); + } + printf("%d records:\n", totalData); + fprintf(fp, "Querying On %d records:\n", totalData); + + for (int j = 0; j < n; j++) { + char condition[BUFFER_SIZE - 30] = "\0"; + char tempS[64] = "\0"; + + int m = 10 < num_of_tables ? 10 : num_of_tables; + + for (int i = 1; i <= m; i++) { + if (i == 1) { + sprintf(tempS, "t1 = %d", i); + } else { + sprintf(tempS, " or t1 = %d ", i); + } + strcat(condition, tempS); + + sprintf(command, "select %s from meters where %s", aggreFunc[j], condition); + + printf("Where condition: %s\n", condition); + fprintf(fp, "%s\n", command); + + double t = getCurrentTime(); + + TAOS_RES *pSql = taos_query(taos, command); + int32_t code = taos_errno(pSql); + + if (code != 0) { + fprintf(stderr, "Failed to query:%s\n", taos_errstr(pSql)); + taos_free_result(pSql); + taos_close(taos); + return NULL; + } + int count = 0; + while (taos_fetch_row(pSql) != NULL) { + count++; + } + t = getCurrentTime() - t; + + fprintf(fp, "| Speed: %12.2f(per s) | Latency: %.4f(ms) |\n", num_of_tables * num_of_DPT / t, t * 1000); + printf("select %10s took %.6f second(s)\n\n", aggreFunc[j], t); + + taos_free_result(pSql); + } + fprintf(fp, "\n"); + } + fclose(fp); +#endif + return NULL; +} + + +int insertTestProcess() { + + g_fpOfInsertResult = fopen(g_Dbs.resultFile, "a"); + if (NULL == g_fpOfInsertResult) { + fprintf(stderr, "Failed to open %s for save result\n", g_Dbs.resultFile); + return 1; + }; + + printfInsertMeta(); + printfInsertMetaToFile(g_fpOfInsertResult); + + printf("Press enter key to continue\n\n"); + (void)getchar(); + + init_rand_data(); + + // create database and super tables + (void)createDatabases(); + + // pretreatement + prePareSampleData(); + + double start; + double end; + + // create child tables + start = getCurrentTime(); + createChildTables(); + end = getCurrentTime(); + if (g_totalChildTables > 0) { + printf("Spent %.4f seconds to create %d tables with %d thread(s)\n\n", end - start, g_totalChildTables, g_Dbs.threadCount); + fprintf(g_fpOfInsertResult, "Spent %.4f seconds to create %d tables with %d thread(s)\n\n", end - start, g_totalChildTables, g_Dbs.threadCount); + } + + usleep(1000*1000); + + // create sub threads for inserting data + //start = getCurrentTime(); + for (int i = 0; i < g_Dbs.dbCount; i++) { + for (int j = 0; j < g_Dbs.db[i].superTblCount; j++) { + SSuperTable* superTblInfo = &g_Dbs.db[i].superTbls[j]; + startMultiThreadInsertData(g_Dbs.threadCount, g_Dbs.db[i].dbName, g_Dbs.db[i].dbCfg.precision, superTblInfo); + } + } + //end = getCurrentTime(); + + //int64_t totalRowsInserted = 0; + //int64_t totalAffectedRows = 0; + //for (int i = 0; i < g_Dbs.dbCount; i++) { + // for (int j = 0; j < g_Dbs.db[i].superTblCount; j++) { + // totalRowsInserted += g_Dbs.db[i].superTbls[j].totalRowsInserted; + // totalAffectedRows += g_Dbs.db[i].superTbls[j].totalAffectedRows; + //} + //printf("Spent %.4f seconds to insert rows: %"PRId64", affected rows: %"PRId64" with %d thread(s)\n\n", end - start, totalRowsInserted, totalAffectedRows, g_Dbs.threadCount); + if (NULL == g_args.metaFile && false == g_Dbs.insert_only) { + // query data + pthread_t read_id; + threadInfo *rInfo = malloc(sizeof(threadInfo)); + rInfo->start_time = 1500000000000; // 2017-07-14 10:40:00.000 + rInfo->start_table_id = 0; + rInfo->end_table_id = g_Dbs.db[0].superTbls[0].childTblCount - 1; + //rInfo->do_aggreFunc = g_Dbs.do_aggreFunc; + //rInfo->nrecords_per_table = g_Dbs.db[0].superTbls[0].insertRows; + rInfo->superTblInfo = &g_Dbs.db[0].superTbls[0]; + rInfo->taos = taos_connect(g_Dbs.host, g_Dbs.user, g_Dbs.password, g_Dbs.db[0].dbName, g_Dbs.port); + strcpy(rInfo->tb_prefix, g_Dbs.db[0].superTbls[0].childTblPrefix); + strcpy(rInfo->fp, g_Dbs.resultFile); + + if (!g_Dbs.use_metric) { + pthread_create(&read_id, NULL, readTable, rInfo); + } else { + pthread_create(&read_id, NULL, readMetric, rInfo); + } + pthread_join(read_id, NULL); + taos_close(rInfo->taos); + } + + postFreeResource(); + + return 0; +} + +void *superQueryProcess(void *sarg) { + threadInfo *winfo = (threadInfo *)sarg; + + //char sqlStr[MAX_TB_NAME_SIZE*2]; + //sprintf(sqlStr, "use %s", g_queryInfo.dbName); + //queryDB(winfo->taos, sqlStr); + + int64_t st = 0; + int64_t et = 0; + while (1) { + if (g_queryInfo.superQueryInfo.rate && (et - st) < g_queryInfo.superQueryInfo.rate*1000) { + taosMsleep(g_queryInfo.superQueryInfo.rate*1000 - (et - st)); // ms + //printf("========sleep duration:%"PRId64 "========inserted rows:%d, table range:%d - %d\n", (1000 - (et - st)), i, winfo->start_table_id, winfo->end_table_id); + } + + st = taosGetTimestampMs(); + for (int i = 0; i < g_queryInfo.superQueryInfo.sqlCount; i++) { + if (0 == strncasecmp(g_queryInfo.queryMode, "taosc", 5)) { + int64_t t1 = taosGetTimestampUs(); + selectAndGetResult(winfo->taos, g_queryInfo.superQueryInfo.sql[i], g_queryInfo.superQueryInfo.result[i]); + int64_t t2 = taosGetTimestampUs(); + printf("taosc select sql return, Spent %f s\n", (t2 - t1)/1000000.0); + } else { + #ifdef TD_LOWA_CURL + int64_t t1 = taosGetTimestampUs(); + int retCode = curlProceSql(g_queryInfo.host, g_queryInfo.port, g_queryInfo.superQueryInfo.sql[i], winfo->curl_handle); + int64_t t2 = taosGetTimestampUs(); + printf("http select sql return, Spent %f s \n", (t2 - t1)/1000000.0); + + if (0 != retCode) { + printf("========curl return fail, threadID[%d]\n", winfo->threadID); + return NULL; + } + #endif + } + } + et = taosGetTimestampMs(); + printf("========thread[%"PRIu64"] complete all sqls to super table once queries duration:%.6fs\n\n", (uint64_t)pthread_self(), (double)(et - st)/1000.0); + } + return NULL; +} + +void replaceSubTblName(char* inSql, char* outSql, int tblIndex) { + char sourceString[32] = "xxxx"; + char subTblName[MAX_TB_NAME_SIZE*3]; + sprintf(subTblName, "%s.%s", g_queryInfo.dbName, g_queryInfo.subQueryInfo.childTblName + tblIndex*TSDB_TABLE_NAME_LEN); + + //printf("inSql: %s\n", inSql); + + char* pos = strstr(inSql, sourceString); + if (0 == pos) { + return; + } + + strncpy(outSql, inSql, pos - inSql); + //printf("1: %s\n", outSql); + strcat(outSql, subTblName); + //printf("2: %s\n", outSql); + strcat(outSql, pos+strlen(sourceString)); + //printf("3: %s\n", outSql); +} + +void *subQueryProcess(void *sarg) { + char sqlstr[1024]; + threadInfo *winfo = (threadInfo *)sarg; + int64_t st = 0; + int64_t et = 0; + while (1) { + if (g_queryInfo.subQueryInfo.rate && (et - st) < g_queryInfo.subQueryInfo.rate*1000) { + taosMsleep(g_queryInfo.subQueryInfo.rate*1000 - (et - st)); // ms + //printf("========sleep duration:%"PRId64 "========inserted rows:%d, table range:%d - %d\n", (1000 - (et - st)), i, winfo->start_table_id, winfo->end_table_id); + } + + st = taosGetTimestampMs(); + for (int i = winfo->start_table_id; i <= winfo->end_table_id; i++) { + for (int i = 0; i < g_queryInfo.subQueryInfo.sqlCount; i++) { + memset(sqlstr,0,sizeof(sqlstr)); + replaceSubTblName(g_queryInfo.subQueryInfo.sql[i], sqlstr, i); + selectAndGetResult(winfo->taos, sqlstr, g_queryInfo.subQueryInfo.result[i]); + } + } + et = taosGetTimestampMs(); + printf("========thread[%"PRIu64"] complete all sqls to allocate all sub-tables once queries duration:%.4fs\n\n", (uint64_t)pthread_self(), (double)(et - st)/1000.0); + } + return NULL; +} + +int queryTestProcess() { + printfQueryMeta(); + + printf("Press enter key to continue\n\n"); + (void)getchar(); + + TAOS * taos = NULL; + taos_init(); + taos = taos_connect(g_queryInfo.host, g_queryInfo.user, g_queryInfo.password, g_queryInfo.dbName, g_queryInfo.port); + if (taos == NULL) { + fprintf(stderr, "Failed to connect to TDengine, reason:%s\n", taos_errstr(NULL)); + exit(-1); + } + + if (0 != g_queryInfo.subQueryInfo.sqlCount) { + (void)getAllChildNameOfSuperTable(taos, g_queryInfo.dbName, g_queryInfo.subQueryInfo.sTblName, &g_queryInfo.subQueryInfo.childTblName, &g_queryInfo.subQueryInfo.childTblCount); + } + + pthread_t *pids = NULL; + threadInfo *infos = NULL; + //==== create sub threads for query from super table + if (g_queryInfo.superQueryInfo.sqlCount > 0 && g_queryInfo.superQueryInfo.concurrent > 0) { + + pids = malloc(g_queryInfo.superQueryInfo.concurrent * sizeof(pthread_t)); + infos = malloc(g_queryInfo.superQueryInfo.concurrent * sizeof(threadInfo)); + if ((NULL == pids) || (NULL == infos)) { + printf("malloc failed for create threads\n"); + taos_close(taos); + exit(-1); + } + + for (int i = 0; i < g_queryInfo.superQueryInfo.concurrent; i++) { + threadInfo *t_info = infos + i; + t_info->threadID = i; + + if (0 == strncasecmp(g_queryInfo.queryMode, "taosc", 5)) { + t_info->taos = taos; + + char sqlStr[MAX_TB_NAME_SIZE*2]; + sprintf(sqlStr, "use %s", g_queryInfo.dbName); + (void)queryDbExec(t_info->taos, sqlStr, NO_INSERT_TYPE); + } else { + t_info->taos = NULL; + #ifdef TD_LOWA_CURL + t_info->curl_handle = curl_easy_init(); + #endif + } + + pthread_create(pids + i, NULL, superQueryProcess, t_info); + } + }else { + g_queryInfo.superQueryInfo.concurrent = 0; + } + + pthread_t *pidsOfSub = NULL; + threadInfo *infosOfSub = NULL; + //==== create sub threads for query from sub table + if ((g_queryInfo.subQueryInfo.sqlCount > 0) && (g_queryInfo.subQueryInfo.threadCnt > 0)) { + pidsOfSub = malloc(g_queryInfo.subQueryInfo.threadCnt * sizeof(pthread_t)); + infosOfSub = malloc(g_queryInfo.subQueryInfo.threadCnt * sizeof(threadInfo)); + if ((NULL == pidsOfSub) || (NULL == infosOfSub)) { + printf("malloc failed for create threads\n"); + taos_close(taos); + exit(-1); + } + + int ntables = g_queryInfo.subQueryInfo.childTblCount; + int threads = g_queryInfo.subQueryInfo.threadCnt; + + int a = ntables / threads; + if (a < 1) { + threads = ntables; + a = 1; + } + + int b = 0; + if (threads != 0) { + b = ntables % threads; + } + + int last = 0; + for (int i = 0; i < threads; i++) { + threadInfo *t_info = infosOfSub + i; + t_info->threadID = i; + + t_info->start_table_id = last; + t_info->end_table_id = i < b ? last + a : last + a - 1; + t_info->taos = taos; + pthread_create(pidsOfSub + i, NULL, subQueryProcess, t_info); + } + + g_queryInfo.subQueryInfo.threadCnt = threads; + }else { + g_queryInfo.subQueryInfo.threadCnt = 0; + } + + for (int i = 0; i < g_queryInfo.superQueryInfo.concurrent; i++) { + pthread_join(pids[i], NULL); + } + + tmfree((char*)pids); + tmfree((char*)infos); + + for (int i = 0; i < g_queryInfo.subQueryInfo.threadCnt; i++) { + pthread_join(pidsOfSub[i], NULL); + } + + tmfree((char*)pidsOfSub); + tmfree((char*)infosOfSub); + + taos_close(taos); + return 0; +} + +static void subscribe_callback(TAOS_SUB* tsub, TAOS_RES *res, void* param, int code) { + if (res == NULL || taos_errno(res) != 0) { + printf("failed to subscribe result, code:%d, reason:%s\n", code, taos_errstr(res)); + return; + } + + getResult(res, (char*)param); + taos_free_result(res); +} + +static TAOS_SUB* subscribeImpl(TAOS *taos, char *sql, char* topic, char* resultFileName) { + TAOS_SUB* tsub = NULL; + + if (g_queryInfo.superQueryInfo.subscribeMode) { + tsub = taos_subscribe(taos, g_queryInfo.superQueryInfo.subscribeRestart, topic, sql, subscribe_callback, (void*)resultFileName, g_queryInfo.superQueryInfo.subscribeInterval); + } else { + tsub = taos_subscribe(taos, g_queryInfo.superQueryInfo.subscribeRestart, topic, sql, NULL, NULL, 0); + } + + if (tsub == NULL) { + printf("failed to create subscription. topic:%s, sql:%s\n", topic, sql); + return NULL; + } + + return tsub; +} + +void *subSubscribeProcess(void *sarg) { + threadInfo *winfo = (threadInfo *)sarg; + char subSqlstr[1024]; + + char sqlStr[MAX_TB_NAME_SIZE*2]; + sprintf(sqlStr, "use %s", g_queryInfo.dbName); + if (0 != queryDbExec(winfo->taos, sqlStr, NO_INSERT_TYPE)){ + return NULL; + } + + //int64_t st = 0; + //int64_t et = 0; + do { + //if (g_queryInfo.superQueryInfo.rate && (et - st) < g_queryInfo.superQueryInfo.rate*1000) { + // taosMsleep(g_queryInfo.superQueryInfo.rate*1000 - (et - st)); // ms + // //printf("========sleep duration:%"PRId64 "========inserted rows:%d, table range:%d - %d\n", (1000 - (et - st)), i, winfo->start_table_id, winfo->end_table_id); + //} + + //st = taosGetTimestampMs(); + char topic[32] = {0}; + for (int i = 0; i < g_queryInfo.subQueryInfo.sqlCount; i++) { + sprintf(topic, "taosdemo-subscribe-%d", i); + memset(subSqlstr,0,sizeof(subSqlstr)); + replaceSubTblName(g_queryInfo.subQueryInfo.sql[i], subSqlstr, i); + g_queryInfo.subQueryInfo.tsub[i] = subscribeImpl(winfo->taos, subSqlstr, topic, g_queryInfo.subQueryInfo.result[i]); + if (NULL == g_queryInfo.subQueryInfo.tsub[i]) { + return NULL; + } + } + //et = taosGetTimestampMs(); + //printf("========thread[%"PRId64"] complete all sqls to super table once queries duration:%.4fs\n", pthread_self(), (double)(et - st)/1000.0); + } while (0); + + // start loop to consume result + while (1) { + for (int i = 0; i < g_queryInfo.subQueryInfo.sqlCount; i++) { + if (1 == g_queryInfo.subQueryInfo.subscribeMode) { + continue; + } + + TAOS_RES* res = taos_consume(g_queryInfo.subQueryInfo.tsub[i]); + if (res) { + getResult(res, g_queryInfo.subQueryInfo.result[i]); + taos_free_result(res); + } + } + } + + for (int i = 0; i < g_queryInfo.subQueryInfo.sqlCount; i++) { + taos_unsubscribe(g_queryInfo.subQueryInfo.tsub[i], g_queryInfo.subQueryInfo.subscribeKeepProgress); + } + return NULL; +} + +void *superSubscribeProcess(void *sarg) { + threadInfo *winfo = (threadInfo *)sarg; + + char sqlStr[MAX_TB_NAME_SIZE*2]; + sprintf(sqlStr, "use %s", g_queryInfo.dbName); + if (0 != queryDbExec(winfo->taos, sqlStr, NO_INSERT_TYPE)) { + return NULL; + } + + //int64_t st = 0; + //int64_t et = 0; + do { + //if (g_queryInfo.superQueryInfo.rate && (et - st) < g_queryInfo.superQueryInfo.rate*1000) { + // taosMsleep(g_queryInfo.superQueryInfo.rate*1000 - (et - st)); // ms + // //printf("========sleep duration:%"PRId64 "========inserted rows:%d, table range:%d - %d\n", (1000 - (et - st)), i, winfo->start_table_id, winfo->end_table_id); + //} + + //st = taosGetTimestampMs(); + char topic[32] = {0}; + for (int i = 0; i < g_queryInfo.superQueryInfo.sqlCount; i++) { + sprintf(topic, "taosdemo-subscribe-%d", i); + g_queryInfo.superQueryInfo.tsub[i] = subscribeImpl(winfo->taos, g_queryInfo.superQueryInfo.sql[i], topic, g_queryInfo.superQueryInfo.result[i]); + if (NULL == g_queryInfo.superQueryInfo.tsub[i]) { + return NULL; + } + } + //et = taosGetTimestampMs(); + //printf("========thread[%"PRId64"] complete all sqls to super table once queries duration:%.4fs\n", pthread_self(), (double)(et - st)/1000.0); + } while (0); + + // start loop to consume result + while (1) { + for (int i = 0; i < g_queryInfo.superQueryInfo.sqlCount; i++) { + if (1 == g_queryInfo.superQueryInfo.subscribeMode) { + continue; + } + + TAOS_RES* res = taos_consume(g_queryInfo.superQueryInfo.tsub[i]); + if (res) { + getResult(res, g_queryInfo.superQueryInfo.result[i]); + taos_free_result(res); + } + } + } + + for (int i = 0; i < g_queryInfo.superQueryInfo.sqlCount; i++) { + taos_unsubscribe(g_queryInfo.superQueryInfo.tsub[i], g_queryInfo.superQueryInfo.subscribeKeepProgress); + } + return NULL; +} + +int subscribeTestProcess() { + printfQueryMeta(); + + printf("Press enter key to continue\n\n"); + (void)getchar(); + + TAOS * taos = NULL; + taos_init(); + taos = taos_connect(g_queryInfo.host, g_queryInfo.user, g_queryInfo.password, g_queryInfo.dbName, g_queryInfo.port); + if (taos == NULL) { + fprintf(stderr, "Failed to connect to TDengine, reason:%s\n", taos_errstr(NULL)); + exit(-1); + } + + if (0 != g_queryInfo.subQueryInfo.sqlCount) { + (void)getAllChildNameOfSuperTable(taos, g_queryInfo.dbName, g_queryInfo.subQueryInfo.sTblName, &g_queryInfo.subQueryInfo.childTblName, &g_queryInfo.subQueryInfo.childTblCount); + } + + + pthread_t *pids = NULL; + threadInfo *infos = NULL; + //==== create sub threads for query from super table + if (g_queryInfo.superQueryInfo.sqlCount > 0 && g_queryInfo.superQueryInfo.concurrent > 0) { + pids = malloc(g_queryInfo.superQueryInfo.concurrent * sizeof(pthread_t)); + infos = malloc(g_queryInfo.superQueryInfo.concurrent * sizeof(threadInfo)); + if ((NULL == pids) || (NULL == infos)) { + printf("malloc failed for create threads\n"); + taos_close(taos); + exit(-1); + } + + for (int i = 0; i < g_queryInfo.superQueryInfo.concurrent; i++) { + threadInfo *t_info = infos + i; + t_info->threadID = i; + t_info->taos = taos; + pthread_create(pids + i, NULL, superSubscribeProcess, t_info); + } + } + + //==== create sub threads for query from sub table + pthread_t *pidsOfSub = NULL; + threadInfo *infosOfSub = NULL; + if ((g_queryInfo.subQueryInfo.sqlCount > 0) && (g_queryInfo.subQueryInfo.threadCnt > 0)) { + pidsOfSub = malloc(g_queryInfo.subQueryInfo.threadCnt * sizeof(pthread_t)); + infosOfSub = malloc(g_queryInfo.subQueryInfo.threadCnt * sizeof(threadInfo)); + if ((NULL == pidsOfSub) || (NULL == infosOfSub)) { + printf("malloc failed for create threads\n"); + taos_close(taos); + exit(-1); + } + + int ntables = g_queryInfo.subQueryInfo.childTblCount; + int threads = g_queryInfo.subQueryInfo.threadCnt; + + int a = ntables / threads; + if (a < 1) { + threads = ntables; + a = 1; + } + + int b = 0; + if (threads != 0) { + b = ntables % threads; + } + + int last = 0; + for (int i = 0; i < threads; i++) { + threadInfo *t_info = infosOfSub + i; + t_info->threadID = i; + + t_info->start_table_id = last; + t_info->end_table_id = i < b ? last + a : last + a - 1; + t_info->taos = taos; + pthread_create(pidsOfSub + i, NULL, subSubscribeProcess, t_info); + } + g_queryInfo.subQueryInfo.threadCnt = threads; + } + + for (int i = 0; i < g_queryInfo.superQueryInfo.concurrent; i++) { + pthread_join(pids[i], NULL); + } + + tmfree((char*)pids); + tmfree((char*)infos); + + for (int i = 0; i < g_queryInfo.subQueryInfo.threadCnt; i++) { + pthread_join(pidsOfSub[i], NULL); + } + + tmfree((char*)pidsOfSub); + tmfree((char*)infosOfSub); + taos_close(taos); + return 0; +} + +void initOfInsertMeta() { + memset(&g_Dbs, 0, sizeof(SDbs)); + + // set default values + strncpy(g_Dbs.host, "127.0.0.1", MAX_DB_NAME_SIZE); + g_Dbs.port = 6030; + strncpy(g_Dbs.user, TSDB_DEFAULT_USER, MAX_DB_NAME_SIZE); + strncpy(g_Dbs.password, TSDB_DEFAULT_PASS, MAX_DB_NAME_SIZE); + g_Dbs.threadCount = 2; + g_Dbs.use_metric = true; +} + +void initOfQueryMeta() { + memset(&g_queryInfo, 0, sizeof(SQueryMetaInfo)); + + // set default values + strncpy(g_queryInfo.host, "127.0.0.1", MAX_DB_NAME_SIZE); + g_queryInfo.port = 6030; + strncpy(g_queryInfo.user, TSDB_DEFAULT_USER, MAX_DB_NAME_SIZE); + strncpy(g_queryInfo.password, TSDB_DEFAULT_PASS, MAX_DB_NAME_SIZE); +} + +void setParaFromArg(){ + if (g_args.host) { + strcpy(g_Dbs.host, g_args.host); + } else { + strncpy(g_Dbs.host, "127.0.0.1", MAX_DB_NAME_SIZE); + } + + if (g_args.user) { + strcpy(g_Dbs.user, g_args.user); + } + + if (g_args.password) { + strcpy(g_Dbs.password, g_args.password); + } + + if (g_args.port) { + g_Dbs.port = g_args.port; + } + + g_Dbs.dbCount = 1; + g_Dbs.db[0].drop = 1; + + strncpy(g_Dbs.db[0].dbName, g_args.database, MAX_DB_NAME_SIZE); + g_Dbs.db[0].dbCfg.replica = g_args.replica; + strncpy(g_Dbs.db[0].dbCfg.precision, "ms", MAX_DB_NAME_SIZE); + + + strncpy(g_Dbs.resultFile, g_args.output_file, MAX_FILE_NAME_LEN); + + g_Dbs.use_metric = g_args.use_metric; + g_Dbs.insert_only = g_args.insert_only; + + g_Dbs.db[0].superTblCount = 1; + strncpy(g_Dbs.db[0].superTbls[0].sTblName, "meters", MAX_TB_NAME_SIZE); + g_Dbs.db[0].superTbls[0].childTblCount = g_args.num_of_tables; + g_Dbs.threadCount = g_args.num_of_threads; + g_Dbs.queryMode = g_args.mode; + + g_Dbs.db[0].superTbls[0].autoCreateTable = PRE_CREATE_SUBTBL; + g_Dbs.db[0].superTbls[0].superTblExists = TBL_NO_EXISTS; + g_Dbs.db[0].superTbls[0].childTblExists = TBL_NO_EXISTS; + g_Dbs.db[0].superTbls[0].insertRate = 0; + g_Dbs.db[0].superTbls[0].disorderRange = g_args.disorderRange; + g_Dbs.db[0].superTbls[0].disorderRatio = g_args.disorderRatio; + strncpy(g_Dbs.db[0].superTbls[0].childTblPrefix, g_args.tb_prefix, MAX_TB_NAME_SIZE); + strncpy(g_Dbs.db[0].superTbls[0].dataSource, "rand", MAX_TB_NAME_SIZE); + strncpy(g_Dbs.db[0].superTbls[0].insertMode, "taosc", MAX_TB_NAME_SIZE); + strncpy(g_Dbs.db[0].superTbls[0].startTimestamp, "2017-07-14 10:40:00.000", MAX_TB_NAME_SIZE); + g_Dbs.db[0].superTbls[0].timeStampStep = 10; + + // g_args.num_of_RPR; + g_Dbs.db[0].superTbls[0].insertRows = g_args.num_of_DPT; + g_Dbs.db[0].superTbls[0].maxSqlLen = TSDB_PAYLOAD_SIZE; + + g_Dbs.do_aggreFunc = true; + + char dataString[STRING_LEN]; + char **data_type = g_args.datatype; + + memset(dataString, 0, STRING_LEN); + + if (strcasecmp(data_type[0], "BINARY") == 0 || strcasecmp(data_type[0], "BOOL") == 0 || strcasecmp(data_type[0], "NCHAR") == 0 ) { + g_Dbs.do_aggreFunc = false; + } + + g_Dbs.db[0].superTbls[0].columnCount = 0; + for (int i = 0; i < MAX_NUM_DATATYPE; i++) { + if (data_type[i] == NULL) { + break; + } + + strncpy(g_Dbs.db[0].superTbls[0].columns[i].dataType, data_type[i], MAX_TB_NAME_SIZE); + g_Dbs.db[0].superTbls[0].columns[i].dataLen = g_args.len_of_binary; + g_Dbs.db[0].superTbls[0].columnCount++; + } + + if (g_Dbs.db[0].superTbls[0].columnCount > g_args.num_of_CPR) { + g_Dbs.db[0].superTbls[0].columnCount = g_args.num_of_CPR; + } else { + for (int i = g_Dbs.db[0].superTbls[0].columnCount; i < g_args.num_of_CPR; i++) { + strncpy(g_Dbs.db[0].superTbls[0].columns[i].dataType, "INT", MAX_TB_NAME_SIZE); + g_Dbs.db[0].superTbls[0].columns[i].dataLen = 0; + g_Dbs.db[0].superTbls[0].columnCount++; + } + } + + if (g_Dbs.use_metric) { + strncpy(g_Dbs.db[0].superTbls[0].tags[0].dataType, "INT", MAX_TB_NAME_SIZE); + g_Dbs.db[0].superTbls[0].tags[0].dataLen = 0; + + strncpy(g_Dbs.db[0].superTbls[0].tags[1].dataType, "BINARY", MAX_TB_NAME_SIZE); + g_Dbs.db[0].superTbls[0].tags[1].dataLen = g_args.len_of_binary; + g_Dbs.db[0].superTbls[0].tagCount = 2; + } else { + g_Dbs.db[0].superTbls[0].tagCount = 0; + } +} + +/* Function to do regular expression check */ +static int regexMatch(const char *s, const char *reg, int cflags) { + regex_t regex; + char msgbuf[100] = {0}; + + /* Compile regular expression */ + if (regcomp(®ex, reg, cflags) != 0) { + printf("Fail to compile regex\n"); + exit(-1); + } + + /* Execute regular expression */ + int reti = regexec(®ex, s, 0, NULL, 0); + if (!reti) { + regfree(®ex); + return 1; + } else if (reti == REG_NOMATCH) { + regfree(®ex); + return 0; + } else { + regerror(reti, ®ex, msgbuf, sizeof(msgbuf)); + printf("Regex match failed: %s\n", msgbuf); + regfree(®ex); + exit(-1); + } + + return 0; +} + +static int isCommentLine(char *line) { + if (line == NULL) return 1; + + return regexMatch(line, "^\\s*#.*", REG_EXTENDED); +} + +void querySqlFile(TAOS* taos, char* sqlFile) +{ + FILE *fp = fopen(sqlFile, "r"); + if (fp == NULL) { + printf("failed to open file %s, reason:%s\n", sqlFile, strerror(errno)); + return; + } + + int read_len = 0; + char * cmd = calloc(1, MAX_SQL_SIZE); + size_t cmd_len = 0; + char * line = NULL; + size_t line_len = 0; + + double t = getCurrentTime(); + + while ((read_len = tgetline(&line, &line_len, fp)) != -1) { + if (read_len >= MAX_SQL_SIZE) 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); + queryDbExec(taos, cmd, NO_INSERT_TYPE); + memset(cmd, 0, MAX_SQL_SIZE); + cmd_len = 0; + } + + t = getCurrentTime() - t; + printf("run %s took %.6f second(s)\n\n", sqlFile, t); + + tmfree(cmd); + tmfree(line); + tmfclose(fp); + return; +} + +int main(int argc, char *argv[]) { + parse_args(argc, argv, &g_args); + + if (g_args.metaFile) { + initOfInsertMeta(); + initOfQueryMeta(); + if (false == getInfoFromJsonFile(g_args.metaFile)) { + printf("Failed to read %s\n", g_args.metaFile); + return 1; + } + } else { + + memset(&g_Dbs, 0, sizeof(SDbs)); + g_jsonType = INSERT_MODE; + setParaFromArg(); + + if (NULL != g_args.sqlFile) { + TAOS* qtaos = taos_connect(g_Dbs.host, g_Dbs.user, g_Dbs.password, g_Dbs.db[0].dbName, g_Dbs.port); + querySqlFile(qtaos, g_args.sqlFile); + taos_close(qtaos); + return 0; + } + + (void)insertTestProcess(); + if (g_Dbs.insert_only) return 0; + + // select + + //printf("At present, there is no integration of taosdemo, please wait patiently!\n"); + return 0; + } + + if (INSERT_MODE == g_jsonType) { + if (g_Dbs.cfgDir[0]) taos_options(TSDB_OPTION_CONFIGDIR, g_Dbs.cfgDir); + (void)insertTestProcess(); + } else if (QUERY_MODE == g_jsonType) { + if (g_queryInfo.cfgDir[0]) taos_options(TSDB_OPTION_CONFIGDIR, g_queryInfo.cfgDir); + (void)queryTestProcess(); + } else if (SUBSCRIBE_MODE == g_jsonType) { + if (g_queryInfo.cfgDir[0]) taos_options(TSDB_OPTION_CONFIGDIR, g_queryInfo.cfgDir); + (void)subscribeTestProcess(); + } else { + ; + } + + taos_cleanup(); + return 0; +} + From 15ddb067c0bc015896fb4f3743dab1a920288e26 Mon Sep 17 00:00:00 2001 From: dapan1121 Date: Tue, 29 Dec 2020 06:42:38 +0000 Subject: [PATCH 04/29] remove unknow charactor --- src/client/src/tscSQLParser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/src/tscSQLParser.c b/src/client/src/tscSQLParser.c index b9d2762d9c..013661be37 100644 --- a/src/client/src/tscSQLParser.c +++ b/src/client/src/tscSQLParser.c @@ -4564,7 +4564,7 @@ int32_t parseFillClause(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SQuerySQL* pQuery int32_t numOfExprs = tscSqlExprNumOfExprs(pQueryInfo); for(int32_t i = 0; i < numOfExprs; ++i) { SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, i); - if (pExpr->functionId == TSDB_FUNC_TOP || pExpr->functionId == TSDB_FUNC_BOTTOM) { + if (pExpr->functionId == TSDB_FUNC_TOP || pExpr->functionId == TSDB_FUNC_BOTTOM) { return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg3); } } From 4858bee76b69f60560a7960f6d8c2f0cb46b30d9 Mon Sep 17 00:00:00 2001 From: Hui Li Date: Tue, 29 Dec 2020 14:53:30 +0800 Subject: [PATCH 05/29] [TD-2103] taosdemo enhancement --- packaging/deb/DEBIAN/prerm | 1 + packaging/deb/makedeb.sh | 1 + packaging/rpm/tdengine.spec | 4 +++- packaging/tools/install.sh | 2 ++ packaging/tools/install_client.sh | 2 ++ packaging/tools/install_client_power.sh | 6 ++++-- packaging/tools/install_power.sh | 2 ++ packaging/tools/makeclient.sh | 2 +- packaging/tools/makeclient_power.sh | 1 + packaging/tools/makepkg.sh | 2 +- packaging/tools/makepkg_power.sh | 1 + packaging/tools/post.sh | 4 ++++ packaging/tools/remove.sh | 1 + packaging/tools/remove_client.sh | 1 + packaging/tools/remove_client_power.sh | 1 + packaging/tools/remove_power.sh | 1 + 16 files changed, 27 insertions(+), 5 deletions(-) diff --git a/packaging/deb/DEBIAN/prerm b/packaging/deb/DEBIAN/prerm index d24502a1cb..3d57ece2ad 100644 --- a/packaging/deb/DEBIAN/prerm +++ b/packaging/deb/DEBIAN/prerm @@ -26,6 +26,7 @@ else ${csudo} rm -f ${bin_link_dir}/taos || : ${csudo} rm -f ${bin_link_dir}/taosd || : ${csudo} rm -f ${bin_link_dir}/taosdemo || : + ${csudo} rm -f ${bin_link_dir}/taosdemox || : ${csudo} rm -f ${bin_link_dir}/taosdump || : ${csudo} rm -f ${cfg_link_dir}/* || : ${csudo} rm -f ${inc_link_dir}/taos.h || : diff --git a/packaging/deb/makedeb.sh b/packaging/deb/makedeb.sh index edc7de9692..431093be95 100755 --- a/packaging/deb/makedeb.sh +++ b/packaging/deb/makedeb.sh @@ -48,6 +48,7 @@ cp ${compile_dir}/../packaging/deb/taosd ${pkg_dir}${install_home_pat cp ${compile_dir}/../packaging/tools/post.sh ${pkg_dir}${install_home_path}/script cp ${compile_dir}/../packaging/tools/preun.sh ${pkg_dir}${install_home_path}/script cp ${compile_dir}/build/bin/taosdemo ${pkg_dir}${install_home_path}/bin +cp ${compile_dir}/build/bin/taosdemox ${pkg_dir}${install_home_path}/bin cp ${compile_dir}/build/bin/taosdump ${pkg_dir}${install_home_path}/bin cp ${compile_dir}/build/bin/taosd ${pkg_dir}${install_home_path}/bin cp ${compile_dir}/build/bin/taos ${pkg_dir}${install_home_path}/bin diff --git a/packaging/rpm/tdengine.spec b/packaging/rpm/tdengine.spec index 8c23ab802d..6f012aa80e 100644 --- a/packaging/rpm/tdengine.spec +++ b/packaging/rpm/tdengine.spec @@ -58,6 +58,7 @@ cp %{_compiledir}/../packaging/tools/preun.sh %{buildroot}%{homepath}/scri cp %{_compiledir}/build/bin/taos %{buildroot}%{homepath}/bin cp %{_compiledir}/build/bin/taosd %{buildroot}%{homepath}/bin cp %{_compiledir}/build/bin/taosdemo %{buildroot}%{homepath}/bin +cp %{_compiledir}/build/bin/taosdemox %{buildroot}%{homepath}/bin cp %{_compiledir}/build/bin/taosdump %{buildroot}%{homepath}/bin cp %{_compiledir}/build/lib/${libfile} %{buildroot}%{homepath}/driver cp %{_compiledir}/../src/inc/taos.h %{buildroot}%{homepath}/include @@ -135,7 +136,8 @@ if [ $1 -eq 0 ];then ${csudo} rm -f ${bin_link_dir}/taos || : ${csudo} rm -f ${bin_link_dir}/taosd || : ${csudo} rm -f ${bin_link_dir}/taosdemo || : - #${csudo} rm -f ${bin_link_dir}/taosdump || : + ${csudo} rm -f ${bin_link_dir}/taosdemox || : + ${csudo} rm -f ${bin_link_dir}/taosdump || : ${csudo} rm -f ${cfg_link_dir}/* || : ${csudo} rm -f ${inc_link_dir}/taos.h || : ${csudo} rm -f ${inc_link_dir}/taoserror.h || : diff --git a/packaging/tools/install.sh b/packaging/tools/install.sh index 6f481a6d6c..338abcc6a0 100755 --- a/packaging/tools/install.sh +++ b/packaging/tools/install.sh @@ -175,6 +175,7 @@ function install_bin() { ${csudo} rm -f ${bin_link_dir}/taos || : ${csudo} rm -f ${bin_link_dir}/taosd || : ${csudo} rm -f ${bin_link_dir}/taosdemo || : + ${csudo} rm -f ${bin_link_dir}/taosdemox || : ${csudo} rm -f ${bin_link_dir}/taosdump || : ${csudo} rm -f ${bin_link_dir}/rmtaos || : ${csudo} rm -f ${bin_link_dir}/tarbitrator || : @@ -186,6 +187,7 @@ function install_bin() { [ -x ${install_main_dir}/bin/taos ] && ${csudo} ln -s ${install_main_dir}/bin/taos ${bin_link_dir}/taos || : [ -x ${install_main_dir}/bin/taosd ] && ${csudo} ln -s ${install_main_dir}/bin/taosd ${bin_link_dir}/taosd || : [ -x ${install_main_dir}/bin/taosdemo ] && ${csudo} ln -s ${install_main_dir}/bin/taosdemo ${bin_link_dir}/taosdemo || : + [ -x ${install_main_dir}/bin/taosdemox ] && ${csudo} ln -s ${install_main_dir}/bin/taosdemox ${bin_link_dir}/taosdemox || : [ -x ${install_main_dir}/bin/taosdump ] && ${csudo} ln -s ${install_main_dir}/bin/taosdump ${bin_link_dir}/taosdump || : [ -x ${install_main_dir}/bin/remove.sh ] && ${csudo} ln -s ${install_main_dir}/bin/remove.sh ${bin_link_dir}/rmtaos || : [ -x ${install_main_dir}/bin/set_core.sh ] && ${csudo} ln -s ${install_main_dir}/bin/set_core.sh ${bin_link_dir}/set_core || : diff --git a/packaging/tools/install_client.sh b/packaging/tools/install_client.sh index 0467300953..dd116e9bfb 100755 --- a/packaging/tools/install_client.sh +++ b/packaging/tools/install_client.sh @@ -86,6 +86,7 @@ function install_bin() { ${csudo} rm -f ${bin_link_dir}/taos || : if [ "$osType" != "Darwin" ]; then ${csudo} rm -f ${bin_link_dir}/taosdemo || : + ${csudo} rm -f ${bin_link_dir}/taosdemox || : ${csudo} rm -f ${bin_link_dir}/taosdump || : fi ${csudo} rm -f ${bin_link_dir}/rmtaos || : @@ -97,6 +98,7 @@ function install_bin() { [ -x ${install_main_dir}/bin/taos ] && ${csudo} ln -s ${install_main_dir}/bin/taos ${bin_link_dir}/taos || : if [ "$osType" != "Darwin" ]; then [ -x ${install_main_dir}/bin/taosdemo ] && ${csudo} ln -s ${install_main_dir}/bin/taosdemo ${bin_link_dir}/taosdemo || : + [ -x ${install_main_dir}/bin/taosdemox ] && ${csudo} ln -s ${install_main_dir}/bin/taosdemox ${bin_link_dir}/taosdemox || : [ -x ${install_main_dir}/bin/taosdump ] && ${csudo} ln -s ${install_main_dir}/bin/taosdump ${bin_link_dir}/taosdump || : fi [ -x ${install_main_dir}/bin/remove_client.sh ] && ${csudo} ln -s ${install_main_dir}/bin/remove_client.sh ${bin_link_dir}/rmtaos || : diff --git a/packaging/tools/install_client_power.sh b/packaging/tools/install_client_power.sh index 26977e12f4..04fd23d5ab 100755 --- a/packaging/tools/install_client_power.sh +++ b/packaging/tools/install_client_power.sh @@ -85,8 +85,9 @@ function install_bin() { # Remove links ${csudo} rm -f ${bin_link_dir}/power || : if [ "$osType" != "Darwin" ]; then - ${csudo} rm -f ${bin_link_dir}/powerdemo || : - ${csudo} rm -f ${bin_link_dir}/powerdump || : + ${csudo} rm -f ${bin_link_dir}/powerdemo || : + ${csudo} rm -f ${bin_link_dir}/powerdemox || : + ${csudo} rm -f ${bin_link_dir}/powerdump || : fi ${csudo} rm -f ${bin_link_dir}/rmpower || : ${csudo} rm -f ${bin_link_dir}/set_core || : @@ -97,6 +98,7 @@ function install_bin() { [ -x ${install_main_dir}/bin/power ] && ${csudo} ln -s ${install_main_dir}/bin/power ${bin_link_dir}/power || : if [ "$osType" != "Darwin" ]; then [ -x ${install_main_dir}/bin/powerdemo ] && ${csudo} ln -s ${install_main_dir}/bin/powerdemo ${bin_link_dir}/powerdemo || : + [ -x ${install_main_dir}/bin/powerdemox ] && ${csudo} ln -s ${install_main_dir}/bin/powerdemox ${bin_link_dir}/powerdemox || : [ -x ${install_main_dir}/bin/powerdump ] && ${csudo} ln -s ${install_main_dir}/bin/powerdump ${bin_link_dir}/powerdump || : fi [ -x ${install_main_dir}/bin/remove_client_power.sh ] && ${csudo} ln -s ${install_main_dir}/bin/remove_client_power.sh ${bin_link_dir}/rmpower || : diff --git a/packaging/tools/install_power.sh b/packaging/tools/install_power.sh index 1e3cb81b7d..28788ceb74 100755 --- a/packaging/tools/install_power.sh +++ b/packaging/tools/install_power.sh @@ -174,6 +174,7 @@ function install_bin() { ${csudo} rm -f ${bin_link_dir}/power || : ${csudo} rm -f ${bin_link_dir}/powerd || : ${csudo} rm -f ${bin_link_dir}/powerdemo || : + ${csudo} rm -f ${bin_link_dir}/powerdemox || : ${csudo} rm -f ${bin_link_dir}/rmpower || : ${csudo} rm -f ${bin_link_dir}/tarbitrator || : ${csudo} rm -f ${bin_link_dir}/set_core || : @@ -184,6 +185,7 @@ function install_bin() { [ -x ${install_main_dir}/bin/power ] && ${csudo} ln -s ${install_main_dir}/bin/power ${bin_link_dir}/power || : [ -x ${install_main_dir}/bin/powerd ] && ${csudo} ln -s ${install_main_dir}/bin/powerd ${bin_link_dir}/powerd || : [ -x ${install_main_dir}/bin/powerdemo ] && ${csudo} ln -s ${install_main_dir}/bin/powerdemo ${bin_link_dir}/powerdemo || : + [ -x ${install_main_dir}/bin/powerdemox ] && ${csudo} ln -s ${install_main_dir}/bin/powerdemox ${bin_link_dir}/powerdemox || : [ -x ${install_main_dir}/bin/remove_power.sh ] && ${csudo} ln -s ${install_main_dir}/bin/remove_power.sh ${bin_link_dir}/rmpower || : [ -x ${install_main_dir}/bin/set_core.sh ] && ${csudo} ln -s ${install_main_dir}/bin/set_core.sh ${bin_link_dir}/set_core || : [ -x ${install_main_dir}/bin/tarbitrator ] && ${csudo} ln -s ${install_main_dir}/bin/tarbitrator ${bin_link_dir}/tarbitrator || : diff --git a/packaging/tools/makeclient.sh b/packaging/tools/makeclient.sh index ee79a56040..00dfcb7559 100755 --- a/packaging/tools/makeclient.sh +++ b/packaging/tools/makeclient.sh @@ -45,7 +45,7 @@ if [ "$osType" != "Darwin" ]; then strip ${build_dir}/bin/taos bin_files="${build_dir}/bin/taos ${script_dir}/remove_client.sh" else - bin_files="${build_dir}/bin/taos ${build_dir}/bin/taosdump ${build_dir}/bin/taosdemo ${script_dir}/remove_client.sh ${script_dir}/set_core.sh ${script_dir}/get_client.sh" + bin_files="${build_dir}/bin/taos ${build_dir}/bin/taosdump ${build_dir}/bin/taosdemo ${build_dir}/bin/taosdemox ${script_dir}/remove_client.sh ${script_dir}/set_core.sh ${script_dir}/get_client.sh" fi lib_files="${build_dir}/lib/libtaos.so.${version}" else diff --git a/packaging/tools/makeclient_power.sh b/packaging/tools/makeclient_power.sh index fdb3e0e5cc..509df31297 100755 --- a/packaging/tools/makeclient_power.sh +++ b/packaging/tools/makeclient_power.sh @@ -77,6 +77,7 @@ if [ "$osType" != "Darwin" ]; then cp ${build_dir}/bin/taos ${install_dir}/bin/power cp ${script_dir}/remove_power.sh ${install_dir}/bin cp ${build_dir}/bin/taosdemo ${install_dir}/bin/powerdemo + cp ${build_dir}/bin/taosdemox ${install_dir}/bin/powerdemox cp ${build_dir}/bin/taosdump ${install_dir}/bin/powerdump cp ${script_dir}/set_core.sh ${install_dir}/bin cp ${script_dir}/get_client.sh ${install_dir}/bin diff --git a/packaging/tools/makepkg.sh b/packaging/tools/makepkg.sh index 5ae5cbbcdc..0b4659a911 100755 --- a/packaging/tools/makepkg.sh +++ b/packaging/tools/makepkg.sh @@ -36,7 +36,7 @@ if [ "$pagMode" == "lite" ]; then strip ${build_dir}/bin/taos bin_files="${build_dir}/bin/taosd ${build_dir}/bin/taos ${script_dir}/remove.sh" else - bin_files="${build_dir}/bin/taosd ${build_dir}/bin/taos ${build_dir}/bin/taosdump ${build_dir}/bin/taosdemo ${build_dir}/bin/tarbitrator ${script_dir}/remove.sh ${script_dir}/set_core.sh ${script_dir}/get_client.sh" + bin_files="${build_dir}/bin/taosd ${build_dir}/bin/taos ${build_dir}/bin/taosdump ${build_dir}/bin/taosdemo ${build_dir}/bin/taosdemox ${build_dir}/bin/tarbitrator ${script_dir}/remove.sh ${script_dir}/set_core.sh ${script_dir}/get_client.sh" fi lib_files="${build_dir}/lib/libtaos.so.${version}" diff --git a/packaging/tools/makepkg_power.sh b/packaging/tools/makepkg_power.sh index 1384948469..ba57fe5e96 100755 --- a/packaging/tools/makepkg_power.sh +++ b/packaging/tools/makepkg_power.sh @@ -77,6 +77,7 @@ else cp ${build_dir}/bin/taosd ${install_dir}/bin/powerd cp ${script_dir}/remove_power.sh ${install_dir}/bin cp ${build_dir}/bin/taosdemo ${install_dir}/bin/powerdemo + cp ${build_dir}/bin/taosdemox ${install_dir}/bin/powerdemox cp ${build_dir}/bin/taosdump ${install_dir}/bin/powerdump cp ${build_dir}/bin/tarbitrator ${install_dir}/bin cp ${script_dir}/set_core.sh ${install_dir}/bin diff --git a/packaging/tools/post.sh b/packaging/tools/post.sh index 7a416c5576..9d15b9736e 100755 --- a/packaging/tools/post.sh +++ b/packaging/tools/post.sh @@ -96,6 +96,8 @@ function install_bin() { ${csudo} rm -f ${bin_link_dir}/taos || : ${csudo} rm -f ${bin_link_dir}/taosd || : ${csudo} rm -f ${bin_link_dir}/taosdemo || : + ${csudo} rm -f ${bin_link_dir}/taosdemox || : + ${csudo} rm -f ${bin_link_dir}/taosdump || : ${csudo} rm -f ${bin_link_dir}/rmtaos || : ${csudo} rm -f ${bin_link_dir}/set_core || : @@ -105,6 +107,8 @@ function install_bin() { [ -x ${bin_dir}/taos ] && ${csudo} ln -s ${bin_dir}/taos ${bin_link_dir}/taos || : [ -x ${bin_dir}/taosd ] && ${csudo} ln -s ${bin_dir}/taosd ${bin_link_dir}/taosd || : [ -x ${bin_dir}/taosdemo ] && ${csudo} ln -s ${bin_dir}/taosdemo ${bin_link_dir}/taosdemo || : + [ -x ${bin_dir}/taosdemox ] && ${csudo} ln -s ${bin_dir}/taosdemox ${bin_link_dir}/taosdemox || : + [ -x ${bin_dir}/taosdump ] && ${csudo} ln -s ${bin_dir}/taosdump ${bin_link_dir}/taosdump || : [ -x ${bin_dir}/set_core.sh ] && ${csudo} ln -s ${bin_dir}/set_core.sh ${bin_link_dir}/set_core || : } diff --git a/packaging/tools/remove.sh b/packaging/tools/remove.sh index 2f2660d446..8d96ef851c 100755 --- a/packaging/tools/remove.sh +++ b/packaging/tools/remove.sh @@ -72,6 +72,7 @@ function clean_bin() { ${csudo} rm -f ${bin_link_dir}/taos || : ${csudo} rm -f ${bin_link_dir}/taosd || : ${csudo} rm -f ${bin_link_dir}/taosdemo || : + ${csudo} rm -f ${bin_link_dir}/taosdemox || : ${csudo} rm -f ${bin_link_dir}/taosdump || : ${csudo} rm -f ${bin_link_dir}/rmtaos || : ${csudo} rm -f ${bin_link_dir}/tarbitrator || : diff --git a/packaging/tools/remove_client.sh b/packaging/tools/remove_client.sh index 7579162dc6..e84cdd2620 100755 --- a/packaging/tools/remove_client.sh +++ b/packaging/tools/remove_client.sh @@ -38,6 +38,7 @@ function clean_bin() { # Remove link ${csudo} rm -f ${bin_link_dir}/taos || : ${csudo} rm -f ${bin_link_dir}/taosdemo || : + ${csudo} rm -f ${bin_link_dir}/taosdemox || : ${csudo} rm -f ${bin_link_dir}/taosdump || : ${csudo} rm -f ${bin_link_dir}/rmtaos || : ${csudo} rm -f ${bin_link_dir}/set_core || : diff --git a/packaging/tools/remove_client_power.sh b/packaging/tools/remove_client_power.sh index 580c46e207..1842e86a5b 100755 --- a/packaging/tools/remove_client_power.sh +++ b/packaging/tools/remove_client_power.sh @@ -38,6 +38,7 @@ function clean_bin() { # Remove link ${csudo} rm -f ${bin_link_dir}/power || : ${csudo} rm -f ${bin_link_dir}/powerdemo || : + ${csudo} rm -f ${bin_link_dir}/powerdemox || : ${csudo} rm -f ${bin_link_dir}/powerdump || : ${csudo} rm -f ${bin_link_dir}/rmpower || : ${csudo} rm -f ${bin_link_dir}/set_core || : diff --git a/packaging/tools/remove_power.sh b/packaging/tools/remove_power.sh index 816869cf44..59073105de 100755 --- a/packaging/tools/remove_power.sh +++ b/packaging/tools/remove_power.sh @@ -72,6 +72,7 @@ function clean_bin() { ${csudo} rm -f ${bin_link_dir}/power || : ${csudo} rm -f ${bin_link_dir}/powerd || : ${csudo} rm -f ${bin_link_dir}/powerdemo || : + ${csudo} rm -f ${bin_link_dir}/powerdemox || : ${csudo} rm -f ${bin_link_dir}/powerdump || : ${csudo} rm -f ${bin_link_dir}/rmpower || : ${csudo} rm -f ${bin_link_dir}/tarbitrator || : From 99bfe7dfffba363993a1aa9bab714c3f2630eb2f Mon Sep 17 00:00:00 2001 From: dapan1121 Date: Tue, 29 Dec 2020 06:57:44 +0000 Subject: [PATCH 06/29] fix type warning --- src/client/src/tscSQLParser.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/src/tscSQLParser.c b/src/client/src/tscSQLParser.c index 013661be37..b9fe5e7247 100644 --- a/src/client/src/tscSQLParser.c +++ b/src/client/src/tscSQLParser.c @@ -4561,8 +4561,8 @@ int32_t parseFillClause(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SQuerySQL* pQuery return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg2); } - int32_t numOfExprs = tscSqlExprNumOfExprs(pQueryInfo); - for(int32_t i = 0; i < numOfExprs; ++i) { + size_t numOfExprs = tscSqlExprNumOfExprs(pQueryInfo); + for(size_t i = 0; i < numOfExprs; ++i) { SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, i); if (pExpr->functionId == TSDB_FUNC_TOP || pExpr->functionId == TSDB_FUNC_BOTTOM) { return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg3); From c5cc49331247a16e474d3dfdd7144d596b8b5580 Mon Sep 17 00:00:00 2001 From: zyyang Date: Tue, 29 Dec 2020 16:09:19 +0800 Subject: [PATCH 07/29] [TD-2302]: fix nodejs exception when query a null value --- src/connector/nodejs/test/testNull.js | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/connector/nodejs/test/testNull.js diff --git a/src/connector/nodejs/test/testNull.js b/src/connector/nodejs/test/testNull.js new file mode 100644 index 0000000000..ae3938a634 --- /dev/null +++ b/src/connector/nodejs/test/testNull.js @@ -0,0 +1,10 @@ +const taos = require('../tdengine'); +var conn = taos.connect({host: "127.0.0.1", user: "root", password: "taosdata", config: "/etc/taos", port: 6030}); +var c1 = conn.cursor(); + + +c1.query('select * from test.weather', true).then(function (result) { + result.pretty(); +}); + +conn.close(); \ No newline at end of file From 6342e8a669aadc8dd08542b858b5dd5a87ff26ce Mon Sep 17 00:00:00 2001 From: Hui Li Date: Tue, 29 Dec 2020 16:23:11 +0800 Subject: [PATCH 08/29] [NONE] --- src/kit/taosdemox/taosdemox.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kit/taosdemox/taosdemox.c b/src/kit/taosdemox/taosdemox.c index 8cf6330cf4..5c9fd025f0 100644 --- a/src/kit/taosdemox/taosdemox.c +++ b/src/kit/taosdemox/taosdemox.c @@ -1969,7 +1969,7 @@ static bool getColumnAndTagTypeFromInsertJsonFile(cJSON* stbInfo, SSuperTable* s int count = 1; int index = 0; - StrColumn columnCase = {0}; + StrColumn columnCase; //superTbls->columnCount = columnSize; for (int k = 0; k < columnSize; ++k) { From 77941634479ec97ccb6f766d3ad458ec4e88c258 Mon Sep 17 00:00:00 2001 From: dapan1121 Date: Tue, 29 Dec 2020 08:47:43 +0000 Subject: [PATCH 09/29] fix type mismatch --- src/client/src/tscSQLParser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/src/tscSQLParser.c b/src/client/src/tscSQLParser.c index b9fe5e7247..d105c577db 100644 --- a/src/client/src/tscSQLParser.c +++ b/src/client/src/tscSQLParser.c @@ -4562,7 +4562,7 @@ int32_t parseFillClause(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SQuerySQL* pQuery } size_t numOfExprs = tscSqlExprNumOfExprs(pQueryInfo); - for(size_t i = 0; i < numOfExprs; ++i) { + for(int32_t i = 0; i < numOfExprs; ++i) { SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, i); if (pExpr->functionId == TSDB_FUNC_TOP || pExpr->functionId == TSDB_FUNC_BOTTOM) { return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg3); From f9dd3a97bb09af7a45aeb94da7ed854f5a372c77 Mon Sep 17 00:00:00 2001 From: zyyang Date: Tue, 29 Dec 2020 16:54:41 +0800 Subject: [PATCH 10/29] change --- src/connector/nodejs/nodetaos/cinterface.js | 34 +++++++++++++-------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/connector/nodejs/nodetaos/cinterface.js b/src/connector/nodejs/nodetaos/cinterface.js index 7e58f4eb02..995babdb2b 100644 --- a/src/connector/nodejs/nodetaos/cinterface.js +++ b/src/connector/nodejs/nodetaos/cinterface.js @@ -367,11 +367,15 @@ CTaosInterface.prototype.fetchBlock = function fetchBlock(result, fields) { let offset = 0; for (let i = 0; i < fields.length; i++) { pdata = ref.reinterpret(pblock,8,i*8); - pdata = ref.ref(pdata.readPointer()); - if (!convertFunctions[fields[i]['type']] ) { - throw new errors.DatabaseError("Invalid data type returned from database"); - } - blocks[i] = convertFunctions[fields[i]['type']](pdata, 1, fieldlens[i], offset, isMicro); + if(ref.isNull(pdata.readPointer())){ + blocks[i] = new Array(); + }else{ + pdata = ref.ref(pdata.readPointer()); + if (!convertFunctions[fields[i]['type']] ) { + throw new errors.DatabaseError("Invalid data type returned from database"); + } + blocks[i] = convertFunctions[fields[i]['type']](pdata, 1, fieldlens[i], offset, isMicro); + } } return {blocks: blocks, num_of_rows:Math.abs(num_of_rows)} } @@ -437,14 +441,18 @@ CTaosInterface.prototype.fetch_rows_a = function fetch_rows_a(result, callback, } if (numOfRows2 > 0){ for (let i = 0; i < fields.length; i++) { - if (!convertFunctions[fields[i]['type']] ) { - throw new errors.DatabaseError("Invalid data type returned from database"); - } - let prow = ref.reinterpret(row,8,i*8); - prow = prow.readPointer(); - prow = ref.ref(prow); - blocks[i] = convertFunctions[fields[i]['type']](prow, 1, fieldlens[i], offset, isMicro); - //offset += fields[i]['bytes'] * numOfRows2; + if(ref.isNull(pdata.readPointer())){ + blocks[i] = new Array(); + }else{ + if (!convertFunctions[fields[i]['type']] ) { + throw new errors.DatabaseError("Invalid data type returned from database"); + } + let prow = ref.reinterpret(row,8,i*8); + prow = prow.readPointer(); + prow = ref.ref(prow); + blocks[i] = convertFunctions[fields[i]['type']](prow, 1, fieldlens[i], offset, isMicro); + //offset += fields[i]['bytes'] * numOfRows2; + } } } callback(param2, result2, numOfRows2, blocks); From b71885472716c8ea7a84e0b22afbdcf85c186b6a Mon Sep 17 00:00:00 2001 From: zyyang Date: Tue, 29 Dec 2020 17:12:17 +0800 Subject: [PATCH 11/29] change --- src/connector/nodejs/package.json | 2 +- src/connector/nodejs/test/test.js | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/connector/nodejs/package.json b/src/connector/nodejs/package.json index 3f0600a09c..2d5cf45e1d 100644 --- a/src/connector/nodejs/package.json +++ b/src/connector/nodejs/package.json @@ -1,6 +1,6 @@ { "name": "td2.0-connector", - "version": "2.0.1", + "version": "2.0.4", "description": "A Node.js connector for TDengine.", "main": "tdengine.js", "scripts": { diff --git a/src/connector/nodejs/test/test.js b/src/connector/nodejs/test/test.js index 27c35bb481..bf4bb2c541 100644 --- a/src/connector/nodejs/test/test.js +++ b/src/connector/nodejs/test/test.js @@ -84,10 +84,19 @@ q.execute().then(function(r) { r.pretty(); }); + +// test query null value +c1.execute("create table if not exists td_connector_test.weather(ts timestamp, temperature float, humidity int) tags(location nchar(64))"); +c1.execute("insert into t1 using weather tags('北京') values(now, 11.11, 11)"); +c1.execute("insert into t1(ts, temperature) values(now, 22.22)"); +c1.execute("insert into t1(ts, humidity) values(now, 33)"); +c1.query('select * from test.t1', true).then(function (result) { + result.pretty(); +}); + var q = c1.query('select * from td_connector_test.weather'); console.log(q.query); q.execute().then(function(r) { - //console.log(r); r.pretty(); }); From 8af97223ed7c0f3b6887b2cd2106c6a667569f95 Mon Sep 17 00:00:00 2001 From: zyyang Date: Tue, 29 Dec 2020 17:12:50 +0800 Subject: [PATCH 12/29] change --- src/connector/nodejs/test/testNull.js | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 src/connector/nodejs/test/testNull.js diff --git a/src/connector/nodejs/test/testNull.js b/src/connector/nodejs/test/testNull.js deleted file mode 100644 index ae3938a634..0000000000 --- a/src/connector/nodejs/test/testNull.js +++ /dev/null @@ -1,10 +0,0 @@ -const taos = require('../tdengine'); -var conn = taos.connect({host: "127.0.0.1", user: "root", password: "taosdata", config: "/etc/taos", port: 6030}); -var c1 = conn.cursor(); - - -c1.query('select * from test.weather', true).then(function (result) { - result.pretty(); -}); - -conn.close(); \ No newline at end of file From c2f62c989174a975e7ac7dfaa973dd6c4b7bee1e Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Tue, 29 Dec 2020 18:02:50 +0800 Subject: [PATCH 13/29] TD-2429 --- src/balance/src/bnMain.c | 25 +++- src/inc/taosmsg.h | 21 ++-- src/mnode/inc/mnodeDef.h | 4 +- src/mnode/inc/mnodeVgroup.h | 3 + src/mnode/src/mnodeDnode.c | 1 + src/mnode/src/mnodeVgroup.c | 17 ++- src/vnode/src/vnodeMgmt.c | 1 + tests/script/unique/dnode/lossdata.sim | 165 +++++++++++++++++++++++++ 8 files changed, 218 insertions(+), 19 deletions(-) create mode 100644 tests/script/unique/dnode/lossdata.sim diff --git a/src/balance/src/bnMain.c b/src/balance/src/bnMain.c index 11576c1135..7725aa5db4 100644 --- a/src/balance/src/bnMain.c +++ b/src/balance/src/bnMain.c @@ -224,19 +224,34 @@ static bool bnCheckVgroupReady(SVgObj *pVgroup, SVnodeGid *pRmVnode) { return false; } + int32_t rmVnodeVer = 0; + for (int32_t i = 0; i < pVgroup->numOfVnodes; ++i) { + SVnodeGid *pVnode = pVgroup->vnodeGid + i; + if (pVnode == pRmVnode) { + rmVnodeVer = mnodeGetVgidVer(pVnode->vver); + mTrace("vgId:%d, check vgroup status, vindex:%d dnode:%d status:%s role:%s vver:%d is watching", pVgroup->vgId, i, + pVnode->dnodeId, dnodeStatus[pVnode->pDnode->status], syncRole[pVnode->role], rmVnodeVer); + } + } + bool isReady = false; for (int32_t i = 0; i < pVgroup->numOfVnodes; ++i) { SVnodeGid *pVnode = pVgroup->vnodeGid + i; if (pVnode == pRmVnode) continue; + int32_t vver = mnodeGetVgidVer(pVnode->vver); - mTrace("vgId:%d, check vgroup status, dnode:%d status:%d, vnode role:%s", pVgroup->vgId, pVnode->pDnode->dnodeId, - pVnode->pDnode->status, syncRole[pVnode->role]); + mTrace("vgId:%d, check vgroup status, vindex:%d dnode:%d status:%s role:%s vver:%d, rmvver:%d" , pVgroup->vgId, i, + pVnode->dnodeId, dnodeStatus[pVnode->pDnode->status], syncRole[pVnode->role], vver, rmVnodeVer); if (pVnode->pDnode->status == TAOS_DN_STATUS_DROPPING) continue; if (pVnode->pDnode->status == TAOS_DN_STATUS_OFFLINE) continue; + if (pVnode->role != TAOS_SYNC_ROLE_SLAVE && pVnode->role != TAOS_SYNC_ROLE_MASTER) continue; - if (pVnode->role == TAOS_SYNC_ROLE_SLAVE || pVnode->role == TAOS_SYNC_ROLE_MASTER) { - isReady = true; + if (rmVnodeVer == 0 || vver >= rmVnodeVer) { + mInfo("vgId:%d, is ready for vindex:%d in dnode:%d status:%s role:%s vver:%d larger than rmvver:%d", pVgroup->vgId, i, + pVnode->dnodeId, dnodeStatus[pVnode->pDnode->status], syncRole[pVnode->role], vver, rmVnodeVer); } + + isReady = true; } return isReady; @@ -256,7 +271,7 @@ static int32_t bnRemoveVnode(SVgObj *pVgroup) { mDebug("vgId:%d, is not ready", pVgroup->vgId); return -1; } else { - mDebug("vgId:%d, is ready, discard dnode:%d", pVgroup->vgId, pSelVnode->dnodeId); + mInfo("vgId:%d, is ready, discard dnode:%d", pVgroup->vgId, pSelVnode->dnodeId); bnDiscardVnode(pVgroup, pSelVnode); return TSDB_CODE_SUCCESS; } diff --git a/src/inc/taosmsg.h b/src/inc/taosmsg.h index 200fe2b0f9..b4480951c9 100644 --- a/src/inc/taosmsg.h +++ b/src/inc/taosmsg.h @@ -518,16 +518,17 @@ typedef struct SRetrieveTableRsp { } SRetrieveTableRsp; typedef struct { - int32_t vgId; - int32_t dbCfgVersion; - int64_t totalStorage; - int64_t compStorage; - int64_t pointsWritten; - uint8_t status; - uint8_t role; - uint8_t replica; - uint8_t reserved; - int32_t vgCfgVersion; + int32_t vgId; + int32_t dbCfgVersion; + int64_t totalStorage; + int64_t compStorage; + int64_t pointsWritten; + uint64_t vnodeVersion; + int32_t vgCfgVersion; + uint8_t status; + uint8_t role; + uint8_t replica; + uint8_t reserved; } SVnodeLoad; typedef struct { diff --git a/src/mnode/inc/mnodeDef.h b/src/mnode/inc/mnodeDef.h index 59f9c30bf7..a07607e615 100644 --- a/src/mnode/inc/mnodeDef.h +++ b/src/mnode/inc/mnodeDef.h @@ -128,8 +128,8 @@ typedef struct { typedef struct { int32_t dnodeId; int8_t role; - int8_t reserved[3]; - SDnodeObj* pDnode; + int8_t vver[3]; // To ensure compatibility, 3 bits are used to represent the remainder of 64 bit version + SDnodeObj *pDnode; } SVnodeGid; typedef struct SVgObj { diff --git a/src/mnode/inc/mnodeVgroup.h b/src/mnode/inc/mnodeVgroup.h index ee9ec7ae93..2067ad04cc 100644 --- a/src/mnode/inc/mnodeVgroup.h +++ b/src/mnode/inc/mnodeVgroup.h @@ -53,6 +53,9 @@ void mnodeSendAlterVgroupMsg(SVgObj *pVgroup); SRpcEpSet mnodeGetEpSetFromVgroup(SVgObj *pVgroup); SRpcEpSet mnodeGetEpSetFromIp(char *ep); +int32_t mnodeGetVgidVer(int8_t *vver); +void mnodeSetVgidVer(int8_t *cver, uint64_t iver); + #ifdef __cplusplus } #endif diff --git a/src/mnode/src/mnodeDnode.c b/src/mnode/src/mnodeDnode.c index 1ff2404834..14d1fa5816 100644 --- a/src/mnode/src/mnodeDnode.c +++ b/src/mnode/src/mnodeDnode.c @@ -571,6 +571,7 @@ static int32_t mnodeProcessDnodeStatusMsg(SMnodeMsg *pMsg) { pVload->vgId = htonl(pVload->vgId); pVload->dbCfgVersion = htonl(pVload->dbCfgVersion); pVload->vgCfgVersion = htonl(pVload->vgCfgVersion); + pVload->vnodeVersion = htobe64(pVload->vnodeVersion); SVgObj *pVgroup = mnodeGetVgroup(pVload->vgId); if (pVgroup == NULL) { diff --git a/src/mnode/src/mnodeVgroup.c b/src/mnode/src/mnodeVgroup.c index b0df98c950..b79425afbb 100644 --- a/src/mnode/src/mnodeVgroup.c +++ b/src/mnode/src/mnodeVgroup.c @@ -184,6 +184,7 @@ static int32_t mnodeVgroupActionEncode(SSdbRow *pRow) { for (int32_t i = 0; i < TSDB_MAX_REPLICA; ++i) { pTmpVgroup->vnodeGid[i].pDnode = NULL; pTmpVgroup->vnodeGid[i].role = 0; + memset(pTmpVgroup->vnodeGid[i].vver, 0, sizeof(pTmpVgroup->vnodeGid[i].vver)); } pRow->rowSize = tsVgUpdateSize; @@ -317,9 +318,10 @@ void mnodeUpdateVgroupStatus(SVgObj *pVgroup, SDnodeObj *pDnode, SVnodeLoad *pVl for (int32_t i = 0; i < pVgroup->numOfVnodes; ++i) { SVnodeGid *pVgid = &pVgroup->vnodeGid[i]; if (pVgid->pDnode == pDnode) { - mTrace("dnode:%d, receive status from dnode, vgId:%d status:%s last:%s", pDnode->dnodeId, pVgroup->vgId, - syncRole[pVload->role], syncRole[pVgid->role]); + mTrace("vgId:%d, receive vnode status from dnode:%d, status:%s last:%s vver:%" PRIu64, pVgroup->vgId, + pDnode->dnodeId, syncRole[pVload->role], syncRole[pVgid->role], pVload->vnodeVersion); pVgid->role = pVload->role; + mnodeSetVgidVer(pVgid->vver, pVload->vnodeVersion); if (pVload->role == TAOS_SYNC_ROLE_MASTER) { pVgroup->inUse = i; } @@ -1179,3 +1181,14 @@ void mnodeSendDropAllDbVgroupsMsg(SDbObj *pDropDb) { mInfo("db:%s, all vgroups:%d drop msg is sent to dnode", pDropDb->name, numOfVgroups); } + +int32_t mnodeGetVgidVer(int8_t *cver) { + int32_t iver = ((int32_t)cver[0]) * 10000 + ((int32_t)cver[1]) * 100 + (int32_t)cver[2]; + return iver; +} + +void mnodeSetVgidVer(int8_t *cver, uint64_t iver) { + cver[0] = (int8_t)((int32_t)(iver % 1000000) / 10000); + cver[1] = (int8_t)((int32_t)(iver % 100000) / 100); + cver[2] = (int8_t)(iver % 100); +} \ No newline at end of file diff --git a/src/vnode/src/vnodeMgmt.c b/src/vnode/src/vnodeMgmt.c index 196e488210..8469ab12c1 100644 --- a/src/vnode/src/vnodeMgmt.c +++ b/src/vnode/src/vnodeMgmt.c @@ -142,6 +142,7 @@ static void vnodeBuildVloadMsg(SVnodeObj *pVnode, SStatusMsg *pStatus) { pLoad->totalStorage = htobe64(totalStorage); pLoad->compStorage = htobe64(compStorage); pLoad->pointsWritten = htobe64(pointsWritten); + pLoad->vnodeVersion = htobe64(pVnode->version); pLoad->status = pVnode->status; pLoad->role = pVnode->role; pLoad->replica = pVnode->syncCfg.replica; diff --git a/tests/script/unique/dnode/lossdata.sim b/tests/script/unique/dnode/lossdata.sim new file mode 100644 index 0000000000..d4da2914c1 --- /dev/null +++ b/tests/script/unique/dnode/lossdata.sim @@ -0,0 +1,165 @@ +system sh/stop_dnodes.sh + +system sh/deploy.sh -n dnode1 -i 1 +system sh/deploy.sh -n dnode2 -i 2 +system sh/deploy.sh -n dnode3 -i 3 +system sh/deploy.sh -n dnode4 -i 4 +system sh/deploy.sh -n dnode5 -i 5 + +system sh/cfg.sh -n dnode1 -c balanceInterval -v 10 +system sh/cfg.sh -n dnode2 -c balanceInterval -v 10 +system sh/cfg.sh -n dnode3 -c balanceInterval -v 10 +system sh/cfg.sh -n dnode4 -c balanceInterval -v 10 +system sh/cfg.sh -n dnode5 -c balanceInterval -v 10 + +system sh/cfg.sh -n dnode1 -c mnodeEqualVnodeNum -v 4 +system sh/cfg.sh -n dnode2 -c mnodeEqualVnodeNum -v 4 +system sh/cfg.sh -n dnode3 -c mnodeEqualVnodeNum -v 4 +system sh/cfg.sh -n dnode4 -c mnodeEqualVnodeNum -v 4 +system sh/cfg.sh -n dnode5 -c mnodeEqualVnodeNum -v 4 + +system sh/cfg.sh -n dnode1 -c maxTablesPerVnode -v 4 +system sh/cfg.sh -n dnode2 -c maxTablesPerVnode -v 4 +system sh/cfg.sh -n dnode3 -c maxTablesPerVnode -v 4 +system sh/cfg.sh -n dnode4 -c maxTablesPerVnode -v 4 +system sh/cfg.sh -n dnode5 -c maxTablesPerVnode -v 4 + +print ========== step1 +system sh/exec.sh -n dnode1 -s start +sql connect + +sql create dnode $hostname2 +sql create dnode $hostname3 +system sh/exec.sh -n dnode2 -s start +system sh/exec.sh -n dnode3 -s start +$x = 0 +step1: + $x = $x + 1 + sleep 1000 + if $x == 10 then + return -1 + endi + +sql show dnodes +print dnode1 $data4_1 +print dnode2 $data4_2 +print dnode3 $data4_3 + +if $data4_1 != ready then + goto step1 +endi +if $data4_2 != ready then + goto step1 +endi +if $data4_3 != ready then + goto step1 +endi + +print ========== step2 + +sql create database d1 replica 2 +sql create table d1.t1 (t timestamp, i int) + +print ========== step2.1 + +sql show dnodes +print dnode1 openVnodes $data2_1 +print dnode2 openVnodes $data2_2 +print dnode3 openVnodes $data2_3 +print dnode4 openVnodes $data2_4 + +if $data2_1 != 0 then + return -1 +endi +if $data2_2 != 1 then + return -1 +endi +if $data2_3 != 1 then + return -1 +endi + +print ========== step3 +sql create dnode $hostname4 +system sh/exec.sh -n dnode4 -s start + +$x = 0 +show3: + $x = $x + 1 + sleep 1000 + if $x == 10 then + return -1 + endi + +sql show dnodes +print dnode1 openVnodes $data2_1 +print dnode2 openVnodes $data2_2 +print dnode3 openVnodes $data2_3 +print dnode4 openVnodes $data2_4 + +if $data2_2 != 1 then + goto show3 +endi +if $data2_3 != 1 then + goto show3 +endi +if $data2_4 != 0 then + goto show3 +endi + +sql show d1.vgroups; +print d1.vgroups $data00 $data01 $data02 $data03 $data04 $data05 $data06 $data07 $data08 $data09 + +print ========== step4 +sql drop dnode $hostname3 + +$i = 0 +$rowNum = 10000 + +while $i < $rowNum + $ts = 1500000000000 + $i + sql insert into d1.t1 values( $ts , $i ) + + $i = $i + 1 +endw + +print insert $rowNum finished + +$x = 0 +show4: + $x = $x + 1 + sleep 1000 + if $x == 40 then + return -1 + endi + +sql show dnodes +print dnode1 openVnodes $data2_1 +print dnode2 openVnodes $data2_2 +print dnode3 openVnodes $data2_3 +print dnode4 openVnodes $data2_4 +print dnode5 openVnodes $data2_5 + +if $data2_2 != 1 then + goto show4 +endi +if $data2_3 != null then + goto show4 +endi +if $data2_4 != 1 then + goto show4 +endi + +system sh/exec.sh -n dnode3 -s stop -x SIGINT + +print ========== step5 +sql select count(*) from d1.t1 +print select count(*) from d1.t1 ==> $data00 +if $data00 != $rowNum then + return -1 +endi + +#system sh/exec.sh -n dnode1 -s stop -x SIGINT +#system sh/exec.sh -n dnode2 -s stop -x SIGINT +#system sh/exec.sh -n dnode3 -s stop -x SIGINT +#system sh/exec.sh -n dnode4 -s stop -x SIGINT +#system sh/exec.sh -n dnode5 -s stop -x SIGINT \ No newline at end of file From b449a32f44de2b8b44c4f2bc4ca2f815a21d63d0 Mon Sep 17 00:00:00 2001 From: Hongze Cheng Date: Tue, 29 Dec 2020 10:14:45 +0000 Subject: [PATCH 14/29] [TD-2604]: fix coredump --- src/tsdb/src/tsdbMemTable.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tsdb/src/tsdbMemTable.c b/src/tsdb/src/tsdbMemTable.c index 87bc7b9443..07f001f68a 100644 --- a/src/tsdb/src/tsdbMemTable.c +++ b/src/tsdb/src/tsdbMemTable.c @@ -207,10 +207,10 @@ void *tsdbAllocBytes(STsdbRepo *pRepo, int bytes) { int tsdbAsyncCommit(STsdbRepo *pRepo) { if (pRepo->mem == NULL) return 0; - ASSERT(pRepo->imem == NULL); - sem_wait(&(pRepo->readyToCommit)); + ASSERT(pRepo->imem == NULL); + if (pRepo->code != TSDB_CODE_SUCCESS) { tsdbWarn("vgId:%d try to commit when TSDB not in good state: %s", REPO_ID(pRepo), tstrerror(terrno)); } From 58e23b5295e40b05e37476ca08a8233b9ce5d1df Mon Sep 17 00:00:00 2001 From: Ping Xiao Date: Tue, 29 Dec 2020 18:39:45 +0800 Subject: [PATCH 15/29] [TD-2551]: get insert delay values for taosdemo performance --- tests/perftest-scripts/perftest-query.sh | 8 ++++- tests/pytest/tools/taosdemoPerformance.py | 36 +++++++++++++++++++---- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/tests/perftest-scripts/perftest-query.sh b/tests/perftest-scripts/perftest-query.sh index b96daa5464..8498094181 100755 --- a/tests/perftest-scripts/perftest-query.sh +++ b/tests/perftest-scripts/perftest-query.sh @@ -74,8 +74,14 @@ function runQueryPerfTest { CREATETABLETIME=`grep 'Spent' taosdemoperf.txt | awk 'NR==1{print $2}'` INSERTRECORDSTIME=`grep 'Spent' taosdemoperf.txt | awk 'NR==2{print $2}'` REQUESTSPERSECOND=`grep 'Spent' taosdemoperf.txt | awk 'NR==2{print $13}'` + delay=`grep 'delay' taosdemoperf.txt | awk '{print $4}'` + AVGDELAY=`echo ${delay:0:${#delay}-3}` + delay=`grep 'delay' taosdemoperf.txt | awk '{print $6}'` + MAXDELAY=`echo ${delay:0:${#delay}-3}` + delay=`grep 'delay' taosdemoperf.txt | awk '{print $8}'` + MINDELAY=`echo ${delay:0:${#delay}-2}` - python3 tools/taosdemoPerformance.py -c $LOCAL_COMMIT -t $CREATETABLETIME -i $INSERTRECORDSTIME -r $REQUESTSPERSECOND | tee -a $PERFORMANCE_TEST_REPORT + python3 tools/taosdemoPerformance.py -c $LOCAL_COMMIT -t $CREATETABLETIME -i $INSERTRECORDSTIME -r $REQUESTSPERSECOND -avg $AVGDELAY -max $MAXDELAY -min $MINDELAY | tee -a $PERFORMANCE_TEST_REPORT [ -f taosdemoperf.txt ] && rm taosdemoperf.txt } diff --git a/tests/pytest/tools/taosdemoPerformance.py b/tests/pytest/tools/taosdemoPerformance.py index 6b6296e61a..28f451b6a0 100644 --- a/tests/pytest/tools/taosdemoPerformance.py +++ b/tests/pytest/tools/taosdemoPerformance.py @@ -22,12 +22,15 @@ import argparse import os.path class taosdemoPerformace: - def __init__(self, commitID, dbName, createTableTime, insertRecordsTime, recordsPerSecond): + def __init__(self, commitID, dbName, createTableTime, insertRecordsTime, recordsPerSecond, avgDelay, maxDelay, minDelay): self.commitID = commitID self.dbName = dbName self.createTableTime = createTableTime self.insertRecordsTime = insertRecordsTime - self.recordsPerSecond = recordsPerSecond + self.recordsPerSecond = recordsPerSecond + self.avgDelay = avgDelay + self.maxDelay = maxDelay + self.minDelay = minDelay self.host = "127.0.0.1" self.user = "root" self.password = "taosdata" @@ -43,12 +46,15 @@ class taosdemoPerformace: cursor.execute("create database if not exists %s" % self.dbName) cursor.execute("use %s" % self.dbName) - cursor.execute("create table if not exists taosdemo_perf (ts timestamp, create_table_time float, insert_records_time float, records_per_second float, commit_id binary(50))") + cursor.execute("create table if not exists taosdemo_perf (ts timestamp, create_table_time float, insert_records_time float, records_per_second float, commit_id binary(50), avg_delay float, max_delay float, min_delay float)") print("==================== taosdemo performance ====================") print("create tables time: %f" % self.createTableTime) print("insert records time: %f" % self.insertRecordsTime) print("records per second: %f" % self.recordsPerSecond) - cursor.execute("insert into taosdemo_perf values(now, %f, %f, %f, '%s')" % (self.createTableTime, self.insertRecordsTime, self.recordsPerSecond, self.commitID)) + print("avg delay: %f" % self.avgDelay) + print("max delay: %f" % self.maxDelay) + print("min delay: %f" % self.minDelay) + cursor.execute("insert into taosdemo_perf values(now, %f, %f, %f, '%s', %f, %f, %f)" % (self.createTableTime, self.insertRecordsTime, self.recordsPerSecond, self.commitID, self.avgDelay, self.maxDelay, self.minDelay)) cursor.execute("drop database if exists taosdemo_insert_test") cursor.close() @@ -86,8 +92,28 @@ if __name__ == '__main__': action='store', type=float, help='records per request') + parser.add_argument( + '-avg', + '---avg-delay', + action='store', + type=float, + help='avg delay') + parser.add_argument( + '-max', + '---max-delay', + action='store', + type=float, + help='max delay') + parser.add_argument( + '-min', + '---min-delay', + action='store', + type=float, + help='min delay') + args = parser.parse_args() - perftest = taosdemoPerformace(args.commit_id, args.database_name, args.create_table, args.insert_records, args.records_per_second) + perftest = taosdemoPerformace(args.commit_id, args.database_name, args.create_table, args.insert_records, args.records_per_second, + args.avg_delay, args.max_delay, args.min_delay) perftest.createTablesAndStoreData() \ No newline at end of file From 502c92770ad19556dabf4d08fc0d798e19aaf231 Mon Sep 17 00:00:00 2001 From: Minglei Jin Date: Wed, 30 Dec 2020 09:17:29 +0800 Subject: [PATCH 16/29] [TD-2606]: double TSDB_MAX_WAL_SIZE from 1M to 2M --- src/inc/taosdef.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/inc/taosdef.h b/src/inc/taosdef.h index 1ae37fa28a..7f1ed40815 100644 --- a/src/inc/taosdef.h +++ b/src/inc/taosdef.h @@ -436,7 +436,7 @@ void tsDataSwap(void *pLeft, void *pRight, int32_t type, int32_t size, void* buf #define TSDB_PORT_HTTP 11 #define TSDB_PORT_ARBITRATOR 12 -#define TSDB_MAX_WAL_SIZE (1024*1024) +#define TSDB_MAX_WAL_SIZE (1024*1024*2) typedef enum { TAOS_QTYPE_RPC = 0, From 67a8a7bf5670bb5cb7f58ca9835a8026037c1286 Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Wed, 30 Dec 2020 10:15:05 +0800 Subject: [PATCH 17/29] TD-2429 --- src/dnode/src/dnodeVMgmt.c | 2 +- src/inc/taoserror.h | 4 +++- src/inc/taosmsg.h | 5 +++-- src/mnode/src/mnodeVgroup.c | 3 ++- src/vnode/inc/vnodeInt.h | 4 +++- src/vnode/src/vnodeCfg.c | 29 ++++++++++++++++++++--------- src/vnode/src/vnodeWrite.c | 9 ++++++++- 7 files changed, 40 insertions(+), 16 deletions(-) diff --git a/src/dnode/src/dnodeVMgmt.c b/src/dnode/src/dnodeVMgmt.c index 7e3807d983..bc24d1bf62 100644 --- a/src/dnode/src/dnodeVMgmt.c +++ b/src/dnode/src/dnodeVMgmt.c @@ -143,7 +143,7 @@ static SCreateVnodeMsg* dnodeParseVnodeMsg(SRpcMsg *rpcMsg) { pCreate->cfg.fsyncPeriod = htonl(pCreate->cfg.fsyncPeriod); pCreate->cfg.commitTime = htonl(pCreate->cfg.commitTime); - for (int32_t j = 0; j < pCreate->cfg.replications; ++j) { + for (int32_t j = 0; j < pCreate->cfg.vgReplica; ++j) { pCreate->nodes[j].nodeId = htonl(pCreate->nodes[j].nodeId); } diff --git a/src/inc/taoserror.h b/src/inc/taoserror.h index 69c01e6763..12cff90be2 100644 --- a/src/inc/taoserror.h +++ b/src/inc/taoserror.h @@ -209,9 +209,11 @@ TAOS_DEFINE_ERROR(TSDB_CODE_VND_APP_ERROR, 0, 0x0509, "Unexpected TAOS_DEFINE_ERROR(TSDB_CODE_VND_INVALID_VRESION_FILE, 0, 0x050A, "Invalid version file") TAOS_DEFINE_ERROR(TSDB_CODE_VND_IS_FULL, 0, 0x050B, "Database memory is full for commit failed") TAOS_DEFINE_ERROR(TSDB_CODE_VND_IS_FLOWCTRL, 0, 0x050C, "Database memory is full for waiting commit") +TAOS_DEFINE_ERROR(TSDB_CODE_VND_IS_DROPPING, 0, 0x050D, "Database is dropping") +TAOS_DEFINE_ERROR(TSDB_CODE_VND_IS_BALANCING, 0, 0x050E, "Database is balancing") TAOS_DEFINE_ERROR(TSDB_CODE_VND_NOT_SYNCED, 0, 0x0511, "Database suspended") TAOS_DEFINE_ERROR(TSDB_CODE_VND_NO_WRITE_AUTH, 0, 0x0512, "Database write operation denied") -TAOS_DEFINE_ERROR(TSDB_CODE_VND_SYNCING, 0, 0x0513, "Database is syncing") +TAOS_DEFINE_ERROR(TSDB_CODE_VND_IS_SYNCING, 0, 0x0513, "Database is syncing") // tsdb TAOS_DEFINE_ERROR(TSDB_CODE_TDB_INVALID_TABLE_ID, 0, 0x0600, "Invalid table ID") diff --git a/src/inc/taosmsg.h b/src/inc/taosmsg.h index b4480951c9..62c06122b6 100644 --- a/src/inc/taosmsg.h +++ b/src/inc/taosmsg.h @@ -664,13 +664,14 @@ typedef struct { int8_t precision; int8_t compression; int8_t walLevel; - int8_t replications; + int8_t vgReplica; int8_t wals; int8_t quorum; int8_t update; int8_t cacheLastRow; int32_t vgCfgVersion; - int8_t reserved[10]; + int8_t dbReplica; + int8_t reserved[9]; } SVnodeCfg; typedef struct { diff --git a/src/mnode/src/mnodeVgroup.c b/src/mnode/src/mnodeVgroup.c index b79425afbb..5b2e89ce16 100644 --- a/src/mnode/src/mnodeVgroup.c +++ b/src/mnode/src/mnodeVgroup.c @@ -861,11 +861,12 @@ static SCreateVnodeMsg *mnodeBuildVnodeMsg(SVgObj *pVgroup) { pCfg->precision = pDb->cfg.precision; pCfg->compression = pDb->cfg.compression; pCfg->walLevel = pDb->cfg.walLevel; - pCfg->replications = (int8_t) pVgroup->numOfVnodes; + pCfg->vgReplica = (int8_t) pVgroup->numOfVnodes; pCfg->wals = 3; pCfg->quorum = pDb->cfg.quorum; pCfg->update = pDb->cfg.update; pCfg->cacheLastRow = pDb->cfg.cacheLastRow; + pCfg->dbReplica = pDb->cfg.replications; SVnodeDesc *pNodes = pVnode->nodes; for (int32_t j = 0; j < pVgroup->numOfVnodes; ++j) { diff --git a/src/vnode/inc/vnodeInt.h b/src/vnode/inc/vnodeInt.h index fb1868ab13..7adeda590a 100644 --- a/src/vnode/inc/vnodeInt.h +++ b/src/vnode/inc/vnodeInt.h @@ -45,6 +45,9 @@ typedef struct { int8_t accessState; int8_t isFull; int8_t isCommiting; + int8_t dbReplica; + int8_t dropped; + int8_t reserved; uint64_t version; // current version uint64_t cversion; // version while commit start uint64_t fversion; // version on saved data file @@ -64,7 +67,6 @@ typedef struct { void * qMgmt; char * rootDir; tsem_t sem; - int8_t dropped; char db[TSDB_ACCT_LEN + TSDB_DB_NAME_LEN]; pthread_mutex_t statusMutex; } SVnodeObj; diff --git a/src/vnode/src/vnodeCfg.c b/src/vnode/src/vnodeCfg.c index b47fedd46e..0b32f97939 100644 --- a/src/vnode/src/vnodeCfg.c +++ b/src/vnode/src/vnodeCfg.c @@ -38,8 +38,9 @@ static void vnodeLoadCfg(SVnodeObj *pVnode, SCreateVnodeMsg* vnodeMsg) { pVnode->walCfg.walLevel = vnodeMsg->cfg.walLevel; pVnode->walCfg.fsyncPeriod = vnodeMsg->cfg.fsyncPeriod; pVnode->walCfg.keep = TAOS_WAL_NOT_KEEP; - pVnode->syncCfg.replica = vnodeMsg->cfg.replications; + pVnode->syncCfg.replica = vnodeMsg->cfg.vgReplica; pVnode->syncCfg.quorum = vnodeMsg->cfg.quorum; + pVnode->dbReplica = vnodeMsg->cfg.dbReplica; for (int i = 0; i < pVnode->syncCfg.replica; ++i) { SVnodeDesc *node = &vnodeMsg->nodes[i]; @@ -203,12 +204,21 @@ int32_t vnodeReadCfg(SVnodeObj *pVnode) { } vnodeMsg.cfg.wals = (int8_t)wals->valueint; - cJSON *replica = cJSON_GetObjectItem(root, "replica"); - if (!replica || replica->type != cJSON_Number) { + cJSON *vgReplica = cJSON_GetObjectItem(root, "replica"); + if (!vgReplica || vgReplica->type != cJSON_Number) { vError("vgId:%d, failed to read %s, replica not found", pVnode->vgId, file); goto PARSE_VCFG_ERROR; } - vnodeMsg.cfg.replications = (int8_t)replica->valueint; + vnodeMsg.cfg.vgReplica = (int8_t)vgReplica->valueint; + + cJSON *dbReplica = cJSON_GetObjectItem(root, "dbReplica"); + if (!dbReplica || dbReplica->type != cJSON_Number) { + vError("vgId:%d, failed to read %s, dbReplica not found", pVnode->vgId, file); + vnodeMsg.cfg.dbReplica = vnodeMsg.cfg.vgReplica; + vnodeMsg.cfg.vgCfgVersion = 0; + } else { + vnodeMsg.cfg.dbReplica = (int8_t)dbReplica->valueint; + } cJSON *quorum = cJSON_GetObjectItem(root, "quorum"); if (!quorum || quorum->type != cJSON_Number) { @@ -220,8 +230,8 @@ int32_t vnodeReadCfg(SVnodeObj *pVnode) { cJSON *cacheLastRow = cJSON_GetObjectItem(root, "cacheLastRow"); if (!cacheLastRow || cacheLastRow->type != cJSON_Number) { vError("vgId: %d, failed to read %s, cacheLastRow not found", pVnode->vgId, file); - //goto PARSE_VCFG_ERROR; vnodeMsg.cfg.cacheLastRow = 0; + vnodeMsg.cfg.vgCfgVersion = 0; } else { vnodeMsg.cfg.cacheLastRow = (int8_t)cacheLastRow->valueint; } @@ -233,7 +243,7 @@ int32_t vnodeReadCfg(SVnodeObj *pVnode) { } int size = cJSON_GetArraySize(nodeInfos); - if (size != vnodeMsg.cfg.replications) { + if (size != vnodeMsg.cfg.vgReplica) { vError("vgId:%d, failed to read %s, nodeInfos size not matched", pVnode->vgId, file); goto PARSE_VCFG_ERROR; } @@ -311,17 +321,18 @@ int32_t vnodeWriteCfg(SCreateVnodeMsg *pMsg) { len += snprintf(content + len, maxLen - len, " \"compression\": %d,\n", pMsg->cfg.compression); len += snprintf(content + len, maxLen - len, " \"walLevel\": %d,\n", pMsg->cfg.walLevel); len += snprintf(content + len, maxLen - len, " \"fsync\": %d,\n", pMsg->cfg.fsyncPeriod); - len += snprintf(content + len, maxLen - len, " \"replica\": %d,\n", pMsg->cfg.replications); + len += snprintf(content + len, maxLen - len, " \"replica\": %d,\n", pMsg->cfg.vgReplica); + len += snprintf(content + len, maxLen - len, " \"dbReplica\": %d,\n", pMsg->cfg.dbReplica); len += snprintf(content + len, maxLen - len, " \"wals\": %d,\n", pMsg->cfg.wals); len += snprintf(content + len, maxLen - len, " \"quorum\": %d,\n", pMsg->cfg.quorum); len += snprintf(content + len, maxLen - len, " \"cacheLastRow\": %d,\n", pMsg->cfg.cacheLastRow); len += snprintf(content + len, maxLen - len, " \"nodeInfos\": [{\n"); - for (int32_t i = 0; i < pMsg->cfg.replications; i++) { + for (int32_t i = 0; i < pMsg->cfg.vgReplica; i++) { SVnodeDesc *node = &pMsg->nodes[i]; dnodeUpdateEp(node->nodeId, node->nodeEp, NULL, NULL); len += snprintf(content + len, maxLen - len, " \"nodeId\": %d,\n", node->nodeId); len += snprintf(content + len, maxLen - len, " \"nodeEp\": \"%s\"\n", node->nodeEp); - if (i < pMsg->cfg.replications - 1) { + if (i < pMsg->cfg.vgReplica - 1) { len += snprintf(content + len, maxLen - len, " },{\n"); } else { len += snprintf(content + len, maxLen - len, " }]\n"); diff --git a/src/vnode/src/vnodeWrite.c b/src/vnode/src/vnodeWrite.c index 7cbe73fd45..a3a88e8b7b 100644 --- a/src/vnode/src/vnodeWrite.c +++ b/src/vnode/src/vnodeWrite.c @@ -108,6 +108,13 @@ static int32_t vnodeCheckWrite(void *vparam) { return TSDB_CODE_VND_NO_WRITE_AUTH; } + if (pVnode->dbReplica != pVnode->syncCfg.replica && + pVnode->syncCfg.nodeInfo[pVnode->syncCfg.replica - 1].nodeId == dnodeGetDnodeId()) { + vDebug("vgId:%d, vnode is balancing and will be dropped, dbReplica:%d vgReplica:%d, refCount:%d pVnode:%p", + pVnode->vgId, pVnode->dbReplica, pVnode->syncCfg.replica, pVnode->refCount, pVnode); + return TSDB_CODE_VND_IS_BALANCING; + } + // tsdb may be in reset state if (pVnode->tsdb == NULL) { vDebug("vgId:%d, tsdb is null, refCount:%d pVnode:%p", pVnode->vgId, pVnode->refCount, pVnode); @@ -271,7 +278,7 @@ void vnodeFreeFromWQueue(void *vparam, SVWriteMsg *pWrite) { static void vnodeFlowCtrlMsgToWQueue(void *param, void *tmrId) { SVWriteMsg *pWrite = param; SVnodeObj * pVnode = pWrite->pVnode; - int32_t code = TSDB_CODE_VND_SYNCING; + int32_t code = TSDB_CODE_VND_IS_SYNCING; if (pVnode->flowctrlLevel <= 0) code = TSDB_CODE_VND_IS_FLOWCTRL; From e7d5499372ce9ab14e5575e5c07e548a4ce910f5 Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Wed, 30 Dec 2020 10:49:12 +0800 Subject: [PATCH 18/29] scripts --- tests/script/jenkins/basic.txt | 1 + tests/script/unique/dnode/lossdata.sim | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/script/jenkins/basic.txt b/tests/script/jenkins/basic.txt index e3555e700a..ccfed3da8d 100644 --- a/tests/script/jenkins/basic.txt +++ b/tests/script/jenkins/basic.txt @@ -288,6 +288,7 @@ cd ../../../debug; make ./test.sh -f unique/dnode/data1.sim ./test.sh -f unique/dnode/m2.sim ./test.sh -f unique/dnode/m3.sim +./test.sh -f unique/dnode/lossdata.sim ./test.sh -f unique/dnode/offline1.sim ./test.sh -f unique/dnode/offline2.sim ./test.sh -f unique/dnode/offline3.sim diff --git a/tests/script/unique/dnode/lossdata.sim b/tests/script/unique/dnode/lossdata.sim index d4da2914c1..89ba716970 100644 --- a/tests/script/unique/dnode/lossdata.sim +++ b/tests/script/unique/dnode/lossdata.sim @@ -158,8 +158,8 @@ if $data00 != $rowNum then return -1 endi -#system sh/exec.sh -n dnode1 -s stop -x SIGINT -#system sh/exec.sh -n dnode2 -s stop -x SIGINT -#system sh/exec.sh -n dnode3 -s stop -x SIGINT -#system sh/exec.sh -n dnode4 -s stop -x SIGINT -#system sh/exec.sh -n dnode5 -s stop -x SIGINT \ No newline at end of file +system sh/exec.sh -n dnode1 -s stop -x SIGINT +system sh/exec.sh -n dnode2 -s stop -x SIGINT +system sh/exec.sh -n dnode3 -s stop -x SIGINT +system sh/exec.sh -n dnode4 -s stop -x SIGINT +system sh/exec.sh -n dnode5 -s stop -x SIGINT \ No newline at end of file From 856ada1b410258dc289560e49620659976ae4162 Mon Sep 17 00:00:00 2001 From: liuyq-617 Date: Wed, 30 Dec 2020 13:18:38 +0800 Subject: [PATCH 19/29] [TD-2457]bottom+interval+order by --- tests/pytest/functions/function_bottom.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/pytest/functions/function_bottom.py b/tests/pytest/functions/function_bottom.py index 4074166f92..5e570dc8e0 100644 --- a/tests/pytest/functions/function_bottom.py +++ b/tests/pytest/functions/function_bottom.py @@ -85,6 +85,9 @@ class TDTestCase: tdSql.checkData(0, 1, 0.1) tdSql.checkData(1, 1, 1.1) + #TD-2457 bottom + interval + order by + tdSql.error('select top(col2,1) from test interval(1y) order by col2;') + def stop(self): tdSql.close() tdLog.success("%s successfully executed" % __file__) From f175b1cd08172934decd7665a389253c38cc8509 Mon Sep 17 00:00:00 2001 From: Ping Xiao Date: Wed, 30 Dec 2020 13:52:49 +0800 Subject: [PATCH 20/29] [TD-2560] add test case for show tables --- tests/pytest/table/create.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/pytest/table/create.py b/tests/pytest/table/create.py index 8fedd4e920..a0991d674a 100644 --- a/tests/pytest/table/create.py +++ b/tests/pytest/table/create.py @@ -39,6 +39,23 @@ class TDTestCase: except Exception as e: tdLog.exit(e) + # case for defect: https://jira.taosdata.com:18080/browse/TD-2560 + tdSql.execute("create table db.tb02 using st tags(2)") + tdSql.execute("create table db.tb03 using st tags(3)") + tdSql.execute("create table db.tb04 using st tags(4)") + + tdSql.query("show tables like 'tb%' ") + tdSql.checkRows(4) + + tdSql.query("show tables like 'tb0%' ") + tdSql.checkRows(3) + + tdSql.execute("create table db.st0 (ts timestamp, i int) tags(j int)") + tdSql.execute("create table db.st1 (ts timestamp, i int, c2 int) tags(j int, loc nchar(20))") + + tdSql.query("show stables like 'st%' ") + tdSql.checkRows(3) + def stop(self): tdSql.close() tdLog.success("%s successfully executed" % __file__) From 305d3c10c5dced347cfbbca86515365d405c2920 Mon Sep 17 00:00:00 2001 From: liuyq-617 Date: Wed, 30 Dec 2020 14:05:59 +0800 Subject: [PATCH 21/29] [TD-2563]bottom/top+interval --- tests/pytest/functions/function_bottom.py | 13 +++++++++++++ tests/pytest/functions/function_top.py | 14 ++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/tests/pytest/functions/function_bottom.py b/tests/pytest/functions/function_bottom.py index 5e570dc8e0..3cc3892218 100644 --- a/tests/pytest/functions/function_bottom.py +++ b/tests/pytest/functions/function_bottom.py @@ -88,6 +88,19 @@ class TDTestCase: #TD-2457 bottom + interval + order by tdSql.error('select top(col2,1) from test interval(1y) order by col2;') + #TD-2563 top + super_table + interval + tdSql.execute("create table meters(ts timestamp, c int) tags (d int)") + tdSql.execute("create table t1 using meters tags (1)") + sql = 'insert into t1 values ' + for i in range(20000): + sql = sql + '(%d, %d)' % (self.ts + i , i % 47) + if i % 2000 == 0: + tdSql.execute(sql) + sql = 'insert into t1 values ' + tdSql.execute(sql) + tdSql.query('select bottom(c,1) from meters interval(10a)') + tdSql.checkData(0,1,0) + def stop(self): tdSql.close() tdLog.success("%s successfully executed" % __file__) diff --git a/tests/pytest/functions/function_top.py b/tests/pytest/functions/function_top.py index e24ff1cc53..a98f31eea0 100644 --- a/tests/pytest/functions/function_top.py +++ b/tests/pytest/functions/function_top.py @@ -89,6 +89,20 @@ class TDTestCase: tdSql.checkRows(2) tdSql.checkData(0, 1, 8.1) tdSql.checkData(1, 1, 9.1) + + #TD-2563 top + super_table + interval + tdSql.execute("create table meters(ts timestamp, c int) tags (d int)") + tdSql.execute("create table t1 using meters tags (1)") + sql = 'insert into t1 values ' + for i in range(20000): + sql = sql + '(%d, %d)' % (self.ts + i , i % 47) + if i % 2000 == 0: + tdSql.execute(sql) + sql = 'insert into t1 values ' + tdSql.execute(sql) + tdSql.query('select top(c,1) from meters interval(10a)') + tdSql.checkData(0,1,9) + def stop(self): tdSql.close() From 44b170427d5705915bb95cb83e171a22724cbb1d Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Wed, 30 Dec 2020 14:43:50 +0800 Subject: [PATCH 22/29] TD-2616 --- src/client/src/tscUtil.c | 2 +- src/os/inc/osSemphone.h | 11 +++++---- src/os/src/detail/osSemphone.c | 3 ++- src/os/src/windows/wSemphone.c | 8 ++++--- src/query/src/qExecutor.c | 4 ++-- src/rpc/src/rpcCache.c | 4 ++-- src/rpc/src/rpcMain.c | 4 ++-- src/sync/src/syncMain.c | 36 +++++++++++++--------------- src/sync/src/syncRestore.c | 11 +++++++-- src/sync/src/syncRetrieve.c | 15 +++++++++--- src/util/src/tlog.c | 4 ++-- src/util/src/tnote.c | 2 +- src/util/src/tref.c | 4 ++-- src/util/src/ttimer.c | 8 +++---- tests/script/unique/mnode/mgmt20.sim | 18 ++++++++++++++ 15 files changed, 84 insertions(+), 50 deletions(-) diff --git a/src/client/src/tscUtil.c b/src/client/src/tscUtil.c index 172887c110..52e26fe95a 100644 --- a/src/client/src/tscUtil.c +++ b/src/client/src/tscUtil.c @@ -2503,7 +2503,7 @@ bool tscSetSqlOwner(SSqlObj* pSql) { SSqlRes* pRes = &pSql->res; // set the sql object owner - uint64_t threadId = taosGetPthreadId(); + uint64_t threadId = taosGetSelfPthreadId(); if (atomic_val_compare_exchange_64(&pSql->owner, 0, threadId) != 0) { pRes->code = TSDB_CODE_QRY_IN_EXEC; return false; diff --git a/src/os/inc/osSemphone.h b/src/os/inc/osSemphone.h index a71e74e97f..74e1bd4878 100644 --- a/src/os/inc/osSemphone.h +++ b/src/os/inc/osSemphone.h @@ -29,12 +29,13 @@ extern "C" { #endif // TAOS_OS_FUNC_SEMPHONE_PTHREAD -bool taosCheckPthreadValid(pthread_t thread); -int64_t taosGetPthreadId(); -void taosResetPthread(pthread_t *thread); -bool taosComparePthread(pthread_t first, pthread_t second); +bool taosCheckPthreadValid(pthread_t thread); +int64_t taosGetSelfPthreadId(); +int64_t taosGetPthreadId(pthread_t thread); +void taosResetPthread(pthread_t* thread); +bool taosComparePthread(pthread_t first, pthread_t second); int32_t taosGetPId(); -int32_t taosGetCurrentAPPName(char *name, int32_t* len); +int32_t taosGetCurrentAPPName(char* name, int32_t* len); #ifdef __cplusplus } diff --git a/src/os/src/detail/osSemphone.c b/src/os/src/detail/osSemphone.c index 9eb8c18a40..d379e56ed8 100644 --- a/src/os/src/detail/osSemphone.c +++ b/src/os/src/detail/osSemphone.c @@ -31,7 +31,8 @@ int tsem_wait(tsem_t* sem) { #ifndef TAOS_OS_FUNC_SEMPHONE_PTHREAD bool taosCheckPthreadValid(pthread_t thread) { return thread != 0; } -int64_t taosGetPthreadId() { return (int64_t)pthread_self(); } +int64_t taosGetSelfPthreadId() { return (int64_t)pthread_self(); } +int64_t taosGetPthreadId(pthread_t thread) { return (int64_t)thread; } void taosResetPthread(pthread_t *thread) { *thread = 0; } bool taosComparePthread(pthread_t first, pthread_t second) { return first == second; } int32_t taosGetPId() { return getpid(); } diff --git a/src/os/src/windows/wSemphone.c b/src/os/src/windows/wSemphone.c index 1f723540f6..0bc760b35e 100644 --- a/src/os/src/windows/wSemphone.c +++ b/src/os/src/windows/wSemphone.c @@ -25,14 +25,16 @@ bool taosCheckPthreadValid(pthread_t thread) { return thread.p != NULL; } void taosResetPthread(pthread_t *thread) { thread->p = 0; } -int64_t taosGetPthreadId() { +int64_t taosGetPthreadId(pthread_t thread) { #ifdef PTW32_VERSION - return pthread_getw32threadid_np(pthread_self()); + return pthread_getw32threadid_np(thread); #else - return (int64_t)pthread_self(); + return (int64_t)thread; #endif } +int64_t taosGetSelfPthreadId() { return taosGetPthreadId(pthread_self()); } + bool taosComparePthread(pthread_t first, pthread_t second) { return first.p == second.p; } diff --git a/src/query/src/qExecutor.c b/src/query/src/qExecutor.c index 7fb366160c..d9630edb9e 100644 --- a/src/query/src/qExecutor.c +++ b/src/query/src/qExecutor.c @@ -7250,7 +7250,7 @@ static bool doBuildResCheck(SQInfo* pQInfo) { // clear qhandle owner, it must be in the secure area. other thread may run ahead before current, after it is // put into task to be executed. - assert(pQInfo->owner == taosGetPthreadId()); + assert(pQInfo->owner == taosGetSelfPthreadId()); pQInfo->owner = 0; pthread_mutex_unlock(&pQInfo->lock); @@ -7263,7 +7263,7 @@ static bool doBuildResCheck(SQInfo* pQInfo) { bool qTableQuery(qinfo_t qinfo) { SQInfo *pQInfo = (SQInfo *)qinfo; assert(pQInfo && pQInfo->signature == pQInfo); - int64_t threadId = taosGetPthreadId(); + int64_t threadId = taosGetSelfPthreadId(); int64_t curOwner = 0; if ((curOwner = atomic_val_compare_exchange_64(&pQInfo->owner, 0, threadId)) != 0) { diff --git a/src/rpc/src/rpcCache.c b/src/rpc/src/rpcCache.c index 09d8f3bff1..60a12c26b7 100644 --- a/src/rpc/src/rpcCache.c +++ b/src/rpc/src/rpcCache.c @@ -272,7 +272,7 @@ static int rpcHashConn(void *handle, char *fqdn, uint16_t port, int8_t connType) } static void rpcLockCache(int64_t *lockedBy) { - int64_t tid = taosGetPthreadId(); + int64_t tid = taosGetSelfPthreadId(); int i = 0; while (atomic_val_compare_exchange_64(lockedBy, 0, tid) != 0) { if (++i % 100 == 0) { @@ -282,7 +282,7 @@ static void rpcLockCache(int64_t *lockedBy) { } static void rpcUnlockCache(int64_t *lockedBy) { - int64_t tid = taosGetPthreadId(); + int64_t tid = taosGetSelfPthreadId(); if (atomic_val_compare_exchange_64(lockedBy, tid, 0) != tid) { assert(false); } diff --git a/src/rpc/src/rpcMain.c b/src/rpc/src/rpcMain.c index ec1ee75dbb..13d6ed8ed5 100644 --- a/src/rpc/src/rpcMain.c +++ b/src/rpc/src/rpcMain.c @@ -1604,7 +1604,7 @@ static int rpcCheckAuthentication(SRpcConn *pConn, char *msg, int msgLen) { } static void rpcLockConn(SRpcConn *pConn) { - int64_t tid = taosGetPthreadId(); + int64_t tid = taosGetSelfPthreadId(); int i = 0; while (atomic_val_compare_exchange_64(&(pConn->lockedBy), 0, tid) != 0) { if (++i % 1000 == 0) { @@ -1614,7 +1614,7 @@ static void rpcLockConn(SRpcConn *pConn) { } static void rpcUnlockConn(SRpcConn *pConn) { - int64_t tid = taosGetPthreadId(); + int64_t tid = taosGetSelfPthreadId(); if (atomic_val_compare_exchange_64(&(pConn->lockedBy), tid, 0) != tid) { assert(false); } diff --git a/src/sync/src/syncMain.c b/src/sync/src/syncMain.c index 380e44780f..436f4de098 100644 --- a/src/sync/src/syncMain.c +++ b/src/sync/src/syncMain.c @@ -478,9 +478,7 @@ static void syncAddArbitrator(SSyncNode *pNode) { static void syncFreeNode(void *param) { SSyncNode *pNode = param; - - int32_t refCount = atomic_sub_fetch_32(&pNode->refCount, 1); - sDebug("vgId:%d, syncnode is freed, refCount:%d", pNode->vgId, refCount); + sDebug("vgId:%d, node is freed, refCount:%d", pNode->vgId, pNode->refCount); pthread_mutex_destroy(&pNode->mutex); tfree(pNode->pRecv); @@ -491,10 +489,10 @@ static void syncFreeNode(void *param) { SSyncNode *syncAcquireNode(int64_t rid) { SSyncNode *pNode = taosAcquireRef(tsNodeRefId, rid); if (pNode == NULL) { - sDebug("failed to acquire syncnode from refId:%" PRId64, rid); + sDebug("failed to acquire node from refId:%" PRId64, rid); } else { int32_t refCount = atomic_add_fetch_32(&pNode->refCount, 1); - sTrace("vgId:%d, acquire syncnode refId:%" PRId64 ", refCount:%d", pNode->vgId, rid, refCount); + sTrace("vgId:%d, acquire node refId:%" PRId64 ", refCount:%d", pNode->vgId, rid, refCount); } return pNode; @@ -502,16 +500,14 @@ SSyncNode *syncAcquireNode(int64_t rid) { void syncReleaseNode(SSyncNode *pNode) { int32_t refCount = atomic_sub_fetch_32(&pNode->refCount, 1); - sTrace("vgId:%d, dec syncnode refId:%" PRId64 " refCount:%d", pNode->vgId, pNode->rid, refCount); + sTrace("vgId:%d, release node refId:%" PRId64 ", refCount:%d", pNode->vgId, pNode->rid, refCount); taosReleaseRef(tsNodeRefId, pNode->rid); } static void syncFreePeer(void *param) { SSyncPeer *pPeer = param; - - int32_t refCount = atomic_sub_fetch_32(&pPeer->refCount, 1); - sDebug("%s, peer is freed, refCount:%d", pPeer->id, refCount); + sDebug("%s, peer is freed, refCount:%d", pPeer->id, pPeer->refCount); syncReleaseNode(pPeer->pSyncNode); tfree(pPeer); @@ -531,7 +527,7 @@ SSyncPeer *syncAcquirePeer(int64_t rid) { void syncReleasePeer(SSyncPeer *pPeer) { int32_t refCount = atomic_sub_fetch_32(&pPeer->refCount, 1); - sTrace("%s, dec peer refId:%" PRId64 ", refCount:%d", pPeer->id, pPeer->rid, refCount); + sTrace("%s, release peer refId:%" PRId64 ", refCount:%d", pPeer->id, pPeer->rid, refCount); taosReleaseRef(tsPeerRefId, pPeer->rid); } @@ -879,14 +875,14 @@ static void syncProcessSyncRequest(char *msg, SSyncPeer *pPeer) { int32_t ret = pthread_create(&thread, &thattr, syncRetrieveData, (void *)pPeer->rid); pthread_attr_destroy(&thattr); - if (ret != 0) { - sError("%s, failed to create sync thread since %s", pPeer->id, strerror(errno)); + if (ret < 0) { + sError("%s, failed to create sync retrieve thread since %s", pPeer->id, strerror(errno)); + syncReleasePeer(pPeer); } else { pPeer->sstatus = TAOS_SYNC_STATUS_START; - sDebug("%s, thread is created to retrieve data, set sstatus:%s", pPeer->id, syncStatus[pPeer->sstatus]); + sDebug("%s, sync retrieve thread:0x%08" PRIx64 " create successfully, rid:%" PRId64 ", set sstatus:%s", pPeer->id, + taosGetPthreadId(thread), pPeer->rid, syncStatus[pPeer->sstatus]); } - - syncReleasePeer(pPeer); } static void syncNotStarted(void *param, void *tmrId) { @@ -1154,19 +1150,19 @@ static void syncCreateRestoreDataThread(SSyncPeer *pPeer) { (void)syncAcquirePeer(pPeer->rid); - int32_t ret = pthread_create(&(thread), &thattr, (void *)syncRestoreData, (void *)pPeer->rid); + int32_t ret = pthread_create(&thread, &thattr, (void *)syncRestoreData, (void *)pPeer->rid); pthread_attr_destroy(&thattr); if (ret < 0) { SSyncNode *pNode = pPeer->pSyncNode; nodeSStatus = TAOS_SYNC_STATUS_INIT; - sError("%s, failed to create sync thread, set sstatus:%s", pPeer->id, syncStatus[nodeSStatus]); + sError("%s, failed to create sync restore thread, set sstatus:%s", pPeer->id, syncStatus[nodeSStatus]); taosClose(pPeer->syncFd); + syncReleasePeer(pPeer); } else { - sInfo("%s, sync connection is up", pPeer->id); + sInfo("%s, sync restore thread:0x%08" PRIx64 " create successfully, rid:%" PRId64, pPeer->id, + taosGetPthreadId(thread), pPeer->rid); } - - syncReleasePeer(pPeer); } static void syncProcessIncommingConnection(int32_t connFd, uint32_t sourceIp) { diff --git a/src/sync/src/syncRestore.c b/src/sync/src/syncRestore.c index e815594883..a5e268cdd2 100644 --- a/src/sync/src/syncRestore.c +++ b/src/sync/src/syncRestore.c @@ -353,12 +353,16 @@ static int32_t syncRestoreDataStepByStep(SSyncPeer *pPeer) { void *syncRestoreData(void *param) { int64_t rid = (int64_t)param; SSyncPeer *pPeer = syncAcquirePeer(rid); - if (pPeer == NULL) return NULL; + if (pPeer == NULL) { + sError("failed to restore data, invalid peer rid:%" PRId64, rid); + return NULL; + } SSyncNode *pNode = pPeer->pSyncNode; taosBlockSIGPIPE(); __sync_fetch_and_add(&tsSyncNum, 1); + sInfo("%s, start to restore data, sstatus:%s", pPeer->id, syncStatus[nodeSStatus]); (*pNode->notifyRole)(pNode->vgId, TAOS_SYNC_ROLE_SYNCING); @@ -380,11 +384,14 @@ void *syncRestoreData(void *param) { (*pNode->notifyRole)(pNode->vgId, nodeRole); nodeSStatus = TAOS_SYNC_STATUS_INIT; - sInfo("%s, sync over, set sstatus:%s", pPeer->id, syncStatus[nodeSStatus]); + sInfo("%s, restore data over, set sstatus:%s", pPeer->id, syncStatus[nodeSStatus]); taosClose(pPeer->syncFd); syncCloseRecvBuffer(pNode); __sync_fetch_and_sub(&tsSyncNum, 1); + + // The ref is obtained in both the create thread and the current thread, so it is released twice + syncReleasePeer(pPeer); syncReleasePeer(pPeer); return NULL; diff --git a/src/sync/src/syncRetrieve.c b/src/sync/src/syncRetrieve.c index f3e0a6d353..b3be1ace39 100644 --- a/src/sync/src/syncRetrieve.c +++ b/src/sync/src/syncRetrieve.c @@ -194,7 +194,7 @@ static int32_t syncReadOneWalRecord(int32_t sfd, SWalHead *pHead) { } if (ret == 0) { - sTrace("sfd:%d, read to the end of file, ret:%d", sfd, ret); + sDebug("sfd:%d, read to the end of file, ret:%d", sfd, ret); return 0; } @@ -253,7 +253,7 @@ static int32_t syncRetrieveLastWal(SSyncPeer *pPeer, char *name, uint64_t fversi break; } - sTrace("%s, last wal is forwarded, hver:%" PRIu64, pPeer->id, pHead->version); + sDebug("%s, last wal is forwarded, hver:%" PRIu64, pPeer->id, pHead->version); int32_t wsize = code; int32_t ret = taosWriteMsg(pPeer->syncFd, pHead, wsize); @@ -466,10 +466,15 @@ static int32_t syncRetrieveDataStepByStep(SSyncPeer *pPeer) { void *syncRetrieveData(void *param) { int64_t rid = (int64_t)param; SSyncPeer *pPeer = syncAcquirePeer(rid); - if (pPeer == NULL) return NULL; + if (pPeer == NULL) { + sError("failed to retrieve data, invalid peer rid:%" PRId64, rid); + return NULL; + } SSyncNode *pNode = pPeer->pSyncNode; + taosBlockSIGPIPE(); + sInfo("%s, start to retrieve data, sstatus:%s", pPeer->id, syncStatus[pPeer->sstatus]); if (pNode->notifyFlowCtrl) (*pNode->notifyFlowCtrl)(pNode->vgId, pPeer->numOfRetrieves); @@ -496,7 +501,11 @@ void *syncRetrieveData(void *param) { pPeer->fileChanged = 0; taosClose(pPeer->syncFd); + + // The ref is obtained in both the create thread and the current thread, so it is released twice + syncReleasePeer(pPeer); syncReleasePeer(pPeer); + sInfo("%s, sync retrieve data over, sstatus:%s", pPeer->id, syncStatus[pPeer->sstatus]); return NULL; } diff --git a/src/util/src/tlog.c b/src/util/src/tlog.c index fa6a9db8ec..e0fe51e22a 100644 --- a/src/util/src/tlog.c +++ b/src/util/src/tlog.c @@ -364,7 +364,7 @@ void taosPrintLog(const char *flags, int32_t dflag, const char *format, ...) { ptm = localtime_r(&curTime, &Tm); len = sprintf(buffer, "%02d/%02d %02d:%02d:%02d.%06d 0x%08" PRIx64 " ", ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, - ptm->tm_min, ptm->tm_sec, (int32_t)timeSecs.tv_usec, taosGetPthreadId()); + ptm->tm_min, ptm->tm_sec, (int32_t)timeSecs.tv_usec, taosGetSelfPthreadId()); len += sprintf(buffer + len, "%s", flags); va_start(argpointer, format); @@ -450,7 +450,7 @@ void taosPrintLongString(const char *flags, int32_t dflag, const char *format, . ptm = localtime_r(&curTime, &Tm); len = sprintf(buffer, "%02d/%02d %02d:%02d:%02d.%06d 0x%08" PRIx64 " ", ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, - ptm->tm_min, ptm->tm_sec, (int32_t)timeSecs.tv_usec, taosGetPthreadId()); + ptm->tm_min, ptm->tm_sec, (int32_t)timeSecs.tv_usec, taosGetSelfPthreadId()); len += sprintf(buffer + len, "%s", flags); va_start(argpointer, format); diff --git a/src/util/src/tnote.c b/src/util/src/tnote.c index f2db0b3316..56f2322a7b 100644 --- a/src/util/src/tnote.c +++ b/src/util/src/tnote.c @@ -249,7 +249,7 @@ void taosNotePrint(SNoteObj *pNote, const char *const format, ...) { curTime = timeSecs.tv_sec; ptm = localtime_r(&curTime, &Tm); len = sprintf(buffer, "%02d/%02d %02d:%02d:%02d.%06d 0x%08" PRIx64 " ", ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, - ptm->tm_min, ptm->tm_sec, (int32_t)timeSecs.tv_usec, taosGetPthreadId()); + ptm->tm_min, ptm->tm_sec, (int32_t)timeSecs.tv_usec, taosGetSelfPthreadId()); va_start(argpointer, format); len += vsnprintf(buffer + len, MAX_NOTE_LINE_SIZE - len, format, argpointer); va_end(argpointer); diff --git a/src/util/src/tref.c b/src/util/src/tref.c index 1f83abcb84..3ef45e9b19 100644 --- a/src/util/src/tref.c +++ b/src/util/src/tref.c @@ -447,7 +447,7 @@ static int taosDecRefCount(int rsetId, int64_t rid, int remove) { } static void taosLockList(int64_t *lockedBy) { - int64_t tid = taosGetPthreadId(); + int64_t tid = taosGetSelfPthreadId(); int i = 0; while (atomic_val_compare_exchange_64(lockedBy, 0, tid) != 0) { if (++i % 100 == 0) { @@ -457,7 +457,7 @@ static void taosLockList(int64_t *lockedBy) { } static void taosUnlockList(int64_t *lockedBy) { - int64_t tid = taosGetPthreadId(); + int64_t tid = taosGetSelfPthreadId(); if (atomic_val_compare_exchange_64(lockedBy, tid, 0) != tid) { assert(false); } diff --git a/src/util/src/ttimer.c b/src/util/src/ttimer.c index 3c0462e980..015c687b3d 100644 --- a/src/util/src/ttimer.c +++ b/src/util/src/ttimer.c @@ -119,7 +119,7 @@ static void timerDecRef(tmr_obj_t* timer) { } static void lockTimerList(timer_list_t* list) { - int64_t tid = taosGetPthreadId(); + int64_t tid = taosGetSelfPthreadId(); int i = 0; while (atomic_val_compare_exchange_64(&(list->lockedBy), 0, tid) != 0) { if (++i % 1000 == 0) { @@ -129,7 +129,7 @@ static void lockTimerList(timer_list_t* list) { } static void unlockTimerList(timer_list_t* list) { - int64_t tid = taosGetPthreadId(); + int64_t tid = taosGetSelfPthreadId(); if (atomic_val_compare_exchange_64(&(list->lockedBy), tid, 0) != tid) { assert(false); tmrError("%" PRId64 " trying to unlock a timer list not locked by current thread.", tid); @@ -257,7 +257,7 @@ static bool removeFromWheel(tmr_obj_t* timer) { static void processExpiredTimer(void* handle, void* arg) { tmr_obj_t* timer = (tmr_obj_t*)handle; - timer->executedBy = taosGetPthreadId(); + timer->executedBy = taosGetSelfPthreadId(); uint8_t state = atomic_val_compare_exchange_8(&timer->state, TIMER_STATE_WAITING, TIMER_STATE_EXPIRED); if (state == TIMER_STATE_WAITING) { const char* fmt = "%s timer[id=%" PRIuPTR ", fp=%p, param=%p] execution start."; @@ -406,7 +406,7 @@ static bool doStopTimer(tmr_obj_t* timer, uint8_t state) { return false; } - if (timer->executedBy == taosGetPthreadId()) { + if (timer->executedBy == taosGetSelfPthreadId()) { // taosTmrReset is called in the timer callback, should do nothing in this // case to avoid dead lock. note taosTmrReset must be the last statement // of the callback funtion, will be a bug otherwise. diff --git a/tests/script/unique/mnode/mgmt20.sim b/tests/script/unique/mnode/mgmt20.sim index 6eb35b67ac..ee9c2b914f 100644 --- a/tests/script/unique/mnode/mgmt20.sim +++ b/tests/script/unique/mnode/mgmt20.sim @@ -50,6 +50,24 @@ $d1_first = $rows sql select * from log.dn2 $d2_first = $rows +$x = 0 +show4: + $x = $x + 1 + sleep 1000 + if $x == 20 then + return -1 + endi + +sql show mnodes +print dnode1 ==> $data2_1 +print dnode2 ==> $data2_2 +if $data2_1 != master then + goto show4 +endi +if $data2_2 != slave then + goto show4 +endi + sleep 3000 sql select * from log.dn1 $d1_second = $rows From 2cab4f2bf17f7f772e95ef3ea6e8c10faaea3c64 Mon Sep 17 00:00:00 2001 From: liuyq-617 Date: Wed, 30 Dec 2020 15:33:14 +0800 Subject: [PATCH 23/29] [TD-2617]restore log of failed case --- tests/test-all.sh | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/test-all.sh b/tests/test-all.sh index a85ac39b44..19d7803255 100755 --- a/tests/test-all.sh +++ b/tests/test-all.sh @@ -6,7 +6,16 @@ GREEN='\033[1;32m' GREEN_DARK='\033[0;32m' GREEN_UNDERLINE='\033[4;32m' NC='\033[0m' - +function git_branch { + branch="`git branch 2>/dev/null | grep "^\*" | sed -e "s/^\*\ //"`" + if [ "${branch}" != "" ];then + if [ "${branch}" = "(no branch)" ];then + branch="(`git rev-parse --short HEAD`...)" + fi + branch=(${branch////_}) + echo "$branch" + fi +} function runSimCaseOneByOne { while read -r line; do if [[ $line =~ ^./test.sh* ]] || [[ $line =~ ^run* ]]; then @@ -44,6 +53,11 @@ function runSimCaseOneByOnefq { out_log=`tail -1 out.log ` if [[ $out_log =~ 'failed' ]];then + if [[ "$tests_dir" == *"$IN_TDINTERNAL"* ]]; then + cp -r ../../../sim ~/sim_$(git_branch)_`date "+%Y_%m_%d_%H:%M:%S"` + else + cp -r ../../sim ~/sim_$(git_branch)_`date "+%Y_%m_%d_%H:%M:%S" ` + fi exit 8 fi end_time=`date +%s` @@ -95,6 +109,7 @@ function runPyCaseOneByOnefq { end_time=`date +%s` out_log=`tail -1 pytest-out.log ` if [[ $out_log =~ 'failed' ]];then + cp -r ../../sim ~/sim_$(git_branch)_`date "+%Y_%m_%d_%H:%M:%S" ` exit 8 fi echo execution time of $case was `expr $end_time - $start_time`s. | tee -a pytest-out.log From 0e2a548ebe0bbc13249b121f325375074ac40371 Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Wed, 30 Dec 2020 21:09:00 +0800 Subject: [PATCH 24/29] TD-2602 --- src/mnode/src/mnodeCluster.c | 2 +- src/mnode/src/mnodeMnode.c | 1 + src/mnode/src/mnodeSdb.c | 4 ++ tests/script/jenkins/basic.txt | 1 + tests/script/jenkins/unique.txt | 8 ++++ tests/script/unique/mnode/mgmt30.sim | 68 ++++++++++++++++++++++++++++ 6 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 tests/script/unique/mnode/mgmt30.sim diff --git a/src/mnode/src/mnodeCluster.c b/src/mnode/src/mnodeCluster.c index 56229daffa..a35e304810 100644 --- a/src/mnode/src/mnodeCluster.c +++ b/src/mnode/src/mnodeCluster.c @@ -171,7 +171,7 @@ void mnodeUpdateClusterId() { void *pIter = mnodeGetNextCluster(NULL, &pCluster); if (pCluster != NULL) { tstrncpy(tsClusterId, pCluster->uid, TSDB_CLUSTER_ID_LEN); - mInfo("cluster id is set to %s", tsClusterId); + mDebug("cluster id is set to %s", tsClusterId); } mnodeDecClusterRef(pCluster); diff --git a/src/mnode/src/mnodeMnode.c b/src/mnode/src/mnodeMnode.c index 6549d58609..3ea41c41c6 100644 --- a/src/mnode/src/mnodeMnode.c +++ b/src/mnode/src/mnodeMnode.c @@ -387,6 +387,7 @@ static bool mnodeAllOnline() { if (pMnode == NULL) break; if (pMnode->role != TAOS_SYNC_ROLE_MASTER && pMnode->role != TAOS_SYNC_ROLE_SLAVE) { allOnline = false; + mDebug("mnode:%d, role:%s, not online", pMnode->mnodeId, syncRole[pMnode->role]); mnodeDecMnodeRef(pMnode); } } diff --git a/src/mnode/src/mnodeSdb.c b/src/mnode/src/mnodeSdb.c index 80a9978925..6997d0a666 100644 --- a/src/mnode/src/mnodeSdb.c +++ b/src/mnode/src/mnodeSdb.c @@ -225,6 +225,10 @@ void sdbUpdateMnodeRoles() { for (int32_t i = 0; i < tsSdbMgmt.cfg.replica; ++i) { SMnodeObj *pMnode = mnodeGetMnode(roles.nodeId[i]); if (pMnode != NULL) { + if (pMnode->role != roles.role[i]) { + bnNotify(); + } + pMnode->role = roles.role[i]; sdbInfo("vgId:1, mnode:%d, role:%s", pMnode->mnodeId, syncRole[pMnode->role]); if (pMnode->mnodeId == dnodeGetDnodeId()) tsSdbMgmt.role = pMnode->role; diff --git a/tests/script/jenkins/basic.txt b/tests/script/jenkins/basic.txt index ccfed3da8d..eaf917c40d 100644 --- a/tests/script/jenkins/basic.txt +++ b/tests/script/jenkins/basic.txt @@ -319,6 +319,7 @@ cd ../../../debug; make ./test.sh -f unique/mnode/mgmt24.sim ./test.sh -f unique/mnode/mgmt25.sim ./test.sh -f unique/mnode/mgmt26.sim +./test.sh -f unique/mnode/mgmt30.sim ./test.sh -f unique/mnode/mgmt33.sim ./test.sh -f unique/mnode/mgmt34.sim ./test.sh -f unique/mnode/mgmtr2.sim diff --git a/tests/script/jenkins/unique.txt b/tests/script/jenkins/unique.txt index 8e3988e79e..372bdc9d9d 100644 --- a/tests/script/jenkins/unique.txt +++ b/tests/script/jenkins/unique.txt @@ -10,6 +10,7 @@ cd ../../../debug; make ./test.sh -f unique/cluster/balance2.sim ./test.sh -f unique/cluster/balance3.sim ./test.sh -f unique/cluster/cache.sim +./test.sh -f unique/cluster/vgroup100.sim ./test.sh -f unique/column/replica3.sim @@ -25,12 +26,17 @@ cd ../../../debug; make ./test.sh -f unique/db/replica_part.sim ./test.sh -f unique/dnode/alternativeRole.sim +./test.sh -f unique/dnode/monitor.sim +./test.sh -f unique/dnode/monitor_bug.sim +./test.sh -f unique/dnode/simple.sim ./test.sh -f unique/dnode/balance1.sim ./test.sh -f unique/dnode/balance2.sim ./test.sh -f unique/dnode/balance3.sim ./test.sh -f unique/dnode/balancex.sim +./test.sh -f unique/dnode/data1.sim ./test.sh -f unique/dnode/m2.sim ./test.sh -f unique/dnode/m3.sim +./test.sh -f unique/dnode/lossdata.sim ./test.sh -f unique/dnode/offline1.sim ./test.sh -f unique/dnode/offline2.sim ./test.sh -f unique/dnode/offline3.sim @@ -54,12 +60,14 @@ cd ../../../debug; make ./test.sh -f unique/stable/replica3_dnode6.sim ./test.sh -f unique/stable/replica3_vnode3.sim +./test.sh -f unique/mnode/mgmt20.sim ./test.sh -f unique/mnode/mgmt21.sim ./test.sh -f unique/mnode/mgmt22.sim ./test.sh -f unique/mnode/mgmt23.sim ./test.sh -f unique/mnode/mgmt24.sim ./test.sh -f unique/mnode/mgmt25.sim ./test.sh -f unique/mnode/mgmt26.sim +./test.sh -f unique/mnode/mgmt30.sim ./test.sh -f unique/mnode/mgmt33.sim ./test.sh -f unique/mnode/mgmt34.sim ./test.sh -f unique/mnode/mgmtr2.sim diff --git a/tests/script/unique/mnode/mgmt30.sim b/tests/script/unique/mnode/mgmt30.sim new file mode 100644 index 0000000000..a948879933 --- /dev/null +++ b/tests/script/unique/mnode/mgmt30.sim @@ -0,0 +1,68 @@ +system sh/stop_dnodes.sh +system sh/deploy.sh -n dnode1 -i 1 +system sh/deploy.sh -n dnode2 -i 2 +system sh/deploy.sh -n dnode3 -i 3 + +system sh/cfg.sh -n dnode1 -c numOfMnodes -v 3 +system sh/cfg.sh -n dnode2 -c numOfMnodes -v 3 +system sh/cfg.sh -n dnode3 -c numOfMnodes -v 3 + +system sh/cfg.sh -n dnode1 -c balanceInterval -v 3000 +system sh/cfg.sh -n dnode2 -c balanceInterval -v 3000 +system sh/cfg.sh -n dnode3 -c balanceInterval -v 3000 + +print ============== step1 +system sh/exec.sh -n dnode1 -s start +sql connect + +sql show mnodes +print dnode1 ==> $data2_1 +print dnode2 ==> $data2_2 +print dnode3 ==> $data3_3 +if $data2_1 != master then + return -1 +endi +if $data3_2 != null then + return -1 +endi +if $data3_3 != null then + return -1 +endi + +print ============== step2 +system sh/exec.sh -n dnode2 -s start +system sh/exec.sh -n dnode3 -s start +sleep 5000 + +sql create dnode $hostname2 +sql create dnode $hostname3 + +$x = 0 +step2: + $x = $x + 1 + sleep 1000 + if $x == 10 then + return -1 + endi + +sql show mnodes +$dnode1Role = $data2_1 +$dnode2Role = $data2_2 +$dnode3Role = $data2_3 +print dnode1 ==> $dnode1Role +print dnode2 ==> $dnode2Role +print dnode3 ==> $dnode3Role + +if $dnode1Role != master then + goto step2 +endi +if $dnode2Role != slave then + goto step2 +endi +if $dnode3Role != slave then + goto step2 +endi + +system sh/exec.sh -n dnode1 -s stop -x SIGINT +system sh/exec.sh -n dnode2 -s stop -x SIGINT +system sh/exec.sh -n dnode3 -s stop -x SIGINT \ No newline at end of file From 041a4c15d168dbd586511317db2f75baaa6c3694 Mon Sep 17 00:00:00 2001 From: liuyq-617 Date: Thu, 31 Dec 2020 09:56:30 +0800 Subject: [PATCH 25/29] enhance --- Jenkinsfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index b46c68e2b9..9544343bec 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -41,13 +41,15 @@ def pre_test(){ cd ${WKC} git checkout develop + git reset --hard HEAD~10 git pull git fetch git checkout ${CHANGE_BRANCH} + git reset --hard HEAD~10 git pull git merge develop cd ${WK} - git reset --hard + git reset --hard HEAD~10 git checkout develop git pull cd ${WK} From 2df734a5e34411281d513229e578541010569a20 Mon Sep 17 00:00:00 2001 From: Bomin Zhang Date: Tue, 29 Dec 2020 08:31:20 +0000 Subject: [PATCH 26/29] [TD-2585]:migrate 4 sim cases to python to improve speed --- tests/pytest/fulltest.sh | 4 + tests/pytest/pytest_1.sh | 4 + tests/pytest/stream/metric_n.py | 123 +++++++ tests/pytest/stream/sys.py | 59 ++++ tests/pytest/stream/table_1.py | 89 +++++ tests/pytest/stream/table_n.py | 143 ++++++++ tests/script/fullGeneralSuite.sim | 4 - tests/script/general/parser/stream_on_sys.sim | 62 ---- tests/script/general/parser/testSuite.sim | 2 - tests/script/general/stream/metrics_n.sim | 262 --------------- tests/script/general/stream/table_1.sim | 317 ------------------ tests/script/general/stream/table_n.sim | 293 ---------------- tests/script/general/stream/testSuite.sim | 3 - tests/script/jenkins/basic.txt | 4 - tests/script/jenkins/basic_3.txt | 4 - tests/script/jenkins/simple.txt | 1 - tests/script/regressionSuite.sim | 7 - 17 files changed, 422 insertions(+), 959 deletions(-) create mode 100644 tests/pytest/stream/metric_n.py create mode 100644 tests/pytest/stream/sys.py create mode 100644 tests/pytest/stream/table_1.py create mode 100644 tests/pytest/stream/table_n.py delete mode 100644 tests/script/general/parser/stream_on_sys.sim delete mode 100644 tests/script/general/stream/metrics_n.sim delete mode 100644 tests/script/general/stream/table_1.sim delete mode 100644 tests/script/general/stream/table_n.sim diff --git a/tests/pytest/fulltest.sh b/tests/pytest/fulltest.sh index f197a95818..f0b3beacbe 100755 --- a/tests/pytest/fulltest.sh +++ b/tests/pytest/fulltest.sh @@ -178,11 +178,15 @@ python3 ./test.py -f query/floatCompare.py #stream python3 ./test.py -f stream/metric_1.py +python3 ./test.py -f stream/metric_n.py python3 ./test.py -f stream/new.py python3 ./test.py -f stream/stream1.py python3 ./test.py -f stream/stream2.py #python3 ./test.py -f stream/parser.py python3 ./test.py -f stream/history.py +python3 ./test.py -f stream/sys.py +python3 ./test.py -f stream/table_1.py +python3 ./test.py -f stream/table_n.py #alter table python3 ./test.py -f alter/alter_table_crash.py diff --git a/tests/pytest/pytest_1.sh b/tests/pytest/pytest_1.sh index 79815cb6c6..ad26c48004 100755 --- a/tests/pytest/pytest_1.sh +++ b/tests/pytest/pytest_1.sh @@ -178,11 +178,15 @@ python3 ./test.py -f query/floatCompare.py #stream python3 ./test.py -f stream/metric_1.py +python3 ./test.py -f stream/metric_n.py python3 ./test.py -f stream/new.py python3 ./test.py -f stream/stream1.py python3 ./test.py -f stream/stream2.py #python3 ./test.py -f stream/parser.py python3 ./test.py -f stream/history.py +python3 ./test.py -f stream/sys.py +python3 ./test.py -f stream/table_1.py +python3 ./test.py -f stream/table_n.py #alter table python3 ./test.py -f alter/alter_table_crash.py diff --git a/tests/pytest/stream/metric_n.py b/tests/pytest/stream/metric_n.py new file mode 100644 index 0000000000..d223fe81fc --- /dev/null +++ b/tests/pytest/stream/metric_n.py @@ -0,0 +1,123 @@ +################################################################### +# Copyright (c) 2016 by TAOS Technologies, Inc. +# All rights reserved. +# +# This file is proprietary and confidential to TAOS Technologies. +# No part of this file may be reproduced, stored, transmitted, +# disclosed or used in any form or by any means other than as +# expressly provided by the written permission from Jianhui Tao +# +################################################################### + +# -*- coding: utf-8 -*- + +import sys +import time +import taos +from util.log import tdLog +from util.cases import tdCases +from util.sql import tdSql + + +class TDTestCase: + def init(self, conn, logSql): + tdLog.debug("start to execute %s" % __file__) + tdSql.init(conn.cursor(), logSql) + + def run(self): + tbNum = 10 + rowNum = 20 + totalNum = tbNum * rowNum + + tdSql.prepare() + + tdLog.info("===== preparing data =====") + tdSql.execute( + "create table stb(ts timestamp, tbcol int, tbcol2 float) tags(tgcol int)") + for i in range(tbNum): + tdSql.execute("create table tb%d using stb tags(%d)" % (i, i)) + for j in range(rowNum): + tdSql.execute( + "insert into tb%d values (now - %dm, %d, %d)" % + (i, 1440 - j, j, j)) + time.sleep(0.1) + + tdLog.info("===== step 1 =====") + tdSql.query("select count(*), count(tbcol), count(tbcol2) from stb interval(1d)") + tdSql.checkData(0, 1, totalNum) + tdSql.checkData(0, 2, totalNum) + tdSql.checkData(0, 3, totalNum) + + tdLog.info("===== step 2 =====") + tdSql.execute("create table strm_c3 as select count(*), count(tbcol), count(tbcol2) from stb interval(1d)") + + tdLog.info("===== step 3 =====") + tdSql.execute("create table strm_c32 as select count(*), count(tbcol) as c1, count(tbcol2) as c2, count(tbcol) as c3, count(tbcol) as c4, count(tbcol) as c5, count(tbcol) as c6, count(tbcol) as c7, count(tbcol) as c8, count(tbcol) as c9, count(tbcol) as c10, count(tbcol) as c11, count(tbcol) as c12, count(tbcol) as c13, count(tbcol) as c14, count(tbcol) as c15, count(tbcol) as c16, count(tbcol) as c17, count(tbcol) as c18, count(tbcol) as c19, count(tbcol) as c20, count(tbcol) as c21, count(tbcol) as c22, count(tbcol) as c23, count(tbcol) as c24, count(tbcol) as c25, count(tbcol) as c26, count(tbcol) as c27, count(tbcol) as c28, count(tbcol) as c29, count(tbcol) as c30 from stb interval(1d)") + + tdLog.info("===== step 4 =====") + tdSql.query("select count(*), count(tbcol) as c1, count(tbcol2) as c2, count(tbcol) as c3, count(tbcol) as c4, count(tbcol) as c5, count(tbcol) as c6, count(tbcol) as c7, count(tbcol) as c8, count(tbcol) as c9, count(tbcol) as c10, count(tbcol) as c11, count(tbcol) as c12, count(tbcol) as c13, count(tbcol) as c14, count(tbcol) as c15, count(tbcol) as c16, count(tbcol) as c17, count(tbcol) as c18, count(tbcol) as c19, count(tbcol) as c20, count(tbcol) as c21, count(tbcol) as c22, count(tbcol) as c23, count(tbcol) as c24, count(tbcol) as c25, count(tbcol) as c26, count(tbcol) as c27, count(tbcol) as c28, count(tbcol) as c29, count(tbcol) as c30 from stb interval(1d)") + tdSql.checkData(0, 1, totalNum) + tdSql.checkData(0, 2, totalNum) + tdSql.checkData(0, 3, totalNum) + + tdLog.info("===== step 5 =====") + tdSql.execute("create table strm_c31 as select count(*), count(tbcol) as c1, count(tbcol2) as c2, count(tbcol) as c3, count(tbcol) as c4, count(tbcol) as c5, count(tbcol) as c6, count(tbcol) as c7, count(tbcol) as c8, count(tbcol) as c9, count(tbcol) as c10, count(tbcol) as c11, count(tbcol) as c12, count(tbcol) as c13, count(tbcol) as c14, count(tbcol) as c15, count(tbcol) as c16, count(tbcol) as c17, count(tbcol) as c18, count(tbcol) as c19, count(tbcol) as c20, count(tbcol) as c21, count(tbcol) as c22, count(tbcol) as c23, count(tbcol) as c24, count(tbcol) as c25, count(tbcol) as c26, count(tbcol) as c27, count(tbcol) as c28, count(tbcol) as c29, count(tbcol) as c30 from stb interval(1d)") + + tdLog.info("===== step 6 =====") + tdSql.query("select avg(tbcol), sum(tbcol), min(tbcol), max(tbcol), first(tbcol), last(tbcol) from stb interval(1d)") + tdSql.checkData(0, 1, 9.5) + tdSql.checkData(0, 2, 1900) + tdSql.checkData(0, 3, 0) + tdSql.checkData(0, 4, 19) + tdSql.checkData(0, 5, 0) + tdSql.checkData(0, 6, 19) + tdSql.execute("create table strm_avg as select avg(tbcol), sum(tbcol), min(tbcol), max(tbcol), first(tbcol), last(tbcol) from stb interval(1d)") + + tdLog.info("===== step 7 =====") + tdSql.query("select avg(tbcol), sum(tbcol), min(tbcol), max(tbcol), first(tbcol), last(tbcol), count(tbcol) from stb where ts < now + 4m interval(1d)") + tdSql.checkData(0, 1, 9.5) + tdSql.checkData(0, 2, 1900) + tdSql.checkData(0, 3, 0) + tdSql.checkData(0, 4, 19) + tdSql.checkData(0, 5, 0) + tdSql.checkData(0, 6, 19) + tdSql.checkData(0, 7, totalNum) + + tdLog.info("===== step 8 =====") + tdSql.query("select avg(tbcol), sum(tbcol), min(tbcol), max(tbcol), first(tbcol), last(tbcol), count(tbcol) from stb where ts < now + 4m interval(1d)") + tdSql.checkData(0, 1, 9.5) + tdSql.checkData(0, 2, 1900) + tdSql.checkData(0, 3, 0) + tdSql.checkData(0, 4, 19) + tdSql.checkData(0, 5, 0) + tdSql.checkData(0, 6, 19) + tdSql.checkData(0, 7, totalNum) + + tdLog.info("===== step 9 =====") + tdSql.waitedQuery("select * from strm_c3", 1, 120) + tdSql.checkData(0, 1, totalNum) + tdSql.checkData(0, 2, totalNum) + tdSql.checkData(0, 3, totalNum) + + tdLog.info("===== step 10 =====") + tdSql.waitedQuery("select * from strm_c31", 1, 30) + for i in range(1, 10): + tdSql.checkData(0, i, totalNum) + + tdLog.info("===== step 11 =====") + tdSql.waitedQuery("select * from strm_avg", 1, 20) + tdSql.checkData(0, 1, 9.5) + tdSql.checkData(0, 2, 1900) + tdSql.checkData(0, 3, 0) + tdSql.checkData(0, 4, 19) + tdSql.checkData(0, 5, 0) + tdSql.checkData(0, 6, 19) + + + def stop(self): + tdSql.close() + tdLog.success("%s successfully executed" % __file__) + + +tdCases.addWindows(__file__, TDTestCase()) +tdCases.addLinux(__file__, TDTestCase()) diff --git a/tests/pytest/stream/sys.py b/tests/pytest/stream/sys.py new file mode 100644 index 0000000000..9202e2a9c0 --- /dev/null +++ b/tests/pytest/stream/sys.py @@ -0,0 +1,59 @@ +################################################################### +# Copyright (c) 2016 by TAOS Technologies, Inc. +# All rights reserved. +# +# This file is proprietary and confidential to TAOS Technologies. +# No part of this file may be reproduced, stored, transmitted, +# disclosed or used in any form or by any means other than as +# expressly provided by the written permission from Jianhui Tao +# +################################################################### + +# migrated from 'stream_on_sys.sim' +# -*- coding: utf-8 -*- +import sys +import time +import taos +from util.log import tdLog +from util.cases import tdCases +from util.sql import tdSql + + +class TDTestCase: + def init(self, conn, logSql): + tdLog.debug("start to execute %s" % __file__) + tdSql.init(conn.cursor(), logSql) + + + def run(self): + tdSql.execute("use log") + + tdSql.execute("create table cpustrm as select count(*), avg(cpu_taosd), max(cpu_taosd), min(cpu_taosd), avg(cpu_system), max(cpu_cores), min(cpu_cores), last(cpu_cores) from log.dn1 interval(4s)") + tdSql.execute("create table memstrm as select count(*), avg(mem_taosd), max(mem_taosd), min(mem_taosd), avg(mem_system), first(mem_total), last(mem_total) from log.dn1 interval(4s)") + tdSql.execute("create table diskstrm as select count(*), avg(disk_used), last(disk_used), avg(disk_total), first(disk_total) from log.dn1 interval(4s)") + tdSql.execute("create table bandstrm as select count(*), avg(band_speed), last(band_speed) from log.dn1 interval(4s)") + tdSql.execute("create table reqstrm as select count(*), avg(req_http), last(req_http), avg(req_select), last(req_select), avg(req_insert), last(req_insert) from log.dn1 interval(4s)") + tdSql.execute("create table iostrm as select count(*), avg(io_read), last(io_read), avg(io_write), last(io_write) from log.dn1 interval(4s)") + + sqls = [ + "select * from cpustrm", + "select * from memstrm", + "select * from diskstrm", + "select * from bandstrm", + "select * from reqstrm", + "select * from iostrm", + ] + for sql in sqls: + (rows, _) = tdSql.waitedQuery(sql, 1, 120) + if rows < 1: + tdLog.exit("failed: sql:%s, expect at least one row" % sql) + + + def stop(self): + tdSql.close() + tdLog.success("%s successfully executed" % __file__) + + +tdCases.addWindows(__file__, TDTestCase()) +tdCases.addLinux(__file__, TDTestCase()) + diff --git a/tests/pytest/stream/table_1.py b/tests/pytest/stream/table_1.py new file mode 100644 index 0000000000..a9fd573931 --- /dev/null +++ b/tests/pytest/stream/table_1.py @@ -0,0 +1,89 @@ +################################################################### +# Copyright (c) 2016 by TAOS Technologies, Inc. +# All rights reserved. +# +# This file is proprietary and confidential to TAOS Technologies. +# No part of this file may be reproduced, stored, transmitted, +# disclosed or used in any form or by any means other than as +# expressly provided by the written permission from Jianhui Tao +# +################################################################### + +# -*- coding: utf-8 -*- + +import sys +import time +import taos +from util.log import tdLog +from util.cases import tdCases +from util.sql import tdSql + + +class TDTestCase: + def init(self, conn, logSql): + tdLog.debug("start to execute %s" % __file__) + tdSql.init(conn.cursor(), logSql) + + def createFuncStream(self, expr, suffix, value): + tbname = "strm_" + suffix + tdLog.info("create stream table %s" % tbname) + tdSql.query("select %s from tb1 interval(1d)" % expr) + tdSql.checkData(0, 1, value) + tdSql.execute("create table %s as select %s from tb1 interval(1d)" % (tbname, expr)) + + def checkStreamData(self, suffix, value): + sql = "select * from strm_" + suffix + tdSql.waitedQuery(sql, 1, 120) + tdSql.checkData(0, 1, value) + + def run(self): + tbNum = 10 + rowNum = 20 + + tdSql.prepare() + + tdLog.info("===== step1 =====") + tdSql.execute( + "create table stb(ts timestamp, tbcol int, tbcol2 float) tags(tgcol int)") + for i in range(tbNum): + tdSql.execute("create table tb%d using stb tags(%d)" % (i, i)) + for j in range(rowNum): + tdSql.execute( + "insert into tb%d values (now - %dm, %d, %d)" % + (i, 1440 - j, j, j)) + time.sleep(0.1) + + self.createFuncStream("count(*)", "c1", rowNum) + self.createFuncStream("count(tbcol)", "c2", rowNum) + self.createFuncStream("count(tbcol2)", "c3", rowNum) + self.createFuncStream("avg(tbcol)", "av", 9.5) + self.createFuncStream("sum(tbcol)", "su", 190) + self.createFuncStream("min(tbcol)", "mi", 0) + self.createFuncStream("max(tbcol)", "ma", 19) + self.createFuncStream("first(tbcol)", "fi", 0) + self.createFuncStream("last(tbcol)", "la", 19) + self.createFuncStream("stddev(tbcol)", "st", 5.766281297335398) + self.createFuncStream("percentile(tbcol, 1)", "pe", 0.19) + self.createFuncStream("count(tbcol)", "as", rowNum) + + self.checkStreamData("c1", rowNum) + self.checkStreamData("c2", rowNum) + self.checkStreamData("c3", rowNum) + self.checkStreamData("av", 9.5) + self.checkStreamData("su", 190) + self.checkStreamData("mi", 0) + self.checkStreamData("ma", 19) + self.checkStreamData("fi", 0) + self.checkStreamData("la", 19) + self.checkStreamData("st", 5.766281297335398) + self.checkStreamData("pe", 0.19) + self.checkStreamData("as", rowNum) + + + def stop(self): + tdSql.close() + tdLog.success("%s successfully executed" % __file__) + + +tdCases.addWindows(__file__, TDTestCase()) +tdCases.addLinux(__file__, TDTestCase()) diff --git a/tests/pytest/stream/table_n.py b/tests/pytest/stream/table_n.py new file mode 100644 index 0000000000..371af76977 --- /dev/null +++ b/tests/pytest/stream/table_n.py @@ -0,0 +1,143 @@ +################################################################### +# Copyright (c) 2016 by TAOS Technologies, Inc. +# All rights reserved. +# +# This file is proprietary and confidential to TAOS Technologies. +# No part of this file may be reproduced, stored, transmitted, +# disclosed or used in any form or by any means other than as +# expressly provided by the written permission from Jianhui Tao +# +################################################################### + +# -*- coding: utf-8 -*- + +import sys +import time +import taos +from util.log import tdLog +from util.cases import tdCases +from util.sql import tdSql + + +class TDTestCase: + def init(self, conn, logSql): + tdLog.debug("start to execute %s" % __file__) + tdSql.init(conn.cursor(), logSql) + + def run(self): + tbNum = 10 + rowNum = 20 + + tdSql.prepare() + + tdLog.info("===== preparing data =====") + tdSql.execute( + "create table stb(ts timestamp, tbcol int, tbcol2 float) tags(tgcol int)") + for i in range(tbNum): + tdSql.execute("create table tb%d using stb tags(%d)" % (i, i)) + for j in range(rowNum): + tdSql.execute( + "insert into tb%d values (now - %dm, %d, %d)" % + (i, 1440 - j, j, j)) + time.sleep(0.1) + + tdLog.info("===== step 1 =====") + tdSql.query("select count(*), count(tbcol), count(tbcol2) from tb1 interval(1d)") + tdSql.checkData(0, 1, rowNum) + tdSql.checkData(0, 2, rowNum) + tdSql.checkData(0, 3, rowNum) + + tdLog.info("===== step 2 =====") + tdSql.execute("create table strm_c3 as select count(*), count(tbcol), count(tbcol2) from tb1 interval(1d)") + + tdLog.info("===== step 3 =====") + tdSql.execute("create table strm_c32 as select count(*), count(tbcol) as c1, count(tbcol2) as c2, count(tbcol) as c3, count(tbcol) as c4, count(tbcol) as c5, count(tbcol) as c6, count(tbcol) as c7, count(tbcol) as c8, count(tbcol) as c9, count(tbcol) as c10, count(tbcol) as c11, count(tbcol) as c12, count(tbcol) as c13, count(tbcol) as c14, count(tbcol) as c15, count(tbcol) as c16, count(tbcol) as c17, count(tbcol) as c18, count(tbcol) as c19, count(tbcol) as c20, count(tbcol) as c21, count(tbcol) as c22, count(tbcol) as c23, count(tbcol) as c24, count(tbcol) as c25, count(tbcol) as c26, count(tbcol) as c27, count(tbcol) as c28, count(tbcol) as c29, count(tbcol) as c30 from tb1 interval(1d)") + + tdLog.info("===== step 4 =====") + tdSql.query("select count(*), count(tbcol) as c1, count(tbcol2) as c2, count(tbcol) as c3, count(tbcol) as c4, count(tbcol) as c5, count(tbcol) as c6, count(tbcol) as c7, count(tbcol) as c8, count(tbcol) as c9, count(tbcol) as c10, count(tbcol) as c11, count(tbcol) as c12, count(tbcol) as c13, count(tbcol) as c14, count(tbcol) as c15, count(tbcol) as c16, count(tbcol) as c17, count(tbcol) as c18, count(tbcol) as c19, count(tbcol) as c20, count(tbcol) as c21, count(tbcol) as c22, count(tbcol) as c23, count(tbcol) as c24, count(tbcol) as c25, count(tbcol) as c26, count(tbcol) as c27, count(tbcol) as c28, count(tbcol) as c29, count(tbcol) as c30 from tb1 interval(1d)") + tdSql.checkData(0, 1, rowNum) + tdSql.checkData(0, 2, rowNum) + tdSql.checkData(0, 3, rowNum) + + tdLog.info("===== step 5 =====") + tdSql.execute("create table strm_c31 as select count(*), count(tbcol) as c1, count(tbcol2) as c2, count(tbcol) as c3, count(tbcol) as c4, count(tbcol) as c5, count(tbcol) as c6, count(tbcol) as c7, count(tbcol) as c8, count(tbcol) as c9, count(tbcol) as c10, count(tbcol) as c11, count(tbcol) as c12, count(tbcol) as c13, count(tbcol) as c14, count(tbcol) as c15, count(tbcol) as c16, count(tbcol) as c17, count(tbcol) as c18, count(tbcol) as c19, count(tbcol) as c20, count(tbcol) as c21, count(tbcol) as c22, count(tbcol) as c23, count(tbcol) as c24, count(tbcol) as c25, count(tbcol) as c26, count(tbcol) as c27, count(tbcol) as c28, count(tbcol) as c29, count(tbcol) as c30 from tb1 interval(1d)") + + tdLog.info("===== step 6 =====") + tdSql.query("select avg(tbcol), sum(tbcol), min(tbcol), max(tbcol), first(tbcol), last(tbcol) from tb1 interval(1d)") + tdSql.checkData(0, 1, 9.5) + tdSql.checkData(0, 2, 190) + tdSql.checkData(0, 3, 0) + tdSql.checkData(0, 4, 19) + tdSql.checkData(0, 5, 0) + tdSql.checkData(0, 6, 19) + tdSql.execute("create table strm_avg as select avg(tbcol), sum(tbcol), min(tbcol), max(tbcol), first(tbcol), last(tbcol) from tb1 interval(1d)") + + tdLog.info("===== step 7 =====") + tdSql.query("select stddev(tbcol), leastsquares(tbcol, 1, 1), percentile(tbcol, 1) from tb1 interval(1d)") + tdSql.checkData(0, 1, 5.766281297335398) + tdSql.checkData(0, 3, 0.19) + tdSql.execute("create table strm_ot as select stddev(tbcol), leastsquares(tbcol, 1, 1), percentile(tbcol, 1) from tb1 interval(1d)") + + tdLog.info("===== step 8 =====") + tdSql.query("select avg(tbcol), sum(tbcol), min(tbcol), max(tbcol), first(tbcol), last(tbcol), stddev(tbcol), percentile(tbcol, 1), count(tbcol), leastsquares(tbcol, 1, 1) from tb1 interval(1d)") + tdSql.checkData(0, 1, 9.5) + tdSql.checkData(0, 2, 190) + tdSql.checkData(0, 3, 0) + tdSql.checkData(0, 4, 19) + tdSql.checkData(0, 5, 0) + tdSql.checkData(0, 6, 19) + tdSql.checkData(0, 7, 5.766281297335398) + tdSql.checkData(0, 8, 0.19) + tdSql.checkData(0, 9, rowNum) + tdSql.execute("create table strm_to as select avg(tbcol), sum(tbcol), min(tbcol), max(tbcol), first(tbcol), last(tbcol), stddev(tbcol), percentile(tbcol, 1), count(tbcol), leastsquares(tbcol, 1, 1) from tb1 interval(1d)") + + tdLog.info("===== step 9 =====") + tdSql.query("select avg(tbcol), sum(tbcol), min(tbcol), max(tbcol), first(tbcol), last(tbcol), stddev(tbcol), percentile(tbcol, 1), count(tbcol), leastsquares(tbcol, 1, 1) from tb1 where ts < now + 4m interval(1d)") + tdSql.checkData(0, 9, rowNum) + tdSql.execute("create table strm_wh as select avg(tbcol), sum(tbcol), min(tbcol), max(tbcol), first(tbcol), last(tbcol), stddev(tbcol), percentile(tbcol, 1), count(tbcol), leastsquares(tbcol, 1, 1) from tb1 where ts < now + 4m interval(1d)") + + tdLog.info("===== step 10 =====") + tdSql.waitedQuery("select * from strm_c3", 1, 120) + tdSql.checkData(0, 1, rowNum) + tdSql.checkData(0, 2, rowNum) + tdSql.checkData(0, 3, rowNum) + + tdLog.info("===== step 11 =====") + tdSql.waitedQuery("select * from strm_c31", 1, 30) + for i in range(1, 10): + tdSql.checkData(0, i, rowNum) + + tdLog.info("===== step 12 =====") + tdSql.waitedQuery("select * from strm_avg", 1, 20) + tdSql.checkData(0, 1, 9.5) + tdSql.checkData(0, 2, 190) + tdSql.checkData(0, 3, 0) + tdSql.checkData(0, 4, 19) + tdSql.checkData(0, 5, 0) + tdSql.checkData(0, 6, 19) + + tdLog.info("===== step 13 =====") + tdSql.waitedQuery("select * from strm_ot", 1, 20) + tdSql.checkData(0, 1, 5.766281297335398) + tdSql.checkData(0, 3, 0.19) + + tdLog.info("===== step 14 =====") + tdSql.waitedQuery("select * from strm_to", 1, 20) + tdSql.checkData(0, 1, 9.5) + tdSql.checkData(0, 2, 190) + tdSql.checkData(0, 3, 0) + tdSql.checkData(0, 4, 19) + tdSql.checkData(0, 5, 0) + tdSql.checkData(0, 6, 19) + tdSql.checkData(0, 7, 5.766281297335398) + tdSql.checkData(0, 8, 0.19) + tdSql.checkData(0, 9, rowNum) + + + def stop(self): + tdSql.close() + tdLog.success("%s successfully executed" % __file__) + + +tdCases.addWindows(__file__, TDTestCase()) +tdCases.addLinux(__file__, TDTestCase()) diff --git a/tests/script/fullGeneralSuite.sim b/tests/script/fullGeneralSuite.sim index 4dd3957f39..707869d115 100644 --- a/tests/script/fullGeneralSuite.sim +++ b/tests/script/fullGeneralSuite.sim @@ -134,7 +134,6 @@ run general/parser/tags_dynamically_specifiy.sim run general/parser/set_tag_vals.sim #unsupport run general/parser/repeatAlter.sim #unsupport run general/parser/slimit_alter_tags.sim -#unsupport run general/parser/stream_on_sys.sim #unsupport run general/parser/repeatStream.sim run general/stable/disk.sim run general/stable/dnode3.sim @@ -213,9 +212,6 @@ run general/vector/table_time.sim run general/stream/restart_stream.sim run general/stream/stream_3.sim run general/stream/stream_restart.sim -run general/stream/table_1.sim -run general/stream/table_n.sim -run general/stream/metrics_n.sim run general/stream/table_del.sim run general/stream/metrics_del.sim run general/stream/table_replica1_vnoden.sim diff --git a/tests/script/general/parser/stream_on_sys.sim b/tests/script/general/parser/stream_on_sys.sim deleted file mode 100644 index 1c8eb82c79..0000000000 --- a/tests/script/general/parser/stream_on_sys.sim +++ /dev/null @@ -1,62 +0,0 @@ -system sh/stop_dnodes.sh - -system sh/deploy.sh -n dnode1 -i 1 -system sh/cfg.sh -n dnode1 -c walLevel -v 0 -system sh/cfg.sh -n dnode1 -c monitor -v 1 -system sh/cfg.sh -n dnode1 -c monitorInterval -v 1 -system sh/exec.sh -n dnode1 -s start - -sleep 500 -sql connect -print ======================== stream_on_sys.sim - -$db = log -$tb = tb -$mt = mt -$strm = strm -$tbNum = 10 -$rowNum = 20 -$totalNum = 200 - -$i = 0 - -sql use $db - -sql create table cpustrm as select count(*), avg(cpu_taosd), max(cpu_taosd), min(cpu_taosd), avg(cpu_system), max(cpu_cores), min(cpu_cores), last(cpu_cores) from log.dn1 interval(4s) -sql create table memstrm as select count(*), avg(mem_taosd), max(mem_taosd), min(mem_taosd), avg(mem_system), first(mem_total), last(mem_total) from log.dn1 interval(4s) -sql create table diskstrm as select count(*), avg(disk_used), last(disk_used), avg(disk_total), first(disk_total) from log.dn1 interval(4s) -sql create table bandstrm as select count(*), avg(band_speed), last(band_speed) from log.dn1 interval(4s) -sql create table reqstrm as select count(*), avg(req_http), last(req_http), avg(req_select), last(req_select), avg(req_insert), last(req_insert) from log.dn1 interval(4s) -sql create table iostrm as select count(*), avg(io_read), last(io_read), avg(io_write), last(io_write) from log.dn1 interval(4s) -sleep 120000 -sql select * from cpustrm -if $rows <= 0 then - return -1 -endi - -sql select * from memstrm -if $rows <= 0 then - return -1 -endi - -sql select * from diskstrm -if $rows <= 0 then - return -1 -endi - -sql select * from bandstrm -if $rows <= 0 then - return -1 -endi - -sql select * from reqstrm -if $rows <= 0 then - return -1 -endi - -sql select * from iostrm -if $rows <= 0 then - return -1 -endi - -system sh/exec.sh -n dnode1 -s stop -x SIGINT \ No newline at end of file diff --git a/tests/script/general/parser/testSuite.sim b/tests/script/general/parser/testSuite.sim index cea6d98679..971c103cf5 100644 --- a/tests/script/general/parser/testSuite.sim +++ b/tests/script/general/parser/testSuite.sim @@ -109,6 +109,4 @@ run general/parser/function.sim #sleep 500 #run general/parser/repeatStream.sim #sleep 500 -#run general/parser/stream_on_sys.sim -#sleep 500 #run general/parser/stream.sim \ No newline at end of file diff --git a/tests/script/general/stream/metrics_n.sim b/tests/script/general/stream/metrics_n.sim deleted file mode 100644 index 7fc08064b2..0000000000 --- a/tests/script/general/stream/metrics_n.sim +++ /dev/null @@ -1,262 +0,0 @@ -system sh/stop_dnodes.sh - -system sh/deploy.sh -n dnode1 -i 1 -system sh/cfg.sh -n dnode1 -c walLevel -v 0 -system sh/exec.sh -n dnode1 -s start - -sleep 3000 -sql connect - -print ======================== dnode1 start - -$dbPrefix = mn_db -$tbPrefix = mn_tb -$mtPrefix = mn_mt -$stPrefix = mn_st -$tbNum = 10 -$rowNum = 20 -$totalNum = 200 - -print =============== step1 -$i = 0 -$db = $dbPrefix . $i -$mt = $mtPrefix . $i -$st = $stPrefix . $i - -sql drop databae $db -x step1 -step1: -sql create database $db -sql use $db -sql create table $mt (ts timestamp, tbcol int, tbcol2 float) TAGS(tgcol int) - -$i = 0 -while $i < $tbNum - $tb = $tbPrefix . $i - sql create table $tb using $mt tags( $i ) - - $x = -1440 - $y = 0 - while $y < $rowNum - $ms = $x . m - sql insert into $tb values (now $ms , $y , $y ) - $x = $x + 1 - $y = $y + 1 - endw - - $i = $i + 1 -endw - -sleep 100 - -print =============== step2 c3 -$i = 1 -$tb = $tbPrefix . $i - -sql select count(*), count(tbcol), count(tbcol2) from $mt interval(1d) -print select count(*), count(tbcol), count(tbcol2) from $mt interval(1d) ===> $data00 $data01 $data02, $data03 -if $data01 != 200 then - return -1 -endi -if $data02 != 200 then - return -1 -endi -if $data03 != 200 then - return -1 -endi - -$st = $stPrefix . c3 -sql create table $st as select count(*), count(tbcol), count(tbcol2) from $mt interval(1d) - -print =============== step3 count32 -#total 32 count in select -sql select count(*), count(tbcol) as c1, count(tbcol2) as c2, count(tbcol) as c3, count(tbcol) as c4, count(tbcol) as c5, count(tbcol) as c6, count(tbcol) as c7, count(tbcol) as c8, count(tbcol) as c9, count(tbcol) as c10, count(tbcol) as c11, count(tbcol) as c12, count(tbcol) as c13, count(tbcol) as c14, count(tbcol) as c15, count(tbcol) as c16, count(tbcol) as c17, count(tbcol) as c18, count(tbcol) as c19, count(tbcol) as c20, count(tbcol) as c21, count(tbcol) as c22, count(tbcol) as c23, count(tbcol) as c24, count(tbcol) as c25, count(tbcol) as c26, count(tbcol) as c27, count(tbcol) as c28, count(tbcol) as c29, count(tbcol) as c30 from $mt interval(1d) - -# total 32 count in stream -$st = $stPrefix . c32 -sql create table $st as select count(*), count(tbcol) as c1, count(tbcol2) as c2, count(tbcol) as c3, count(tbcol) as c4, count(tbcol) as c5, count(tbcol) as c6, count(tbcol) as c7, count(tbcol) as c8, count(tbcol) as c9, count(tbcol) as c10, count(tbcol) as c11, count(tbcol) as c12, count(tbcol) as c13, count(tbcol) as c14, count(tbcol) as c15, count(tbcol) as c16, count(tbcol) as c17, count(tbcol) as c18, count(tbcol) as c19, count(tbcol) as c20, count(tbcol) as c21, count(tbcol) as c22, count(tbcol) as c23, count(tbcol) as c24, count(tbcol) as c25, count(tbcol) as c26, count(tbcol) as c27, count(tbcol) as c28, count(tbcol) as c29, count(tbcol) as c30 from $mt interval(1d) - -print =============== step4 count31 - -#total 31 count in select -sql select count(*), count(tbcol) as c1, count(tbcol2) as c2, count(tbcol) as c3, count(tbcol) as c4, count(tbcol) as c5, count(tbcol) as c6, count(tbcol) as c7, count(tbcol) as c8, count(tbcol) as c9, count(tbcol) as c10, count(tbcol) as c11, count(tbcol) as c12, count(tbcol) as c13, count(tbcol) as c14, count(tbcol) as c15, count(tbcol) as c16, count(tbcol) as c17, count(tbcol) as c18, count(tbcol) as c19, count(tbcol) as c20, count(tbcol) as c21, count(tbcol) as c22, count(tbcol) as c23, count(tbcol) as c24, count(tbcol) as c25, count(tbcol) as c26, count(tbcol) as c27, count(tbcol) as c28, count(tbcol) as c29, count(tbcol) as c30 from $mt interval(1d) -print ===> $data00 $data01 $data02, $data03 -if $data01 != 200 then - return -1 -endi -if $data02 != 200 then - return -1 -endi -if $data03 != 200 then - return -1 -endi - -# total 31 count in stream will crash, 32 will error -$st = $stPrefix . c31 -sql create table $st as select count(*), count(tbcol) as c1, count(tbcol2) as c2, count(tbcol) as c3, count(tbcol) as c4, count(tbcol) as c5, count(tbcol) as c6, count(tbcol) as c7, count(tbcol) as c8, count(tbcol) as c9, count(tbcol) as c10, count(tbcol) as c11, count(tbcol) as c12, count(tbcol) as c13, count(tbcol) as c14, count(tbcol) as c15, count(tbcol) as c16, count(tbcol) as c17, count(tbcol) as c18, count(tbcol) as c19, count(tbcol) as c20, count(tbcol) as c21, count(tbcol) as c22, count(tbcol) as c23, count(tbcol) as c24, count(tbcol) as c25, count(tbcol) as c26, count(tbcol) as c27, count(tbcol) as c28, count(tbcol) as c29, count(tbcol) as c30 from $mt interval(1d) - -print =============== step5 avg ... -sql select avg(tbcol), sum(tbcol), min(tbcol), max(tbcol), first(tbcol), last(tbcol) from $mt interval(1d) -print ===> $data01 $data02 $data03 $data04 $data05 $data06 -if $data01 != 9.500000000 then - return -1 -endi -if $data02 != 1900 then - return -1 -endi -if $data03 != 0 then - return -1 -endi -if $data04 != 19 then - return -1 -endi -if $data05 != 0 then - return -1 -endi -if $data06 != 19 then - return -1 -endi - -$st = $stPrefix . avg -sql create table $st as select avg(tbcol), sum(tbcol), min(tbcol), max(tbcol), first(tbcol), last(tbcol) from $mt interval(1d) - -print =============== step6 others -sql select stddev(tbcol), leastsquares(tbcol, 1, 1), percentile(tbcol, 1) from $mt interval(1d) -x step6 - return -1 -step6: - -$st = $stPrefix . ot -sql create table $st as select stddev(tbcol), leastsquares(tbcol, 1, 1), percentile(tbcol, 1) from $mt interval(1d) -x step61 - return -1 -step61: - -print =============== step7 where -sql select avg(tbcol), sum(tbcol), min(tbcol), max(tbcol), first(tbcol), last(tbcol), count(tbcol) from $mt where ts < now + 4m interval(1d) -print select avg(tbcol), sum(tbcol), min(tbcol), max(tbcol), first(tbcol), last(tbcol), count(tbcol) from $mt where ts < now + 4m interval(1d) -print ===> $data01 $data02 $data03 $data04 $data05 $data06 $data07 -if $data01 != 9.500000000 then - return -1 -endi -if $data02 != 1900 then - return -1 -endi -if $data03 != 0 then - return -1 -endi -if $data04 != 19 then - return -1 -endi -if $data05 != 0 then - return -1 -endi -if $data06 != 19 then - return -1 -endi -if $data07 != 200 then - return -1 -endi - -$st = $stPrefix . wh -#sql create table $st as select avg(tbcol), sum(tbcol), min(tbcol), max(tbcol), first(tbcol), last(tbcol), count(tbcol) from $mt where ts < now + 4m interval(1d) - -print =============== step8 as -sql select avg(tbcol), sum(tbcol), min(tbcol), max(tbcol), first(tbcol), last(tbcol), count(tbcol) from $mt where ts < now + 4m interval(1d) -print ===> $data01 $data02 $data03 $data04 $data05 $data06 $data07 -if $data01 != 9.500000000 then - return -1 -endi -if $data02 != 1900 then - return -1 -endi -if $data03 != 0 then - return -1 -endi -if $data04 != 19 then - return -1 -endi -if $data05 != 0 then - return -1 -endi -if $data06 != 19 then - return -1 -endi -if $data07 != 200 then - return -1 -endi - -$st = $stPrefix . as -#sql create table $st as select avg(tbcol) as a1, sum(tbcol) as a2, min(tbcol) as a3, max(tbcol) as a4, first(tbcol) as a5, last(tbcol) as a6, count(tbcol) as a7, avg(tbcol) as a8, sum(tbcol) as a9, min(tbcol) as a3, max(tbcol) as a4, first(tbcol) as a5, last(tbcol) as a6, count(tbcol) as a7 from $mt where ts < now + 4m interval(1d) - -print =============== step9 -print sleep 120 seconds -sleep 120000 - -print =============== step10 -$st = $stPrefix . c3 -sql select * from $st -print ===> select * from $st -print ===> $data01 $data02 $data03 $data04 $data05 $data06 $data07 $data08 $data09 -if $data01 != 200 then - return -1 -endi -if $data02 != 200 then - return -1 -endi -if $data03 != 200 then - return -1 -endi - -$st = $stPrefix . c31 -sql select * from $st -if $data01 != 200 then - return -1 -endi -if $data02 != 200 then - return -1 -endi -if $data03 != 200 then - return -1 -endi -if $data04 != 200 then - return -1 -endi -if $data05 != 200 then - return -1 -endi -if $data06 != 200 then - return -1 -endi -if $data07 != 200 then - return -1 -endi -if $data08 != 200 then - return -1 -endi -if $data09 != 200 then - return -1 -endi - - - -$st = $stPrefix . avg -sql select * from $st -print ===> select * from $st -print ===> $data01 $data02 $data03 $data04 $data05 $data06 $data07 $data08 $data09 -if $data01 != 9.500000000 then - return -1 -endi -if $data02 != 1900 then - return -1 -endi -if $data03 != 0 then - return -1 -endi -if $data04 != 19 then - return -1 -endi -if $data05 != 0 then - return -1 -endi -if $data06 != 19 then - return -1 -endi - diff --git a/tests/script/general/stream/table_1.sim b/tests/script/general/stream/table_1.sim deleted file mode 100644 index f028b1626d..0000000000 --- a/tests/script/general/stream/table_1.sim +++ /dev/null @@ -1,317 +0,0 @@ -system sh/stop_dnodes.sh - -system sh/deploy.sh -n dnode1 -i 1 -system sh/cfg.sh -n dnode1 -c walLevel -v 0 -system sh/exec.sh -n dnode1 -s start - -sleep 3000 -sql connect - -print ======================== dnode1 start - -$dbPrefix = t1_db -$tbPrefix = t1_tb -$mtPrefix = t1_mt -$stPrefix = t1_st -$tbNum = 10 -$rowNum = 20 -$totalNum = 200 - -print =============== step1 -$i = 0 -$db = $dbPrefix . $i -$mt = $mtPrefix . $i -$st = $stPrefix . $i - -sql drop databae $db -x step1 -step1: -sql create database $db -sql use $db -sql create table $mt (ts timestamp, tbcol int, tbcol2 float) TAGS(tgcol int) - -$i = 0 -while $i < $tbNum - $tb = $tbPrefix . $i - sql create table $tb using $mt tags( $i ) - - $x = -1440 - $y = 0 - while $y < $rowNum - $ms = $x . m - sql insert into $tb values (now $ms , $y , $y ) - $x = $x + 1 - $y = $y + 1 - endw - - $i = $i + 1 -endw - -sleep 100 - -print =============== step2 c1 -$i = 1 -$tb = $tbPrefix . $i - -sql select count(*) from $tb interval(1d) -print select count(*) from $tb interval(1d) ===> $data00 $data01 -if $data01 != $rowNum then - return -1 -endi - -$st = $stPrefix . c1 -sql create table $st as select count(*) from $tb interval(1d) - -print =============== step3 c2 -sql select count(tbcol) from $tb interval(1d) -print select count(tbcol) from $tb interval(1d) ===> $data00 $data01 -if $data01 != $rowNum then - return -1 -endi - -$st = $stPrefix . c2 -sql create table $st as select count(tbcol) from $tb interval(1d) - -print =============== step4 c3 -sql select count(tbcol2) from $tb interval(1d) -print select count(tbcol2) from $tb interval(1d) ===> $data00 $data01 -if $data01 != $rowNum then - return -1 -endi - -$st = $stPrefix . c3 -sql create table $st as select count(tbcol2) from $tb interval(1d) - -print =============== step5 avg -sql select avg(tbcol) from $tb interval(1d) -print select avg(tbcol) from $tb interval(1d) ===> $data00 $data01 -if $data01 != 9.500000000 then - return -1 -endi - -$st = $stPrefix . av -sql create table $st as select avg(tbcol) from $tb interval(1d) - -print =============== step6 su -sql select sum(tbcol) from $tb interval(1d) -print select sum(tbcol) from $tb interval(1d) ===> $data00 $data01 -if $data01 != 190 then - return -1 -endi - -$st = $stPrefix . su -sql create table $st as select sum(tbcol) from $tb interval(1d) - -print =============== step7 mi -sql select min(tbcol) from $tb interval(1d) -print select min(tbcol) from $tb interval(1d) ===> $data00 $data01 -if $data01 != 0 then - return -1 -endi - -$st = $stPrefix . mi -sql create table $st as select min(tbcol) from $tb interval(1d) - -print =============== step8 ma -sql select max(tbcol) from $tb interval(1d) -print select max(tbcol) from $tb interval(1d) ===> $data00 $data01 -if $data01 != 19 then - return -1 -endi - -$st = $stPrefix . ma -sql create table $st as select max(tbcol) from $tb interval(1d) - -print =============== step9 fi -sql select first(tbcol) from $tb interval(1d) -print select first(tbcol) from $tb interval(1d) ===> $data00 $data01 -if $data01 != 0 then - return -1 -endi - -$st = $stPrefix . fi -sql create table $st as select first(tbcol) from $tb interval(1d) - -print =============== step10 la -sql select last(tbcol) from $tb interval(1d) -print select last(tbcol) from $tb interval(1d) ===> $data00 $data01 -if $data01 != 19 then - return -1 -endi - -$st = $stPrefix . la -sql create table $st as select last(tbcol) from $tb interval(1d) - -print =============== step11 st -sql select stddev(tbcol) from $tb interval(1d) -print select stddev(tbcol) from $tb interval(1d) ===> $data00 $data01 -if $data01 != 5.766281297 then - return -1 -endi - -$st = $stPrefix . std -sql create table $st as select stddev(tbcol) from $tb interval(1d) - -print =============== step12 le -sql select leastsquares(tbcol, 1, 1) from $tb interval(1d) -print select leastsquares(tbcol, 1, 1) from $tb interval(1d) ===> $data00 $data01 -#if $data01 != @(0.000017, -25362055.126740)@ then -# return -1 -#endi - -$st = $stPrefix . le -sql create table $st as select leastsquares(tbcol, 1, 1) from $tb interval(1d) - -print =============== step13 -sql select top(tbcol, 1) from $tb interval(1d) - -print =============== step14 -sql select bottom(tbcol, 1) from $tb interval(1d) - -print =============== step15 pe - -sql select percentile(tbcol, 1) from $tb interval(1d) -print select percentile(tbcol, 1) from $tb interval(1d) ===> $data00 $data01 -if $data01 != 0.190000000 then - return -1 -endi - -$st = $stPrefix . pe -sql create table $st as select percentile(tbcol, 1) from $tb interval(1d) - -print =============== step16 -sql select diff(tbcol) from $tb interval(1d) -x step16 - return -1 -step16: - -print =============== step17 wh -sql select count(tbcol) from $tb where ts < now + 4m interval(1d) -print select count(tbcol) from $tb where ts < now + 4m interval(1d) ===> $data00 $data01 -if $data01 != $rowNum then - return -1 -endi - -$st = $stPrefix . wh -#sql create table $st as select count(tbcol) from $tb where ts < now + 4m interval(1d) - -print =============== step18 as -sql select count(tbcol) from $tb interval(1d) -print select count(tbcol) from $tb interval(1d) ===> $data00 $data01 -if $data01 != $rowNum then - return -1 -endi - -$st = $stPrefix . as -sql create table $st as select count(tbcol) as c from $tb interval(1d) - -print =============== step19 gb -sql select count(tbcol) from $tb interval(1d) group by tgcol -x step19 - return -1 -step19: - -print =============== step20 x -sql select count(tbcol) from $tb where ts < now + 4m interval(1d) group by tgcol -x step20 - return -1 -step20: - -print =============== step21 -print sleep 120 seconds -sleep 120000 - -print =============== step22 -$st = $stPrefix . c1 -sql select * from $st -print ===> select * from $st ===> $data00 $data01 -if $data01 != $rowNum then - return -1 -endi - -$st = $stPrefix . c2 -sql select * from $st -print ===> select * from $st ===> $data00 $data01 -if $data01 != $rowNum then - return -1 -endi - -$st = $stPrefix . c3 -sql select * from $st -print ===> select * from $st ===> $data00 $data01 -if $data01 != $rowNum then - return -1 -endi - -$st = $stPrefix . av -sql select * from $st -print ===> select * from $st ===> $data00 $data01 -if $data01 != 9.500000000 then - return -1 -endi - -$st = $stPrefix . su -sql select * from $st -print ===> select * from $st ===> $data00 $data01 -if $data01 != 190 then - return -1 -endi - -$st = $stPrefix . mi -sql select * from $st -print ===> select * from $st ===> $data00 $data01 -if $data01 != 0 then - return -1 -endi - -$st = $stPrefix . ma -sql select * from $st -print ===> select * from $st ===> $data00 $data01 -if $data01 != 19 then - return -1 -endi - -$st = $stPrefix . fi -sql select * from $st -print ===> select * from $st ===> $data00 $data01 -if $data01 != 0 then - return -1 -endi - -$st = $stPrefix . la -sql select * from $st -print ===> select * from $st ===> $data00 $data01 -if $data01 != 19 then - return -1 -endi - -$st = $stPrefix . std -sql select * from $st -print ===> select * from $st ===> $data00 $data01 -if $data01 != 5.766281297 then - return -1 -endi - -$st = $stPrefix . le -sql select * from $st -#print ===> select * from $st ===> $data00 $data01 -#if $data01 != @(0.000017, -25270086.331047)@ then -# return -1 -#endi - -$st = $stPrefix . pe -sql select * from $st -print ===> select * from $st ===> $data00 $data01 -if $data01 != 0.190000000 then - return -1 -endi - -#$st = $stPrefix . wh -#sql select * from $st -#print ===> select * from $st ===> $data00 $data01 -#if $data01 != $rowNum then -# return -1 -#endi - -$st = $stPrefix . as -sql select * from $st -print ===> select * from $st ===> $data00 $data01 -if $data01 != $rowNum then - return -1 -endi diff --git a/tests/script/general/stream/table_n.sim b/tests/script/general/stream/table_n.sim deleted file mode 100644 index a336772a98..0000000000 --- a/tests/script/general/stream/table_n.sim +++ /dev/null @@ -1,293 +0,0 @@ -system sh/stop_dnodes.sh - -system sh/deploy.sh -n dnode1 -i 1 -system sh/cfg.sh -n dnode1 -c walLevel -v 0 -system sh/exec.sh -n dnode1 -s start - -sleep 3000 -sql connect - -print ======================== dnode1 start - -$dbPrefix = tn_db -$tbPrefix = tn_tb -$mtPrefix = tn_mt -$stPrefix = tn_st -$tbNum = 10 -$rowNum = 20 -$totalNum = 200 - -print =============== step1 -$i = 0 -$db = $dbPrefix . $i -$mt = $mtPrefix . $i -$st = $stPrefix . $i - -sql drop databae $db -x step1 -step1: -sql create database $db -sql use $db -sql create table $mt (ts timestamp, tbcol int, tbcol2 float) TAGS(tgcol int) - -$i = 0 -while $i < $tbNum - $tb = $tbPrefix . $i - sql create table $tb using $mt tags( $i ) - - $x = -1440 - $y = 0 - while $y < $rowNum - $ms = $x . m - sql insert into $tb values (now $ms , $y , $y ) - $x = $x + 1 - $y = $y + 1 - endw - - $i = $i + 1 -endw - -sleep 100 - -print =============== step2 c3 -$i = 1 -$tb = $tbPrefix . $i - -sql select count(*), count(tbcol), count(tbcol2) from $tb interval(1d) -print select count(*), count(tbcol), count(tbcol2) from $tb interval(1d) ===> $data00 $data01 $data02, $data03 -if $data01 != $rowNum then - return -1 -endi -if $data02 != $rowNum then - return -1 -endi -if $data03 != $rowNum then - return -1 -endi - -$st = $stPrefix . c3 -sql create table $st as select count(*), count(tbcol), count(tbcol2) from $tb interval(1d) - -print =============== step3 count32 -#total 32 count in select -sql select count(*), count(tbcol) as c1, count(tbcol2) as c2, count(tbcol) as c3, count(tbcol) as c4, count(tbcol) as c5, count(tbcol) as c6, count(tbcol) as c7, count(tbcol) as c8, count(tbcol) as c9, count(tbcol) as c10, count(tbcol) as c11, count(tbcol) as c12, count(tbcol) as c13, count(tbcol) as c14, count(tbcol) as c15, count(tbcol) as c16, count(tbcol) as c17, count(tbcol) as c18, count(tbcol) as c19, count(tbcol) as c20, count(tbcol) as c21, count(tbcol) as c22, count(tbcol) as c23, count(tbcol) as c24, count(tbcol) as c25, count(tbcol) as c26, count(tbcol) as c27, count(tbcol) as c28, count(tbcol) as c29, count(tbcol) as c30 from $tb interval(1d) - -# total 32 count in stream -$st = $stPrefix . c32 -sql create table $st as select count(*), count(tbcol) as c1, count(tbcol2) as c2, count(tbcol) as c3, count(tbcol) as c4, count(tbcol) as c5, count(tbcol) as c6, count(tbcol) as c7, count(tbcol) as c8, count(tbcol) as c9, count(tbcol) as c10, count(tbcol) as c11, count(tbcol) as c12, count(tbcol) as c13, count(tbcol) as c14, count(tbcol) as c15, count(tbcol) as c16, count(tbcol) as c17, count(tbcol) as c18, count(tbcol) as c19, count(tbcol) as c20, count(tbcol) as c21, count(tbcol) as c22, count(tbcol) as c23, count(tbcol) as c24, count(tbcol) as c25, count(tbcol) as c26, count(tbcol) as c27, count(tbcol) as c28, count(tbcol) as c29, count(tbcol) as c30 from $tb interval(1d) - -print =============== step4 count31 - -#total 31 count in select -sql select count(*), count(tbcol) as c1, count(tbcol2) as c2, count(tbcol) as c3, count(tbcol) as c4, count(tbcol) as c5, count(tbcol) as c6, count(tbcol) as c7, count(tbcol) as c8, count(tbcol) as c9, count(tbcol) as c10, count(tbcol) as c11, count(tbcol) as c12, count(tbcol) as c13, count(tbcol) as c14, count(tbcol) as c15, count(tbcol) as c16, count(tbcol) as c17, count(tbcol) as c18, count(tbcol) as c19, count(tbcol) as c20, count(tbcol) as c21, count(tbcol) as c22, count(tbcol) as c23, count(tbcol) as c24, count(tbcol) as c25, count(tbcol) as c26, count(tbcol) as c27, count(tbcol) as c28, count(tbcol) as c29, count(tbcol) as c30 from $tb interval(1d) -print ===> $data00 $data01 $data02, $data03 -if $data01 != $rowNum then - return -1 -endi -if $data02 != $rowNum then - return -1 -endi -if $data03 != $rowNum then - return -1 -endi - -# total 31 count in stream will crash, 32 will error -$st = $stPrefix . c31 -sql create table $st as select count(*), count(tbcol) as c1, count(tbcol2) as c2, count(tbcol) as c3, count(tbcol) as c4, count(tbcol) as c5, count(tbcol) as c6, count(tbcol) as c7, count(tbcol) as c8, count(tbcol) as c9, count(tbcol) as c10, count(tbcol) as c11, count(tbcol) as c12, count(tbcol) as c13, count(tbcol) as c14, count(tbcol) as c15, count(tbcol) as c16, count(tbcol) as c17, count(tbcol) as c18, count(tbcol) as c19, count(tbcol) as c20, count(tbcol) as c21, count(tbcol) as c22, count(tbcol) as c23, count(tbcol) as c24, count(tbcol) as c25, count(tbcol) as c26, count(tbcol) as c27, count(tbcol) as c28, count(tbcol) as c29, count(tbcol) as c30 from $tb interval(1d) - -print =============== step5 avg ... -sql select avg(tbcol), sum(tbcol), min(tbcol), max(tbcol), first(tbcol), last(tbcol) from $tb interval(1d) -print ===> $data01 $data02 $data03 $data04 $data05 $data06 -if $data01 != 9.500000000 then - return -1 -endi -if $data02 != 190 then - return -1 -endi -if $data03 != 0 then - return -1 -endi -if $data04 != 19 then - return -1 -endi -if $data05 != 0 then - return -1 -endi -if $data06 != 19 then - return -1 -endi - -$st = $stPrefix . avg -sql create table $st as select avg(tbcol), sum(tbcol), min(tbcol), max(tbcol), first(tbcol), last(tbcol) from $tb interval(1d) - -print =============== step6 others -sql select stddev(tbcol), leastsquares(tbcol, 1, 1), percentile(tbcol, 1) from $tb interval(1d) -print ===> $data01 $data02 $data03 -if $data01 != 5.766281297 then - return -1 -endi -#if $data02 != @(0.000017, -25362055.126740)@ then -# return -1 -#endi -if $data03 != 0.190000000 then - return -1 -endi - -$st = $stPrefix . ot -sql create table $st as select stddev(tbcol), leastsquares(tbcol, 1, 1), percentile(tbcol, 1) from $tb interval(1d) - -print =============== step7 total ... -sql select avg(tbcol), sum(tbcol), min(tbcol), max(tbcol), first(tbcol), last(tbcol), stddev(tbcol), percentile(tbcol, 1), count(tbcol), leastsquares(tbcol, 1, 1) from $tb interval(1d) -print ===> $data01 $data02 $data03 $data04 $data05 $data06 $data07 $data08 $data09 -if $data01 != 9.500000000 then - return -1 -endi -if $data02 != 190 then - return -1 -endi -if $data03 != 0 then - return -1 -endi -if $data04 != 19 then - return -1 -endi -if $data05 != 0 then - return -1 -endi -if $data06 != 19 then - return -1 -endi -if $data07 != 5.766281297 then - return -1 -endi -if $data08 != 0.190000000 then - return -1 -endi -if $data09 != 20 then - return -1 -endi - -$st = $stPrefix . to -sql create table $st as select avg(tbcol), sum(tbcol), min(tbcol), max(tbcol), first(tbcol), last(tbcol), stddev(tbcol), percentile(tbcol, 1), count(tbcol), leastsquares(tbcol, 1, 1) from $tb interval(1d) - -print =============== step8 where -sql select avg(tbcol), sum(tbcol), min(tbcol), max(tbcol), first(tbcol), last(tbcol), stddev(tbcol), percentile(tbcol, 1), count(tbcol), leastsquares(tbcol, 1, 1) from $tb where ts < now + 4m interval(1d) -print ===> $data01 $data02 $data03 $data04 $data05 $data06 $data07 $data08 $data09 -if $data09 != 20 then - return -1 -endi - -$st = $stPrefix . wh -sql create table $st as select avg(tbcol), sum(tbcol), min(tbcol), max(tbcol), first(tbcol), last(tbcol), stddev(tbcol), percentile(tbcol, 1), count(tbcol), leastsquares(tbcol, 1, 1) from $tb where ts < now + 4m interval(1d) - - -print =============== step9 as -sql select avg(tbcol), sum(tbcol), min(tbcol), max(tbcol), first(tbcol), last(tbcol), stddev(tbcol), percentile(tbcol, 1), count(tbcol), leastsquares(tbcol, 1, 1) from $tb where ts < now + 4m interval(1d) -print ===> $data01 $data02 $data03 $data04 $data05 $data06 $data07 $data08 $data09 -if $data09 != 20 then - return -1 -endi - -$st = $stPrefix . as -#sql create table $st as select avg(tbcol) as a1, sum(tbcol) as a2, min(tbcol) as a3, max(tbcol) as a4, first(tbcol) as a5, last(tbcol) as a6, stddev(tbcol) as a7, percentile(tbcol, 1) as a8, count(tbcol) as a9, leastsquares(tbcol, 1, 1) as a10 from $tb where ts < now + 4m interval(1d) - -print =============== step10 -print sleep 120 seconds -sleep 120000 - -print =============== step11 -$st = $stPrefix . c3 -sql select * from $st -print ===> select * from $st -print ===> $data01 $data02 $data03 $data04 $data05 $data06 $data07 $data08 $data09 -if $data01 != $rowNum then - return -1 -endi -if $data02 != $rowNum then - return -1 -endi -if $data03 != $rowNum then - return -1 -endi - -$st = $stPrefix . c31 -sql select * from $st -if $data01 != $rowNum then - return -1 -endi -if $data02 != $rowNum then - return -1 -endi -if $data03 != $rowNum then - return -1 -endi - -$st = $stPrefix . avg -sql select * from $st -print ===> select * from $st -print ===> $data01 $data02 $data03 $data04 $data05 $data06 $data07 $data08 $data09 -if $data01 != 9.500000000 then - return -1 -endi -if $data02 != 190 then - return -1 -endi -if $data03 != 0 then - return -1 -endi -if $data04 != 19 then - return -1 -endi -if $data05 != 0 then - return -1 -endi -if $data06 != 19 then - return -1 -endi - -$st = $stPrefix . ot -sql select * from $st -print ===> select * from $st -print ===> $data01 $data02 $data03 $data04 $data05 $data06 $data07 $data08 $data09 -if $data01 != 5.766281297 then - return -1 -endi -#if $data02 != @(0.000017, -25362055.126740)@ then -# return -1 -#endi -if $data03 != 0.190000000 then - return -1 -endi - -$st = $stPrefix . to -sql select * from $st -print ===> select * from $st -print ===> $data01 $data02 $data03 $data04 $data05 $data06 $data07 $data08 $data09 -if $data01 != 9.500000000 then - return -1 -endi -if $data02 != 190 then - return -1 -endi -if $data03 != 0 then - return -1 -endi -if $data04 != 19 then - return -1 -endi -if $data05 != 0 then - return -1 -endi -if $data06 != 19 then - return -1 -endi -if $data07 != 5.766281297 then - return -1 -endi -if $data08 != 0.190000000 then - return -1 -endi -if $data09 != 20 then - return -1 -endi - -system sh/exec.sh -n dnode1 -s stop -x SIGINT \ No newline at end of file diff --git a/tests/script/general/stream/testSuite.sim b/tests/script/general/stream/testSuite.sim index 44f886d02b..4a9912b848 100644 --- a/tests/script/general/stream/testSuite.sim +++ b/tests/script/general/stream/testSuite.sim @@ -1,8 +1,5 @@ run general/stream/stream_3.sim run general/stream/stream_restart.sim -run general/stream/table_1.sim -run general/stream/table_n.sim -run general/stream/metrics_n.sim run general/stream/table_del.sim run general/stream/metrics_del.sim run general/stream/table_replica1_vnoden.sim diff --git a/tests/script/jenkins/basic.txt b/tests/script/jenkins/basic.txt index ccfed3da8d..363f4899b2 100644 --- a/tests/script/jenkins/basic.txt +++ b/tests/script/jenkins/basic.txt @@ -330,16 +330,12 @@ cd ../../../debug; make ./test.sh -f unique/vnode/replica3_repeat.sim ./test.sh -f unique/vnode/replica3_vgroup.sim -./test.sh -f general/parser/stream_on_sys.sim ./test.sh -f general/stream/metrics_del.sim -./test.sh -f general/stream/metrics_n.sim ./test.sh -f general/stream/metrics_replica1_vnoden.sim ./test.sh -f general/stream/restart_stream.sim ./test.sh -f general/stream/stream_3.sim ./test.sh -f general/stream/stream_restart.sim -./test.sh -f general/stream/table_1.sim ./test.sh -f general/stream/table_del.sim -./test.sh -f general/stream/table_n.sim ./test.sh -f general/stream/table_replica1_vnoden.sim ./test.sh -f unique/arbitrator/check_cluster_cfg_para.sim diff --git a/tests/script/jenkins/basic_3.txt b/tests/script/jenkins/basic_3.txt index 59ed486d20..d566766dc5 100644 --- a/tests/script/jenkins/basic_3.txt +++ b/tests/script/jenkins/basic_3.txt @@ -66,14 +66,10 @@ ./test.sh -f unique/mnode/mgmt34.sim ./test.sh -f unique/mnode/mgmtr2.sim -./test.sh -f general/parser/stream_on_sys.sim ./test.sh -f general/stream/metrics_del.sim -./test.sh -f general/stream/metrics_n.sim ./test.sh -f general/stream/metrics_replica1_vnoden.sim ./test.sh -f general/stream/restart_stream.sim ./test.sh -f general/stream/stream_3.sim ./test.sh -f general/stream/stream_restart.sim -./test.sh -f general/stream/table_1.sim ./test.sh -f general/stream/table_del.sim -./test.sh -f general/stream/table_n.sim ./test.sh -f general/stream/table_replica1_vnoden.sim diff --git a/tests/script/jenkins/simple.txt b/tests/script/jenkins/simple.txt index 2fe364bf26..ec0a526774 100644 --- a/tests/script/jenkins/simple.txt +++ b/tests/script/jenkins/simple.txt @@ -147,7 +147,6 @@ cd ../../../debug; make ./test.sh -f general/parser/join_multivnode.sim ./test.sh -f general/parser/binary_escapeCharacter.sim ./test.sh -f general/parser/bug.sim -#./test.sh -f general/parser/stream_on_sys.sim ./test.sh -f general/parser/repeatAlter.sim #./test.sh -f general/parser/repeatStream.sim diff --git a/tests/script/regressionSuite.sim b/tests/script/regressionSuite.sim index ff1f9f5355..6d1fd7aacb 100644 --- a/tests/script/regressionSuite.sim +++ b/tests/script/regressionSuite.sim @@ -134,7 +134,6 @@ run general/parser/tags_dynamically_specifiy.sim run general/parser/set_tag_vals.sim run general/parser/repeatAlter.sim ##unsupport run general/parser/slimit_alter_tags.sim -##unsupport run general/parser/stream_on_sys.sim run general/parser/stream.sim #unsupport run general/parser/repeatStream.sim run general/stable/disk.sim @@ -214,14 +213,8 @@ run general/vector/table_mix.sim run general/vector/table_query.sim run general/vector/table_time.sim run general/stream/restart_stream.sim -run general/stream/stream_1.sim -run general/stream/stream_2.sim run general/stream/stream_3.sim run general/stream/stream_restart.sim -run general/stream/table_1.sim -run general/stream/metrics_1.sim -run general/stream/table_n.sim -run general/stream/metrics_n.sim run general/stream/table_del.sim run general/stream/metrics_del.sim run general/stream/table_replica1_vnoden.sim From 616b4ee229a9b6e752680dc74e13e6e3564c3bfc Mon Sep 17 00:00:00 2001 From: Bomin Zhang Date: Wed, 30 Dec 2020 07:58:33 +0000 Subject: [PATCH 27/29] [TD-2585]: fix failed test case --- tests/pytest/stream/sys.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/pytest/stream/sys.py b/tests/pytest/stream/sys.py index 9202e2a9c0..ecbcb651b1 100644 --- a/tests/pytest/stream/sys.py +++ b/tests/pytest/stream/sys.py @@ -20,6 +20,8 @@ from util.sql import tdSql class TDTestCase: + updatecfgDict = {'monitor': 1} + def init(self, conn, logSql): tdLog.debug("start to execute %s" % __file__) tdSql.init(conn.cursor(), logSql) From 782fea6c42ec6550c847fad60c3b3174cd0be7fd Mon Sep 17 00:00:00 2001 From: Bomin Zhang Date: Wed, 30 Dec 2020 07:59:31 +0000 Subject: [PATCH 28/29] [TD-2585]: remove deleted cases from test suit --- tests/script/fullGeneralSuite.sim | 1 - tests/script/general/parser/repeatStream.sim | 9 --------- tests/script/general/parser/testSuite.sim | 5 ----- tests/script/jenkins/simple.txt | 1 - tests/script/regressionSuite.sim | 2 -- 5 files changed, 18 deletions(-) delete mode 100644 tests/script/general/parser/repeatStream.sim diff --git a/tests/script/fullGeneralSuite.sim b/tests/script/fullGeneralSuite.sim index 707869d115..cde51ebdbf 100644 --- a/tests/script/fullGeneralSuite.sim +++ b/tests/script/fullGeneralSuite.sim @@ -134,7 +134,6 @@ run general/parser/tags_dynamically_specifiy.sim run general/parser/set_tag_vals.sim #unsupport run general/parser/repeatAlter.sim #unsupport run general/parser/slimit_alter_tags.sim -#unsupport run general/parser/repeatStream.sim run general/stable/disk.sim run general/stable/dnode3.sim run general/stable/metrics.sim diff --git a/tests/script/general/parser/repeatStream.sim b/tests/script/general/parser/repeatStream.sim deleted file mode 100644 index 616679e78b..0000000000 --- a/tests/script/general/parser/repeatStream.sim +++ /dev/null @@ -1,9 +0,0 @@ -$i = 1 -$repeats = 5 -while $i <= $repeats - print ====== repeat: $i - run general/parser/stream.sim - $i = $i + 1 -endw - -system sh/exec.sh -n dnode1 -s stop -x SIGINT \ No newline at end of file diff --git a/tests/script/general/parser/testSuite.sim b/tests/script/general/parser/testSuite.sim index 971c103cf5..a2cf305fae 100644 --- a/tests/script/general/parser/testSuite.sim +++ b/tests/script/general/parser/testSuite.sim @@ -105,8 +105,3 @@ sleep 500 run general/parser/sliding.sim sleep 500 run general/parser/function.sim - -#sleep 500 -#run general/parser/repeatStream.sim -#sleep 500 -#run general/parser/stream.sim \ No newline at end of file diff --git a/tests/script/jenkins/simple.txt b/tests/script/jenkins/simple.txt index ec0a526774..88ff4d6601 100644 --- a/tests/script/jenkins/simple.txt +++ b/tests/script/jenkins/simple.txt @@ -148,7 +148,6 @@ cd ../../../debug; make ./test.sh -f general/parser/binary_escapeCharacter.sim ./test.sh -f general/parser/bug.sim ./test.sh -f general/parser/repeatAlter.sim -#./test.sh -f general/parser/repeatStream.sim ./test.sh -f general/stable/disk.sim ./test.sh -f general/stable/dnode3.sim diff --git a/tests/script/regressionSuite.sim b/tests/script/regressionSuite.sim index 6d1fd7aacb..e5e2194e87 100644 --- a/tests/script/regressionSuite.sim +++ b/tests/script/regressionSuite.sim @@ -134,8 +134,6 @@ run general/parser/tags_dynamically_specifiy.sim run general/parser/set_tag_vals.sim run general/parser/repeatAlter.sim ##unsupport run general/parser/slimit_alter_tags.sim -run general/parser/stream.sim -#unsupport run general/parser/repeatStream.sim run general/stable/disk.sim run general/stable/dnode3.sim run general/stable/metrics.sim From 45f26e66b4363b90c0dc0ff999ff06f4ba99fe25 Mon Sep 17 00:00:00 2001 From: liuyq-617 Date: Thu, 31 Dec 2020 11:03:47 +0800 Subject: [PATCH 29/29] relo --- .travis.yml | 8 ++++---- tests/script/jenkins/basic_1.txt | 2 ++ tests/script/jenkins/basic_2.txt | 16 +++++++++++++++- tests/script/jenkins/basic_3.txt | 4 ++-- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index eb69370418..f6a3900f7a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -146,7 +146,7 @@ matrix: branch_pattern: coverity_scan - os: linux - dist: trusty + dist: xenial language: c git: - depth: 1 @@ -157,7 +157,7 @@ matrix: - build-essential - cmake env: - - DESC="trusty/gcc-4.8 build" + - DESC="xenial build" before_script: - export TZ=Asia/Harbin @@ -227,7 +227,7 @@ matrix: - os: linux arch: arm64 - dist: trusty + dist: xenial language: c git: - depth: 1 @@ -238,7 +238,7 @@ matrix: - build-essential - cmake env: - - DESC="trusty/gcc-4.8 build" + - DESC="xenial build" before_script: - export TZ=Asia/Harbin diff --git a/tests/script/jenkins/basic_1.txt b/tests/script/jenkins/basic_1.txt index 765e713916..9820a00f40 100644 --- a/tests/script/jenkins/basic_1.txt +++ b/tests/script/jenkins/basic_1.txt @@ -150,6 +150,8 @@ ./test.sh -f general/parser/repeatAlter.sim ./test.sh -f general/parser/union.sim ./test.sh -f general/parser/topbot.sim +./test.sh -f general/db/nosuchfile.sim +./test.sh -f general/parser/function.sim ./test.sh -f general/stable/disk.sim ./test.sh -f general/stable/dnode3.sim diff --git a/tests/script/jenkins/basic_2.txt b/tests/script/jenkins/basic_2.txt index 014313fafe..4f5651219b 100644 --- a/tests/script/jenkins/basic_2.txt +++ b/tests/script/jenkins/basic_2.txt @@ -26,6 +26,9 @@ cd ../../../debug; make ./test.sh -f general/tag/set.sim ./test.sh -f general/tag/smallint.sim ./test.sh -f general/tag/tinyint.sim +./test.sh -f general/wal/sync.sim +./test.sh -f general/wal/kill.sim +./test.sh -f general/wal/maxtables.sim ./test.sh -f general/user/authority.sim ./test.sh -f general/user/monitor.sim @@ -87,4 +90,15 @@ cd ../../../debug; make ./test.sh -f unique/vnode/replica2_repeat.sim ./test.sh -f unique/vnode/replica3_basic.sim ./test.sh -f unique/vnode/replica3_repeat.sim -./test.sh -f unique/vnode/replica3_vgroup.sim \ No newline at end of file +./test.sh -f unique/vnode/replica3_vgroup.sim + +./test.sh -f unique/dnode/monitor.sim +./test.sh -f unique/dnode/monitor_bug.sim +./test.sh -f unique/dnode/simple.sim +./test.sh -f unique/dnode/data1.sim +./test.sh -f unique/dnode/m2.sim +./test.sh -f unique/dnode/m3.sim +./test.sh -f unique/dnode/offline3.sim +./test.sh -f general/wal/sync.sim +./test.sh -f general/wal/kill.sim +./test.sh -f general/wal/maxtables.sim \ No newline at end of file diff --git a/tests/script/jenkins/basic_3.txt b/tests/script/jenkins/basic_3.txt index 59ed486d20..19a376e569 100644 --- a/tests/script/jenkins/basic_3.txt +++ b/tests/script/jenkins/basic_3.txt @@ -60,8 +60,8 @@ ./test.sh -f unique/mnode/mgmt22.sim ./test.sh -f unique/mnode/mgmt23.sim ./test.sh -f unique/mnode/mgmt24.sim -#./test.sh -f unique/mnode/mgmt25.sim -#./test.sh -f unique/mnode/mgmt26.sim +./test.sh -f unique/mnode/mgmt25.sim +./test.sh -f unique/mnode/mgmt26.sim ./test.sh -f unique/mnode/mgmt33.sim ./test.sh -f unique/mnode/mgmt34.sim ./test.sh -f unique/mnode/mgmtr2.sim