FTWRL behavior on same connection

Bug #1269085 reported by Raghavendra D Prabhu on 2014-01-14
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
MySQL patches by Codership
High
Alex Yurchenko
5.5
High
Alex Yurchenko
Percona XtraDB Cluster
Status tracked in 5.6
5.5
Undecided
Unassigned
5.6
Undecided
Unassigned

Bug Description

FTWRL with mysql is no-op after first one in same connection.

================================================
MySQL [(none)]> flush tables with read lock;
Query OK, 0 rows affected (0.00 sec)

MySQL [(none)]> flush tables with read lock;
Query OK, 0 rows affected (0.00 sec)

MySQL [(none)]> flush tables with read lock;
Query OK, 0 rows affected (0.00 sec)

MySQL [(none)]> flush tables with read lock;
Query OK, 0 rows affected (0.00 sec)
=========================================================

With WSREP it tries to resume the provider and then again pause
it

============================================

2014-01-14 22:41:19 15515 [Note] WSREP: Provider paused at 527ab192-366c-11e3-925b-0f08c7cfb132:106493
2014-01-14 22:41:20 15515 [Note] WSREP: GRL was in block commit mode when entering make_global_read_lock_block_commit
2014-01-14 22:41:20 15515 [Note] WSREP: Provider resumed.
2014-01-14 22:41:20 15515 [Note] WSREP: Provider paused at 527ab192-366c-11e3-925b-0f08c7cfb132:106493

=======================================================

The fix for https://bugs.launchpad.net/percona-xtradb-cluster/+bug/1170821 is not used due to this.

This happens because in Global_read_lock::make_global_read_lock_block_commit:

--------------------------------------

  /*
    If we didn't succeed lock_global_read_lock(), or if we already suceeded
    make_global_read_lock_block_commit(), do nothing.
  */

#ifdef WITH_WSREP
  if (m_mdl_blocks_commits_lock)
  {
    WSREP_DEBUG("GRL was in block commit mode when entering "
  "make_global_read_lock_block_commit");
    thd->mdl_context.release_lock(m_mdl_blocks_commits_lock);
    m_mdl_blocks_commits_lock= NULL;
    wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED;
    wsrep->resume(wsrep);
    m_state= GRL_ACQUIRED;
  }
#endif /* WITH_WSREP */

  if (m_state != GRL_ACQUIRED)
    DBUG_RETURN(0);

------------------------------------------------

I think the check

  if (m_state != GRL_ACQUIRED)
    DBUG_RETURN(0);

should go earlier than the WSREP branch.

This is in turn because

 in Global_read_lock::lock_global_read_lock:

 --------------------------

  if (!m_state)
  {
    MDL_request mdl_request;

    DBUG_ASSERT(! thd->mdl_context.is_lock_owner(MDL_key::GLOBAL, "", "",
                                                 MDL_SHARED));
    mdl_request.init(MDL_key::GLOBAL, "", "", MDL_SHARED, MDL_EXPLICIT);

    if (thd->mdl_context.acquire_lock(&mdl_request,
                                      thd->variables.lock_wait_timeout))
      DBUG_RETURN(1);

    m_mdl_global_shared_lock= mdl_request.ticket;
    m_state= GRL_ACQUIRED;
  }
  /*
    We DON'T set global_read_lock_blocks_commit now, it will be set after
    tables are flushed (as the present function serves for FLUSH TABLES WITH
    READ LOCK only). Doing things in this order is necessary to avoid
    deadlocks (we must allow COMMIT until all tables are closed; we should not
    forbid it before, or we can have a 3-thread deadlock if 2 do SELECT FOR
    UPDATE and one does FLUSH TABLES WITH READ LOCK).
  */
  DBUG_RETURN(0);

------------------------------------------------------

GRL is not acquired if it has already been acquired.

Tested with:

=== modified file 'Percona-Server/sql/lock.cc'
--- Percona-Server/sql/lock.cc 2013-02-12 21:54:12 +0000
+++ Percona-Server/sql/lock.cc 2014-01-15 11:04:10 +0000
@@ -1058,6 +1058,8 @@
     If we didn't succeed lock_global_read_lock(), or if we already suceeded
     make_global_read_lock_block_commit(), do nothing.
   */
+ if (m_state != GRL_ACQUIRED)
+ DBUG_RETURN(0);

 #ifdef WITH_WSREP
   if (m_mdl_blocks_commits_lock)
@@ -1072,8 +1074,6 @@
   }
 #endif /* WITH_WSREP */

- if (m_state != GRL_ACQUIRED)
- DBUG_RETURN(0);

   mdl_request.init(MDL_key::COMMIT, "", "", MDL_SHARED, MDL_EXPLICIT);

Works as vanilla mysql now:

MySQL [test]> flush tables with read lock;
Query OK, 0 rows affected (0.00 sec)

MySQL [test]> flush tables with read lock;
Query OK, 0 rows affected (0.00 sec)

MySQL [test]> flush tables with read lock;
Query OK, 0 rows affected (0.00 sec)

MySQL [test]> flush tables with read lock;
Query OK, 0 rows affected (0.00 sec)

It doesn't try to resume and then pause for every FTWRL on same
connection.

Note that this affects FTWRL issued only on same connection and
not other connections (for which it says - "[Warning] WSREP:
Attempt to lock an already locked monitor.").

For the same connection, a lock_global_read_lock after FTWRL is a
no-op, so this makes FTWRL issued on same connection a no-op
after the first one.

The

#ifdef WITH_WSREP
  if (m_mdl_blocks_commits_lock)
  {
    WSREP_DEBUG("GRL was in block commit mode when entering "
  "make_global_read_lock_block_commit");
    thd->mdl_context.release_lock(m_mdl_blocks_commits_lock);
    m_mdl_blocks_commits_lock= NULL;
    wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED;
    wsrep->resume(wsrep);
    m_state= GRL_ACQUIRED;
  }
#endif /* WITH_WSREP */

fragment was added for https://bugs.launchpad.net/codership-mysql/+bug/847353

summary: - FTWRL behavior
+ FTWRL behavior on same connection
no longer affects: codership-mysql
To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Other bug subscribers