| 1 | /* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. |
| 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 as published by |
| 5 | the Free Software Foundation; version 2 of the License. |
| 6 | |
| 7 | This program is distributed in the hope that it will be useful, |
| 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 10 | GNU General Public License for more details. |
| 11 | |
| 12 | You should have received a copy of the GNU General Public License |
| 13 | along with this program; if not, write to the Free Software Foundation, |
| 14 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ |
| 15 | |
| 16 | /** |
| 17 | @file storage/perfschema/table_host_cache.cc |
| 18 | Table HOST_CACHE (implementation). |
| 19 | */ |
| 20 | |
| 21 | #include "my_global.h" |
| 22 | #include "my_pthread.h" |
| 23 | #include "table_host_cache.h" |
| 24 | #include "hostname.h" |
| 25 | |
| 26 | THR_LOCK table_host_cache::m_table_lock; |
| 27 | |
| 28 | PFS_engine_table_share |
| 29 | table_host_cache::m_share= |
| 30 | { |
| 31 | { C_STRING_WITH_LEN("host_cache" ) }, |
| 32 | &pfs_truncatable_acl, |
| 33 | &table_host_cache::create, |
| 34 | NULL, /* write_row */ |
| 35 | table_host_cache::delete_all_rows, |
| 36 | NULL, /* get_row_count */ |
| 37 | 1000, /* records */ |
| 38 | sizeof(PFS_simple_index), /* ref length */ |
| 39 | &m_table_lock, |
| 40 | { C_STRING_WITH_LEN("CREATE TABLE host_cache(" |
| 41 | "IP VARCHAR(64) not null," |
| 42 | "HOST VARCHAR(255) collate utf8_bin," |
| 43 | "HOST_VALIDATED ENUM ('YES', 'NO') not null," |
| 44 | "SUM_CONNECT_ERRORS BIGINT not null," |
| 45 | "COUNT_HOST_BLOCKED_ERRORS BIGINT not null," |
| 46 | "COUNT_NAMEINFO_TRANSIENT_ERRORS BIGINT not null," |
| 47 | "COUNT_NAMEINFO_PERMANENT_ERRORS BIGINT not null," |
| 48 | "COUNT_FORMAT_ERRORS BIGINT not null," |
| 49 | "COUNT_ADDRINFO_TRANSIENT_ERRORS BIGINT not null," |
| 50 | "COUNT_ADDRINFO_PERMANENT_ERRORS BIGINT not null," |
| 51 | "COUNT_FCRDNS_ERRORS BIGINT not null," |
| 52 | "COUNT_HOST_ACL_ERRORS BIGINT not null," |
| 53 | "COUNT_NO_AUTH_PLUGIN_ERRORS BIGINT not null," |
| 54 | "COUNT_AUTH_PLUGIN_ERRORS BIGINT not null," |
| 55 | "COUNT_HANDSHAKE_ERRORS BIGINT not null," |
| 56 | "COUNT_PROXY_USER_ERRORS BIGINT not null," |
| 57 | "COUNT_PROXY_USER_ACL_ERRORS BIGINT not null," |
| 58 | "COUNT_AUTHENTICATION_ERRORS BIGINT not null," |
| 59 | "COUNT_SSL_ERRORS BIGINT not null," |
| 60 | "COUNT_MAX_USER_CONNECTIONS_ERRORS BIGINT not null," |
| 61 | "COUNT_MAX_USER_CONNECTIONS_PER_HOUR_ERRORS BIGINT not null," |
| 62 | "COUNT_DEFAULT_DATABASE_ERRORS BIGINT not null," |
| 63 | "COUNT_INIT_CONNECT_ERRORS BIGINT not null," |
| 64 | "COUNT_LOCAL_ERRORS BIGINT not null," |
| 65 | "COUNT_UNKNOWN_ERRORS BIGINT not null," |
| 66 | "FIRST_SEEN TIMESTAMP(0) NOT NULL default 0," |
| 67 | "LAST_SEEN TIMESTAMP(0) NOT NULL default 0," |
| 68 | "FIRST_ERROR_SEEN TIMESTAMP(0) null default 0," |
| 69 | "LAST_ERROR_SEEN TIMESTAMP(0) null default 0)" ) } |
| 70 | }; |
| 71 | |
| 72 | PFS_engine_table* table_host_cache::create(void) |
| 73 | { |
| 74 | table_host_cache *t= new table_host_cache(); |
| 75 | if (t != NULL) |
| 76 | { |
| 77 | THD *thd= current_thd; |
| 78 | DBUG_ASSERT(thd != NULL); |
| 79 | t->materialize(thd); |
| 80 | } |
| 81 | return t; |
| 82 | } |
| 83 | |
| 84 | int |
| 85 | table_host_cache::delete_all_rows(void) |
| 86 | { |
| 87 | /* |
| 88 | TRUNCATE TABLE performance_schema.host_cache |
| 89 | is an alternate syntax for |
| 90 | FLUSH HOSTS |
| 91 | */ |
| 92 | hostname_cache_refresh(); |
| 93 | return 0; |
| 94 | } |
| 95 | |
| 96 | table_host_cache::table_host_cache() |
| 97 | : PFS_engine_table(&m_share, &m_pos), |
| 98 | m_all_rows(NULL), m_row_count(0), |
| 99 | m_row(NULL), m_pos(0), m_next_pos(0) |
| 100 | {} |
| 101 | |
| 102 | void table_host_cache::materialize(THD *thd) |
| 103 | { |
| 104 | Host_entry *current; |
| 105 | Host_entry *first; |
| 106 | uint size; |
| 107 | uint index; |
| 108 | row_host_cache *rows; |
| 109 | row_host_cache *row; |
| 110 | |
| 111 | DBUG_ASSERT(m_all_rows == NULL); |
| 112 | DBUG_ASSERT(m_row_count == 0); |
| 113 | |
| 114 | hostname_cache_lock(); |
| 115 | |
| 116 | size= hostname_cache_size(); |
| 117 | if (size == 0) |
| 118 | { |
| 119 | /* Normal case, the cache is empty. */ |
| 120 | goto end; |
| 121 | } |
| 122 | |
| 123 | rows= (row_host_cache*) thd->alloc(size * sizeof(row_host_cache)); |
| 124 | if (rows == NULL) |
| 125 | { |
| 126 | /* Out of memory, this thread will error out. */ |
| 127 | goto end; |
| 128 | } |
| 129 | |
| 130 | index= 0; |
| 131 | row= rows; |
| 132 | |
| 133 | first= hostname_cache_first(); |
| 134 | current= first; |
| 135 | |
| 136 | while ((current != NULL) && (index < size)) |
| 137 | { |
| 138 | make_row(current, row); |
| 139 | index++; |
| 140 | row++; |
| 141 | current= current->next(); |
| 142 | } |
| 143 | |
| 144 | m_all_rows= rows; |
| 145 | m_row_count= index; |
| 146 | |
| 147 | end: |
| 148 | hostname_cache_unlock(); |
| 149 | } |
| 150 | |
| 151 | void table_host_cache::make_row(Host_entry *entry, row_host_cache *row) |
| 152 | { |
| 153 | row->m_ip_length= (int)strlen(entry->ip_key); |
| 154 | strcpy(row->m_ip, entry->ip_key); |
| 155 | row->m_hostname_length= entry->m_hostname_length; |
| 156 | if (row->m_hostname_length > 0) |
| 157 | strncpy(row->m_hostname, entry->m_hostname, row->m_hostname_length); |
| 158 | row->m_host_validated= entry->m_host_validated; |
| 159 | row->m_sum_connect_errors= entry->m_errors.m_connect; |
| 160 | row->m_count_host_blocked_errors= entry->m_errors.m_host_blocked; |
| 161 | row->m_count_nameinfo_transient_errors= entry->m_errors.m_nameinfo_transient; |
| 162 | row->m_count_nameinfo_permanent_errors= entry->m_errors.m_nameinfo_permanent; |
| 163 | row->m_count_format_errors= entry->m_errors.m_format; |
| 164 | row->m_count_addrinfo_transient_errors= entry->m_errors.m_addrinfo_transient; |
| 165 | row->m_count_addrinfo_permanent_errors= entry->m_errors.m_addrinfo_permanent; |
| 166 | row->m_count_fcrdns_errors= entry->m_errors.m_FCrDNS; |
| 167 | row->m_count_host_acl_errors= entry->m_errors.m_host_acl; |
| 168 | row->m_count_no_auth_plugin_errors= entry->m_errors.m_no_auth_plugin; |
| 169 | row->m_count_auth_plugin_errors= entry->m_errors.m_auth_plugin; |
| 170 | row->m_count_handshake_errors= entry->m_errors.m_handshake; |
| 171 | row->m_count_proxy_user_errors= entry->m_errors.m_proxy_user; |
| 172 | row->m_count_proxy_user_acl_errors= entry->m_errors.m_proxy_user_acl; |
| 173 | row->m_count_authentication_errors= entry->m_errors.m_authentication; |
| 174 | row->m_count_ssl_errors= entry->m_errors.m_ssl; |
| 175 | row->m_count_max_user_connection_errors= entry->m_errors.m_max_user_connection; |
| 176 | row->m_count_max_user_connection_per_hour_errors= entry->m_errors.m_max_user_connection_per_hour; |
| 177 | row->m_count_default_database_errors= entry->m_errors.m_default_database; |
| 178 | row->m_count_init_connect_errors= entry->m_errors.m_init_connect; |
| 179 | row->m_count_local_errors= entry->m_errors.m_local; |
| 180 | |
| 181 | /* |
| 182 | Reserved for future use, to help with backward compatibility. |
| 183 | When new errors are added in entry->m_errors.m_xxx, |
| 184 | report them in this column (GA releases), |
| 185 | until the table HOST_CACHE structure can be extended (next development version). |
| 186 | */ |
| 187 | row->m_count_unknown_errors= 0; |
| 188 | |
| 189 | row->m_first_seen= entry->m_first_seen; |
| 190 | row->m_last_seen= entry->m_last_seen; |
| 191 | row->m_first_error_seen= entry->m_first_error_seen; |
| 192 | row->m_last_error_seen= entry->m_last_error_seen; |
| 193 | } |
| 194 | |
| 195 | void table_host_cache::reset_position(void) |
| 196 | { |
| 197 | m_pos.m_index= 0; |
| 198 | m_next_pos.m_index= 0; |
| 199 | } |
| 200 | |
| 201 | int table_host_cache::rnd_next(void) |
| 202 | { |
| 203 | int result; |
| 204 | |
| 205 | m_pos.set_at(&m_next_pos); |
| 206 | |
| 207 | if (m_pos.m_index < m_row_count) |
| 208 | { |
| 209 | m_row= &m_all_rows[m_pos.m_index]; |
| 210 | m_next_pos.set_after(&m_pos); |
| 211 | result= 0; |
| 212 | } |
| 213 | else |
| 214 | { |
| 215 | m_row= NULL; |
| 216 | result= HA_ERR_END_OF_FILE; |
| 217 | } |
| 218 | |
| 219 | return result; |
| 220 | } |
| 221 | |
| 222 | int table_host_cache::rnd_pos(const void *pos) |
| 223 | { |
| 224 | set_position(pos); |
| 225 | DBUG_ASSERT(m_pos.m_index < m_row_count); |
| 226 | m_row= &m_all_rows[m_pos.m_index]; |
| 227 | return 0; |
| 228 | } |
| 229 | |
| 230 | int table_host_cache::read_row_values(TABLE *table, |
| 231 | unsigned char *buf, |
| 232 | Field **fields, |
| 233 | bool read_all) |
| 234 | { |
| 235 | Field *f; |
| 236 | |
| 237 | DBUG_ASSERT(m_row); |
| 238 | |
| 239 | /* Set the null bits */ |
| 240 | DBUG_ASSERT(table->s->null_bytes == 1); |
| 241 | buf[0]= 0; |
| 242 | |
| 243 | for (; (f= *fields) ; fields++) |
| 244 | { |
| 245 | if (read_all || bitmap_is_set(table->read_set, f->field_index)) |
| 246 | { |
| 247 | switch(f->field_index) |
| 248 | { |
| 249 | case 0: /* IP */ |
| 250 | set_field_varchar_utf8(f, m_row->m_ip, m_row->m_ip_length); |
| 251 | break; |
| 252 | case 1: /* HOST */ |
| 253 | if (m_row->m_hostname_length > 0) |
| 254 | set_field_varchar_utf8(f, m_row->m_hostname, m_row->m_hostname_length); |
| 255 | else |
| 256 | f->set_null(); |
| 257 | break; |
| 258 | case 2: /* HOST_VALIDATED */ |
| 259 | set_field_enum(f, m_row->m_host_validated ? ENUM_YES : ENUM_NO); |
| 260 | break; |
| 261 | case 3: /* SUM_CONNECT_ERRORS */ |
| 262 | set_field_ulonglong(f, m_row->m_sum_connect_errors); |
| 263 | break; |
| 264 | case 4: /* COUNT_HOST_BLOCKED_ERRORS. */ |
| 265 | set_field_ulonglong(f, m_row->m_count_host_blocked_errors); |
| 266 | break; |
| 267 | case 5: /* COUNT_NAMEINFO_TRANSIENT_ERRORS */ |
| 268 | set_field_ulonglong(f, m_row->m_count_nameinfo_transient_errors); |
| 269 | break; |
| 270 | case 6: /* COUNT_NAMEINFO_PERSISTENT_ERRORS */ |
| 271 | set_field_ulonglong(f, m_row->m_count_nameinfo_permanent_errors); |
| 272 | break; |
| 273 | case 7: /* COUNT_FORMAT_ERRORS */ |
| 274 | set_field_ulonglong(f, m_row->m_count_format_errors); |
| 275 | break; |
| 276 | case 8: /* COUNT_ADDRINFO_TRANSIENT_ERRORS */ |
| 277 | set_field_ulonglong(f, m_row->m_count_addrinfo_transient_errors); |
| 278 | break; |
| 279 | case 9: /* COUNT_ADDRINFO_PERSISTENT_ERRORS */ |
| 280 | set_field_ulonglong(f, m_row->m_count_addrinfo_permanent_errors); |
| 281 | break; |
| 282 | case 10: /* COUNT_FCRDNS_ERRORS */ |
| 283 | set_field_ulonglong(f, m_row->m_count_fcrdns_errors); |
| 284 | break; |
| 285 | case 11: /* COUNT_HOST_ACL_ERRORS */ |
| 286 | set_field_ulonglong(f, m_row->m_count_host_acl_errors); |
| 287 | break; |
| 288 | case 12: /* COUNT_NO_AUTH_PLUGIN_ERRORS */ |
| 289 | set_field_ulonglong(f, m_row->m_count_no_auth_plugin_errors); |
| 290 | break; |
| 291 | case 13: /* COUNT_AUTH_PLUGIN_ERRORS */ |
| 292 | set_field_ulonglong(f, m_row->m_count_auth_plugin_errors); |
| 293 | break; |
| 294 | case 14: /* COUNT_HANDSHAKE_ERRORS */ |
| 295 | set_field_ulonglong(f, m_row->m_count_handshake_errors); |
| 296 | break; |
| 297 | case 15: /* COUNT_PROXY_USER_ERRORS */ |
| 298 | set_field_ulonglong(f, m_row->m_count_proxy_user_errors); |
| 299 | break; |
| 300 | case 16: /* COUNT_PROXY_USER_ACL_ERRORS */ |
| 301 | set_field_ulonglong(f, m_row->m_count_proxy_user_acl_errors); |
| 302 | break; |
| 303 | case 17: /* COUNT_AUTHENTICATION_ERRORS */ |
| 304 | set_field_ulonglong(f, m_row->m_count_authentication_errors); |
| 305 | break; |
| 306 | case 18: /* COUNT_SSL_ERRORS */ |
| 307 | set_field_ulonglong(f, m_row->m_count_ssl_errors); |
| 308 | break; |
| 309 | case 19: /* COUNT_MAX_USER_CONNECTION_ERRORS */ |
| 310 | set_field_ulonglong(f, m_row->m_count_max_user_connection_errors); |
| 311 | break; |
| 312 | case 20: /* COUNT_MAX_USER_CONNECTION_PER_HOUR_ERRORS */ |
| 313 | set_field_ulonglong(f, m_row->m_count_max_user_connection_per_hour_errors); |
| 314 | break; |
| 315 | case 21: /* COUNT_DEFAULT_DATABASE_ERRORS */ |
| 316 | set_field_ulonglong(f, m_row->m_count_default_database_errors); |
| 317 | break; |
| 318 | case 22: /* COUNT_INIT_CONNECT_ERRORS */ |
| 319 | set_field_ulonglong(f, m_row->m_count_init_connect_errors); |
| 320 | break; |
| 321 | case 23: /* COUNT_LOCAL_ERRORS */ |
| 322 | set_field_ulonglong(f, m_row->m_count_local_errors); |
| 323 | break; |
| 324 | case 24: /* COUNT_UNKNOWN_ERRORS */ |
| 325 | set_field_ulonglong(f, m_row->m_count_unknown_errors); |
| 326 | break; |
| 327 | case 25: /* FIRST_SEEN */ |
| 328 | set_field_timestamp(f, m_row->m_first_seen); |
| 329 | break; |
| 330 | case 26: /* LAST_SEEN */ |
| 331 | set_field_timestamp(f, m_row->m_last_seen); |
| 332 | break; |
| 333 | case 27: /* FIRST_ERROR_SEEN */ |
| 334 | if (m_row->m_first_error_seen != 0) |
| 335 | set_field_timestamp(f, m_row->m_first_error_seen); |
| 336 | else |
| 337 | f->set_null(); |
| 338 | break; |
| 339 | case 28: /* LAST_ERROR_SEEN */ |
| 340 | if (m_row->m_last_error_seen != 0) |
| 341 | set_field_timestamp(f, m_row->m_last_error_seen); |
| 342 | else |
| 343 | f->set_null(); |
| 344 | break; |
| 345 | default: |
| 346 | DBUG_ASSERT(false); |
| 347 | } |
| 348 | } |
| 349 | } |
| 350 | |
| 351 | return 0; |
| 352 | } |
| 353 | |
| 354 | |