Skip to content

File cas_xa.c

File List > broker > cas_xa.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.
 *
 */


/*
 * cas_xa.c -
 */

#ident "$Id$"

#include "cas_common.h"
#include "cas.h"
#include "cas_net_buf.h"
#include "cas_network.h"
#include "cas_log.h"
#include "cas_function.h"
#include "cas_execute.h"
#include "cas_db_inc.h"
#include "xa.h"

#define CAS_SUPPORT_XA
#define MAX_GTRIDS  100

#ifdef CAS_SUPPORT_XA
static int net_arg_get_xid (XID * xid, char *buf);
static void net_buf_cp_xid (T_NET_BUF * net_buf, XID * xid);
static int compare_xid (XID * xid1, XID * xid2);
#endif /* CAS_SUPPORT_XA */

static bool xa_prepare_flag = false;

FN_RETURN
fn_xa_prepare (SOCKET sock_fd, int argc, void **argv, T_NET_BUF * net_buf, T_REQ_INFO * req_info)
{
#ifdef CAS_SUPPORT_XA
  XID xid;
  int err_code, gtrid;

  if ((argc < 1) || (net_arg_get_xid (&xid, (char *) argv[0]) < 0))
    {
      ERROR_INFO_SET (CAS_ER_ARGS, CAS_ERROR_INDICATOR);
      NET_BUF_ERR_SET (net_buf);
      return FN_KEEP_CONN;
    }

  gtrid = db_2pc_start_transaction ();
  if (gtrid < 0)
    {
      ERROR_INFO_SET (gtrid, DBMS_ERROR_INDICATOR);
      NET_BUF_ERR_SET (net_buf);
      return FN_KEEP_CONN;
    }

  err_code = db_set_global_transaction_info (gtrid, (void *) &xid, sizeof (XID));
  if (err_code < 0)
    {
      ERROR_INFO_SET (err_code, DBMS_ERROR_INDICATOR);
      NET_BUF_ERR_SET (net_buf);
      return FN_KEEP_CONN;
    }

  err_code = db_2pc_prepare_transaction ();
  if (err_code < 0)
    {
      ERROR_INFO_SET (err_code, DBMS_ERROR_INDICATOR);
      NET_BUF_ERR_SET (net_buf);
      return FN_KEEP_CONN;
    }

  set_xa_prepare_flag ();

  net_buf_cp_int (net_buf, 0, NULL);

  cas_log_write (0, true, "xa_prepare");
#else /* CAS_SUPPORT_XA */
  ERROR_INFO_SET (CAS_ER_NOT_IMPLEMENTED, CAS_ERROR_INDICATOR);
  NET_BUF_ERR_SET (net_buf);
#endif /* CAS_SUPPORT_XA */
  return FN_KEEP_CONN;
}

FN_RETURN
fn_xa_recover (SOCKET sock_fd, int argc, void **argv, T_NET_BUF * net_buf, T_REQ_INFO * req_info)
{
#ifdef CAS_SUPPORT_XA
  int count;
  int gtrids[MAX_GTRIDS];
  int i, err_code;
  XID xid;

  count = db_2pc_prepared_transactions (gtrids, MAX_GTRIDS);
  if (count < 0)
    {
      ERROR_INFO_SET (count, DBMS_ERROR_INDICATOR);
      NET_BUF_ERR_SET (net_buf);
      return FN_KEEP_CONN;
    }

  net_buf_cp_int (net_buf, count, NULL);

  for (i = 0; i < count; i++)
    {
      err_code = db_get_global_transaction_info (gtrids[i], (void *) &xid, sizeof (XID));
      if (err_code < 0)
    {
      ERROR_INFO_SET (err_code, DBMS_ERROR_INDICATOR);
      NET_BUF_ERR_SET (net_buf);
      return FN_KEEP_CONN;
    }
      net_buf_cp_xid (net_buf, &xid);
    }

  cas_log_write (0, true, "xa_recover");
#else /* CAS_SUPPORT_XA */
  ERROR_INFO_SET (CAS_ER_NOT_IMPLEMENTED, CAS_ERROR_INDICATOR);
  NET_BUF_ERR_SET (net_buf);
#endif /* CAS_SUPPORT_XA */
  return FN_KEEP_CONN;
}

