List:Maria Storage Engine« Previous MessageNext Message »
From:Guilhem Bichot Date:October 9 2008 8:04pm
Subject:bzr commit into MySQL/Maria:mysql-maria branch (guilhem:2683) Bug#39697
View as plain text  
#At bzr+ssh://bk-internal.mysql.com/bzrroot/server/mysql-maria/

 2683 Guilhem Bichot	2008-10-09
      Fix for BUG#39697 "Maria: hang when failing to insert due to UNIQUE (seen in pushbuild2 too)"
      It was a forgotten rw_unlock(), due to the deadlock detector feature (so bug was only in 5.1-maria, not
      6.0-maria).
modified:
  mysql-test/suite/maria/r/maria3.result
  mysql-test/suite/maria/t/maria3.test
  storage/maria/ha_maria.cc
  storage/maria/ma_blockrec.c
  storage/maria/ma_commit.c
  storage/maria/ma_init.c
  storage/maria/ma_open.c
  storage/maria/ma_write.c
  storage/maria/maria_def.h

per-file messages:
  mysql-test/suite/maria/r/maria3.result
    result, all fine
  mysql-test/suite/maria/t/maria3.test
    Test of BUG#39697: two scenarios (transactional tables, and non-transactional table but dynamic row format so still taking the rwlock) where the hang happened.
    t2 added by this test was masked by a temporary table created earlier in the test, which we forgot to drop.
  storage/maria/ha_maria.cc
    use new macro
  storage/maria/ma_blockrec.c
    use new macro
  storage/maria/ma_commit.c
    use new macro
  storage/maria/ma_init.c
    putting address of dummy_transaction_object in --debug trace can be useful
  storage/maria/ma_open.c
    use new macro
  storage/maria/ma_write.c
    if local_lock_tree is true, we have acquired keyinfo->root_lock so need to release it before "goto err".
    A pair of assertions so that our usage of TrIDs is kept sensible.
  storage/maria/maria_def.h
    A macro so that changes of MARIA_HA::trn can be tracked with --debug. It helped to understand in what cases,
    in maria_write(), we could have !(info->dup_key_trid == info->trn->trid) && !share->now_transactional
    (answer: ALTER TABLE adding UNIQUE index on transactional table).
=== modified file 'mysql-test/suite/maria/r/maria3.result'
--- a/mysql-test/suite/maria/r/maria3.result	2008-10-01 12:13:39 +0000
+++ b/mysql-test/suite/maria/r/maria3.result	2008-10-09 20:03:54 +0000
@@ -506,7 +506,7 @@ count(*)
 select count(*) from t1 where a >= 4;
 count(*)
 1
-drop table t1;
+drop table t1, t2;
 create table t1 (i int auto_increment not null primary key) transactional=0;
 check table t1 extended;
 Table	Op	Msg_type	Msg_text
@@ -540,3 +540,14 @@ TABLE_SCHEMA='test' and TABLE_NAME='t1';
 CREATE_OPTIONS
 transactional=1
 drop table t1;
+create table t1 (a int, unique(a)) engine=maria transactional=1;
+insert into t1 values(1);
+insert into t1 values(2),(2);
+ERROR 23000: Duplicate entry '2' for key 'a'
+create table t2 (a int, unique(a)) engine=maria transactional=0 row_format=dynamic;
+insert into t2 values(1);
+insert into t2 values(2),(2);
+ERROR 23000: Duplicate entry '2' for key 'a'
+insert into t1 values(3);
+insert into t2 values(3);
+drop table t1, t2;

=== modified file 'mysql-test/suite/maria/t/maria3.test'
--- a/mysql-test/suite/maria/t/maria3.test	2008-10-01 12:13:39 +0000
+++ b/mysql-test/suite/maria/t/maria3.test	2008-10-09 20:03:54 +0000
@@ -406,7 +406,7 @@ insert into t2 select * from t1;
 insert into t1 select NULL from t2;
 select count(*) from t1;
 select count(*) from t1 where a >= 4;
-drop table t1;
+drop table t1, t2;
 
 #
 # Test problems with small rows and row_type=page 
