Commit 87ae5a15 authored by unknown's avatar unknown
Browse files

BUG#12162 - one can start two transactions with the same XID.

Now we keep all active XID's in a hash

parent e10362b4
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ a
xa start 'testa','testb';
insert t1 values (30);
xa end 'testa','testb';
xa start 'testa','testb';
ERROR XAE08: XAER_DUPID: The XID already exists
xa start 0x7465737462, 0x2030405060, 0xb;
insert t1 values (40);
xa end 'testb',' 0@P`',11;
@@ -35,11 +37,11 @@ formatID gtrid_length bqual_length data
11	5	5	testb 0@P`
1	5	5	testatestb
xa commit 'testb',0x2030405060,11;
ERROR XAE04: XAER_NOTA: Unknown XID
xa rollback 'testa','testb';
xa start 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz';
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1
select * from t1;
a
20
40
drop table t1;
+4 −0
Original line number Diff line number Diff line
@@ -31,6 +31,9 @@ xa end 'testa','testb';
connect (con1,localhost,,,);
connection con1;

--error 1438
xa start 'testa','testb';

#        gtrid [ , bqual [ , formatID ] ]
xa start 0x7465737462, 0x2030405060, 0xb;
insert t1 values (40);
@@ -47,6 +50,7 @@ xa prepare 'testa','testb';

xa recover;

--error 1397
xa commit 'testb',0x2030405060,11;
xa rollback 'testa','testb';

+1 −1
Original line number Diff line number Diff line
@@ -7037,7 +7037,7 @@ innobase_xa_prepare(
		return(0);
	}

        trx->xid=thd->transaction.xid;
        trx->xid=thd->transaction.xid_state.xid;

	/* Release a possible FIFO ticket and search latch. Since we will
	reserve the kernel mutex, we have to release the search system latch
+22 −41
Original line number Diff line number Diff line
@@ -547,8 +547,8 @@ void trans_register_ha(THD *thd, bool all, handlerton *ht_arg)
  trans->ht[trans->nht++]=ht_arg;
  DBUG_ASSERT(*ht == ht_arg);
  trans->no_2pc|=(ht_arg->prepare==0);
  if (thd->transaction.xid.is_null())
    thd->transaction.xid.set(thd->query_id);
  if (thd->transaction.xid_state.xid.is_null())
    thd->transaction.xid_state.xid.set(thd->query_id);
  DBUG_VOID_RETURN;
}

@@ -595,7 +595,7 @@ int ha_commit_trans(THD *thd, bool all)
  THD_TRANS *trans= all ? &thd->transaction.all : &thd->transaction.stmt;
  bool is_real_trans= all || thd->transaction.all.nht == 0;
  handlerton **ht= trans->ht;
  my_xid xid= thd->transaction.xid.get_my_xid();
  my_xid xid= thd->transaction.xid_state.xid.get_my_xid();
  DBUG_ENTER("ha_commit_trans");

  if (thd->in_sub_stmt)
@@ -695,7 +695,7 @@ int ha_commit_one_phase(THD *thd, bool all)
    trans->nht=0;
    trans->no_2pc=0;
    if (is_real_trans)
      thd->transaction.xid.null();
      thd->transaction.xid_state.xid.null();
    if (all)
    {
#ifdef HAVE_QUERY_CACHE
@@ -751,7 +751,7 @@ int ha_rollback_trans(THD *thd, bool all)
    trans->nht=0;
    trans->no_2pc=0;
    if (is_real_trans)
      thd->transaction.xid.null();
      thd->transaction.xid_state.xid.null();
    if (all)
    {
      thd->variables.tx_isolation=thd->session_tx_isolation;
@@ -945,6 +945,7 @@ int ha_recover(HASH *commit_list)
          char buf[XIDDATASIZE*4+6]; // see xid_to_str
          sql_print_information("ignore xid %s", xid_to_str(buf, list+i));
#endif
          xid_cache_insert(list+i, XA_PREPARED);
          found_foreign_xids++;
          continue;
        }
@@ -1008,10 +1009,8 @@ bool mysql_xa_recover(THD *thd)
{
  List<Item> field_list;
  Protocol *protocol= thd->protocol;
  handlerton **ht= handlertons, **end_ht=ht+total_ha;
  bool error=TRUE;
  int len, got;
  XID *list=0;
  int i=0;
  XID_STATE *xs;
  DBUG_ENTER("mysql_xa_recover");

  field_list.push_back(new Item_int("formatID",0,11));
@@ -1021,48 +1020,30 @@ bool mysql_xa_recover(THD *thd)

  if (protocol->send_fields(&field_list,
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
    DBUG_RETURN(TRUE);

  for (len= MAX_XID_LIST_SIZE ; list==0 && len > MIN_XID_LIST_SIZE; len/=2)
  {
    list=(XID *)my_malloc(len*sizeof(XID), MYF(0));
  }
  if (!list)
  {
    my_error(ER_OUTOFMEMORY, MYF(0), len);
    DBUG_RETURN(1);
  }

  for ( ; ht < end_ht ; ht++)
  pthread_mutex_lock(&LOCK_xid_cache);
  while (xs=(XID_STATE*)hash_element(&xid_cache, i++))
  {
    if (!(*ht)->recover)
      continue;
    while ((got=(*(*ht)->recover)(list, len)) > 0 )
    if (xs->xa_state==XA_PREPARED)
    {
      XID *xid, *end;
      for (xid=list, end=list+got; xid < end; xid++)
      {
        if (xid->get_my_xid())
          continue; // skip "our" xids
      protocol->prepare_for_resend();
        protocol->store_longlong((longlong)xid->formatID, FALSE);
        protocol->store_longlong((longlong)xid->gtrid_length, FALSE);
        protocol->store_longlong((longlong)xid->bqual_length, FALSE);
        protocol->store(xid->data, xid->gtrid_length+xid->bqual_length,
      protocol->store_longlong((longlong)xs->xid.formatID, FALSE);
      protocol->store_longlong((longlong)xs->xid.gtrid_length, FALSE);
      protocol->store_longlong((longlong)xs->xid.bqual_length, FALSE);
      protocol->store(xs->xid.data, xs->xid.gtrid_length+xs->xid.bqual_length,
                      &my_charset_bin);
      if (protocol->write())
          goto err;
      {
        pthread_mutex_unlock(&LOCK_xid_cache);
        DBUG_RETURN(1);
      }
      if (got < len)
        break;
    }
  }

  error=FALSE;
  pthread_mutex_unlock(&LOCK_xid_cache);
  send_eof(thd);
err:
  my_free((gptr)list, MYF(0));
  DBUG_RETURN(error);
  DBUG_RETURN(0);
}

/*
+7 −2
Original line number Diff line number Diff line
@@ -227,11 +227,11 @@ struct xid_t {
  char data[XIDDATASIZE];  // not \0-terminated !

  bool eq(struct xid_t *xid)
  { return !memcmp(this, xid, sizeof(long)*3+gtrid_length+bqual_length); }
  { return !memcmp(this, xid, length()); }
  bool eq(long g, long b, const char *d)
  { return g == gtrid_length && b == bqual_length && !memcmp(d, data, g+b); }
  void set(struct xid_t *xid)
  { memcpy(this, xid, sizeof(long)*3+xid->gtrid_length+xid->bqual_length); }
  { memcpy(this, xid, xid->length()); }
  void set(long f, const char *g, long gl, const char *b, long bl)
  {
    formatID= f;
@@ -270,6 +270,11 @@ struct xid_t {
           !memcmp(data, MYSQL_XID_PREFIX, MYSQL_XID_PREFIX_LEN) ?
           quick_get_my_xid() : 0;
  }
  uint length()
  {
    return sizeof(formatID)+sizeof(gtrid_length)+sizeof(bqual_length)+
           gtrid_length+bqual_length;
  }
};
typedef struct xid_t XID;

Loading