/* Copyright (c) 2013, 2024, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is designed to work with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have either included with the program or referenced in the documentation. 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, version 2.0, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "sql/conn_handler/init_net_server_extension.h" #include #include #include "lex_string.h" #include "my_compiler.h" #include "my_psi_config.h" #include "mysql/components/services/bits/psi_socket_bits.h" #include "mysql/components/services/bits/psi_statement_bits.h" #include "mysql/psi/mysql_idle.h" // MYSQL_SOCKET_SET_STATE, #include "mysql/psi/mysql_socket.h" #include "mysql/psi/mysql_statement.h" #include "mysql_com.h" #include "mysql_com_server.h" // MYSQL_START_IDLE_WAIT #include "sql/mysqld.h" // stage_starting #include "sql/protocol_classic.h" #include "sql/sql_class.h" // THD #include "violite.h" #ifdef HAVE_PSI_STATEMENT_INTERFACE // TODO: << nonconformance with // HAVE_PSI_INTERFACE PSI_statement_info stmt_info_new_packet; #endif static void net_before_header_psi(NET *net [[maybe_unused]], void *user_data, size_t /* unused: count */) { THD *thd; thd = static_cast(user_data); assert(thd != nullptr); if (thd->m_server_idle) { /* The server is IDLE, waiting for the next command. Technically, it is a wait on a socket, which may take a long time, because the call is blocking. Disable the socket instrumentation, to avoid recording a SOCKET event. Instead, start explicitly an IDLE event. */ MYSQL_SOCKET_SET_STATE(net->vio->mysql_socket, PSI_SOCKET_STATE_IDLE); MYSQL_START_IDLE_WAIT(thd->m_idle_psi, &thd->m_idle_state); } mysql_thread_set_secondary_engine(false); } static void net_after_header_psi(NET *net [[maybe_unused]], void *user_data, size_t /* unused: count */, bool rc) { THD *thd; thd = static_cast(user_data); assert(thd != nullptr); if (thd->m_server_idle) { /* The server just got data for a network packet header, from the network layer. The IDLE event is now complete, since we now have a message to process. We need to: - start a new STATEMENT event - start a new STAGE event, within this statement, - start recording SOCKET WAITS events, within this stage. The proper order is critical to get events numbered correctly, and nested in the proper parent. */ MYSQL_END_IDLE_WAIT(thd->m_idle_psi); #ifdef HAVE_PSI_THREAD_INTERFACE PSI_thread *thread = thd_get_psi(thd); if (thread != nullptr) { PSI_THREAD_CALL(detect_telemetry)(thread); } #endif if (!rc) { assert(thd->m_statement_psi == nullptr); thd->m_statement_psi = MYSQL_START_STATEMENT( &thd->m_statement_state, stmt_info_new_packet.m_key, thd->db().str, thd->db().length, thd->charset(), nullptr); /* Starts a new stage in performance schema, if compiled in and enabled. Also sets THD::proc_info (used by SHOW PROCESSLIST, column STATE) */ THD_STAGE_INFO(thd, stage_starting); } /* TODO: consider recording a SOCKET event for the bytes just read, by also passing count here. */ MYSQL_SOCKET_SET_STATE(net->vio->mysql_socket, PSI_SOCKET_STATE_ACTIVE); thd->m_server_idle = false; } } void init_net_server_extension(THD *thd) { /* Start with a clean state for connection events. */ thd->m_idle_psi = nullptr; thd->m_statement_psi = nullptr; thd->m_server_idle = false; /* Hook up the NET_SERVER callback in the net layer. */ thd->m_net_server_extension.m_user_data = thd; thd->m_net_server_extension.m_before_header = net_before_header_psi; thd->m_net_server_extension.m_after_header = net_after_header_psi; thd->m_net_server_extension.compress_ctx.algorithm = MYSQL_UNCOMPRESSED; thd->m_net_server_extension.timeout_on_full_packet = false; /* Activate this private extension for the mysqld server. */ thd->get_protocol_classic()->get_net()->extension = &thd->m_net_server_extension; }