Skip to content

File broker_tester.c

File List > broker > broker_tester.c

Go to the documentation of this file

/*
 * Copyright 2008 Search Solution Corporation
 * Copyright 2016 CUBRID Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */


/*
 * broker_tester.c -
 */

#ident "$Id$"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>

#if defined(WINDOWS)
#include <process.h>
#include "porting.h"
#include <sys/timeb.h>
#else /* WINDOWS */
#include <sys/time.h>
#endif /* WINDOWS */

#include "broker_config.h"
#include "broker_util.h"
#include "broker_config.h"
#include "broker_shm.h"
#include "broker_filename.h"
#include "cas_protocol.h"
#include "cas_common.h"
#include "cubrid_getopt.h"
#include "cas_cci.h"

#if defined(WINDOWS)
#include "broker_wsa_init.h"
#endif /* WINDOWS */

#include "ini_parser.h"

#define TESTER_ERR_MSG_SIZE            1024
#define TIME_BUF_SIZE                  50
#define MAX_DISPLAY_LENGTH             20

#define DEFAULT_EMPTY_STRING           "\0"
#define DEFAULT_CUB_USER_NAME          "PUBLIC"

#define RESULT_FORMAT            "%-15s"
#define SHARD_ID_FORMAT          "%-10d"
#define STR_SHARD_ID_FORMAT      "%-10s"
#define ROWCOUNT_FORMAT          "%-15d"
#define QUERY_FORMAT             "%s"
#define STR_ROWCOUNT_FORMAT      "%-15s"
#define TIME_FORMAT              "%-20s"

#define PRINT_CCI_ERROR(...)                         \
        do {                                         \
          if (br_tester_info.verbose_mode)           \
           {                                         \
            if (out_file_fp != NULL)                 \
            {                                        \
             fprintf (out_file_fp , "<Error>\n");\
             fprintf (out_file_fp , __VA_ARGS__);    \
            }                                        \
            fprintf (stderr, "<Error>\n");       \
            fprintf (stderr, __VA_ARGS__);           \
           }                                         \
        } while(0)

#define PRINT_RESULT(...)                            \
        do {                                         \
          if (out_file_fp != NULL)                   \
          {                                          \
            fprintf (out_file_fp ,__VA_ARGS__);      \
          }                                          \
          fprintf (stdout, __VA_ARGS__);             \
        } while (0)

#define PRINT_TITLE(n, ...)                          \
        do {                                         \
          if (out_file_fp != NULL)                   \
          {                                          \
            fprintf (out_file_fp ,__VA_ARGS__);      \
          }                                          \
          n += fprintf (stdout, __VA_ARGS__);        \
        } while (0)

static const char SECTION_NAME[] = "broker";

static FILE *out_file_fp;

static char tester_err_msg[TESTER_ERR_MSG_SIZE];

typedef struct
{
  char *db_name;
  char *db_user;
  char *db_passwd;
  char *command;
  char *input_file_name;
  char *output_file_name;
  int broker_port;
  bool verbose_mode;
  bool single_shard;
  bool shard_flag;
  int num_shard;
} TESTER_INFO;

TESTER_INFO br_tester_info;

static int init_tester_info (char *broker_name);
static void init_default_conn_info (int appl_server_type);

static int get_master_shm_id (void);
static void get_time (struct timeval *start_time, char *time, int buf_len);

static int execute_test_with_query (int conn_handle, char *query, int shard_flag);
static int execute_test (int conn_handle, int shard_flag);

static void print_usage (void);
static void print_conn_result (char *broker_name, int conn_hd_id);
static void print_shard_result (void);
static void print_title (int shard_flag);
static void print_result (int row_count, int err_code, int shard_flag, int shard_id, char *time, char *query);
static int print_result_set (int req, T_CCI_ERROR * err_buf, T_CCI_COL_INFO * col_info, int col_count);
static void print_query_test_result (int ret);
static void print_line (const char *ch, int num);

static void free_br_tester_info (void);
static bool is_number_type (T_CCI_U_TYPE type);