@@ -461,6 +461,24 @@ select CREATE_OPTIONS from information_s
 TABLE_SCHEMA='test' and TABLE_NAME='t1';
 drop table t1;
 
+#
+# BUG#39697 - Maria: hang when failing to insert due to UNIQUE
+#
+create table t1 (a int, unique(a)) engine=maria transactional=1;
+insert into t1 values(1);
+--error 1062
+insert into t1 values(2),(2);
+create table t2 (a int, unique(a)) engine=maria transactional=0 row_format=dynamic;
+insert into t2 values(1);
+--error 1062
+insert into t2 values(2),(2);
+connect (root,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK);
+connection root;
+insert into t1 values(3);
+insert into t2 values(3);
+connection default;
+drop table t1, t2;
+
 # End of 5.1 tests
 
 --disable_result_log

=== modified file 'storage/maria/ha_maria.cc'
--- a/storage/maria/ha_maria.cc	2008-09-28 18:32:59 +0000
+++ b/storage/maria/ha_maria.cc	2008-10-09 20:03:54 +0000
@@ -2223,7 +2223,8 @@ int ha_maria::extra(enum ha_extra_functi
        operation == HA_EXTRA_PREPARE_FOR_RENAME))
   {
     THD *thd= table->in_use;
-    file->trn= THD_TRN;
+    TRN *trn= THD_TRN;
+    _ma_set_trn_for_table(file, trn);
   }
   return maria_extra(file, operation, 0);
 }
@@ -2296,7 +2297,7 @@ int ha_maria::external_lock(THD *thd, in
         if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
           trans_register_ha(thd, TRUE, maria_hton);
       }
-      file->trn= trn;
+      _ma_set_trn_for_table(file, trn);
       if (!trnman_increment_locked_tables(trn))
       {
         trans_register_ha(thd, FALSE, maria_hton);
@@ -2352,7 +2353,7 @@ int ha_maria::external_lock(THD *thd, in
       if (_ma_reenable_logging_for_table(file, TRUE))
         DBUG_RETURN(1);
       /** @todo zero file->trn also in commit and rollback */
-      file->trn= 0;                             // Safety
+      _ma_set_trn_for_table(file, NULL);        // Safety
       /*
         Ensure that file->state points to the current number of rows. This
         is needed if someone calls maria_info() without first doing an
@@ -2409,7 +2410,7 @@ int ha_maria::start_stmt(THD *thd, thr_l
       different ha_maria than 'this' then this->file->trn is a stale
       pointer. We fix it:
     */
-    file->trn= trn;
+    _ma_set_trn_for_table(file, trn);
     /*
       As external_lock() was already called, don't increment locked_tables.
       Note that we call the function below possibly several times when
@@ -2501,7 +2502,7 @@ int ha_maria::implicit_commit(THD *thd, 
         MARIA_HA *handler= ((ha_maria*) table->file)->file;
         if (handler->s->base.born_transactional)
         {
-          handler->trn= trn;
+          _ma_set_trn_for_table(handler, trn);
           if (handler->s->lock.get_status)
           {
             if (_ma_setup_live_state(handler))

=== modified file 'storage/maria/ma_blockrec.c'
--- a/storage/maria/ma_blockrec.c	2008-08-28 18:52:23 +0000
+++ b/storage/maria/ma_blockrec.c	2008-10-09 20:03:54 +0000
@@ -7081,7 +7081,7 @@ void maria_ignore_trids(MARIA_HA *info)
   if (info->s->base.born_transactional)
   {
     if (!info->trn)
-      info->trn= &dummy_transaction_object;
+      _ma_set_trn_for_table(info, &dummy_transaction_object);
     /* Ignore transaction id when row is read */
     info->trn->min_read_from= ~(TrID) 0;
   }

=== modified file 'storage/maria/ma_commit.c'
--- a/storage/maria/ma_commit.c	2008-08-07 20:57:25 +0000
+++ b/storage/maria/ma_commit.c	2008-10-09 20:03:54 +0000
@@ -111,7 +111,7 @@ int maria_begin(MARIA_HA *info)
       DBUG_RETURN(HA_ERR_OUT_OF_MEM);
 
     DBUG_PRINT("info", ("TRN set to 0x%lx", (ulong) trn));
-    info->trn= trn;
+    _ma_set_trn_for_table(info, trn);
   }
   DBUG_RETURN(0);
 }

