[Commits] 369c026: MDEV-7053: WSREP_STATUS & WSREP_MEMBERSHIP I_S tables

nirbhay at mariadb.com nirbhay at mariadb.com
Sat Nov 22 21:33:52 EET 2014


revision-id: 369c02674cb024ceb1995433913ef2fb32f815ca
parent(s): cbc318fcf3680c01dca1320b87f625124a497528
committer: Nirbhay Choubey
branch nick: server_galera_is
timestamp: 2014-11-22 14:33:51 -0500
message:

MDEV-7053: WSREP_STATUS & WSREP_MEMBERSHIP I_S tables

wsrep_info INFORMATION_SCHEMA plugin to provide WSREP_STATUS
and WSREP_MEMBERSHIP tables.

---
 mysql-test/include/galera_cluster.inc              |  10 +
 mysql-test/include/galera_connect.inc              |  45 ++++
 mysql-test/include/galera_diff.inc                 | 100 ++++++++
 mysql-test/include/galera_end.inc                  |  25 ++
 mysql-test/include/galera_init.inc                 |  26 ++
 mysql-test/include/have_wsrep_enabled.inc          |  11 +
 mysql-test/suite/wsrep/include/galera_cluster.inc  |  10 -
 mysql-test/suite/wsrep/include/galera_connect.inc  |  45 ----
 mysql-test/suite/wsrep/include/galera_diff.inc     | 100 --------
 mysql-test/suite/wsrep/include/galera_end.inc      |  25 --
 mysql-test/suite/wsrep/include/galera_init.inc     |  26 --
 .../suite/wsrep/include/have_wsrep_enabled.inc     |  11 -
 plugin/wsrep_info/CMakeLists.txt                   |   5 +
 plugin/wsrep_info/mysql-test/wsrep_info/my.cnf     |  35 +++
 .../mysql-test/wsrep_info/r/plugin.result          |  17 ++
 plugin/wsrep_info/mysql-test/wsrep_info/suite.opt  |   1 +
 plugin/wsrep_info/mysql-test/wsrep_info/suite.pm   |  43 ++++
 .../wsrep_info/mysql-test/wsrep_info/t/plugin.test |  23 ++
 plugin/wsrep_info/plugin.cc                        | 265 +++++++++++++++++++++
 sql/wsrep_mysqld.cc                                |  27 ++-
 sql/wsrep_mysqld.h                                 |   1 +
 sql/wsrep_sst.cc                                   |   4 +-
 sql/wsrep_utils.h                                  |  70 +++++-
 23 files changed, 686 insertions(+), 239 deletions(-)