static int
init_tester_info (char *broker_name)
{
  int i;
  int master_shm_id = 0;
  T_SHM_BROKER *shm_br = NULL;
  T_SHM_PROXY *shm_proxy = NULL;
  T_BROKER_INFO *broker_info_p = NULL;

  master_shm_id = get_master_shm_id ();
  if (master_shm_id <= 0)
    {
      return -1;
    }

  shm_br = (T_SHM_BROKER *) uw_shm_open (master_shm_id, SHM_BROKER, SHM_MODE_MONITOR);
  if (shm_br == NULL)
    {
      fprintf (stderr, "master shared memory open error[0x%x]\n", master_shm_id);
      return -1;
    }

  for (i = 0; i < shm_br->num_broker; i++)
    {
      if (strcasecmp (broker_name, shm_br->br_info[i].name) == 0)
    {
      broker_info_p = &shm_br->br_info[i];
      break;
    }
    }

  if (broker_info_p == NULL)
    {

      fprintf (stderr, "Cannot find Broker [%s]\n", broker_name);
      uw_shm_detach (shm_br);
      return -1;
    }

  br_tester_info.broker_port = broker_info_p->port;
  br_tester_info.shard_flag = broker_info_p->shard_flag;

  if (broker_info_p->shard_flag == ON)
    {
      shm_proxy = (T_SHM_PROXY *) uw_shm_open (broker_info_p->proxy_shm_id, SHM_PROXY, SHM_MODE_MONITOR);
      if (shm_proxy == NULL)
    {
      uw_shm_detach (shm_br);
      fprintf (stderr, "proxy shared memory open error[0x%x]\n", broker_info_p->proxy_shm_id);
      return -1;
    }
      br_tester_info.num_shard = shm_proxy->shm_shard_conn.num_shard_conn;

      uw_shm_detach (shm_proxy);

      if (br_tester_info.db_name == NULL)
    {
      br_tester_info.db_name = strdup (broker_info_p->shard_db_name);
    }

      if (br_tester_info.db_user == NULL)
    {
      br_tester_info.db_user = strdup (broker_info_p->shard_db_user);
    }

      if (br_tester_info.db_passwd == NULL)
    {
      br_tester_info.db_passwd = strdup (broker_info_p->shard_db_password);
    }
    }

  init_default_conn_info (broker_info_p->appl_server);

  uw_shm_detach (shm_br);

  return 0;
}

static void
init_default_conn_info (int appl_server_type)
{
  const char *user_name;
  const char *user_password;

  if (br_tester_info.db_name == NULL)
    {
      br_tester_info.db_name = strdup (DEFAULT_EMPTY_STRING);
    }

  switch (appl_server_type)
    {
    case APPL_SERVER_CAS:
      user_name = DEFAULT_CUB_USER_NAME;
      user_password = DEFAULT_EMPTY_STRING;
      break;

    default:
      user_name = DEFAULT_EMPTY_STRING;
      user_password = DEFAULT_EMPTY_STRING;
    }

  if (br_tester_info.db_user == NULL)
    {
      br_tester_info.db_user = strdup (user_name);

      FREE_MEM (br_tester_info.db_passwd);
      br_tester_info.db_passwd = strdup (user_password);
    }

  if (br_tester_info.db_passwd == NULL)
    {
      br_tester_info.db_passwd = strdup (DEFAULT_EMPTY_STRING);
    }

  return;
}

static int
get_master_shm_id (void)
{
  int master_shm_id = 0;
  struct stat stat_buf;
  INI_TABLE *ini = NULL;
  const char *conf_file;
  char conf_file_path[BROKER_PATH_MAX];

  conf_file = envvar_get ("BROKER_CONF_FILE");

  if (conf_file != NULL)
    {
      strncpy_bufsize (conf_file_path, conf_file);
    }
  else
    {
      get_cubrid_file (FID_CUBRID_BROKER_CONF, conf_file_path, BROKER_PATH_MAX);
    }

  if (stat (conf_file_path, &stat_buf) == 0)
    {
      ini = ini_parser_load (conf_file_path);
      if (ini == NULL)
    {
      fprintf (stderr, "cannot open conf file %s\n", conf_file_path);
      return -1;
    }

      if (!ini_findsec (ini, SECTION_NAME))
    {
      fprintf (stderr, "cannot find [%s] section in conf file %s\n", SECTION_NAME, conf_file_path);
      ini_parser_free (ini);
      return -1;
    }

      master_shm_id = ini_gethex (ini, SECTION_NAME, "MASTER_SHM_ID", 0, NULL);
      if (master_shm_id <= 0)
    {
      fprintf (stderr, "cannot find MASTER_SHM_ID in [%s] section\n", SECTION_NAME);
    }
    }

  ini_parser_free (ini);

  return master_shm_id;
}

