1 /*
2       Copyright (c) 2013, 2021, Oracle and/or its affiliates.
3 
4       This program is free software; you can redistribute it and/or modify
5       it under the terms of the GNU General Public License, version 2.0,
6       as published by the Free Software Foundation.
7 
8       This program is also distributed with certain software (including
9       but not limited to OpenSSL) that is licensed under separate terms,
10       as designated in a particular file or component or in included license
11       documentation.  The authors of MySQL hereby grant you an additional
12       permission to link the program and your derivative works with the
13       separately licensed software that they have included with MySQL.
14 
15       This program is distributed in the hope that it will be useful,
16       but WITHOUT ANY WARRANTY; without even the implied warranty of
17       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18       GNU General Public License, version 2.0, for more details.
19 
20       You should have received a copy of the GNU General Public License
21       along with this program; if not, write to the Free Software
22       Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
23 
24 /**
25   @file storage/perfschema/table_replication_group_members.cc
26   Table replication_group_members (implementation).
27 */
28 
29 #define HAVE_REPLICATION
30 
31 #include "my_global.h"
32 #include "table_replication_group_members.h"
33 #include "pfs_instr_class.h"
34 #include "pfs_instr.h"
35 #include "log.h"
36 #include "rpl_group_replication.h"
37 
38 /*
39   Callbacks implementation for GROUP_REPLICATION_GROUP_MEMBERS_CALLBACKS.
40 */
set_channel_name(void * const context,const char & value,size_t length)41 static void set_channel_name(void* const context, const char& value,
42                              size_t length)
43 {
44   struct st_row_group_members* row=
45       static_cast<struct st_row_group_members*>(context);
46   const size_t max= CHANNEL_NAME_LENGTH;
47   length= std::min(length, max);
48 
49   row->channel_name_length= length;
50   memcpy(row->channel_name, &value, length);
51 }
52 
set_member_id(void * const context,const char & value,size_t length)53 static void set_member_id(void* const context, const char& value,
54                           size_t length)
55 {
56   struct st_row_group_members* row=
57       static_cast<struct st_row_group_members*>(context);
58   const size_t max= UUID_LENGTH;
59   length= std::min(length, max);
60 
61   row->member_id_length= length;
62   memcpy(row->member_id, &value, length);
63 }
64 
set_member_host(void * const context,const char & value,size_t length)65 static void set_member_host(void* const context, const char& value,
66                             size_t length)
67 {
68   struct st_row_group_members* row=
69       static_cast<struct st_row_group_members*>(context);
70   const size_t max= HOSTNAME_LENGTH;
71   length= std::min(length, max);
72 
73   row->member_host_length= length;
74   memcpy(row->member_host, &value, length);
75 }
76 
set_member_port(void * const context,unsigned int value)77 static void set_member_port(void* const context, unsigned int value)
78 {
79   struct st_row_group_members* row=
80       static_cast<struct st_row_group_members*>(context);
81   row->member_port= value;
82 }
83 
set_member_state(void * const context,const char & value,size_t length)84 static void set_member_state(void* const context, const char& value,
85                              size_t length)
86 {
87   struct st_row_group_members* row=
88       static_cast<struct st_row_group_members*>(context);
89   const size_t max= NAME_LEN;
90   length= std::min(length, max);
91 
92   row->member_state_length= length;
93   memcpy(row->member_state, &value, length);
94 }
95 
96 
97 THR_LOCK table_replication_group_members::m_table_lock;
98 
99 /* Numbers in varchar count utf8 characters. */
100 static const TABLE_FIELD_TYPE field_types[]=
101 {
102   {
103     {C_STRING_WITH_LEN("CHANNEL_NAME")},
104     {C_STRING_WITH_LEN("char(64)")},
105     {NULL, 0}
106   },
107   {
108     {C_STRING_WITH_LEN("MEMBER_ID")},
109     {C_STRING_WITH_LEN("char(36)")},
110     {NULL, 0}
111   },
112   {
113     {C_STRING_WITH_LEN("MEMBER_HOST")},
114     {C_STRING_WITH_LEN("char(60)")},
115     {NULL, 0}
116   },
117   {
118     {C_STRING_WITH_LEN("MEMBER_PORT")},
119     {C_STRING_WITH_LEN("int(11)")},
120     {NULL, 0}
121   },
122   {
123     {C_STRING_WITH_LEN("MEMBER_STATE")},
124     {C_STRING_WITH_LEN("char(64)")},
125     {NULL, 0}
126   }
127 };
128 
129 TABLE_FIELD_DEF
130 table_replication_group_members::m_field_def=
131 { 5, field_types };
132 
133 PFS_engine_table_share
134 table_replication_group_members::m_share=
135 {
136   { C_STRING_WITH_LEN("replication_group_members") },
137   &pfs_readonly_acl,
138   &table_replication_group_members::create,
139   NULL, /* write_row */
140   NULL, /* delete_all_rows */
141   table_replication_group_members::get_row_count,
142   sizeof(PFS_simple_index), /* ref length */
143   &m_table_lock,
144   &m_field_def,
145   false, /* checked */
146   false  /* perpetual */
147 };
148 
create(void)149 PFS_engine_table* table_replication_group_members::create(void)
150 {
151   return new table_replication_group_members();
152 }
153 
table_replication_group_members()154 table_replication_group_members::table_replication_group_members()
155   : PFS_engine_table(&m_share, &m_pos),
156     m_row_exists(false), m_pos(0), m_next_pos(0)
157 {}
158 
~table_replication_group_members()159 table_replication_group_members::~table_replication_group_members()
160 {}
161 
reset_position(void)162 void table_replication_group_members::reset_position(void)
163 {
164   m_pos.m_index= 0;
165   m_next_pos.m_index= 0;
166 }
167 
get_row_count()168 ha_rows table_replication_group_members::get_row_count()
169 {
170   return get_group_replication_members_number_info();
171 }
172 
rnd_next(void)173 int table_replication_group_members::rnd_next(void)
174 {
175   if (!is_group_replication_plugin_loaded())
176     return HA_ERR_END_OF_FILE;
177 
178   for (m_pos.set_at(&m_next_pos);
179        m_pos.m_index < get_row_count();
180        m_pos.next())
181   {
182     make_row(m_pos.m_index);
183     m_next_pos.set_after(&m_pos);
184     return 0;
185   }
186 
187   return HA_ERR_END_OF_FILE;
188 }
189 
rnd_pos(const void * pos)190 int table_replication_group_members::rnd_pos(const void *pos)
191 {
192   if (!is_group_replication_plugin_loaded())
193     return HA_ERR_END_OF_FILE;
194 
195   set_position(pos);
196   assert(m_pos.m_index < get_row_count());
197   make_row(m_pos.m_index);
198 
199   return 0;
200 }
201 
make_row(uint index)202 void table_replication_group_members::make_row(uint index)
203 {
204   DBUG_ENTER("table_replication_group_members::make_row");
205   // Set default values.
206   m_row_exists= false;
207   m_row.channel_name_length= 0;
208   m_row.member_id_length= 0;
209   m_row.member_host_length= 0;
210   m_row.member_port= 0;
211   m_row.member_state_length= 0;
212 
213   // Set callbacks on GROUP_REPLICATION_GROUP_MEMBERS_CALLBACKS.
214   const GROUP_REPLICATION_GROUP_MEMBERS_CALLBACKS callbacks=
215   {
216     &m_row,
217     &set_channel_name,
218     &set_member_id,
219     &set_member_host,
220     &set_member_port,
221     &set_member_state,
222   };
223 
224   // Query plugin and let callbacks do their job.
225   if (get_group_replication_group_members_info(index, callbacks))
226   {
227     DBUG_PRINT("info", ("Group Replication stats not available!"));
228   }
229   else
230   {
231     m_row_exists= true;
232   }
233 
234   DBUG_VOID_RETURN;
235 }
236 
237 
read_row_values(TABLE * table,unsigned char * buf,Field ** fields,bool read_all)238 int table_replication_group_members::read_row_values(TABLE *table,
239                                                      unsigned char *buf,
240                                                      Field **fields,
241                                                      bool read_all)
242 {
243   Field *f;
244 
245   if (unlikely(! m_row_exists))
246     return HA_ERR_RECORD_DELETED;
247 
248   assert(table->s->null_bytes == 1);
249   buf[0]= 0;
250 
251   for (; (f= *fields) ; fields++)
252   {
253     if (read_all || bitmap_is_set(table->read_set, f->field_index))
254     {
255       switch(f->field_index)
256       {
257       case 0: /** channel_name */
258         set_field_char_utf8(f, m_row.channel_name, m_row.channel_name_length);
259         break;
260       case 1: /** member_id */
261         set_field_char_utf8(f, m_row.member_id, m_row.member_id_length);
262         break;
263       case 2: /** member_host */
264         set_field_char_utf8(f, m_row.member_host, m_row.member_host_length);
265         break;
266       case 3: /** member_port */
267         if (m_row.member_port > 0)
268           set_field_ulong(f, m_row.member_port);
269         else
270           f->set_null();
271         break;
272       case 4: /** member_state */
273         set_field_char_utf8(f, m_row.member_state, m_row.member_state_length);
274         break;
275       default:
276         assert(false);
277       }
278     }
279   }
280   return 0;
281 }
282