aboutsummaryrefslogtreecommitdiff
path: root/mysql/libmysql/mysql_trace.c
diff options
context:
space:
mode:
Diffstat (limited to 'mysql/libmysql/mysql_trace.c')
-rw-r--r--mysql/libmysql/mysql_trace.c215
1 files changed, 215 insertions, 0 deletions
diff --git a/mysql/libmysql/mysql_trace.c b/mysql/libmysql/mysql_trace.c
new file mode 100644
index 0000000..3073479
--- /dev/null
+++ b/mysql/libmysql/mysql_trace.c
@@ -0,0 +1,215 @@
+/* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ 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 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 */
+
+/**
+ @file
+
+ =============================================
+ Client-side protocol tracing infrastructure
+ =============================================
+
+ If a plugin of type MYSQL_CLIENT_TRACE_PLUGIN is loaded into
+ libmysql and its instance is pointed by the global trace_plugin
+ pointer, this plugin is notified of various protocol trace events.
+ See include/mysql/plugin_trace.h for documentation of trace plugin
+ methods and the list of possible trace events.
+
+ These trace events are generated with MYSQL_TRACE() macro put in
+ relevant places in libmysql code. The macro calls mysql_trace_trace()
+ function defined here. This function calls trace plugin's
+ trace_event() method, if it is defined.
+
+ For each traced connection, the state is kept in st_mysql_trace_info
+ structure (see mysql_trace.h).
+
+ To correctly interpret each trace event, trace plugin is informed
+ of the current protocol stage (see include/mysql/plugin_trace.h for
+ list of stages). The current protocol stage is part of the
+ connection tracing state. It is updated with MYSQL_TRACE_STAGE()
+ hooks within libmysql code.
+*/
+
+#include <my_global.h>
+#include "mysql.h"
+#include "mysql_trace.h"
+
+/*
+ Definition of the global trace_plugin pointer - see plugin_trace.h
+ for declaration and description.
+*/
+struct st_mysql_client_plugin_TRACE *trace_plugin= NULL;
+
+/*
+ Macros for manipulating trace_info structure.
+*/
+#define GET_DATA(TI) (TI)->trace_plugin_data
+#define SET_DATA(TI,D) GET_DATA(TI) = (D)
+#define GET_STAGE(TI) (TI)->stage
+#define TEST_STAGE(TI,X) (GET_STAGE(TI) == PROTOCOL_STAGE_ ## X)
+#define SET_STAGE(TI,X) GET_STAGE(TI) = PROTOCOL_STAGE_ ## X
+
+
+/**
+ Initialize tracing in a given connection.
+
+ This function is called from MYSQL_TRACE_STAGE() when the initial
+ CONNECTING stage is reported. It allocates and initializes trace_info
+ structure which is then attached to the connection handle.
+*/
+
+void mysql_trace_start(struct st_mysql *m)
+{
+ struct st_mysql_trace_info *trace_info;
+
+ trace_info= my_malloc(PSI_NOT_INSTRUMENTED,
+ sizeof(struct st_mysql_trace_info),
+ MYF(MY_ZEROFILL));
+ if (!trace_info)
+ {
+ /*
+ Note: in this case trace_data of the connection will
+ remain NULL and thus tracing will be disabled.
+ */
+ return;
+ }
+
+ /*
+ This function should be called only when a trace plugin
+ is loaded and thus trace_plugin pointer is not NULL. This
+ is handled in MYSQL_TRACE_STAGE() macro (mysql_trace.h).
+ */
+ DBUG_ASSERT(trace_plugin);
+
+ trace_info->plugin= trace_plugin;
+ trace_info->stage= PROTOCOL_STAGE_CONNECTING;
+
+ /*
+ Call plugin's tracing_start() method, if defined.
+ */
+
+ if (trace_info->plugin->tracing_start)
+ {
+ trace_info->trace_plugin_data=
+ trace_info->plugin->tracing_start(
+ trace_info->plugin,
+ m, PROTOCOL_STAGE_CONNECTING);
+ }
+ else
+ {
+ trace_info->trace_plugin_data= NULL;
+ }
+
+ /* Store trace_info in the connection handle. */
+
+ TRACE_DATA(m)= trace_info;
+}
+
+
+/**
+ Report a protocol trace event to trace plugin.
+
+ Calls plugin's trace_event() method, if it is defined, passing to
+ it the event, the current protocol stage and event arguments (if any).
+
+ Terminates tracing of the connection when appropriate.
+
+ @param m MYSQL connection handle
+ @param ev trace event to be reported
+ @param args trace event arguments
+*/
+
+void mysql_trace_trace(struct st_mysql *m,
+ enum trace_event ev,
+ struct st_trace_event_args args)
+{
+ struct st_mysql_trace_info *trace_info= TRACE_DATA(m);
+ struct st_mysql_client_plugin_TRACE *plugin= trace_info ? trace_info->plugin : NULL;
+ int quit_tracing= 0;
+
+ /*
+ If trace_info is NULL then this connection is not traced and this
+ function should not be called - this is handled inside MYSQL_TRACE()
+ macro.
+ */
+ DBUG_ASSERT(trace_info);
+
+ /* Call plugin's trace_event() method if defined */
+
+ if (plugin->trace_event)
+ {
+ /*
+ Temporarily disable tracing while executing plugin's method
+ by setting trace data pointer to NULL. Also, set reconnect
+ flag to 0 in case plugin executes any queries.
+ */
+ my_bool saved_reconnect_flag= m->reconnect;
+
+ TRACE_DATA(m)= NULL;
+ m->reconnect= 0;
+ quit_tracing= plugin->trace_event(plugin, GET_DATA(trace_info), m,
+ GET_STAGE(trace_info), ev, args);
+ m->reconnect= saved_reconnect_flag;
+ TRACE_DATA(m)= trace_info;
+ }
+
+ /* Stop tracing if requested or end of connection. */
+
+ if (quit_tracing
+ || TEST_STAGE(trace_info, DISCONNECTED)
+ || TRACE_EVENT_DISCONNECTED == ev)
+ {
+ /* Note: this disables further tracing */
+ TRACE_DATA(m)= NULL;
+
+ if (plugin->tracing_stop)
+ plugin->tracing_stop(plugin, m, GET_DATA(trace_info));
+
+ my_free(trace_info);
+ }
+}
+
+
+#ifndef DBUG_OFF
+/*
+ These functions are declared in plugin_trace.h.
+
+ Consult documentation of *_LIST() macros (plugin_trace.h) to see how
+ switch() bodies are constructed with the *_get_name() macros.
+*/
+
+#define protocol_stage_get_name(X) case PROTOCOL_STAGE_ ## X: return #X;
+
+const char* protocol_stage_name(enum protocol_stage stage)
+{
+ switch(stage)
+ {
+ PROTOCOL_STAGE_LIST(get_name)
+ default: return "<unknown stage>";
+ }
+}
+
+
+#define trace_event_get_name(X) case TRACE_EVENT_ ## X: return #X;
+
+const char* trace_event_name(enum trace_event ev)
+{
+ switch(ev)
+ {
+ TRACE_EVENT_LIST(get_name)
+ default: return "<unknown event>";
+ }
+}
+
+#endif