static void
get_time (struct timeval *start_time, char *time, int buf_len)
{
  struct timeval end_time;
  struct timeval elapsed_time;

  assert (time);
  assert (start_time);

  gettimeofday (&end_time, NULL);

  elapsed_time.tv_sec = end_time.tv_sec - start_time->tv_sec;
  elapsed_time.tv_usec = end_time.tv_usec - start_time->tv_usec;
  if (elapsed_time.tv_usec < 0)
    {
      elapsed_time.tv_sec--;
      elapsed_time.tv_usec += 1000000;
    }
  snprintf (time, buf_len, "%ld.%06ld sec", elapsed_time.tv_sec, elapsed_time.tv_usec);
  return;
}

static int
execute_test_with_query (int conn_handle, char *query, int shard_flag)
{
  int shard_id = 0;
  int err_num = 0;
  int ret, req, col_count;
  char time[TIME_BUF_SIZE];
  char query_with_hint[LINE_MAX];
  struct timeval start_time;
  T_CCI_ERROR err_buf;
  T_CCI_SQLX_CMD cmd_type;
  T_CCI_COL_INFO *col_info = NULL;

  do
    {
      memset (tester_err_msg, 0, sizeof (tester_err_msg));

      if (br_tester_info.shard_flag == ON && !br_tester_info.single_shard)
    {
      snprintf (query_with_hint, sizeof (query_with_hint), "%s /*+ shard_id(%d) */ /* broker_tester */", query,
            shard_id);
    }
      else
    {
      snprintf (query_with_hint, sizeof (query_with_hint), "%s /* broker_tester */", query);
    }

      gettimeofday (&start_time, NULL);

      req = cci_prepare (conn_handle, query_with_hint, 0, &err_buf);
      if (req < 0)
    {
      snprintf_dots_truncate (tester_err_msg, sizeof (tester_err_msg) - 1, "ERROR CODE : %d\n%s\n\n",
                  err_buf.err_code, err_buf.err_msg);
      ret = -1;
      err_num++;
      goto end_tran;
    }

      ret = cci_execute (req, 0, 0, &err_buf);
      if (ret < 0)
    {
      snprintf_dots_truncate (tester_err_msg, sizeof (tester_err_msg) - 1, "ERROR CODE : %d\n%s\n\n",
                  err_buf.err_code, err_buf.err_msg);
      err_num++;
      goto end_tran;
    }

      if (br_tester_info.shard_flag == ON && br_tester_info.single_shard)
    {
      int ret;

      ret = cci_get_shard_id_with_req_handle (req, &shard_id, &err_buf);
      if (ret < 0)
        {
          snprintf_dots_truncate (tester_err_msg, sizeof (tester_err_msg) - 1, "ERROR CODE : %d\n%s\n\n",
                      err_buf.err_code, err_buf.err_msg);
          err_num++;
          goto end_tran;
        }
    }

      if (br_tester_info.verbose_mode)
    {
      col_info = cci_get_result_info (req, &cmd_type, &col_count);
      if (cmd_type == CUBRID_STMT_SELECT && col_info == NULL)
        {
          snprintf_dots_truncate (tester_err_msg, sizeof (tester_err_msg) - 1, "ERROR CODE : %d\n%s\n\n",
                      err_buf.err_code, err_buf.err_msg);
          ret = -1;
          err_num++;
        }
    }

    end_tran:
      get_time (&start_time, time, sizeof (time));

      print_result (ret, err_buf.err_code, shard_flag, shard_id, time, query);

      if (ret >= 0 && br_tester_info.verbose_mode && cmd_type == CUBRID_STMT_SELECT)
    {
      ret = print_result_set (req, &err_buf, col_info, col_count);
      if (ret < 0)
        {
          err_num++;
        }
    }

      cci_close_req_handle (req);

      cci_end_tran (conn_handle, CCI_TRAN_ROLLBACK, &err_buf);

      if (br_tester_info.shard_flag == OFF || br_tester_info.single_shard)
    {
      break;
    }
    }
  while (++shard_id < br_tester_info.num_shard);

  return (-1 * err_num);
}

