taosdemo.c 34.6 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
    return 1;
  }
  char command[BUFFER_SIZE] = "\0";

  sprintf(command, "drop database %s;", db_name);
473 474
  TAOS_RES* res = taos_query(taos, command);
  taos_free_result(res);
H
hzcheng 已提交
475 476

  sprintf(command, "create database %s;", db_name);
477 478
  res = taos_query(taos, command);
  taos_free_result(res);
H
hzcheng 已提交
479

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

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

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

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

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

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

    /* 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;
      }
525
    if (j % 2 == 0) {
526
      snprintf(command, BUFFER_SIZE, "create table if not exists %s.%s%d using %s.meters tags (%d,\"%s\");", db_name, tb_prefix, i, db_name, j, "shanghai");
527
    } else {
528
      snprintf(command, BUFFER_SIZE, "create table if not exists %s.%s%d using %s.meters tags (%d,\"%s\");", db_name, tb_prefix, i, db_name, j, "beijing");
529
    }
H
hzcheng 已提交
530 531 532 533 534 535 536
      queryDB(taos, command);
    }

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

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

S
Shuaiqiang Chang 已提交
545
  int a = ntables / threads;
H
hzcheng 已提交
546
  if (a < 1) {
S
Shuaiqiang Chang 已提交
547
    threads = ntables;
H
hzcheng 已提交
548 549
    a = 1;
  }
S
Shuaiqiang Chang 已提交
550
  int b = ntables % threads;
H
hzcheng 已提交
551
  int last = 0;
S
Shuaiqiang Chang 已提交
552
  for (int i = 0; i < threads; i++) {
H
hzcheng 已提交
553 554
    info *t_info = infos + i;
    t_info->threadID = i;
H
Hui Li 已提交
555 556
    tstrncpy(t_info->db_name, db_name, MAX_DB_NAME_SIZE);
    tstrncpy(t_info->tb_prefix, tb_prefix, MAX_TB_NAME_SIZE);
H
hzcheng 已提交
557 558 559 560 561 562 563 564
    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 已提交
565 566
    t_info->data_of_order = order;
    t_info->data_of_rate = rate;
H
hzcheng 已提交
567 568 569 570 571 572 573 574 575 576 577 578 579
    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 已提交
580
  for (int i = 0; i < threads; i++) {
H
hzcheng 已提交
581 582 583 584 585
    pthread_join(pids[i], NULL);
  }

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

  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 已提交
600
  for (int i = 0; i < threads; i++) {
H
hzcheng 已提交
601 602 603 604 605 606 607 608 609 610
    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 已提交
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 659
  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 已提交
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 688
  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 已提交
689
  int64_t sTime = rinfo->start_time;
H
hzcheng 已提交
690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707
  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 已提交
708
      sprintf(command, "select %s from %s%d where ts>= %" PRId64, aggreFunc[j], tb_prefix, i, sTime);
H
hzcheng 已提交
709 710

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

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

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

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

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

    fprintf(fp, "|%10s  |   %10d   |  %12.2f   |   %10.2f  |\n",
S
slguan 已提交
732
            aggreFunc[j][0] == '*' ? "   *   " : aggreFunc[j], totalData,
H
hzcheng 已提交
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 759
            (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 已提交
760
    char condition[BUFFER_SIZE - 30] = "\0";
B
Bomin Zhang 已提交
761
    char tempS[64] = "\0";
H
hzcheng 已提交
762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779

    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 已提交
780 781 782 783
      TAOS_RES *pSql = taos_query(taos, command);
      int32_t code = taos_errno(pSql);

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

  fclose(fp);
  return NULL;
}

void queryDB(TAOS *taos, char *command) {
808
  int i = 5;
S
Shuaiqiang Chang 已提交
809 810 811 812 813 814 815 816 817 818
  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;
    }
819 820
    i--; 
  }
S
Shuaiqiang Chang 已提交
821

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

H
hzcheng 已提交
826 827 828 829 830 831 832 833 834 835 836 837 838 839
    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 已提交
840
  int64_t time_counter = winfo->start_time;
H
hzcheng 已提交
841 842 843
  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 已提交
844
      int64_t tmp_time = time_counter;
H
hzcheng 已提交
845 846 847 848 849

      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;) {
850
        int rand_num = rand() % 100;
851 852
        int len = -1;
        if (winfo->data_of_order ==1 && rand_num < winfo->data_of_rate) {
853
          long d = tmp_time - rand() % 1000000 + rand_num;
854 855 856
          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 已提交
857
        }
858 859 860 861 862 863

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

H
hzcheng 已提交
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 901
        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 已提交
902 903
    tb_info->data_of_order = winfo->data_of_order;
    tb_info->data_of_rate = winfo->data_of_rate;
H
hzcheng 已提交
904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922

    /* 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 已提交
923
  int64_t tmp_time = tb_info->timestamp;
H
hzcheng 已提交
924 925

  if (code < 0) {
H
Haojun Liao 已提交
926
    fprintf(stderr, "failed to insert data %d:reason; %s\n", code, taos_errstr(res));
H
hzcheng 已提交
927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944
    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++) {
945
    int rand_num = rand() % 100;
S
Shuaiqiang Chang 已提交
946 947
    if (tb_info->data_of_order ==1 && rand_num < tb_info->data_of_rate)
    {
948
      long d = tmp_time - rand() % 1000000 + rand_num;
S
Shuaiqiang Chang 已提交
949 950 951 952 953
      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 已提交
954 955 956 957 958 959 960
    pstr += sprintf(pstr, "%s", data);
    tb_info->counter++;

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

  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;
}

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

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

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

H
hzcheng 已提交
995 996
  for (int i = 0; i < num_of_cols; i++) {
    if (strcasecmp(data_type[i % c], "tinyint") == 0) {
997
      pstr += sprintf(pstr, ", %d", (int)(rand() % 128));
H
hzcheng 已提交
998
    } else if (strcasecmp(data_type[i % c], "smallint") == 0) {
999
      pstr += sprintf(pstr, ", %d", (int)(rand() % 32767));
H
hzcheng 已提交
1000
    } else if (strcasecmp(data_type[i % c], "int") == 0) {
1001
      pstr += sprintf(pstr, ", %d", (int)(rand() % 10)); 
H
hzcheng 已提交
1002
    } else if (strcasecmp(data_type[i % c], "bigint") == 0) {
1003
      pstr += sprintf(pstr, ", %" PRId64, rand() % 2147483648);
H
hzcheng 已提交
1004
    } else if (strcasecmp(data_type[i % c], "float") == 0) {
1005
      pstr += sprintf(pstr, ", %10.4f", (float)(rand() / 1000.0));
H
hzcheng 已提交
1006
    } else if (strcasecmp(data_type[i % c], "double") == 0) {
1007
      double t = (double)(rand() / 1000000.0);
H
hzcheng 已提交
1008 1009
      pstr += sprintf(pstr, ", %20.8f", t);
    } else if (strcasecmp(data_type[i % c], "bool") == 0) {
1010
      bool b = rand() & 1;
H
hzcheng 已提交
1011 1012 1013 1014
      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 已提交
1015
      pstr += sprintf(pstr, ", \"%s\"", s);
H
hzcheng 已提交
1016
    }
1017 1018 1019 1020 1021

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

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

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

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