taosdemo.c 34.5 KB
Newer Older
H
hzcheng 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
 *
 * This program is free software: you can use, redistribute, and/or modify
 * it under the terms of the GNU Affero General Public License, version 3
 * or later ("AGPL"), as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

S
slguan 已提交
16
#define _GNU_SOURCE
H
hzcheng 已提交
17 18 19

#include <argp.h>
#include <assert.h>
L
lihui 已提交
20
#include <inttypes.h>
S
#1022  
slguan 已提交
21 22

#ifndef _ALPINE
H
hzcheng 已提交
23
#include <error.h>
F
Frozen 已提交
24
#endif
H
hzcheng 已提交
25 26 27 28 29 30 31 32 33 34 35 36
#include <pthread.h>
#include <semaphore.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include <wordexp.h>

#include "taos.h"
H
Hui Li 已提交
37
#include "tutil.h"
S
slguan 已提交
38 39 40

extern char configDir[];

H
hzcheng 已提交
41 42 43 44 45 46
#define BUFFER_SIZE      65536
#define MAX_DB_NAME_SIZE 64
#define MAX_TB_NAME_SIZE 64
#define MAX_DATA_SIZE    1024
#define MAX_NUM_DATATYPE 8
#define OPT_ABORT        1 /* –abort */
47
#define STRING_LEN       512
H
hzcheng 已提交
48 49 50 51 52 53

/* The options we understand. */
static struct argp_option options[] = {
  {0, 'h', "host",                     0, "The host to connect to TDEngine. Default is localhost.",                                                           0},
  {0, 'p', "port",                     0, "The TCP/IP port number to use for the connection. Default is 0.",                                                  1},
  {0, 'u', "user",                     0, "The TDEngine user name to use when connecting to the server. Default is 'root'.",                                  2},
S
Shuaiqiang Chang 已提交
54 55
  {0, 'P', "password",                 0, "The password to use when connecting to the server. Default is 'taosdata'.",                                        3},
  {0, 'd', "database",                 0, "Destination database. Default is 'test'.",                                                                         3},
H
hzcheng 已提交
56 57 58 59 60 61
  {0, 'm', "table_prefix",             0, "Table prefix name. Default is 't'.",                                                                               3},
  {0, 'M', 0,                          0, "Use metric flag.",                                                                                                 13},
  {0, 'o', "outputfile",               0, "Direct output to the named file. Default is './output.txt'.",                                                      14},
  {0, 'q', "query_mode",               0, "Query mode--0: SYNC, 1: ASYNC. Default is SYNC.",                                                                  6},
  {0, 'b', "type_of_cols",             0, "The data_type of columns: 'INT', 'TINYINT', 'SMALLINT', 'BIGINT', 'FLOAT', 'DOUBLE', 'BINARY'. Default is 'INT'.", 7},
  {0, 'w', "length_of_binary",         0, "The length of data_type 'BINARY'. Only applicable when type of cols is 'BINARY'. Default is 8",                    8},
62
  {0, 'l', "num_of_cols_per_record",   0, "The number of columns per record. Default is 3.",                                                                  8},
S
Shuaiqiang Chang 已提交
63
  {0, 'T', "num_of_threads",           0, "The number of threads. Default is 10.",                                                                            9},
S
slguan 已提交
64 65 66
  {0, 'r', "num_of_records_per_req",   0, "The number of records per request. Default is 1000.",                                                              10},
  {0, 't', "num_of_tables",            0, "The number of tables. Default is 10000.",                                                                          11},
  {0, 'n', "num_of_records_per_table", 0, "The number of records per table. Default is 100000.",                                                              12},
S
Shuaiqiang Chang 已提交
67
  {0, 'c', "config_directory",         0, "Configuration directory. Default is '/etc/taos/'.",                                                                14},
H
hzcheng 已提交
68
  {0, 'x', 0,                          0, "Insert only flag.",                                                                                                13},
S
Shuaiqiang Chang 已提交
69 70 71
  {0, 'O', "order",                    0, "Insert mode--0: In order, 1: Out of order. Default is in order.",                                                  14},
  {0, 'R', "rate",                     0, "Out of order data's rate--if order=1 Default 10, min: 0, max: 50.",                                                14},
  {0, 'D', "delete table",             0, "Delete data methods——0: don't delete, 1: delete by table, 2: delete by stable, 3: delete by database",             14},
H
hzcheng 已提交
72 73 74
  {0}};

/* Used by main to communicate with parse_opt. */
75
typedef struct DemoArguments {
H
hzcheng 已提交
76
  char  *host;
L
lihui 已提交
77
  uint16_t    port;
H
hzcheng 已提交
78 79 80 81 82 83 84 85
  char  *user;
  char  *password;
  char  *database;
  char  *tb_prefix;
  bool   use_metric;
  bool   insert_only;
  char  *output_file;
  int    mode;
H
Hui Li 已提交
86
  char  *datatype[MAX_NUM_DATATYPE+1];
H
hzcheng 已提交
87 88
  int    len_of_binary;
  int    num_of_CPR;
S
Shuaiqiang Chang 已提交
89
  int    num_of_threads;
H
hzcheng 已提交
90 91 92 93
  int    num_of_RPR;
  int    num_of_tables;
  int    num_of_DPT;
  int    abort;
S
Shuaiqiang Chang 已提交
94 95
  int    order;
  int    rate;
S
Shuaiqiang Chang 已提交
96
  int    method_of_delete;
H
hzcheng 已提交
97
  char **arg_list;
98
} SDemoArguments;
H
hzcheng 已提交
99 100 101 102 103