static int
execute_test (int conn_handle, int shard_flag)
{
  char query[LINE_MAX];
  char *p;
  int ret = 0;
  int err_num = 0;
  FILE *file = NULL;

  file = fopen (br_tester_info.input_file_name, "r");
  if (file == NULL)
    {
      fprintf (stderr, "cannot open input file %s\n", br_tester_info.input_file_name);
      return -1;
    }

  print_title (shard_flag);

  while (fgets (query, LINE_MAX - 1, file) != NULL)
    {
      trim (query);

      p = strchr (query, '#');

      if (p != NULL)
    {
      *p = '\0';
    }

      if (query[0] == '\0')
    {
      continue;
    }

      ret = execute_test_with_query (conn_handle, query, shard_flag);
      if (ret < 0)
    {
      err_num++;
    }
    }

  fclose (file);

  return (-1 * err_num);
}

static void
print_line (const char *ch, int num)
{
  int i;

  if (num <= 0)
    {
      return;
    }

  for (i = 0; i < num; i++)
    {
      PRINT_RESULT (ch);
    }
}

static void
print_usage (void)
{
  printf
    ("broker_tester <broker_name> [-D <database_name>] [-u <user_name>] [-p <user_password>] [-c <SQL_command>] [-i <input_file>] [-o <output_file>] [-v] [-s]\n");
  printf ("\t-D database-name\n");
  printf ("\t-u alternate user name\n");
  printf ("\t-p password string, give \"\" for none\n");
  printf ("\t-c SQL-command\n");
  printf ("\t-i input-file-name\n");
  printf ("\t-o ouput-file-name\n");
  printf ("\t-v verbose mode\n");
  printf ("\t-s single shard database\n");
}

static void
print_title (int shard_flag)
{
  int title_len = 0;

  PRINT_TITLE (title_len, RESULT_FORMAT, "RESULT");

  if (shard_flag == ON)
    {
      PRINT_TITLE (title_len, STR_SHARD_ID_FORMAT, "SHARD_ID");
    }

  PRINT_TITLE (title_len, STR_ROWCOUNT_FORMAT, "ROW COUNT");

  PRINT_TITLE (title_len, TIME_FORMAT, "EXECUTION TIME");

  PRINT_TITLE (title_len, QUERY_FORMAT, "QUERY\n");

  print_line ("=", title_len);

  PRINT_RESULT ("\n");
}

static void
print_conn_result (char *broker_name, int conn_hd_id)
{
  if (conn_hd_id < 0)
    {
      PRINT_RESULT ("@ [FAIL] ");
    }
  else
    {
      PRINT_RESULT ("@ [OK] ");
    }

  PRINT_RESULT ("CONNECT %s DB [%s] USER [%s]\n\n", broker_name, br_tester_info.db_name, br_tester_info.db_user);
  return;
}

static void
print_query_test_result (int ret)
{
  if (ret < 0)
    {
      PRINT_RESULT ("@ [FAIL] ");
    }
  else
    {
      PRINT_RESULT ("@ [OK] ");
    }

  PRINT_RESULT ("QUERY TEST\n");

  return;
}

static void
print_shard_result (void)
{
  PRINT_RESULT ("@ SHARD ");

  if (br_tester_info.shard_flag == ON)
    {
      PRINT_RESULT ("ON\n\n");
    }
  else
    {
      PRINT_RESULT ("OFF\n\n");
    }

  return;
}

