[Commits] 5e926f6: MDEV-7053: WSREP_STATUS & WSREP_MEMBERSHIP I_S tables

nirbhay at mariadb.com nirbhay at mariadb.com
Sat Nov 8 20:38:42 EET 2014


revision-id: 5e926f6d779d29159841ef34358d5c045554642c
parent(s): 3c2c03624803abd20e5e4e589fa6b14bd92c29f5
committer: Nirbhay Choubey
branch nick: server_galera_is
timestamp: 2014-11-08 13:38:41 -0500
message:

MDEV-7053: WSREP_STATUS & WSREP_MEMBERSHIP I_S tables

Added an I_S plugin to expose wsrep status and cluster
membership via WSREP_STATUS and WSREP_MEMBERSHIP tables
respectively.

---
 plugin/wsrep_info/CMakeLists.txt |   5 +
 plugin/wsrep_info/plugin.cc      | 223 +++++++++++++++++++++++++++++++++++++++
 sql/wsrep_mysqld.cc              |  27 +++--
 sql/wsrep_mysqld.h               |   1 +
 sql/wsrep_sst.cc                 |   4 +-
 sql/wsrep_utils.h                |  68 ++++++++++--
 6 files changed, 306 insertions(+), 22 deletions(-)

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/plugin.cc b/plugin/wsrep_info/plugin.cc
new file mode 100644
index 0000000..3ea1c54
--- /dev/null
+++ b/plugin/wsrep_info/plugin.cc
@@ -0,0 +1,223 @@
+/* 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>
+
+#define COLUMN_WSREP_MEMB_INDEX 0               /* Node index */
+#define COLUMN_WSREP_MEMB_UUID 1                /* Unique member ID */
+#define COLUMN_WSREP_MEMB_NAME 2                /* Human-readable name */
+#define COLUMN_WSREP_MEMB_ADDRESS 3             /* Incoming address */
+
+#define COLUMN_WSREP_STATUS_NODE_INDEX 0        /* Node index */
+#define COLUMN_WSREP_STATUS_NODE_STATUS 1       /* Node status */
+#define COLUMN_WSREP_STATUS_CLUSTER_SIZE 2      /* Cluster size */
+#define COLUMN_WSREP_STATUS_CLUSTER_UUID 3      /* Global cluster ID */
+#define COLUMN_WSREP_STATUS_PRIMARY 4           /* Is primary ? */
+#define COLUMN_WSREP_STATUS_GAP 5               /* Gap b/w global & local states */
+#define COLUMN_WSREP_STATUS_PROTO_VERSION 6     /* Application protocol version */
+
+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";
+}
+
+/* ST_FIELD_INFO is defined in table.h */
+static ST_FIELD_INFO wsrep_memb_fields[]=
+{
+  {"INDEX", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, 0, 0},
+  {"UUID", WSREP_UUID_STR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, 0},
+  {"NAME", WSREP_MEMBER_NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0, 0},
+  {"ADDRESS", WSREP_INCOMING_LEN, MYSQL_TYPE_STRING, 0, 0, 0, 0},
+  {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
+};
+
+/* ST_FIELD_INFO is defined in table.h */
+static ST_FIELD_INFO wsrep_status_fields[]=
+{
+  {"NODE_INDEX", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, 0, 0},
+  {"NODE_STATUS", 16, MYSQL_TYPE_STRING, 0, 0, 0, 0},
+  {"CLUSTER_SIZE", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, 0, 0},
+  {"CLUSTER_UUID", WSREP_UUID_STR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, 0},
+  {"PRIMARY", 10, MYSQL_TYPE_STRING, 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_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_UUID]->store(uuid, sizeof(uuid),
+                                                        system_charset_info);
+
+  const char *prim= (view.view >= 0) ? "YES" : "NO";
+  table->field[COLUMN_WSREP_STATUS_PRIMARY]->store(prim, strlen(prim),
+                                                   system_charset_info);
+
+  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      */
+  "Lists all members in Galera cluster.",       /* 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_GAMMA
+},
+{
+  MYSQL_INFORMATION_SCHEMA_PLUGIN,
+  &wsrep_status_plugin,
+  "WSREP_STATUS",                               /* Plugin name        */
+  "Nirbhay Choubey",                            /* Plugin author      */
+  "Lists various cluster 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_GAMMA
+}
+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..596eddd 100644
--- a/sql/wsrep_utils.h
+++ b/sql/wsrep_utils.h
@@ -17,32 +17,80 @@
 #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);
+    status_= status;
+  }
+
+  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