/* 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. */
104
  SDemoArguments *arguments = state->input;
H
hzcheng 已提交
105 106 107 108 109 110 111 112 113 114 115 116
  wordexp_t full_path;
  char **sptr;
  switch (key) {
    case 'h':
      arguments->host = arg;
      break;
    case 'p':
      arguments->port = atoi(arg);
      break;
    case 'u':
      arguments->user = arg;
      break;
S
Shuaiqiang Chang 已提交
117
    case 'P':
H
hzcheng 已提交
118 119 120 121 122 123 124 125
      arguments->password = arg;
      break;
    case 'o':
      arguments->output_file = arg;
      break;
    case 'q':
      arguments->mode = atoi(arg);
      break;
S
Shuaiqiang Chang 已提交
126 127
    case 'T':
      arguments->num_of_threads = atoi(arg);
H
hzcheng 已提交
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
      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, "BIGINT") != 0 && strcasecmp(arg, "DOUBLE") != 0 &&
            strcasecmp(arg, "BINARY")) {
          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, "BIGINT") != 0 &&
              strcasecmp(token, "DOUBLE") != 0 && strcasecmp(token, "BINARY")) {
            argp_error(state, "Invalid data_type!");
          }
          sptr[index++] = token;
          token = strsep(&running, ", ");
        }
      }
      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 = true;
      break;
S
Shuaiqiang Chang 已提交
187
    case 'c':
H
hzcheng 已提交
188 189 190 191
      if (wordexp(arg, &full_path, 0) != 0) {
        fprintf(stderr, "Invalid path %s\n", arg);
        return -1;
      }
192
      taos_options(TSDB_OPTION_CONFIGDIR, full_path.we_wordv[0]);
H
hzcheng 已提交
193 194
      wordfree(&full_path);
      break;
S
Shuaiqiang Chang 已提交
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
    case 'O':
      arguments->order = atoi(arg);
      if (arguments->order > 1 || arguments->order < 0)
      {
        arguments->order = 0;
      } else if (arguments->order == 1)
      {
        arguments->rate = 10;
      }
      break;
    case 'R':
      arguments->rate = atoi(arg);
      if (arguments->order == 1 && (arguments->rate > 50 || arguments->rate <= 0))
      {
        arguments->rate = 10;
      }
      break;
S
Shuaiqiang Chang 已提交
212 213 214 215 216 217 218
    case 'D':
      arguments->method_of_delete = atoi(arg);
      if (arguments->method_of_delete < 0 || arguments->method_of_delete > 3)
      {
        arguments->method_of_delete = 0;
      }
      break;
H
hzcheng 已提交
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
    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;
}

/* ******************************* Structure
 * definition*******************************  */
enum MODE {
  SYNC, ASYNC
};
typedef struct {
  TAOS *taos;
  int threadID;
  char db_name[MAX_DB_NAME_SIZE];
  char fp[4096];
  char **datatype;
  int len_of_binary;
  char tb_prefix[MAX_TB_NAME_SIZE];
  int start_table_id;
  int end_table_id;
  int ncols_per_record;
  int nrecords_per_table;
  int nrecords_per_request;
S
Shuaiqiang Chang 已提交
252 253
  int data_of_order;
  int data_of_rate;
S
slguan 已提交
254
  int64_t start_time;
H
hzcheng 已提交
255 256 257 258 259 260 261 262 263 264 265
  bool do_aggreFunc;

  sem_t mutex_sem;
  int notFinished;
  sem_t lock_sem;
} info;

typedef struct {
  TAOS  *taos;

  char   tb_name[MAX_TB_NAME_SIZE];
S
slguan 已提交
266
  int64_t   timestamp;
H
hzcheng 已提交
267 268 269 270 271 272
  int    target;
  int    counter;
  int    nrecords_per_request;
  int    ncols_per_record;
  char **data_type;
  int    len_of_binary;
S
Shuaiqiang Chang 已提交
273 274
  int data_of_order;
  int data_of_rate;
H
hzcheng 已提交
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296

  sem_t *mutex_sem;
  int   *notFinished;
  sem_t *lock_sem;
} sTable;

/* ******************************* Global
 * variables*******************************  */
char *aggreFunc[] = {"*", "count(*)", "avg(f1)", "sum(f1)", "max(f1)", "min(f1)", "first(f1)", "last(f1)"};

/* ******************************* Global
 * functions*******************************  */
static struct argp argp = {options, parse_opt, 0, 0};

void queryDB(TAOS *taos, char *command);

void *readTable(void *sarg);

void *readMetric(void *sarg);

void *syncWrite(void *sarg);

S
Shuaiqiang Chang 已提交
297 298
void *deleteTable();

H
hzcheng 已提交
299 300
void *asyncWrite(void *sarg);

301
int generateData(char *res, char **data_type, int num_of_cols, int64_t timestamp, int len_of_binary);
H
hzcheng 已提交
302 303 304 305 306 307 308 309

void rand_string(char *str, int size);

double getCurrentTime();

void callBack(void *param, TAOS_RES *res, int code);