FN_RETURN
fn_xa_end_tran (SOCKET sock_fd, int argc, void **argv, T_NET_BUF * net_buf, T_REQ_INFO * req_info)
{
#ifdef CAS_SUPPORT_XA
  int tran_type;
  XID xid, tmp_xid;
  int gtrids[MAX_GTRIDS];
  int i, err_code, gtrid, count;

  if ((argc < 2) || (net_arg_get_xid (&xid, (char *) argv[0]) < 0))
    {
      ERROR_INFO_SET (CAS_ER_ARGS, CAS_ERROR_INDICATOR);
      NET_BUF_ERR_SET (net_buf);
      return FN_KEEP_CONN;
    }
  net_arg_get_char (tran_type, argv[1]);
  if (tran_type != CCI_TRAN_COMMIT && tran_type != CCI_TRAN_ROLLBACK)
    {
      ERROR_INFO_SET (CAS_ER_TRAN_TYPE, CAS_ERROR_INDICATOR);
      NET_BUF_ERR_SET (net_buf);
      return FN_KEEP_CONN;
    }

  count = db_2pc_prepared_transactions (gtrids, MAX_GTRIDS);
  if (count < 0)
    {
      ERROR_INFO_SET (count, DBMS_ERROR_INDICATOR);
      NET_BUF_ERR_SET (net_buf);
      return FN_KEEP_CONN;
    }

  for (gtrid = -1, i = 0; i < count; i++)
    {
      err_code = db_get_global_transaction_info (gtrids[i], (void *) &tmp_xid, sizeof (XID));
      if (err_code < 0)
    {
      ERROR_INFO_SET (err_code, DBMS_ERROR_INDICATOR);
      NET_BUF_ERR_SET (net_buf);
      return FN_KEEP_CONN;
    }
      if (compare_xid (&xid, &tmp_xid) == 0)
    {
      gtrid = gtrids[i];
      break;
    }
    }

  if (gtrid >= 0)
    {
#if 0
      ux_end_tran (CCI_TRAN_ROLLBACK);
#endif

      err_code = db_2pc_attach_transaction (gtrid);
      if (err_code < 0)
    {
      ERROR_INFO_SET (err_code, DBMS_ERROR_INDICATOR);
      NET_BUF_ERR_SET (net_buf);
      return FN_KEEP_CONN;
    }

      ux_end_tran (tran_type, true, true);
      set_xa_prepare_flag ();
    }

  net_buf_cp_int (net_buf, 0, NULL);
  cas_log_write (0, true, "xa_end_tran %d", tran_type);
#else /* CAS_SUPPORT_XA */
  ERROR_INFO_SET (CAS_ER_NOT_IMPLEMENTED, CAS_ERROR_INDICATOR);
  NET_BUF_ERR_SET (net_buf);
#endif /* CAS_SUPPORT_XA */
  return FN_CLOSE_CONN;
}

#ifdef CAS_SUPPORT_XA
static int
net_arg_get_xid (XID * xid, char *buf)
{
  int data_size;
  int i, id[3];

  memset (xid, 0, sizeof (XID));

  memcpy (&data_size, buf, 4);
  data_size = ntohl (data_size);
  buf += 4;

  for (i = 0; i < 3; i++)
    {
      if (data_size < 4)
    return -1;
      memcpy (&id[i], buf, 4);
      id[i] = ntohl (id[i]);
      buf += 4;
      data_size -= 4;
    }

  if (data_size < id[1] + id[2])
    return -1;

  xid->formatID = id[0];
  xid->gtrid_length = id[1];
  xid->bqual_length = id[2];
  memcpy (xid->data, buf, id[1] + id[2]);
  return 0;
}

static void
net_buf_cp_xid (T_NET_BUF * net_buf, XID * xid)
{
  net_buf_cp_int (net_buf, 12 + xid->gtrid_length + xid->bqual_length, NULL);
  net_buf_cp_int (net_buf, xid->formatID, NULL);
  net_buf_cp_int (net_buf, xid->gtrid_length, NULL);
  net_buf_cp_int (net_buf, xid->bqual_length, NULL);
  net_buf_cp_str (net_buf, xid->data, xid->gtrid_length + xid->bqual_length);
}

static int
compare_xid (XID * xid1, XID * xid2)
{
  if (xid1->formatID != xid2->formatID)
    return -1;
  if (xid1->gtrid_length != xid2->gtrid_length)
    return -1;
  if (xid1->bqual_length != xid2->bqual_length)
    return -1;
  return (memcmp (xid1->data, xid2->data, xid1->gtrid_length + xid1->bqual_length));
}
#endif /* CAS_SUPPORT_XA */

bool
is_xa_prepared (void)
{
  return xa_prepare_flag;
}

void
set_xa_prepare_flag (void)
{
  xa_prepare_flag = true;
}

void
unset_xa_prepare_flag (void)
{
  xa_prepare_flag = false;
}