static void
print_result (int row_count, int err_code, int shard_flag, int shard_id, char *time, char *query)
{
  if (row_count >= 0)
    {
      PRINT_RESULT (RESULT_FORMAT, "OK");
    }
  else
    {
      char result_buf[15];

      snprintf (result_buf, sizeof (result_buf), "FAIL(%d) ", err_code);
      row_count = -1;
      PRINT_RESULT (RESULT_FORMAT, result_buf);
    }

  if (shard_flag == ON)
    {
      PRINT_RESULT (SHARD_ID_FORMAT, (row_count < 0) ? -1 : shard_id);
    }

  PRINT_RESULT (ROWCOUNT_FORMAT, row_count);

  PRINT_RESULT (TIME_FORMAT, time);

  PRINT_RESULT (QUERY_FORMAT, query);
  PRINT_RESULT ("\n");

  if (tester_err_msg[0] != '\0')
    {
      PRINT_CCI_ERROR ("%s", tester_err_msg);
    }

  return;
}

static int
print_result_set (int req, T_CCI_ERROR * err_buf, T_CCI_COL_INFO * col_info, int col_count)
{
  int i;
  int ind;
  int ret = 0;
  int title_len = 0;
  int malloc_size = 0;
  int *col_size_arr;
  char *data;
  char *col_name;
  char *data_with_quot = NULL;
  T_CCI_U_EXT_TYPE *col_type_arr;

  col_size_arr = (int *) malloc (sizeof (int) * col_count);
  if (col_size_arr == NULL)
    {
      fprintf (stderr, "malloc error\n");
      return -1;
    }

  col_type_arr = (T_CCI_U_EXT_TYPE *) malloc (sizeof (T_CCI_U_EXT_TYPE) * col_count);
  if (col_type_arr == NULL)
    {
      FREE_MEM (col_size_arr);

      fprintf (stderr, "malloc error\n");
      return -1;
    }

  PRINT_RESULT ("<Result of SELECT Command>\n");

  for (i = 1; i < col_count + 1; i++)
    {
      col_name = CCI_GET_RESULT_INFO_NAME (col_info, i);
      col_size_arr[i - 1] = MIN (MAX_DISPLAY_LENGTH, CCI_GET_RESULT_INFO_PRECISION (col_info, i));
      col_size_arr[i - 1] = MAX (col_size_arr[i - 1], (int) strlen (col_name));
      col_type_arr[i - 1] = CCI_GET_RESULT_INFO_TYPE (col_info, i);

      PRINT_TITLE (title_len, "  %-*s", col_size_arr[i - 1], col_name);
    }
  PRINT_RESULT ("\n");

  print_line ("-", title_len);

  PRINT_RESULT ("\n");

  while (1)
    {
      ret = cci_cursor (req, 1, CCI_CURSOR_CURRENT, err_buf);
      if (ret == CCI_ER_NO_MORE_DATA)
    {
      ret = 0;
      break;
    }

      if (ret < 0)
    {
      PRINT_CCI_ERROR ("ERROR CODE : %d\n%s\n\n", err_buf->err_code, err_buf->err_msg);
      goto end;
    }

      ret = cci_fetch (req, err_buf);
      if (ret < 0)
    {
      PRINT_CCI_ERROR ("ERROR CODE : %d\n%s\n\n", err_buf->err_code, err_buf->err_msg);
      goto end;
    }

      for (i = 1; i < col_count + 1; i++)
    {
      ret = cci_get_data (req, i, CCI_A_TYPE_STR, &data, &ind);
      if (ret < 0)
        {
          PRINT_CCI_ERROR ("ERROR CODE : %d\n%s\n\n", err_buf->err_code, err_buf->err_msg);
          goto end;
        }

      if (is_number_type ((T_CCI_U_TYPE) col_type_arr[i - 1]))
        {
          PRINT_RESULT ("  %-*s", col_size_arr[i - 1], data);
        }
      else
        {
          int len = (int) strlen (data) + 3;
          if (malloc_size < len)
        {
          FREE_MEM (data_with_quot);
          malloc_size = len;
          data_with_quot = (char *) malloc (malloc_size);
          if (data_with_quot == NULL)
            {
              fprintf (stderr, "malloc error\n");
              ret = -1;
              goto end;
            }
        }
          snprintf (data_with_quot, len, "'%s'", data);

          PRINT_RESULT ("  %-*s", col_size_arr[i - 1], data_with_quot);
        }
    }
      PRINT_RESULT ("\n");
    }
  PRINT_RESULT ("\n");

end:

  FREE_MEM (data_with_quot);
  FREE_MEM (col_size_arr);
  FREE_MEM (col_type_arr);

  return ret;
}