=== modified file 'storage/maria/ma_init.c'
--- a/storage/maria/ma_init.c	2008-06-26 05:18:28 +0000
+++ b/storage/maria/ma_init.c	2008-10-09 20:03:54 +0000
@@ -68,6 +68,8 @@ int maria_init(void)
   }
   hash_init(&maria_stored_state, &my_charset_bin, 32,
             0, sizeof(LSN), 0, (hash_free_key) history_state_free, 0);
+  DBUG_PRINT("info",("dummy_transaction_object: %p",
+                     &dummy_transaction_object));
   return 0;
 }
 

=== modified file 'storage/maria/ma_open.c'
--- a/storage/maria/ma_open.c	2008-08-26 12:34:57 +0000
+++ b/storage/maria/ma_open.c	2008-10-09 20:03:54 +0000
@@ -178,7 +178,8 @@ static MARIA_HA *maria_clone_internal(MA
 
   if (!share->base.born_transactional)   /* For transactional ones ... */
   {
-    info.trn= &dummy_transaction_object; /* ... force crash if no trn given */
+    /* ... force crash if no trn given */
+    _ma_set_trn_for_table(&info, &dummy_transaction_object);
     info.state= &share->state.state;	/* Change global values by default */
   }
   else

=== modified file 'storage/maria/ma_write.c'
--- a/storage/maria/ma_write.c	2008-09-01 19:43:11 +0000
+++ b/storage/maria/ma_write.c	2008-10-09 20:03:54 +0000
@@ -194,8 +194,23 @@ int maria_write(MARIA_HA *info, uchar *r
             Also, filter out non-thread maria use, and table modified in
             the same transaction.
           */
-          if (!local_lock_tree || info->dup_key_trid == info->trn->trid)
+          if (!local_lock_tree)
             goto err;
+          if (info->dup_key_trid == info->trn->trid)
+          {
+	    rw_unlock(&keyinfo->root_lock);
+            goto err;
+          }
+          /* Different TrIDs: table must be transactional */
+          DBUG_ASSERT(share->base.born_transactional);
+          /*
+            If transactions are disabled, and dup_key_trid is different from
+            our TrID, it must be ALTER TABLE with dup_key_trid==0 (no
+            transaction). ALTER TABLE does have MARIA_HA::TRN not dummy but
+            puts TrID=0 in rows/keys.
+          */
+          DBUG_ASSERT(share->now_transactional ||
+                      (info->dup_key_trid == 0));
           blocker= trnman_trid_to_trn(info->trn, info->dup_key_trid);
           /*
             if blocker TRN was not found, it means that the conflicting

=== modified file 'storage/maria/maria_def.h'
--- a/storage/maria/maria_def.h	2008-08-28 18:52:23 +0000
+++ b/storage/maria/maria_def.h	2008-10-09 20:03:54 +0000
@@ -698,6 +698,19 @@ struct st_maria_handler
 #define get_pack_length(length) ((length) >= 255 ? 3 : 1)
 #define _ma_have_versioning(info) ((info)->row_flag & ROW_FLAG_TRANSID)
 
+/**
+   Sets table's trn and prints debug information
+   @param tbl              MARIA_HA of table
+   @param newtrn           what to put into tbl->trn
+   @note cast of newtrn is because %p of NULL gives warning (NULL is int)
+*/
+#define _ma_set_trn_for_table(tbl, newtrn) do {                         \
+    DBUG_PRINT("info",("table: %p trn: %p -> %p",                       \
+                       (tbl), (tbl)->trn, (void *)(newtrn)));           \
+    (tbl)->trn= (newtrn);                                               \
+  } while (0)
+
+
 #define MARIA_MIN_BLOCK_LENGTH	20		/* Because of delete-link */
 /* Don't use to small record-blocks */
 #define MARIA_EXTEND_BLOCK_LENGTH	20

Thread
bzr commit into MySQL/Maria:mysql-maria branch (guilhem:2683) Bug#39697Guilhem Bichot9 Oct