diff --git a/mysql-test/include/galera_cluster.inc b/mysql-test/include/galera_cluster.inc
new file mode 100644
index 0000000..bc65222
--- /dev/null
+++ b/mysql-test/include/galera_cluster.inc
@@ -0,0 +1,10 @@
+# galera_cluster.inc
+# ==================
+#
+# Description
+# -----------
+# Configure galera cluster with 2 nodes.
+#
+
+--let $galera_cluster_size = 2
+--source include/galera_init.inc
diff --git a/mysql-test/include/galera_connect.inc b/mysql-test/include/galera_connect.inc
new file mode 100644
index 0000000..bfd9b18
--- /dev/null
+++ b/mysql-test/include/galera_connect.inc
@@ -0,0 +1,45 @@
+# galera_connect.inc
+# ==================
+#
+# Description
+# -----------
+# Open a connection to the specified server number ($galera_server_number).
+# The connection itself would be identified by $galera_connection_name.
+#
+# Parameters
+# ----------
+# $galera_connection_name
+#   Name of the resulting connection.
+#
+# $galera_server_number
+#   Sequence number of the node in the galera cluster.
+#
+# $galera_debug
+#   Print debug information.
+#
+
+if (!$galera_connection_name)
+{
+  --die ERROR IN TEST: $galera_connection_name must be set before sourcing include/galera_connect.inc
+}
+
+if (!$galera_server_number)
+{
+  --die ERROR IN TEST: $galera_server_number must be set before sourcing include/galera_connect.inc
+}
+
+--let $_galera_port= \$NODE_MYPORT_$galera_server_number
+if (!$_galera_port)
+{
+  --echo Bug in test case: '\$NODE_MYPORT_$galera_server_number' not initialized. Check the test's .cfg file.
+  --die Not all NODE_MYPORT_* environment variables are setup correctly.
+}
+
+if ($galera_debug)
+{
+  --echo connect($galera_connection_name,127.0.0.1,root,,test,$_galera_port,)
+}
+
+# Open a connection
+--connect($galera_connection_name,127.0.0.1,root,,test,$_galera_port,)
+
diff --git a/mysql-test/include/galera_diff.inc b/mysql-test/include/galera_diff.inc
new file mode 100644
index 0000000..6043b58
--- /dev/null
+++ b/mysql-test/include/galera_diff.inc
@@ -0,0 +1,100 @@
+# galera_diff.inc
+# ===============
+#
+# Description
+# -----------
+# Compare the output of the given statement on all the nodes of the cluster.
+#
+# Parameters
+# ----------
+# $galera_diff_statement
+#   Statement for which the output would be compared.
+# 
+# $galera_diff_database
+#   Database against which the above statement would be executed.
+#   (Default : test)
+#
+# $galera_diff_servers
+#   Comma separated list of servers to executed the diff statement on. If not
+#   set, a list of servers will be generated based on $galera_cluster_size.
+#
+# $galerra_debug
+#   Print debug information.
+#
+
+if (!$galera_diff_statement)
+{
+  --die ERROR IN TEST: $galera_diff_statement must be set before sourcing include/galera_diff.inc
+}
+
+--let $_galera_diff_database = $galera_diff_database
+if (!$_galera_diff_database)
+{
+  --let $_galera_diff_database = test 
+}
+
+--let $_galera_diff_servers= $galera_diff_servers
+if (!$_galera_diff_servers)
+{
+  --let $_i= $galera_cluster_size
+  --let $_galera_diff_servers= 
+  while ($_i)
+  {
+    --let $_galera_diff_servers= $_i,$_galera_diff_servers
+    --dec $_i
+  }
+}
+if ($galera_debug)
+{
+  --echo \$galera_diff_servers= '$_galera_diff_servers'
+}
+
+if (!$galera_debug)
+{
+  --disable_query_log
+}
+
+# Generate file containing $galera_diff_statement. We don't pass the
+# statement on the command line, because it would be subject to shell
+# substitutions.
+--let $write_to_file= GENERATE
+--let $write_var= $galera_diff_statement
+--source include/write_var_to_file.inc
+--let $_galera_diff_statement_file= $write_to_file
+
+if (!$galera_debug)
+{
+  --enable_query_log
+}
+
+# Compare all servers.
+--let $_galera_diff_first= 1
+while ($_galera_diff_servers)
+{
+  # Set $_galera_diff_server_i to the first number in the list
+  --let $_galera_diff_server_i= `SELECT SUBSTRING_INDEX('$_galera_diff_servers', ',', 1)`
+  # Remove $_galera_diff_server_i from the list
+  --let $_galera_diff_servers= `SELECT SUBSTRING('$_galera_diff_servers', LENGTH('$_galera_diff_server_i') + 2)`
+
+  # Execute statement
+  --let $_galera_diff_file= $MYSQLTEST_VARDIR/tmp/_galera_diff_server-$_galera_diff_server_i.tmp
+  --exec $MYSQL --defaults-group-suffix=.$_galera_diff_server_i $_galera_diff_database < $_galera_diff_statement_file > $_galera_diff_file
+
+  # Compare
+  if (!$_galera_diff_first)
+  {
+    if ($galera_debug)
+    {
+      --echo diffing $_galera_diff_file and $_galera_diff_prev_file
+    }
+    --diff_files $_galera_diff_file $_galera_diff_prev_file
+    --remove_file $_galera_diff_prev_file
+  }
+  --let $_galera_diff_prev_file= $_galera_diff_file
+  --let $_galera_diff_first= 0
+}
+
+# Cleanup
+--remove_file $_galera_diff_prev_file
+--remove_file $_galera_diff_statement_file
+
diff --git a/mysql-test/include/galera_end.inc b/mysql-test/include/galera_end.inc
new file mode 100644
index 0000000..0fb5479
--- /dev/null
+++ b/mysql-test/include/galera_end.inc
@@ -0,0 +1,25 @@
+# galera_end.inc
+# ==============
+#
+# Description
+# -----------
+# Closes the connections opened via include/galera_init.inc
+#
+# Parameters
+# ----------
+# $galera_cluster_size
+#   Number of nodes in the cluster.
+#
+
+--let $_galera_node= $galera_cluster_size
+
+while ($_galera_node)
+{
+  if ($galera_debug)
+  {
+    --echo Disconnecting node_$_galera_node
+  }
+  --disconnect node_$_galera_node
+  --dec $_galera_node
+}
+
diff --git a/mysql-test/include/galera_init.inc b/mysql-test/include/galera_init.inc
new file mode 100644
index 0000000..7959197
--- /dev/null
+++ b/mysql-test/include/galera_init.inc
@@ -0,0 +1,26 @@
+# galera_init.inc
+# ===============
+#
+# Description
+# -----------
+# Set up a Galera cluster with $wsrep_cluster_size nodes.
+#
+# Parameters
+# ----------
+# $galera_cluster_size
+#   Number of nodes in the cluster.
+#
+
+--source include/have_wsrep_enabled.inc
+
+--let $_galera_node= $galera_cluster_size
+
+while ($_galera_node)
+{
+  --let $galera_connection_name= node_$_galera_node
+  --let $galera_server_number= $_galera_node
+  --source include/galera_connect.inc
+
+  --dec $_galera_node
+}
+
diff --git a/mysql-test/include/have_wsrep_enabled.inc b/mysql-test/include/have_wsrep_enabled.inc
new file mode 100644
index 0000000..94eccad
--- /dev/null
+++ b/mysql-test/include/have_wsrep_enabled.inc
@@ -0,0 +1,11 @@
+# To be used in a test which requires wsrep plugin to be ACTIVE and enabled
+# (i.e. wsrep_on=ON). It includes have_wsrep.inc.
+
+--source include/have_wsrep.inc
+--source include/have_innodb.inc
+
+if (`SELECT COUNT(*)=0 FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME = 'wsrep_on' AND VARIABLE_VALUE='ON'`)
+{
+  --skip Test requires wsrep_on=ON
+}
+
diff --git a/mysql-test/suite/wsrep/include/galera_cluster.inc b/mysql-test/suite/wsrep/include/galera_cluster.inc
deleted file mode 100644
index bc65222..0000000
--- a/mysql-test/suite/wsrep/include/galera_cluster.inc
+++ /dev/null
@@ -1,10 +0,0 @@
-# galera_cluster.inc
-# ==================
-#
-# Description
-# -----------
-# Configure galera cluster with 2 nodes.
-#
-
---let $galera_cluster_size = 2
---source include/galera_init.inc
diff --git a/mysql-test/suite/wsrep/include/galera_connect.inc b/mysql-test/suite/wsrep/include/galera_connect.inc
deleted file mode 100644
index bfd9b18..0000000
--- a/mysql-test/suite/wsrep/include/galera_connect.inc
+++ /dev/null
@@ -1,45 +0,0 @@
-# galera_connect.inc
-# ==================
-#
-# Description
-# -----------
-# Open a connection to the specified server number ($galera_server_number).
-# The connection itself would be identified by $galera_connection_name.
-#
-# Parameters
-# ----------
-# $galera_connection_name
-#   Name of the resulting connection.
-#
-# $galera_server_number
-#   Sequence number of the node in the galera cluster.
-#
-# $galera_debug
-#   Print debug information.
-#
-
-if (!$galera_connection_name)
-{
-  --die ERROR IN TEST: $galera_connection_name must be set before sourcing include/galera_connect.inc
-}
-
-if (!$galera_server_number)
-{
-  --die ERROR IN TEST: $galera_server_number must be set before sourcing include/galera_connect.inc
-}
-
---let $_galera_port= \$NODE_MYPORT_$galera_server_number
-if (!$_galera_port)
-{
-  --echo Bug in test case: '\$NODE_MYPORT_$galera_server_number' not initialized. Check the test's .cfg file.
-  --die Not all NODE_MYPORT_* environment variables are setup correctly.
-}
-
-if ($galera_debug)
-{
-  --echo connect($galera_connection_name,127.0.0.1,root,,test,$_galera_port,)
-}
-
-# Open a connection
---connect($galera_connection_name,127.0.0.1,root,,test,$_galera_port,)
-
diff --git a/mysql-test/suite/wsrep/include/galera_diff.inc b/mysql-test/suite/wsrep/include/galera_diff.inc
deleted file mode 100644
index 6043b58..0000000
--- a/mysql-test/suite/wsrep/include/galera_diff.inc
+++ /dev/null
@@ -1,100 +0,0 @@
-# galera_diff.inc
-# ===============
-#
-# Description
-# -----------
-# Compare the output of the given statement on all the nodes of the cluster.
-#
-# Parameters
-# ----------
-# $galera_diff_statement
-#   Statement for which the output would be compared.
-# 
-# $galera_diff_database
-#   Database against which the above statement would be executed.
-#   (Default : test)
-#
-# $galera_diff_servers
-#   Comma separated list of servers to executed the diff statement on. If not
-#   set, a list of servers will be generated based on $galera_cluster_size.
-#
-# $galerra_debug
-#   Print debug information.
-#
-
-if (!$galera_diff_statement)
-{
-  --die ERROR IN TEST: $galera_diff_statement must be set before sourcing include/galera_diff.inc
-}
-
---let $_galera_diff_database = $galera_diff_database
-if (!$_galera_diff_database)
-{
-  --let $_galera_diff_database = test 
-}
-
---let $_galera_diff_servers= $galera_diff_servers
-if (!$_galera_diff_servers)
-{
-  --let $_i= $galera_cluster_size
-  --let $_galera_diff_servers= 
-  while ($_i)
-  {
-    --let $_galera_diff_servers= $_i,$_galera_diff_servers
-    --dec $_i
-  }
-}
-if ($galera_debug)
-{
-  --echo \$galera_diff_servers= '$_galera_diff_servers'
-}
-
-if (!$galera_debug)
-{
-  --disable_query_log
-}
-
-# Generate file containing $galera_diff_statement. We don't pass the
-# statement on the command line, because it would be subject to shell
-# substitutions.
---let $write_to_file= GENERATE
---let $write_var= $galera_diff_statement
---source include/write_var_to_file.inc
---let $_galera_diff_statement_file= $write_to_file
-
-if (!$galera_debug)
-{
-  --enable_query_log
-}
-
-# Compare all servers.
---let $_galera_diff_first= 1
-while ($_galera_diff_servers)
-{
-  # Set $_galera_diff_server_i to the first number in the list
-  --let $_galera_diff_server_i= `SELECT SUBSTRING_INDEX('$_galera_diff_servers', ',', 1)`
-  # Remove $_galera_diff_server_i from the list
-  --let $_galera_diff_servers= `SELECT SUBSTRING('$_galera_diff_servers', LENGTH('$_galera_diff_server_i') + 2)`
-
-  # Execute statement
-  --let $_galera_diff_file= $MYSQLTEST_VARDIR/tmp/_galera_diff_server-$_galera_diff_server_i.tmp
-  --exec $MYSQL --defaults-group-suffix=.$_galera_diff_server_i $_galera_diff_database < $_galera_diff_statement_file > $_galera_diff_file
-
-  # Compare
-  if (!$_galera_diff_first)
-  {
-    if ($galera_debug)
-    {
-      --echo diffing $_galera_diff_file and $_galera_diff_prev_file
-    }
-    --diff_files $_galera_diff_file $_galera_diff_prev_file
-    --remove_file $_galera_diff_prev_file
-  }
-  --let $_galera_diff_prev_file= $_galera_diff_file
-  --let $_galera_diff_first= 0
-}
-
-# Cleanup
---remove_file $_galera_diff_prev_file
---remove_file $_galera_diff_statement_file
-
diff --git a/mysql-test/suite/wsrep/include/galera_end.inc b/mysql-test/suite/wsrep/include/galera_end.inc
deleted file mode 100644
index 0fb5479..0000000
--- a/mysql-test/suite/wsrep/include/galera_end.inc
+++ /dev/null
@@ -1,25 +0,0 @@
-# galera_end.inc
-# ==============
-#
-# Description
-# -----------
-# Closes the connections opened via include/galera_init.inc
-#
-# Parameters
-# ----------
-# $galera_cluster_size
-#   Number of nodes in the cluster.
-#
-
---let $_galera_node= $galera_cluster_size
-
-while ($_galera_node)
-{
-  if ($galera_debug)
-  {
-    --echo Disconnecting node_$_galera_node
-  }
-  --disconnect node_$_galera_node
-  --dec $_galera_node
-}
-
diff --git a/mysql-test/suite/wsrep/include/galera_init.inc b/mysql-test/suite/wsrep/include/galera_init.inc
deleted file mode 100644
index 7959197..0000000
--- a/mysql-test/suite/wsrep/include/galera_init.inc
+++ /dev/null
@@ -1,26 +0,0 @@
-# galera_init.inc
-# ===============
-#
-# Description
-# -----------
-# Set up a Galera cluster with $wsrep_cluster_size nodes.
-#
-# Parameters
-# ----------
-# $galera_cluster_size
-#   Number of nodes in the cluster.
-#
-
---source include/have_wsrep_enabled.inc
-
---let $_galera_node= $galera_cluster_size
-
-while ($_galera_node)
-{
-  --let $galera_connection_name= node_$_galera_node
-  --let $galera_server_number= $_galera_node
-  --source include/galera_connect.inc
-
-  --dec $_galera_node
-}
-
diff --git a/mysql-test/suite/wsrep/include/have_wsrep_enabled.inc b/mysql-test/suite/wsrep/include/have_wsrep_enabled.inc
deleted file mode 100644
index 94eccad..0000000
--- a/mysql-test/suite/wsrep/include/have_wsrep_enabled.inc
+++ /dev/null
@@ -1,11 +0,0 @@
-# To be used in a test which requires wsrep plugin to be ACTIVE and enabled
-# (i.e. wsrep_on=ON). It includes have_wsrep.inc.
-
---source include/have_wsrep.inc
---source include/have_innodb.inc
-
-if (`SELECT COUNT(*)=0 FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME = 'wsrep_on' AND VARIABLE_VALUE='ON'`)
-{
-  --skip Test requires wsrep_on=ON
-}
-
diff --git a/plugin/wsrep_info/CMakeLists.txt b/plugin/wsrep_info/CMakeLists.txt
new file mode 100644
index 0000000..4d7c3ed
--- /dev/null
+++ b/plugin/wsrep_info/CMakeLists.txt
@@ -0,0 +1,5 @@
+IF (WITH_WSREP)
+  INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql
+                      ${CMAKE_SOURCE_DIR}/wsrep)
+  MYSQL_ADD_PLUGIN(WSREP_STATUS plugin.cc)
+ENDIF()
diff --git a/plugin/wsrep_info/mysql-test/wsrep_info/my.cnf b/plugin/wsrep_info/mysql-test/wsrep_info/my.cnf
new file mode 100644
index 0000000..4af933f
--- /dev/null
+++ b/plugin/wsrep_info/mysql-test/wsrep_info/my.cnf
@@ -0,0 +1,35 @@
+# Use default setting for mysqld processes
+!include include/default_mysqld.cnf
+
+[mysqld]
+wsrep-on=1
+binlog-format=row
+innodb-autoinc-lock-mode=2
+innodb-locks-unsafe-for-binlog=1
+wsrep-cluster-address=gcomm://
+wsrep_provider=@ENV.WSREP_PROVIDER
+# enforce read-committed characteristics across the cluster
+wsrep_causal_reads=ON
+
+[mysqld.1]
+#galera_port=@OPT.port
+#sst_port=@OPT.port
+wsrep_provider_options='base_port=@mysqld.1.#galera_port'
+wsrep_sst_receive_address='127.0.0.1:@mysqld.1.#sst_port'
+wsrep_node_name=test-node-1
+
+[mysqld.2]
+#galera_port=@OPT.port
+#sst_port=@OPT.port
+wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
+wsrep_provider_options='base_port=@mysqld.2.#galera_port'
+wsrep_sst_receive_address='127.0.0.1:@mysqld.2.#sst_port'
+wsrep_node_name=test-node-2
+
+[ENV]
+NODE_MYPORT_1= @mysqld.1.port
+NODE_MYSOCK_1= @mysqld.1.socket
+
+NODE_MYPORT_2= @mysqld.2.port
+NODE_MYSOCK_2= @mysqld.2.socket
+
diff --git a/plugin/wsrep_info/mysql-test/wsrep_info/r/plugin.result b/plugin/wsrep_info/mysql-test/wsrep_info/r/plugin.result
new file mode 100644
index 0000000..1aef7c3
--- /dev/null
+++ b/plugin/wsrep_info/mysql-test/wsrep_info/r/plugin.result
@@ -0,0 +1,17 @@
+# On node 1
+SELECT * FROM INFORMATION_SCHEMA.WSREP_STATUS;
+NODE_INDEX	NODE_STATUS	CLUSTER_STATUS	CLUSTER_SIZE	CLUSTER_STATE_UUID	CLUSTER_STATE_SEQNO	CLUSTER_CONF_ID	GAP	PROTOCOL_VERSION
+<IDX>	Synced	Primary	2	<CLUSTER_STATE_UUID>	0	2	NO	3
+SELECT * FROM INFORMATION_SCHEMA.WSREP_MEMBERSHIP ORDER BY NAME;
+INDEX	UUID	NAME	ADDRESS
+<IDX>	<MEMBER_ID>	test-node-1	<ADDRESS>
+<IDX>	<MEMBER_ID>	test-node-2	<ADDRESS>
+# On node 2
+SELECT * FROM INFORMATION_SCHEMA.WSREP_STATUS;
+NODE_INDEX	NODE_STATUS	CLUSTER_STATUS	CLUSTER_SIZE	CLUSTER_STATE_UUID	CLUSTER_STATE_SEQNO	CLUSTER_CONF_ID	GAP	PROTOCOL_VERSION
+<IDX>	Synced	Primary	2	<CLUSTER_STATE_UUID>	0	2	YES	3
+SELECT * FROM INFORMATION_SCHEMA.WSREP_MEMBERSHIP ORDER BY NAME;
+INDEX	UUID	NAME	ADDRESS
+<IDX>	<MEMBER_ID>	test-node-1	<ADDRESS>
+<IDX>	<MEMBER_ID>	test-node-2	<ADDRESS>
+# End of test
diff --git a/plugin/wsrep_info/mysql-test/wsrep_info/suite.opt b/plugin/wsrep_info/mysql-test/wsrep_info/suite.opt
new file mode 100644
index 0000000..c806c2e
--- /dev/null
+++ b/plugin/wsrep_info/mysql-test/wsrep_info/suite.opt
@@ -0,0 +1 @@
+--plugin-load-add=$WSREP_STATUS_SO
diff --git a/plugin/wsrep_info/mysql-test/wsrep_info/suite.pm b/plugin/wsrep_info/mysql-test/wsrep_info/suite.pm
new file mode 100644
index 0000000..5af1daa
--- /dev/null
+++ b/plugin/wsrep_info/mysql-test/wsrep_info/suite.pm
@@ -0,0 +1,43 @@
+package My::Suite::WSREP_STATUS;
+use File::Basename;
+use My::Find;
+
+ at ISA = qw(My::Suite);
+
+return "Not run for embedded server" if $::opt_embedded_server;
+
+return "WSREP is not compiled in" unless defined $::mysqld_variables{'wsrep-on'};
+
+my ($provider) = grep { -f $_ } $ENV{WSREP_PROVIDER},
+                                "/usr/lib/galera/libgalera_smm.so",
+                                "/usr/lib64/galera/libgalera_smm.so";
+
+return "No wsrep provider library" unless -f $provider;
+
+return "No WSREP_STATUS plugin" unless $ENV{WSREP_STATUS_SO};
+
+$ENV{WSREP_PROVIDER} = $provider;
+
+my ($spath) = grep { -f "$_/wsrep_sst_rsync"; } "$::bindir/scripts", $::path_client_bindir;
+return "No SST scripts" unless $spath;
+
+my ($epath) = grep { -f "$_/my_print_defaults"; } "$::bindir/extra", $::path_client_bindir;
+return "No my_print_defaults" unless $epath;
+
+push @::global_suppressions,
+  (
+     qr(WSREP:.*down context.*),
+     qr(WSREP: Failed to send state UUID:.*),
+     qr(WSREP: wsrep_sst_receive_address.*),
+     qr(WSREP: Could not open saved state file for reading: .*),
+     qr(WSREP: last inactive check more than .* skipping check),
+     qr(WSREP: Gap in state sequence. Need state transfer.),
+     qr(WSREP: Failed to prepare for incremental state transfer: .*),
+   );
+
+
+$ENV{PATH}="$epath:$ENV{PATH}";
+$ENV{PATH}="$spath:$ENV{PATH}" unless $epath eq $spath;
+
+bless { };
+
diff --git a/plugin/wsrep_info/mysql-test/wsrep_info/t/plugin.test b/plugin/wsrep_info/mysql-test/wsrep_info/t/plugin.test
new file mode 100644
index 0000000..9b06f15
--- /dev/null
+++ b/plugin/wsrep_info/mysql-test/wsrep_info/t/plugin.test
@@ -0,0 +1,23 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--echo # On node 1
+--connection node_1
+
+--replace_column 1 <IDX> 5 <CLUSTER_STATE_UUID>
+SELECT * FROM INFORMATION_SCHEMA.WSREP_STATUS;
+
+--replace_column 1 <IDX> 2 <MEMBER_ID> 4 <ADDRESS>
+SELECT * FROM INFORMATION_SCHEMA.WSREP_MEMBERSHIP ORDER BY NAME;
+
+--echo # On node 2
+--connection node_2
+
+--replace_column 1 <IDX> 5 <CLUSTER_STATE_UUID>
+SELECT * FROM INFORMATION_SCHEMA.WSREP_STATUS;
+
+--replace_column 1 <IDX> 2 <MEMBER_ID> 4 <ADDRESS>
+SELECT * FROM INFORMATION_SCHEMA.WSREP_MEMBERSHIP ORDER BY NAME;
+
+--source include/galera_end.inc
+--echo # End of test
diff --git a/plugin/wsrep_info/plugin.cc b/plugin/wsrep_info/plugin.cc
new file mode 100644
index 0000000..50c2019
--- /dev/null
+++ b/plugin/wsrep_info/plugin.cc
@@ -0,0 +1,265 @@
+/* Copyright (C) 2014 MariaDB Corporation.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef MYSQL_SERVER
+#define MYSQL_SERVER
+#endif
+
+#include <mysql/plugin.h>
+#include <table.h>                              /* ST_SCHEMA_TABLE */
+#include <sql_show.h>
+#include <sql_acl.h>                            /* check_global_access() */
+#include <wsrep_mysqld.h>
+#include <wsrep_utils.h>
+
+/* WSREP_MEMBERSHIP table fields */
+
+/* Node index */
+#define COLUMN_WSREP_MEMB_INDEX 0
+/* Unique member ID */
+#define COLUMN_WSREP_MEMB_UUID 1
+/* Human-readable name */
+#define COLUMN_WSREP_MEMB_NAME 2
+/* Incoming address */
+#define COLUMN_WSREP_MEMB_ADDRESS 3
+
+/* WSREP_STATUS table fields */
+
+/* Node index */
+#define COLUMN_WSREP_STATUS_NODE_INDEX 0
+/* Node status */
+#define COLUMN_WSREP_STATUS_NODE_STATUS 1
+/* Cluster status */
+#define COLUMN_WSREP_STATUS_CLUSTER_STATUS 2
+/* Cluster size */
+#define COLUMN_WSREP_STATUS_CLUSTER_SIZE 3
+/* Global cluster state UUID */
+#define COLUMN_WSREP_STATUS_CLUSTER_STATE_UUID 4
+/* Global cluster state Sequence number */
+#define COLUMN_WSREP_STATUS_CLUSTER_STATE_SEQNO 5
+/* Cluster membership changes */
+#define COLUMN_WSREP_STATUS_CLUSTER_CONF_ID 6
+/* Gap between global and local states ? */
+#define COLUMN_WSREP_STATUS_GAP 7
+/* Application protocol version */
+#define COLUMN_WSREP_STATUS_PROTO_VERSION 8
+
+static const char* get_member_status(wsrep_member_status_t status)
+{
+  switch (status)
+  {
+    case WSREP_MEMBER_UNDEFINED: return "Undefined";
+    case WSREP_MEMBER_JOINER: return "Joiner";
+    case WSREP_MEMBER_DONOR: return "Donor";
+    case WSREP_MEMBER_JOINED: return "Joined";
+    case WSREP_MEMBER_SYNCED: return "Synced";
+    case WSREP_MEMBER_ERROR: return "Error";
+    default: break;
+  }
+  return "UNKNOWN";
+}
+
+static const char* get_cluster_status(wsrep_view_status_t status)
+{
+  switch (status)
+  {
+    case WSREP_VIEW_PRIMARY: return "Primary";
+    case WSREP_VIEW_NON_PRIMARY: return "Non-primary";
+    case WSREP_VIEW_DISCONNECTED: return "Disconnected";
+    default: break;
+  }
+  return "UNKNOWN";
+}
+
+static ST_FIELD_INFO wsrep_memb_fields[]=
+{
+  {"INDEX", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Index", 0},
+  {"UUID", WSREP_UUID_STR_LEN, MYSQL_TYPE_STRING, 0, 0, "Uuid", 0},
+  {"NAME", WSREP_MEMBER_NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Name", 0},
+  {"ADDRESS", WSREP_INCOMING_LEN, MYSQL_TYPE_STRING, 0, 0, "Address", 0},
+  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
+};
+
+static ST_FIELD_INFO wsrep_status_fields[]=
+{
+  {"NODE_INDEX", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
+    0, 0, "Node_Index", 0},
+  {"NODE_STATUS", 16, MYSQL_TYPE_STRING, 0, 0, "Node_Status", 0},
+  {"CLUSTER_STATUS", 16, MYSQL_TYPE_STRING, 0, 0, "Cluster_Status", 0},
+  {"CLUSTER_SIZE", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
+    0, 0, "Cluster_Size", 0},
+  {"CLUSTER_STATE_UUID", WSREP_UUID_STR_LEN, MYSQL_TYPE_STRING,
+    0, 0, 0, 0},
+  {"CLUSTER_STATE_SEQNO", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
+    0, 0, 0, 0},
+  {"CLUSTER_CONF_ID", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
+    0, 0, 0, 0},
+  {"GAP", 10, MYSQL_TYPE_STRING, 0, 0, 0, 0},
+  {"PROTOCOL_VERSION", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
+    0, 0, 0, 0},
+  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
+};
+
+static int wsrep_memb_fill_table(THD *thd, TABLE_LIST *tables, COND *cond)
+{
+  int rc= 0;
+
+  if (check_global_access(thd, SUPER_ACL, true))
+    return rc;
+
+  wsrep_config_state.lock();
+
+  Dynamic_array<wsrep_member_info_t> *memb_arr=
+    wsrep_config_state.get_member_info();
+
+  TABLE *table= tables->table;
+
+  for (unsigned int i= 0; i < memb_arr->elements(); i ++)
+  {
+    wsrep_member_info_t memb= memb_arr->at(i);
+
+    table->field[COLUMN_WSREP_MEMB_INDEX]->store(i, 0);
+
+    char uuid[40];
+    wsrep_uuid_print(&memb.id, uuid, sizeof(uuid));
+    table->field[COLUMN_WSREP_MEMB_UUID]->store(uuid, sizeof(uuid),
+                                                system_charset_info);
+    table->field[COLUMN_WSREP_MEMB_NAME]->store(memb.name, strlen(memb.name),
+                                                system_charset_info);
+    table->field[COLUMN_WSREP_MEMB_ADDRESS]->store(memb.incoming,
+                                                   strlen(memb.incoming),
+                                                   system_charset_info);
+
+    if (schema_table_store_record(thd, table))
+    {
+      rc= 1;
+      goto end;
+    }
+  }
+
+end:
+  wsrep_config_state.unlock();
+  return rc;
+}
+
+static int wsrep_memb_plugin_init(void *p)
+{
+  ST_SCHEMA_TABLE *schema= (ST_SCHEMA_TABLE *)p;
+
+  schema->fields_info= wsrep_memb_fields;
+  schema->fill_table= wsrep_memb_fill_table;
+
+  return 0;
+}
+
+static struct st_mysql_information_schema wsrep_memb_plugin=
+{ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
+
+static int wsrep_status_fill_table(THD *thd, TABLE_LIST *tables, COND *cond)
+{
+  int rc= 0;
+
+  if (check_global_access(thd, SUPER_ACL, true))
+    return rc;
+
+  wsrep_config_state.lock();
+
+  wsrep_view_info_t view= wsrep_config_state.get_view_info();
+  wsrep_member_status_t status= wsrep_config_state.get_status();
+
+  TABLE *table= tables->table;
+
+  table->field[COLUMN_WSREP_STATUS_NODE_INDEX]
+    ->store(view.my_idx, 0);
+  table->field[COLUMN_WSREP_STATUS_NODE_STATUS]
+    ->store(get_member_status(status), strlen(get_member_status(status)),
+            system_charset_info);
+  table->field[COLUMN_WSREP_STATUS_CLUSTER_STATUS]
+    ->store(get_cluster_status(view.status),
+            strlen(get_cluster_status(view.status)),
+            system_charset_info);
+  table->field[COLUMN_WSREP_STATUS_CLUSTER_SIZE]->store(view.memb_num, 0);
+
+  char uuid[40];
+  wsrep_uuid_print(&view.state_id.uuid, uuid, sizeof(uuid));
+  table->field[COLUMN_WSREP_STATUS_CLUSTER_STATE_UUID]
+    ->store(uuid, sizeof(uuid), system_charset_info);
+
+  table->field[COLUMN_WSREP_STATUS_CLUSTER_STATE_SEQNO]
+    ->store(view.state_id.seqno, 0);
+  table->field[COLUMN_WSREP_STATUS_CLUSTER_CONF_ID]->store(view.view, 0);
+
+  const char *gap= (view.state_gap == true) ? "YES" : "NO";
+  table->field[COLUMN_WSREP_STATUS_GAP]->store(gap, strlen(gap),
+                                               system_charset_info);
+  table->field[COLUMN_WSREP_STATUS_PROTO_VERSION]->store(view.proto_ver, 0);
+
+  if (schema_table_store_record(thd, table))
+    rc= 1;
+
+  wsrep_config_state.unlock();
+  return rc;
+}
+
+static int wsrep_status_plugin_init(void *p)
+{
+  ST_SCHEMA_TABLE *schema= (ST_SCHEMA_TABLE *)p;
+
+  schema->fields_info= wsrep_status_fields;
+  schema->fill_table= wsrep_status_fill_table;
+
+  return 0;
+}
+
+static struct st_mysql_information_schema wsrep_status_plugin=
+{ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
+
+/*
+  Plugin library descriptor
+*/
+
+maria_declare_plugin(wsrep_status)
+{
+  MYSQL_INFORMATION_SCHEMA_PLUGIN,
+  &wsrep_memb_plugin,
+  "WSREP_MEMBERSHIP",                           /* Plugin name        */
+  "Nirbhay Choubey",                            /* Plugin author      */
+  "Information about group members",            /* Plugin description */
+  PLUGIN_LICENSE_GPL,                           /* License            */
+  wsrep_memb_plugin_init,                       /* Plugin Init        */
+  0,                                            /* Plugin Deinit      */
+  0x0100,                                       /* Version (hex)      */
+  NULL,                                         /* Status variables   */
+  NULL,                                         /* System variables   */
+  "1.0",                                        /* Version (string)   */
+  MariaDB_PLUGIN_MATURITY_ALPHA                 /* Maturity           */
+},
+{
+  MYSQL_INFORMATION_SCHEMA_PLUGIN,
+  &wsrep_status_plugin,
+  "WSREP_STATUS",                               /* Plugin name        */
+  "Nirbhay Choubey",                            /* Plugin author      */
+  "Group view information",                     /* Plugin description */
+  PLUGIN_LICENSE_GPL,                           /* License            */
+  wsrep_status_plugin_init,                     /* Plugin Init        */
+  0,                                            /* Plugin Deinit      */
+  0x0100,                                       /* Version (hex)      */
+  NULL,                                         /* Status variables   */
+  NULL,                                         /* System variables   */
+  "1.0",                                        /* Version (string)   */
+  MariaDB_PLUGIN_MATURITY_ALPHA                 /* Maturity           */
+}
+maria_declare_plugin_end;
+
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
index 81b1e18..fed3519 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -110,6 +110,8 @@ mysql_mutex_t LOCK_wsrep_replaying;
 mysql_cond_t  COND_wsrep_replaying;
 mysql_mutex_t LOCK_wsrep_slave_threads;
 mysql_mutex_t LOCK_wsrep_desync;
+mysql_mutex_t LOCK_wsrep_config_state;
+
 int wsrep_replaying= 0;
 ulong  wsrep_running_threads = 0; // # of currently running wsrep threads
 ulong  my_bind_addr;
@@ -118,7 +120,8 @@ ulong  my_bind_addr;
 PSI_mutex_key key_LOCK_wsrep_rollback, key_LOCK_wsrep_thd,
   key_LOCK_wsrep_replaying, key_LOCK_wsrep_ready, key_LOCK_wsrep_sst,
   key_LOCK_wsrep_sst_thread, key_LOCK_wsrep_sst_init,
-  key_LOCK_wsrep_slave_threads, key_LOCK_wsrep_desync;
+  key_LOCK_wsrep_slave_threads, key_LOCK_wsrep_desync,
+  key_LOCK_wsrep_config_state;
 
 PSI_cond_key key_COND_wsrep_rollback, key_COND_wsrep_thd,
   key_COND_wsrep_replaying, key_COND_wsrep_ready, key_COND_wsrep_sst,
@@ -135,7 +138,8 @@ static PSI_mutex_info wsrep_mutexes[]=
   { &key_LOCK_wsrep_thd, "THD::LOCK_wsrep_thd", 0},
   { &key_LOCK_wsrep_replaying, "LOCK_wsrep_replaying", PSI_FLAG_GLOBAL},
   { &key_LOCK_wsrep_slave_threads, "LOCK_wsrep_slave_threads", PSI_FLAG_GLOBAL},
-  { &key_LOCK_wsrep_desync, "LOCK_wsrep_desync", PSI_FLAG_GLOBAL}
+  { &key_LOCK_wsrep_desync, "LOCK_wsrep_desync", PSI_FLAG_GLOBAL},
+  { &key_LOCK_wsrep_config_state, "LOCK_wsrep_config_state", PSI_FLAG_GLOBAL}
 };
 
 static PSI_cond_info wsrep_conds[]=
@@ -186,9 +190,10 @@ const char* wsrep_provider_vendor    = provider_vendor;
 
 wsrep_uuid_t     local_uuid   = WSREP_UUID_UNDEFINED;
 wsrep_seqno_t    local_seqno  = WSREP_SEQNO_UNDEFINED;
-wsp::node_status local_status;
 long             wsrep_protocol_version = 3;
 
+wsp::Config_state wsrep_config_state;
+
 // Boolean denoting if server is in initial startup phase. This is needed
 // to make sure that main thread waiting in wsrep_sst_wait() is signaled
 // if there was no state gap on receiving first view event.
@@ -306,7 +311,7 @@ wsrep_view_handler_cb (void*                    app_ctx,
   *sst_req     = NULL;
   *sst_req_len = 0;
 
-  wsrep_member_status_t new_status= local_status.get();
+  wsrep_member_status_t memb_status= wsrep_config_state.get_status();
 
   if (memcmp(&cluster_uuid, &view->state_id.uuid, sizeof(wsrep_uuid_t)))
   {
@@ -331,7 +336,7 @@ wsrep_view_handler_cb (void*                    app_ctx,
   /* Proceed further only if view is PRIMARY */
   if (WSREP_VIEW_PRIMARY != view->status) {
     wsrep_ready_set(FALSE);
-    new_status= WSREP_MEMBER_UNDEFINED;
+    memb_status= WSREP_MEMBER_UNDEFINED;
     /* Always record local_uuid and local_seqno in non-prim since this
      * may lead to re-initializing provider and start position is
      * determined according to these variables */
@@ -386,13 +391,13 @@ wsrep_view_handler_cb (void*                    app_ctx,
     {
       WSREP_ERROR("SST preparation failed: %zd (%s)", -req_len,
                   strerror(-req_len));
-      new_status= WSREP_MEMBER_UNDEFINED;
+      memb_status= WSREP_MEMBER_UNDEFINED;
     }
     else
     {
       assert(sst_req != NULL);
       *sst_req_len= req_len;
-      new_status= WSREP_MEMBER_JOINER;
+      memb_status= WSREP_MEMBER_JOINER;
     }
   }
   else
@@ -420,7 +425,7 @@ wsrep_view_handler_cb (void*                    app_ctx,
       XID xid;
       wsrep_xid_init(&xid, &local_uuid, local_seqno);
       wsrep_set_SE_checkpoint(&xid);
-      new_status= WSREP_MEMBER_JOINED;
+      memb_status= WSREP_MEMBER_JOINED;
 #ifdef GTID_SUPPORT
       wsrep_init_sidno(local_uuid);
 #endif /* GTID_SUPPORT */
@@ -456,7 +461,7 @@ wsrep_view_handler_cb (void*                    app_ctx,
 
 out:
   if (view->status == WSREP_VIEW_PRIMARY) wsrep_startup= FALSE;
-  local_status.set(new_status, view);
+  wsrep_config_state.set(memb_status, view);
 
   return WSREP_CB_SUCCESS;
 }
@@ -498,7 +503,7 @@ static void wsrep_synced_cb(void* app_ctx)
     signal_main= true;
 
   }
-  local_status.set(WSREP_MEMBER_SYNCED);
+  wsrep_config_state.set(WSREP_MEMBER_SYNCED);
   mysql_mutex_unlock (&LOCK_wsrep_ready);
 
   if (signal_main)
@@ -601,6 +606,7 @@ int wsrep_init()
   mysql_cond_init(key_COND_wsrep_replaying, &COND_wsrep_replaying, NULL);
   mysql_mutex_init(key_LOCK_wsrep_slave_threads, &LOCK_wsrep_slave_threads, MY_MUTEX_INIT_FAST);
   mysql_mutex_init(key_LOCK_wsrep_desync, &LOCK_wsrep_desync, MY_MUTEX_INIT_FAST);
+  mysql_mutex_init(key_LOCK_wsrep_config_state, &LOCK_wsrep_config_state, MY_MUTEX_INIT_FAST);
 
   wsrep_ready_set(FALSE);
   assert(wsrep_provider);
@@ -846,6 +852,7 @@ void wsrep_deinit(bool free_options)
   mysql_cond_destroy(&COND_wsrep_replaying);
   mysql_mutex_destroy(&LOCK_wsrep_slave_threads);
   mysql_mutex_destroy(&LOCK_wsrep_desync);
+  mysql_mutex_destroy(&LOCK_wsrep_config_state);
 }
 
 void wsrep_recover()
diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h
index ce22dc4..22f62dc 100644
--- a/sql/wsrep_mysqld.h
+++ b/sql/wsrep_mysqld.h
@@ -232,6 +232,7 @@ extern mysql_mutex_t LOCK_wsrep_replaying;
 extern mysql_cond_t  COND_wsrep_replaying;
 extern mysql_mutex_t LOCK_wsrep_slave_threads;
 extern mysql_mutex_t LOCK_wsrep_desync;
+extern mysql_mutex_t LOCK_wsrep_config_state;
 extern wsrep_aborting_thd_t wsrep_aborting_thd;
 extern my_bool       wsrep_emulate_bin_log;
 extern int           wsrep_to_isolation;
diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc
index 1794330..bdd8aa9 100644
--- a/sql/wsrep_sst.cc
+++ b/sql/wsrep_sst.cc
@@ -1102,8 +1102,8 @@ wsrep_cb_status_t wsrep_sst_donate_cb (void* app_ctx, void* recv_ctx,
 {
   /* This will be reset when sync callback is called.
    * Should we set wsrep_ready to FALSE here too? */
-//  wsrep_notify_status(WSREP_MEMBER_DONOR);
-  local_status.set(WSREP_MEMBER_DONOR);
+
+  wsrep_config_state.set(WSREP_MEMBER_DONOR);
 
   const char* method = (char*)msg;
   size_t method_len  = strlen (method);
diff --git a/sql/wsrep_utils.h b/sql/wsrep_utils.h
index 3376782..0e459c7 100644
--- a/sql/wsrep_utils.h
+++ b/sql/wsrep_utils.h
@@ -17,32 +17,82 @@
 #define WSREP_UTILS_H
 
 #include "wsrep_priv.h"
+#include "wsrep_mysqld.h"
 
 unsigned int wsrep_check_ip (const char* addr);
 size_t wsrep_guess_ip (char* buf, size_t buf_len);
 size_t wsrep_guess_address(char* buf, size_t buf_len);
 
 namespace wsp {
-class node_status
+
+class Config_state
 {
 public:
-  node_status() : status(WSREP_MEMBER_UNDEFINED) {}
-  void set(wsrep_member_status_t new_status,
-           const wsrep_view_info_t* view = 0)
+  Config_state() : view_(), status_(WSREP_MEMBER_UNDEFINED)
+  {}
+
+  void set(wsrep_member_status_t status, const wsrep_view_info_t* view)
   {
-    if (status != new_status || 0 != view)
+    wsrep_notify_status(status, view);
+
+    lock();
+
+    status_= status;
+    view_= *view;
+    member_info_.clear();
+
+    wsrep_member_info_t memb;
+    for(int i= 0; i < view->memb_num; i ++)
     {
-      wsrep_notify_status(new_status, view);
-      status = new_status;
+      memb= view->members[i];
+      member_info_.append_val(memb);
     }
+
+    unlock();
+  }
+
+  void set(wsrep_member_status_t status)
+  {
+    wsrep_notify_status(status, 0);
+    lock();
+    status_= status;
+    unlock();
+  }
+
+  wsrep_view_info_t get_view_info() const
+  {
+    return view_;
+  }
+
+  wsrep_member_status_t get_status() const
+  {
+    return status_;
   }
-  wsrep_member_status_t get() const { return status; }
+
+  Dynamic_array<wsrep_member_info_t> * get_member_info()
+  {
+    return &member_info_;
+  }
+
+  int lock()
+  {
+    return mysql_mutex_lock(&LOCK_wsrep_config_state);
+  }
+
+  int unlock()
+  {
+    return mysql_mutex_unlock(&LOCK_wsrep_config_state);
+  }
+
 private:
-  wsrep_member_status_t status;
+  wsrep_view_info_t                  view_;
+  wsrep_member_status_t              status_;
+  Dynamic_array<wsrep_member_info_t> member_info_;
 };
+
 } /* namespace wsp */
 
-extern wsp::node_status local_status;
+extern wsp::Config_state wsrep_config_state;
 
 namespace wsp {
 /* A small class to run external programs. */


More information about the commits mailing list