static bool
is_number_type (T_CCI_U_TYPE type)
{
  switch (type)
    {
    case CCI_U_TYPE_INT:
    case CCI_U_TYPE_SHORT:
    case CCI_U_TYPE_FLOAT:
    case CCI_U_TYPE_DOUBLE:
    case CCI_U_TYPE_BIGINT:
      return true;
    default:
      return false;
    }

  return false;
}

static void
free_br_tester_info (void)
{
  FREE_MEM (br_tester_info.db_name);
  FREE_MEM (br_tester_info.db_user);
  FREE_MEM (br_tester_info.db_passwd);
  FREE_MEM (br_tester_info.command);
  FREE_MEM (br_tester_info.input_file_name);
  FREE_MEM (br_tester_info.output_file_name);
}

int
main (int argc, char *argv[])
{
  int ret = 0;
  int opt;
  int conn_handle = -1;
  char broker_name[BROKER_NAME_LEN];
  char conn_url[LINE_MAX];
  T_CCI_ERROR err_buf;

  if (argc < 2)
    {
      print_usage ();
      return -1;
    }

  memset (&br_tester_info, 0, sizeof (br_tester_info));

  strncpy (broker_name, argv[1], sizeof (broker_name) - 1);

  while ((opt = getopt (argc, argv, "D:u:p:c:i:o:sv")) != -1)
    {
      switch (opt)
    {
    case 'D':
      br_tester_info.db_name = strdup (optarg);
      break;
    case 'u':
      br_tester_info.db_user = strdup (optarg);
      break;
    case 'p':
      br_tester_info.db_passwd = strdup (optarg);
      break;
    case 'c':
      br_tester_info.command = strdup (optarg);
      break;
    case 'i':
      br_tester_info.input_file_name = strdup (optarg);
      break;
    case 'o':
      br_tester_info.output_file_name = strdup (optarg);
      break;
    case 'v':
      br_tester_info.verbose_mode = true;
      break;
    case 's':
      br_tester_info.single_shard = true;
      break;
    default:
      print_usage ();
      return -1;
    }
    }

  ret = init_tester_info (broker_name);
  if (ret < 0)
    {
      return -1;
    }

  snprintf (conn_url, sizeof (conn_url), "cci:cubrid:localhost:%u:%s:::", br_tester_info.broker_port,
        br_tester_info.db_name);
  conn_handle = cci_connect_with_url_ex (conn_url, br_tester_info.db_user, br_tester_info.db_passwd, &err_buf);

  if (br_tester_info.output_file_name != NULL)
    {
      out_file_fp = fopen (br_tester_info.output_file_name, "w");
      if (out_file_fp == NULL)
    {
      fprintf (stderr, "cannot open output file %s\n", br_tester_info.input_file_name);
      goto end;
    }
    }

  print_conn_result (broker_name, conn_handle);

  if (conn_handle < 0)
    {
      PRINT_CCI_ERROR ("ERROR CODE : %d\n%s\n\n", err_buf.err_code, err_buf.err_msg);
      free_br_tester_info ();
      return -1;
    }

  ret = cci_set_autocommit (conn_handle, CCI_AUTOCOMMIT_FALSE);
  if (ret < 0)
    {
      fprintf (stderr, "cannot set autocommit mode\n");
      goto end;
    }


  print_shard_result ();

  if (br_tester_info.command != NULL)
    {
      print_title (br_tester_info.shard_flag);

      ret = execute_test_with_query (conn_handle, br_tester_info.command, br_tester_info.shard_flag);
    }
  else if (br_tester_info.input_file_name != NULL)
    {
      ret = execute_test (conn_handle, br_tester_info.shard_flag);
    }
  else
    {
      goto end;
    }

  print_query_test_result (ret);

end:
  if (conn_handle >= 0)
    {
      cci_disconnect (conn_handle, &err_buf);
    }

  if (out_file_fp != NULL)
    {
      fclose (out_file_fp);
    }

  free_br_tester_info ();

  return ret;
}