|
| 1 | +/* |
| 2 | + Copyright (c) 2013, 2022, 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 | +#include "init_net_server_extension.h" |
| 26 | + |
| 27 | +#include "violite.h" // Vio |
| 28 | +#include "channel_info.h" // Channel_info |
| 29 | +#include "connection_handler_manager.h" // Connection_handler_manager |
| 30 | +#include "mysqld.h" // key_socket_tcpip |
| 31 | +#include "log.h" // sql_print_error |
| 32 | +#include "sql_class.h" // THD |
| 33 | + |
| 34 | +#include <pfs_idle_provider.h> |
| 35 | +#include <mysql/psi/mysql_idle.h> |
| 36 | + |
| 37 | +#ifdef HAVE_PSI_STATEMENT_INTERFACE |
| 38 | +extern PSI_statement_info stmt_info_new_packet; |
| 39 | +#endif |
| 40 | + |
| 41 | +static void net_before_header_psi(struct st_net *net, void *user_data, |
| 42 | + size_t /* unused: count */) { |
| 43 | + THD *thd; |
| 44 | + thd = static_cast<THD *>(user_data); |
| 45 | + assert(thd != NULL); |
| 46 | + |
| 47 | + if (thd->m_server_idle) { |
| 48 | + /* |
| 49 | + The server is IDLE, waiting for the next command. |
| 50 | + Technically, it is a wait on a socket, which may take a long time, |
| 51 | + because the call is blocking. |
| 52 | + Disable the socket instrumentation, to avoid recording a SOCKET event. |
| 53 | + Instead, start explicitly an IDLE event. |
| 54 | + */ |
| 55 | + MYSQL_SOCKET_SET_STATE(net->vio->mysql_socket, PSI_SOCKET_STATE_IDLE); |
| 56 | + MYSQL_START_IDLE_WAIT(thd->m_idle_psi, &thd->m_idle_state); |
| 57 | + } |
| 58 | +} |
| 59 | + |
| 60 | +static void net_after_header_psi(struct st_net *net, void *user_data, |
| 61 | + size_t /* unused: count */, my_bool rc) { |
| 62 | + THD *thd; |
| 63 | + thd = static_cast<THD *>(user_data); |
| 64 | + assert(thd != NULL); |
| 65 | + |
| 66 | + if (thd->m_server_idle) { |
| 67 | + /* |
| 68 | + The server just got data for a network packet header, |
| 69 | + from the network layer. |
| 70 | + The IDLE event is now complete, since we now have a message to process. |
| 71 | + We need to: |
| 72 | + - start a new STATEMENT event |
| 73 | + - start a new STAGE event, within this statement, |
| 74 | + - start recording SOCKET WAITS events, within this stage. |
| 75 | + The proper order is critical to get events numbered correctly, |
| 76 | + and nested in the proper parent. |
| 77 | + */ |
| 78 | + MYSQL_END_IDLE_WAIT(thd->m_idle_psi); |
| 79 | + |
| 80 | + if (!rc) { |
| 81 | + assert(thd->m_statement_psi == NULL); |
| 82 | + thd->m_statement_psi = MYSQL_START_STATEMENT( |
| 83 | + &thd->m_statement_state, stmt_info_new_packet.m_key, thd->db().str, |
| 84 | + thd->db().length, thd->charset(), NULL); |
| 85 | + |
| 86 | + /* |
| 87 | + Starts a new stage in performance schema, if compiled in and enabled. |
| 88 | + Also sets THD::proc_info (used by SHOW PROCESSLIST, column STATE) |
| 89 | + */ |
| 90 | + THD_STAGE_INFO(thd, stage_starting); |
| 91 | + } |
| 92 | + |
| 93 | + /* |
| 94 | + TODO: consider recording a SOCKET event for the bytes just read, |
| 95 | + by also passing count here. |
| 96 | + */ |
| 97 | + MYSQL_SOCKET_SET_STATE(net->vio->mysql_socket, PSI_SOCKET_STATE_ACTIVE); |
| 98 | + thd->m_server_idle = false; |
| 99 | + } |
| 100 | +} |
| 101 | + |
| 102 | +void init_net_server_extension(THD *thd) { |
| 103 | + /* Start with a clean state for connection events. */ |
| 104 | + thd->m_idle_psi = NULL; |
| 105 | + thd->m_statement_psi = NULL; |
| 106 | + thd->m_server_idle = false; |
| 107 | + |
| 108 | + /* Hook up the NET_SERVER callback in the net layer. */ |
| 109 | + thd->m_net_server_extension.m_user_data = thd; |
| 110 | + thd->m_net_server_extension.m_before_header = net_before_header_psi; |
| 111 | + thd->m_net_server_extension.m_after_header = net_after_header_psi; |
| 112 | + thd->m_net_server_extension.timeout_on_full_packet = FALSE; |
| 113 | + |
| 114 | + /* Activate this private extension for the mysqld server. */ |
| 115 | + thd->get_protocol_classic()->get_net()->extension = |
| 116 | + &thd->m_net_server_extension; |
| 117 | +} |
0 commit comments