1 /* Copyright (c) 2015, 2021, Oracle and/or its affiliates.
2 
3   This program is free software; you can redistribute it and/or modify
4   it under the terms of the GNU General Public License, version 2.0,
5   as published by the Free Software Foundation.
6 
7   This program is also distributed with certain software (including
8   but not limited to OpenSSL) that is licensed under separate terms,
9   as designated in a particular file or component or in included license
10   documentation.  The authors of MySQL hereby grant you an additional
11   permission to link the program and your derivative works with the
12   separately licensed software that they have included with MySQL.
13 
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License, version 2.0, for more details.
18 
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 /**
24   @file storage/perfschema/table_global_status.cc
25   Table global_status (implementation).
26 */
27 
28 #include "my_global.h"
29 #include "table_global_status.h"
30 #include "my_thread.h"
31 #include "pfs_instr_class.h"
32 #include "pfs_column_types.h"
33 #include "pfs_column_values.h"
34 #include "pfs_global.h"
35 
36 THR_LOCK table_global_status::m_table_lock;
37 
38 static const TABLE_FIELD_TYPE field_types[]=
39 {
40   {
41     { C_STRING_WITH_LEN("VARIABLE_NAME") },
42     { C_STRING_WITH_LEN("varchar(64)") },
43     { NULL, 0}
44   },
45   {
46     { C_STRING_WITH_LEN("VARIABLE_VALUE") },
47     { C_STRING_WITH_LEN("varchar(1024)") },
48     { NULL, 0}
49   }
50 };
51 
52 TABLE_FIELD_DEF
53 table_global_status::m_field_def=
54 { 2, field_types };
55 
56 PFS_engine_table_share
57 table_global_status::m_share=
58 {
59   { C_STRING_WITH_LEN("global_status") },
60   &pfs_truncatable_world_acl,
61   table_global_status::create,
62   NULL, /* write_row */
63   table_global_status::delete_all_rows,
64   table_global_status::get_row_count,
65   sizeof(pos_t),
66   &m_table_lock,
67   &m_field_def,
68   false, /* checked */
69   true   /* perpetual */
70 };
71 
72 PFS_engine_table*
create(void)73 table_global_status::create(void)
74 {
75   return new table_global_status();
76 }
77 
delete_all_rows(void)78 int table_global_status::delete_all_rows(void)
79 {
80   mysql_mutex_lock(&LOCK_status);
81   reset_status_by_thread();
82   reset_status_by_account();
83   reset_status_by_user();
84   reset_status_by_host();
85   reset_global_status();
86   mysql_mutex_unlock(&LOCK_status);
87   return 0;
88 }
89 
get_row_count(void)90 ha_rows table_global_status::get_row_count(void)
91 {
92   mysql_mutex_lock(&LOCK_status);
93   ha_rows status_var_count= all_status_vars.size();
94   mysql_mutex_unlock(&LOCK_status);
95   return status_var_count;
96 }
97 
table_global_status()98 table_global_status::table_global_status()
99   : PFS_engine_table(&m_share, &m_pos),
100     m_status_cache(false), m_row_exists(false), m_pos(0), m_next_pos(0)
101 {}
102 
reset_position(void)103 void table_global_status::reset_position(void)
104 {
105   m_pos.m_index= 0;
106   m_next_pos.m_index= 0;
107 }
108 
rnd_init(bool scan)109 int table_global_status::rnd_init(bool scan)
110 {
111   /* Build a cache of all global status variables. Sum across threads. */
112   m_status_cache.materialize_global();
113 
114   /* Record the current number of status variables to detect subsequent changes. */
115   ulonglong status_version= m_status_cache.get_status_array_version();
116 
117   /*
118     The table context holds the current version of the global status array.
119     If scan == true, then allocate a new context from mem_root and store in TLS.
120     If scan == false, then restore from TLS.
121   */
122   m_context= (table_global_status_context *)current_thd->alloc(sizeof(table_global_status_context));
123   new(m_context) table_global_status_context(status_version, !scan);
124   return 0;
125 }
126 
rnd_next(void)127 int table_global_status::rnd_next(void)
128 {
129   for (m_pos.set_at(&m_next_pos);
130        m_pos.m_index < m_status_cache.size();
131        m_pos.next())
132   {
133     const Status_variable *status_var= m_status_cache.get(m_pos.m_index);
134     if (status_var != NULL)
135     {
136       make_row(status_var);
137       m_next_pos.set_after(&m_pos);
138       return 0;
139     }
140   }
141   return HA_ERR_END_OF_FILE;
142 }
143 
rnd_pos(const void * pos)144 int table_global_status::rnd_pos(const void *pos)
145 {
146   /* If global status array has changed, do nothing. */ // TODO: Issue warning
147   if (!m_context->versions_match())
148     return HA_ERR_RECORD_DELETED;
149 
150   set_position(pos);
151   const Status_variable *status_var= m_status_cache.get(m_pos.m_index);
152   if (status_var != NULL)
153   {
154     make_row(status_var);
155     return 0;
156   }
157 
158   return HA_ERR_RECORD_DELETED;
159 }
160 
161 void table_global_status
make_row(const Status_variable * status_var)162 ::make_row(const Status_variable *status_var)
163 {
164   m_row_exists= false;
165   if (status_var->is_null())
166     return;
167   m_row.m_variable_name.make_row(status_var->m_name, status_var->m_name_length);
168   m_row.m_variable_value.make_row(status_var);
169   m_row_exists= true;
170 }
171 
172 int table_global_status
read_row_values(TABLE * table,unsigned char * buf,Field ** fields,bool read_all)173 ::read_row_values(TABLE *table,
174                   unsigned char *buf,
175                   Field **fields,
176                   bool read_all)
177 {
178   Field *f;
179 
180   if (unlikely(! m_row_exists))
181     return HA_ERR_RECORD_DELETED;
182 
183   /* Set the null bits */
184   assert(table->s->null_bytes == 1);
185   buf[0]= 0;
186 
187   for (; (f= *fields) ; fields++)
188   {
189     if (read_all || bitmap_is_set(table->read_set, f->field_index))
190     {
191       switch(f->field_index)
192       {
193       case 0: /* VARIABLE_NAME */
194         set_field_varchar_utf8(f, m_row.m_variable_name.m_str, m_row.m_variable_name.m_length);
195         break;
196       case 1: /* VARIABLE_VALUE */
197         m_row.m_variable_value.set_field(f);
198         break;
199       default:
200         assert(false);
201       }
202     }
203   }
204 
205   return 0;
206 }
207 
208