int main(int argc, char *argv[]) {
310
  SDemoArguments arguments = {  NULL,            // host
H
Hongze Cheng 已提交
311 312 313 314 315 316 317 318 319 320 321
                                0,               // port
                                "root",          // user
                                "taosdata",      // password
                                "test",          // database
                                "t",             // tb_prefix
                                false,           // use_metric
                                false,           // insert_only
                                "./output.txt",  // output_file
                                0,               // mode
                                {
                                "int",           // datatype
H
hzcheng 已提交
322 323 324 325 326 327
                                "",
                                "",
                                "",
                                "",
                                "",
                                "",
H
Hongze Cheng 已提交
328 329 330 331
                                ""
                                },
                                8,               // len_of_binary
                                1,               // num_of_CPR
S
Shuaiqiang Chang 已提交
332
                                1,               // num_of_connections/thread
H
Hongze Cheng 已提交
333 334 335 336
                                1,               // num_of_RPR
                                1,               // num_of_tables
                                50000,           // num_of_DPT
                                0,               // abort
S
Shuaiqiang Chang 已提交
337 338
                                0,               // order
                                0,               // rate
S
Shuaiqiang Chang 已提交
339
                                0,               // method_of_delete
H
Hongze Cheng 已提交
340 341
                                NULL             // arg_list
                                };
H
hzcheng 已提交
342 343 344

  /* Parse our arguments; every option seen by parse_opt will be
     reflected in arguments. */
345
  // For demo use, change default values for some parameters;
346
  arguments.num_of_tables = 10000;
347
  arguments.num_of_CPR = 3; 
S
Shuaiqiang Chang 已提交
348
  arguments.num_of_threads = 10;
349 350
  arguments.num_of_DPT = 100000;
  arguments.num_of_RPR = 1000;
351 352
  arguments.use_metric = true;
  arguments.insert_only = true;
S
slguan 已提交
353
  // end change
354

H
hzcheng 已提交
355 356
  argp_parse(&argp, argc, argv, 0, 0, &arguments);

F
Frozen 已提交
357
  if (arguments.abort) {
S
#1022  
slguan 已提交
358
    #ifndef _ALPINE
F
Frozen 已提交
359 360 361 362 363
      error(10, 0, "ABORTED");
    #else
      abort();
    #endif
  }
364
  
H
hzcheng 已提交
365 366
  enum MODE query_mode = arguments.mode;
  char *ip_addr = arguments.host;
L
lihui 已提交
367
  uint16_t port = arguments.port;
H
hzcheng 已提交
368 369 370 371 372 373
  char *user = arguments.user;
  char *pass = arguments.password;
  char *db_name = arguments.database;
  char *tb_prefix = arguments.tb_prefix;
  int len_of_binary = arguments.len_of_binary;
  int ncols_per_record = arguments.num_of_CPR;
S
Shuaiqiang Chang 已提交
374 375
  int order = arguments.order;
  int rate = arguments.rate;
S
Shuaiqiang Chang 已提交
376
  int method_of_delete = arguments.method_of_delete;
H
hzcheng 已提交
377
  int ntables = arguments.num_of_tables;
S
Shuaiqiang Chang 已提交
378
  int threads = arguments.num_of_threads;
H
hzcheng 已提交
379 380 381 382 383 384
  int nrecords_per_table = arguments.num_of_DPT;
  int nrecords_per_request = arguments.num_of_RPR;
  bool use_metric = arguments.use_metric;
  bool insert_only = arguments.insert_only;
  char **data_type = arguments.datatype;
  int count_data_type = 0;
385
  char dataString[STRING_LEN];
H
hzcheng 已提交
386
  bool do_aggreFunc = true;
387

388 389
  memset(dataString, 0, STRING_LEN);
  int len = 0;
390

H
hzcheng 已提交
391 392 393 394 395 396 397
  if (strcasecmp(data_type[0], "BINARY") == 0 || strcasecmp(data_type[0], "BOOL") == 0) {
    do_aggreFunc = false;
  }
  for (; count_data_type <= MAX_NUM_DATATYPE; count_data_type++) {
    if (strcasecmp(data_type[count_data_type], "") == 0) {
      break;
    }
398 399

    len += snprintf(dataString + len, STRING_LEN - len, "%s ", data_type[count_data_type]);
H
hzcheng 已提交
400 401 402
  }

  FILE *fp = fopen(arguments.output_file, "a");
403 404 405 406 407
  if (NULL == fp) {
    fprintf(stderr, "Failed to open %s for writing\n", arguments.output_file);
    return 1;
  };
  
H
hzcheng 已提交
408 409
  time_t tTime = time(NULL);
  struct tm tm = *localtime(&tTime);
S
Shuaiqiang Chang 已提交
410 411 412 413 414 415 416 417 418
  printf("###################################################################\n");
  printf("# Server IP:                         %s:%hu\n", ip_addr == NULL ? "localhost" : ip_addr, port);
  printf("# User:                              %s\n", user);
  printf("# Password:                          %s\n", pass);
  printf("# Use metric:                        %s\n", use_metric ? "true" : "false");
  printf("# Datatype of Columns:               %s\n", dataString);
  printf("# Binary Length(If applicable):      %d\n",
          (strcasestr(dataString, "BINARY") != NULL) ? len_of_binary : -1);
  printf("# Number of Columns per record:      %d\n", ncols_per_record);
S
Shuaiqiang Chang 已提交
419
  printf("# Number of Threads:                 %d\n", threads);
S
Shuaiqiang Chang 已提交
420 421 422 423 424
  printf("# Number of Tables:                  %d\n", ntables);
  printf("# Number of Data per Table:          %d\n", nrecords_per_table);
  printf("# Records/Request:                   %d\n", nrecords_per_request);
  printf("# Database name:                     %s\n", db_name);
  printf("# Table prefix:                      %s\n", tb_prefix);
S
Shuaiqiang Chang 已提交
425 426
  if (order == 1)
  {
S
Shuaiqiang Chang 已提交
427 428
    printf("# Data order:                        %d\n", order);
    printf("# Data out of order rate:            %d\n", rate);
S
Shuaiqiang Chang 已提交
429 430

  }
S
Shuaiqiang Chang 已提交
431
  printf("# Delete method:                     %d\n", method_of_delete);
S
Shuaiqiang Chang 已提交
432 433 434 435
  printf("# Test time:                         %d-%02d-%02d %02d:%02d:%02d\n", tm.tm_year + 1900, tm.tm_mon + 1,
          tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
  printf("###################################################################\n\n");
  printf("Press enter key to continue");
H
Hui Li 已提交
436
  (void)getchar();
H
hzcheng 已提交
437 438

  fprintf(fp, "###################################################################\n");
L
lihui 已提交
439
  fprintf(fp, "# Server IP:                         %s:%hu\n", ip_addr == NULL ? "localhost" : ip_addr, port);
H
hzcheng 已提交
440 441 442 443 444 445 446
  fprintf(fp, "# User:                              %s\n", user);
  fprintf(fp, "# Password:                          %s\n", pass);
  fprintf(fp, "# Use metric:                        %s\n", use_metric ? "true" : "false");
  fprintf(fp, "# Datatype of Columns:               %s\n", dataString);
  fprintf(fp, "# Binary Length(If applicable):      %d\n",
          (strcasestr(dataString, "BINARY") != NULL) ? len_of_binary : -1);
  fprintf(fp, "# Number of Columns per record:      %d\n", ncols_per_record);
S
Shuaiqiang Chang 已提交
447
  fprintf(fp, "# Number of Threads:                 %d\n", threads);
H
hzcheng 已提交
448 449 450 451 452
  fprintf(fp, "# Number of Tables:                  %d\n", ntables);
  fprintf(fp, "# Number of Data per Table:          %d\n", nrecords_per_table);
  fprintf(fp, "# Records/Request:                   %d\n", nrecords_per_request);
  fprintf(fp, "# Database name:                     %s\n", db_name);
  fprintf(fp, "# Table prefix:                      %s\n", tb_prefix);
S
Shuaiqiang Chang 已提交
453 454 455 456 457 458
  if (order == 1)
  {
    printf("# Data order:                        %d\n", order);
    printf("# Data out of order rate:            %d\n", rate);

  }
H
hzcheng 已提交
459 460 461 462 463 464 465 466
  fprintf(fp, "# Test time:                         %d-%02d-%02d %02d:%02d:%02d\n", tm.tm_year + 1900, tm.tm_mon + 1,
          tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
  fprintf(fp, "###################################################################\n\n");
  fprintf(fp, "|  WRecords  | Records/Second | Requests/Second |  WLatency(ms) |\n");

  taos_init();
  TAOS *taos = taos_connect(ip_addr, user, pass, NULL, port);
  if (taos == NULL) {
S
Shuaiqiang Chang 已提交
467
    fprintf(stderr, "Failed to connect to TDengine, reason:%s\n", taos_errstr(NULL));
H
hzcheng 已提交
468 469 470 471 472 473
    return 1;
  }
  char command[BUFFER_SIZE] = "\0";

  sprintf(command, "drop database %s;", db_name);
  taos_query(taos, command);
S
Shuaiqiang Chang 已提交
474
  
H
hzcheng 已提交
475 476 477 478

  sprintf(command, "create database %s;", db_name);
  taos_query(taos, command);

479
  char cols[STRING_LEN] = "\0";
H
hzcheng 已提交
480
  int colIndex = 0;
481
  len = 0;
H
hzcheng 已提交
482 483 484

  for (; colIndex < ncols_per_record - 1; colIndex++) {
    if (strcasecmp(data_type[colIndex % count_data_type], "BINARY") != 0) {
485
      len += snprintf(cols + len, STRING_LEN - len, ",f%d %s", colIndex + 1, data_type[colIndex % count_data_type]);
H
hzcheng 已提交
486
    } else {
487
      len += snprintf(cols + len, STRING_LEN - len, ",f%d %s(%d)", colIndex + 1, data_type[colIndex % count_data_type], len_of_binary);
H
hzcheng 已提交
488 489 490 491
    }
  }

  if (strcasecmp(data_type[colIndex % count_data_type], "BINARY") != 0) {
492
    len += snprintf(cols + len, STRING_LEN - len, ",f%d %s)", colIndex + 1, data_type[colIndex % count_data_type]);
H
hzcheng 已提交
493
  } else {
494
    len += snprintf(cols + len, STRING_LEN - len, ",f%d %s(%d))", colIndex + 1, data_type[colIndex % count_data_type], len_of_binary);
H
hzcheng 已提交
495 496 497 498 499 500
  }

  if (!use_metric) {
    /* Create all the tables; */
    printf("Creating %d table(s)......\n", ntables);
    for (int i = 0; i < ntables; i++) {
501
      snprintf(command, BUFFER_SIZE, "create table %s.%s%d (ts timestamp%s;", db_name, tb_prefix, i, cols);
H
hzcheng 已提交
502 503 504 505 506 507 508 509
      queryDB(taos, command);
    }

    printf("Table(s) created!\n");
    taos_close(taos);

  } else {
    /* Create metric table */
510
    printf("Creating meters super table...\n");
511
    snprintf(command, BUFFER_SIZE, "create table %s.meters (ts timestamp%s tags (areaid int, loc binary(10))", db_name, cols);
H
hzcheng 已提交
512
    queryDB(taos, command);
513
    printf("meters created!\n");
H
hzcheng 已提交
514 515 516 517 518 519 520 521 522 523

    /* Create all the tables; */
    printf("Creating %d table(s)......\n", ntables);
    for (int i = 0; i < ntables; i++) {
      int j;
      if (i % 10 == 0) {
        j = 10;
      } else {
        j = i % 10;
      }
524
    if (j % 2 == 0) {
525 526 527 528
      snprintf(command, BUFFER_SIZE, "create table %s.%s%d using %s.meters tags (%d,\"%s\");", db_name, tb_prefix, i, db_name, j, "shanghai");
    } else {
      snprintf(command, BUFFER_SIZE, "create table %s.%s%d using %s.meters tags (%d,\"%s\");", db_name, tb_prefix, i, db_name, j, "beijing");
    }
H
hzcheng 已提交
529 530 531 532 533 534 535
      queryDB(taos, command);
    }

    printf("Table(s) created!\n");
    taos_close(taos);
  }
  /* Wait for table to create  */
S
Shuaiqiang Chang 已提交
536
  
H
hzcheng 已提交
537 538 539 540

  /* Insert data */
  double ts = getCurrentTime();
  printf("Inserting data......\n");
S
Shuaiqiang Chang 已提交
541 542
  pthread_t *pids = malloc(threads * sizeof(pthread_t));
  info *infos = malloc(threads * sizeof(info));
H
hzcheng 已提交
543

S
Shuaiqiang Chang 已提交
544
  int a = ntables / threads;
H
hzcheng 已提交
545
  if (a < 1) {
S
Shuaiqiang Chang 已提交
546
    threads = ntables;
H
hzcheng 已提交
547 548
    a = 1;
  }
S
Shuaiqiang Chang 已提交
549
  int b = ntables % threads;
H
hzcheng 已提交
550
  int last = 0;
S
Shuaiqiang Chang 已提交
551
  for (int i = 0; i < threads; i++) {
H
hzcheng 已提交
552 553 554 555 556 557 558 559 560 561 562 563
    info *t_info = infos + i;
    t_info->threadID = i;
    strcpy(t_info->db_name, db_name);
    strcpy(t_info->tb_prefix, tb_prefix);
    t_info->datatype = data_type;
    t_info->ncols_per_record = ncols_per_record;
    t_info->nrecords_per_table = nrecords_per_table;
    t_info->start_time = 1500000000000;
    t_info->taos = taos_connect(ip_addr, user, pass, db_name, port);
    t_info->len_of_binary = len_of_binary;
    t_info->nrecords_per_request = nrecords_per_request;
    t_info->start_table_id = last;
S
Shuaiqiang Chang 已提交
564 565
    t_info->data_of_order = order;
    t_info->data_of_rate = rate;
H
hzcheng 已提交
566 567 568 569 570 571 572 573 574 575 576 577 578
    t_info->end_table_id = i < b ? last + a : last + a - 1;
    last = t_info->end_table_id + 1;

    sem_init(&(t_info->mutex_sem), 0, 1);
    t_info->notFinished = t_info->end_table_id - t_info->start_table_id + 1;
    sem_init(&(t_info->lock_sem), 0, 0);

    if (query_mode == SYNC) {
      pthread_create(pids + i, NULL, syncWrite, t_info);
    } else {
      pthread_create(pids + i, NULL, asyncWrite, t_info);
    }
  }
S
Shuaiqiang Chang 已提交
579
  for (int i = 0; i < threads; i++) {
H
hzcheng 已提交
580 581 582 583 584
    pthread_join(pids[i], NULL);
  }

  double t = getCurrentTime() - ts;
  if (query_mode == SYNC) {
S
Shuaiqiang Chang 已提交
585
    printf("SYNC Insert with %d connections:\n", threads);
H
hzcheng 已提交
586
  } else {
S
Shuaiqiang Chang 已提交
587
    printf("ASYNC Insert with %d connections:\n", threads);
H
hzcheng 已提交
588 589 590 591 592 593 594 595 596 597 598
  }

  fprintf(fp, "|%10.d  |  %10.2f    |  %10.2f     |  %10.4f   |\n\n",
          ntables * nrecords_per_table, ntables * nrecords_per_table / t,
          (ntables * nrecords_per_table) / (t * nrecords_per_request),
          t * 1000);

  printf("Spent %.4f seconds to insert %d records with %d record(s) per request: %.2f records/second\n",
         t, ntables * nrecords_per_table, nrecords_per_request,
         ntables * nrecords_per_table / t);

S
Shuaiqiang Chang 已提交
599
  for (int i = 0; i < threads; i++) {
H
hzcheng 已提交
600 601 602 603 604 605 606 607 608 609
    info *t_info = infos + i;
    taos_close(t_info->taos);
    sem_destroy(&(t_info->mutex_sem));
    sem_destroy(&(t_info->lock_sem));
  }

  free(pids);
  free(infos);
  fclose(fp);

S
Shuaiqiang Chang 已提交
610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658
  if (method_of_delete != 0)
  {
    TAOS *dtaos = taos_connect(ip_addr, user, pass, db_name, port);
    double dts = getCurrentTime();
    printf("Deleteing %d table(s)......\n", ntables);

    switch (method_of_delete)
    {
    case 1:
      // delete by table
      /* Create all the tables; */
      for (int i = 0; i < ntables; i++) {
        sprintf(command, "drop table %s.%s%d;", db_name, tb_prefix, i);
        queryDB(dtaos, command);
      }
      break;
    case 2:
      // delete by stable
      if (!use_metric) {
        break;
      }
      else
      {
        sprintf(command, "drop table %s.meters;", db_name);
        queryDB(dtaos, command);
      }
      break;
    case 3:
      // delete by database
      sprintf(command, "drop database %s;", db_name);
      queryDB(dtaos, command);
      break;
    default:
      break;
    }

    printf("Table(s) droped!\n");
    taos_close(dtaos);

    double dt = getCurrentTime() - dts;
    printf("Spent %.4f seconds to drop %d tables\n", dt, ntables);

    FILE *fp = fopen(arguments.output_file, "a");
    fprintf(fp, "Spent %.4f seconds to drop %d tables\n", dt, ntables);
    fclose(fp);

  }
  

H
hzcheng 已提交
659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687
  if (!insert_only) {
    // query data
    pthread_t read_id;
    info *rInfo = malloc(sizeof(info));
    rInfo->start_time = 1500000000000;
    rInfo->start_table_id = 0;
    rInfo->end_table_id = ntables - 1;
    rInfo->do_aggreFunc = do_aggreFunc;
    rInfo->nrecords_per_table = nrecords_per_table;
    rInfo->taos = taos_connect(ip_addr, user, pass, db_name, port);
    strcpy(rInfo->tb_prefix, tb_prefix);
    strcpy(rInfo->fp, arguments.output_file);

    if (!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);
  }

  return 0;
}

void *readTable(void *sarg) {
  info *rinfo = (info *)sarg;
  TAOS *taos = rinfo->taos;
  char command[BUFFER_SIZE] = "\0";
S
slguan 已提交
688
  int64_t sTime = rinfo->start_time;
H
hzcheng 已提交
689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
  char *tb_prefix = rinfo->tb_prefix;
  FILE *fp = fopen(rinfo->fp, "a");
  int num_of_DPT = rinfo->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 = rinfo->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++) {
L
lihui 已提交
707
      sprintf(command, "select %s from %s%d where ts>= %" PRId64, aggreFunc[j], tb_prefix, i, sTime);
H
hzcheng 已提交
708 709

      double t = getCurrentTime();
S
Shuaiqiang Chang 已提交
710 711
      TAOS_RES *pSql = taos_query(taos, command);
      int32_t code = taos_errno(pSql);
H
hzcheng 已提交
712

S
Shuaiqiang Chang 已提交
713
      if (code != 0) {
H
Haojun Liao 已提交
714
        fprintf(stderr, "Failed to query:%s\n", taos_errstr(pSql));
S
Shuaiqiang Chang 已提交
715
        taos_free_result(pSql);
H
hzcheng 已提交
716
        taos_close(taos);
S
Shuaiqiang Chang 已提交
717
        exit(EXIT_FAILURE);
H
hzcheng 已提交
718 719
      }

S
Shuaiqiang Chang 已提交
720
      while (taos_fetch_row(pSql) != NULL) {
H
hzcheng 已提交
721 722 723 724 725 726
        count++;
      }

      t = getCurrentTime() - t;
      totalT += t;

S
Shuaiqiang Chang 已提交
727
      taos_free_result(pSql);
H
hzcheng 已提交
728 729 730
    }

    fprintf(fp, "|%10s  |   %10d   |  %12.2f   |   %10.2f  |\n",
S
slguan 已提交
731
            aggreFunc[j][0] == '*' ? "   *   " : aggreFunc[j], totalData,
H
hzcheng 已提交
732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758
            (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);
  return NULL;
}

void *readMetric(void *sarg) {
  info *rinfo = (info *)sarg;
  TAOS *taos = rinfo->taos;
  char command[BUFFER_SIZE] = "\0";
  FILE *fp = fopen(rinfo->fp, "a");
  int num_of_DPT = rinfo->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 = rinfo->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++) {
sangshuduo's avatar
sangshuduo 已提交
759
    char condition[BUFFER_SIZE - 30] = "\0";
B
Bomin Zhang 已提交
760
    char tempS[64] = "\0";
H
hzcheng 已提交
761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778

    int m = 10 < num_of_tables ? 10 : num_of_tables;

    for (int i = 1; i <= m; i++) {
      if (i == 1) {
        sprintf(tempS, "index = %d", i);
      } else {
        sprintf(tempS, " or index = %d ", i);
      }
      strcat(condition, tempS);

      sprintf(command, "select %s from m1 where %s", aggreFunc[j], condition);

      printf("Where condition: %s\n", condition);
      fprintf(fp, "%s\n", command);

      double t = getCurrentTime();

S
Shuaiqiang Chang 已提交
779 780 781 782
      TAOS_RES *pSql = taos_query(taos, command);
      int32_t code = taos_errno(pSql);

      if (code != 0) {
H
Haojun Liao 已提交
783
        fprintf(stderr, "Failed to query:%s\n", taos_errstr(pSql));
S
Shuaiqiang Chang 已提交
784
        taos_free_result(pSql);
H
hzcheng 已提交
785 786 787 788
        taos_close(taos);
        exit(1);
      }
      int count = 0;
S
Shuaiqiang Chang 已提交
789
      while (taos_fetch_row(pSql) != NULL) {
H
hzcheng 已提交
790 791 792 793 794 795 796
        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);

S
Shuaiqiang Chang 已提交
797
      taos_free_result(pSql);
H
hzcheng 已提交
798 799 800 801 802 803 804 805 806
    }
    fprintf(fp, "\n");
  }

  fclose(fp);
  return NULL;
}

void queryDB(TAOS *taos, char *command) {
807
  int i = 5;
S
Shuaiqiang Chang 已提交
808 809 810 811 812 813 814 815 816 817
  TAOS_RES *pSql = NULL;
  int32_t code = -1;
  while (i > 0 && code != 0) {
    pSql = taos_query(taos, command);
    code = taos_errno(pSql);
    taos_free_result(pSql);
    pSql = NULL;
    if (code == 0) {
      break;
    }
818 819
    i--; 
  }
S
Shuaiqiang Chang 已提交
820

dengyihao's avatar
dengyihao 已提交
821
  if (code != 0) {
H
Haojun Liao 已提交
822 823 824
    fprintf(stderr, "Failed to run %s, reason: %s\n", command, taos_errstr(pSql));
    taos_free_result(pSql);

H
hzcheng 已提交
825 826 827 828 829 830 831 832 833 834 835 836 837 838
    taos_close(taos);
    exit(EXIT_FAILURE);
  }
}

// sync insertion
void *syncWrite(void *sarg) {
  info *winfo = (info *)sarg;
  char buffer[BUFFER_SIZE] = "\0";
  char data[MAX_DATA_SIZE];
  char **data_type = winfo->datatype;
  int len_of_binary = winfo->len_of_binary;
  int ncols_per_record = winfo->ncols_per_record;
  srand(time(NULL));
S
slguan 已提交
839
  int64_t time_counter = winfo->start_time;
H
hzcheng 已提交
840 841 842
  for (int i = 0; i < winfo->nrecords_per_table;) {
    for (int tID = winfo->start_table_id; tID <= winfo->end_table_id; tID++) {
      int inserted = i;
S
slguan 已提交
843
      int64_t tmp_time = time_counter;
H
hzcheng 已提交
844 845 846 847 848

      char *pstr = buffer;
      pstr += sprintf(pstr, "insert into %s.%s%d values", winfo->db_name, winfo->tb_prefix, tID);
      int k;
      for (k = 0; k < winfo->nrecords_per_request;) {
H
Hui Li 已提交
849
        int rand_num = trand() % 100;
850 851
        int len = -1;
        if (winfo->data_of_order ==1 && rand_num < winfo->data_of_rate) {
H
Hui Li 已提交
852
          long d = tmp_time - trand() % 1000000 + rand_num;
853 854 855
          len = generateData(data, data_type, ncols_per_record, d, len_of_binary);
        } else {
          len = generateData(data, data_type, ncols_per_record, tmp_time += 1000, len_of_binary);
S
Shuaiqiang Chang 已提交
856
        }
857 858 859 860 861 862

        //assert(len + pstr - buffer < BUFFER_SIZE);
        if (len + pstr - buffer >= BUFFER_SIZE) { // too long
          break;
        }

H
hzcheng 已提交
863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900
        pstr += sprintf(pstr, " %s", data);
        inserted++;
        k++;

        if (inserted >= winfo->nrecords_per_table) break;
      }

      /* puts(buffer); */
      queryDB(winfo->taos, buffer);

      if (tID == winfo->end_table_id) {
        i = inserted;
        time_counter = tmp_time;
      }
    }
  }
  return NULL;
}

void *asyncWrite(void *sarg) {
  info *winfo = (info *)sarg;

  sTable *tb_infos = (sTable *)malloc(sizeof(sTable) * (winfo->end_table_id - winfo->start_table_id + 1));

  for (int tID = winfo->start_table_id; tID <= winfo->end_table_id; tID++) {
    sTable *tb_info = tb_infos + tID - winfo->start_table_id;
    tb_info->data_type = winfo->datatype;
    tb_info->ncols_per_record = winfo->ncols_per_record;
    tb_info->taos = winfo->taos;
    sprintf(tb_info->tb_name, "%s.%s%d", winfo->db_name, winfo->tb_prefix, tID);
    tb_info->timestamp = winfo->start_time;
    tb_info->counter = 0;
    tb_info->target = winfo->nrecords_per_table;
    tb_info->len_of_binary = winfo->len_of_binary;
    tb_info->nrecords_per_request = winfo->nrecords_per_request;
    tb_info->mutex_sem = &(winfo->mutex_sem);
    tb_info->notFinished = &(winfo->notFinished);
    tb_info->lock_sem = &(winfo->lock_sem);
S
Shuaiqiang Chang 已提交
901 902
    tb_info->data_of_order = winfo->data_of_order;
    tb_info->data_of_rate = winfo->data_of_rate;
H
hzcheng 已提交
903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921

    /* char buff[BUFFER_SIZE] = "\0"; */
    /* sprintf(buff, "insert into %s values (0, 0)", tb_info->tb_name); */
    /* queryDB(tb_info->taos,buff); */

    taos_query_a(winfo->taos, "show databases", callBack, tb_info);
  }

  sem_wait(&(winfo->lock_sem));
  free(tb_infos);

  return NULL;
}

void callBack(void *param, TAOS_RES *res, int code) {
  sTable *tb_info = (sTable *)param;
  char **datatype = tb_info->data_type;
  int ncols_per_record = tb_info->ncols_per_record;
  int len_of_binary = tb_info->len_of_binary;
S
slguan 已提交
922
  int64_t tmp_time = tb_info->timestamp;
H
hzcheng 已提交
923 924

  if (code < 0) {
H
Haojun Liao 已提交
925
    fprintf(stderr, "failed to insert data %d:reason; %s\n", code, taos_errstr(res));
H
hzcheng 已提交
926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943
    exit(EXIT_FAILURE);
  }

  // If finished;
  if (tb_info->counter >= tb_info->target) {
    sem_wait(tb_info->mutex_sem);
    (*(tb_info->notFinished))--;
    if (*(tb_info->notFinished) == 0) sem_post(tb_info->lock_sem);
    sem_post(tb_info->mutex_sem);
    return;
  }

  char buffer[BUFFER_SIZE] = "\0";
  char data[MAX_DATA_SIZE];
  char *pstr = buffer;
  pstr += sprintf(pstr, "insert into %s values", tb_info->tb_name);

  for (int i = 0; i < tb_info->nrecords_per_request; i++) {
H
Hui Li 已提交
944
    int rand_num = trand() % 100;
S
Shuaiqiang Chang 已提交
945 946
    if (tb_info->data_of_order ==1 && rand_num < tb_info->data_of_rate)
    {
H
Hui Li 已提交
947
      long d = tmp_time - trand() % 1000000 + rand_num;
S
Shuaiqiang Chang 已提交
948 949 950 951 952
      generateData(data, datatype, ncols_per_record, d, len_of_binary);
    } else 
    {
      generateData(data, datatype, ncols_per_record, tmp_time += 1000, len_of_binary);
    }
H
hzcheng 已提交
953 954 955 956 957 958 959
    pstr += sprintf(pstr, "%s", data);
    tb_info->counter++;

    if (tb_info->counter >= tb_info->target) {
      break;
    }
  }
S
Shuaiqiang Chang 已提交
960
   tb_info->timestamp = tmp_time;
H
hzcheng 已提交
961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976

  taos_query_a(tb_info->taos, buffer, callBack, tb_info);

  taos_free_result(res);
}

double getCurrentTime() {
  struct timeval tv;
  if (gettimeofday(&tv, NULL) != 0) {
    perror("Failed to get current time in ms");
    exit(EXIT_FAILURE);
  }

  return tv.tv_sec + tv.tv_usec / 1E6;
}

977
int32_t generateData(char *res, char **data_type, int num_of_cols, int64_t timestamp, int len_of_binary) {
H
hzcheng 已提交
978 979
  memset(res, 0, MAX_DATA_SIZE);
  char *pstr = res;
L
lihui 已提交
980
  pstr += sprintf(pstr, "(%" PRId64, timestamp);
H
hzcheng 已提交
981 982 983 984 985 986 987 988
  int c = 0;

  for (; c < MAX_NUM_DATATYPE; c++) {
    if (strcasecmp(data_type[c], "") == 0) {
      break;
    }
  }

H
Hui Li 已提交
989 990 991 992 993
  if (0 == c) {
    perror("data type error!");
    exit(-1);
  }

H
hzcheng 已提交
994 995
  for (int i = 0; i < num_of_cols; i++) {
    if (strcasecmp(data_type[i % c], "tinyint") == 0) {
H
Hui Li 已提交
996
      pstr += sprintf(pstr, ", %d", (int)(trand() % 128));
H
hzcheng 已提交
997
    } else if (strcasecmp(data_type[i % c], "smallint") == 0) {
H
Hui Li 已提交
998
      pstr += sprintf(pstr, ", %d", (int)(trand() % 32767));
H
hzcheng 已提交
999
    } else if (strcasecmp(data_type[i % c], "int") == 0) {
H
Hui Li 已提交
1000
      pstr += sprintf(pstr, ", %d", (int)(trand() % 10)); 
H
hzcheng 已提交
1001
    } else if (strcasecmp(data_type[i % c], "bigint") == 0) {
H
Hui Li 已提交
1002
      pstr += sprintf(pstr, ", %" PRId64, trand() % 2147483648);
H
hzcheng 已提交
1003
    } else if (strcasecmp(data_type[i % c], "float") == 0) {
H
Hui Li 已提交
1004
      pstr += sprintf(pstr, ", %10.4f", (float)(trand() / 1000));
H
hzcheng 已提交
1005
    } else if (strcasecmp(data_type[i % c], "double") == 0) {
H
Hui Li 已提交
1006
      double t = (double)(trand() / 1000000);
H
hzcheng 已提交
1007 1008
      pstr += sprintf(pstr, ", %20.8f", t);
    } else if (strcasecmp(data_type[i % c], "bool") == 0) {
H
Hui Li 已提交
1009
      bool b = trand() & 1;
H
hzcheng 已提交
1010 1011 1012 1013
      pstr += sprintf(pstr, ", %s", b ? "true" : "false");
    } else if (strcasecmp(data_type[i % c], "binary") == 0) {
      char s[len_of_binary];
      rand_string(s, len_of_binary);
F
fang 已提交
1014
      pstr += sprintf(pstr, ", \"%s\"", s);
H
hzcheng 已提交
1015
    }
1016 1017 1018 1019 1020

    if (pstr - res > MAX_DATA_SIZE) {
      perror("column length too long, abort");
      exit(-1);
    }
H
hzcheng 已提交
1021 1022 1023
  }

  pstr += sprintf(pstr, ")");
1024 1025

  return pstr - res;
H
hzcheng 已提交
1026 1027
}

S
Shuaiqiang Chang 已提交
1028
static const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJK1234567890";
H
hzcheng 已提交
1029
void rand_string(char *str, int size) {
S
Shuaiqiang Chang 已提交
1030 1031
  str[0] = 0;
  if (size > 0) {
H
hzcheng 已提交
1032
    --size;
S
Shuaiqiang Chang 已提交
1033 1034
    int n;
    for (n = 0; n < size; n++) {
H
Hui Li 已提交
1035
      int key = trand() % (int)(sizeof charset - 1);
S
Shuaiqiang Chang 已提交
1036
      str[n] = charset[key];
H
hzcheng 已提交
1037
    }
S
Shuaiqiang Chang 已提交
1038
    str[n] = 0;
H
hzcheng 已提交
1039 1040
  }
}