summaryrefslogtreecommitdiffstats
path: root/sql/session_tracker.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--sql/session_tracker.h498
1 files changed, 498 insertions, 0 deletions
diff --git a/sql/session_tracker.h b/sql/session_tracker.h
new file mode 100644
index 00000000..c78778ac
--- /dev/null
+++ b/sql/session_tracker.h
@@ -0,0 +1,498 @@
+#ifndef SESSION_TRACKER_INCLUDED
+#define SESSION_TRACKER_INCLUDED
+
+/* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2016, 2017, MariaDB Corporation.
+
+ 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 */
+
+#include "m_string.h"
+#include "thr_lock.h"
+#include "sql_hset.h"
+
+#ifndef EMBEDDED_LIBRARY
+/* forward declarations */
+class THD;
+class set_var;
+class String;
+class user_var_entry;
+
+
+enum enum_session_tracker
+{
+ SESSION_SYSVARS_TRACKER, /* Session system variables */
+ CURRENT_SCHEMA_TRACKER, /* Current schema */
+ SESSION_STATE_CHANGE_TRACKER,
+ TRANSACTION_INFO_TRACKER, /* Transaction state */
+#ifdef USER_VAR_TRACKING
+ USER_VARIABLES_TRACKER,
+#endif // USER_VAR_TRACKING
+ SESSION_TRACKER_END /* must be the last */
+};
+
+/**
+ State_tracker
+
+ An abstract class that defines the interface for any of the server's
+ 'session state change tracker'. A tracker, however, is a sub- class of
+ this class which takes care of tracking the change in value of a part-
+ icular session state type and thus defines various methods listed in this
+ interface. The change information is later serialized and transmitted to
+ the client through protocol's OK packet.
+
+ Tracker system variables :-
+ A tracker is normally mapped to a system variable. So in order to enable,
+ disable or modify the sub-entities of a tracker, the user needs to modify
+ the respective system variable either through SET command or via command
+ line option. As required in system variable handling, this interface also
+ includes two functions to help in the verification of the supplied value
+ (ON_UPDATE) of the tracker system variable, namely - update().
+*/
+
+class State_tracker
+{
+protected:
+ /**
+ Is tracking enabled for a particular session state type ?
+
+ @note: it is a cache of the corresponding thd->variables.session_track_xxx
+ variable
+ */
+ bool m_enabled;
+
+ void set_changed(THD *thd);
+
+private:
+ /** Has the session state type changed ? */
+ bool m_changed;
+
+public:
+ virtual ~State_tracker() {}
+
+ /** Getters */
+ bool is_enabled() const
+ { return m_enabled; }
+
+ bool is_changed() const
+ { return m_changed; }
+
+ void reset_changed() { m_changed= false; }
+
+ /**
+ Called by THD::init() when new connection is being created
+
+ We may inherit m_changed from previous connection served by this THD if
+ connection was broken or client didn't have session tracking capability.
+ Thus we have to reset it here.
+ */
+ virtual bool enable(THD *thd)
+ {
+ reset_changed();
+ return update(thd, 0);
+ }
+
+ /** To be invoked when the tracker's system variable is updated (ON_UPDATE).*/
+ virtual bool update(THD *thd, set_var *var)= 0;
+
+ /** Store changed data into the given buffer. */
+ virtual bool store(THD *thd, String *buf)= 0;
+
+ /** Mark the entity as changed. */
+ void mark_as_changed(THD *thd) { if (is_enabled()) set_changed(thd); }
+};
+
+
+/**
+ Session_sysvars_tracker
+
+ This is a tracker class that enables & manages the tracking of session
+ system variables. It internally maintains a hash of user supplied variable
+ references and a boolean field to store if the variable was changed by the
+ last statement.
+*/
+
+class Session_sysvars_tracker: public State_tracker
+{
+ struct sysvar_node_st {
+ sys_var *m_svar;
+ bool *test_load;
+ bool m_changed;
+ };
+
+ class vars_list
+ {
+ /**
+ Registered system variables. (@@session_track_system_variables)
+ A hash to store the name of all the system variables specified by the
+ user.
+ */
+ HASH m_registered_sysvars;
+ /**
+ If TRUE then we want to check all session variable.
+ */
+ bool track_all;
+ void init()
+ {
+ my_hash_init(PSI_INSTRUMENT_ME, &m_registered_sysvars, &my_charset_bin,
+ 0, 0, 0, (my_hash_get_key) sysvars_get_key, my_free,
+ HASH_UNIQUE | (mysqld_server_initialized ? HASH_THREAD_SPECIFIC : 0));
+ }
+ void free_hash()
+ {
+ DBUG_ASSERT(my_hash_inited(&m_registered_sysvars));
+ my_hash_free(&m_registered_sysvars);
+ }
+
+ sysvar_node_st *search(const sys_var *svar)
+ {
+ return reinterpret_cast<sysvar_node_st*>(
+ my_hash_search(&m_registered_sysvars,
+ reinterpret_cast<const uchar*>(&svar),
+ sizeof(sys_var*)));
+ }
+
+ sysvar_node_st *at(ulong i)
+ {
+ DBUG_ASSERT(i < m_registered_sysvars.records);
+ return reinterpret_cast<sysvar_node_st*>(
+ my_hash_element(&m_registered_sysvars, i));
+ }
+ public:
+ vars_list(): track_all(false) { init(); }
+ ~vars_list() { if (my_hash_inited(&m_registered_sysvars)) free_hash(); }
+ void deinit() { free_hash(); }
+
+ sysvar_node_st *insert_or_search(const sys_var *svar)
+ {
+ sysvar_node_st *res= search(svar);
+ if (!res)
+ {
+ if (track_all)
+ {
+ insert(svar);
+ return search(svar);
+ }
+ }
+ return res;
+ }
+
+ bool insert(const sys_var *svar);
+ void reinit();
+ void reset();
+ inline bool is_enabled()
+ {
+ return track_all || m_registered_sysvars.records;
+ }
+ void copy(vars_list* from, THD *thd);
+ bool parse_var_list(THD *thd, LEX_STRING var_list, bool throw_error,
+ CHARSET_INFO *char_set);
+ bool construct_var_list(char *buf, size_t buf_len);
+ bool store(THD *thd, String *buf);
+ };
+ /**
+ Two objects of vars_list type are maintained to manage
+ various operations.
+ */
+ vars_list orig_list;
+ bool m_parsed;
+
+public:
+ void init(THD *thd);
+ void deinit(THD *thd);
+ bool enable(THD *thd);
+ bool update(THD *thd, set_var *var);
+ bool store(THD *thd, String *buf);
+ void mark_as_changed(THD *thd, const sys_var *var);
+ void deinit() { orig_list.deinit(); }
+ /* callback */
+ static uchar *sysvars_get_key(const char *entry, size_t *length,
+ my_bool not_used __attribute__((unused)));
+
+ friend bool sysvartrack_global_update(THD *thd, char *str, size_t len);
+};
+
+
+bool sysvartrack_validate_value(THD *thd, const char *str, size_t len);
+bool sysvartrack_global_update(THD *thd, char *str, size_t len);
+
+
+/**
+ Current_schema_tracker,
+
+ This is a tracker class that enables & manages the tracking of current
+ schema for a particular connection.
+*/
+
+class Current_schema_tracker: public State_tracker
+{
+public:
+ bool update(THD *thd, set_var *var);
+ bool store(THD *thd, String *buf);
+};
+
+
+/*
+ Session_state_change_tracker
+
+ This is a boolean tracker class that will monitor any change that contributes
+ to a session state change.
+ Attributes that contribute to session state change include:
+ - Successful change to System variables
+ - User defined variables assignments
+ - temporary tables created, altered or deleted
+ - prepared statements added or removed
+ - change in current database
+ - change of current role
+*/
+
+class Session_state_change_tracker: public State_tracker
+{
+public:
+ bool update(THD *thd, set_var *var);
+ bool store(THD *thd, String *buf);
+};
+
+
+/*
+ Transaction_state_tracker
+*/
+
+/**
+ Transaction state (no transaction, transaction active, work attached, etc.)
+*/
+enum enum_tx_state {
+ TX_EMPTY = 0, ///< "none of the below"
+ TX_EXPLICIT = 1, ///< an explicit transaction is active
+ TX_IMPLICIT = 2, ///< an implicit transaction is active
+ TX_READ_TRX = 4, ///< transactional reads were done
+ TX_READ_UNSAFE = 8, ///< non-transaction reads were done
+ TX_WRITE_TRX = 16, ///< transactional writes were done
+ TX_WRITE_UNSAFE = 32, ///< non-transactional writes were done
+ TX_STMT_UNSAFE = 64, ///< "unsafe" (non-deterministic like UUID()) stmts
+ TX_RESULT_SET = 128, ///< result set was sent
+ TX_WITH_SNAPSHOT= 256, ///< WITH CONSISTENT SNAPSHOT was used
+ TX_LOCKED_TABLES= 512 ///< LOCK TABLES is active
+};
+
+
+/**
+ Transaction access mode
+*/
+enum enum_tx_read_flags {
+ TX_READ_INHERIT = 0, ///< not explicitly set, inherit session.tx_read_only
+ TX_READ_ONLY = 1, ///< START TRANSACTION READ ONLY, or tx_read_only=1
+ TX_READ_WRITE = 2, ///< START TRANSACTION READ WRITE, or tx_read_only=0
+};
+
+
+/**
+ Transaction isolation level
+*/
+enum enum_tx_isol_level {
+ TX_ISOL_INHERIT = 0, ///< not explicitly set, inherit session.tx_isolation
+ TX_ISOL_UNCOMMITTED = 1,
+ TX_ISOL_COMMITTED = 2,
+ TX_ISOL_REPEATABLE = 3,
+ TX_ISOL_SERIALIZABLE= 4
+};
+
+
+/**
+ Transaction tracking level
+*/
+enum enum_session_track_transaction_info {
+ TX_TRACK_NONE = 0, ///< do not send tracker items on transaction info
+ TX_TRACK_STATE = 1, ///< track transaction status
+ TX_TRACK_CHISTICS = 2 ///< track status and characteristics
+};
+
+
+/**
+ This is a tracker class that enables & manages the tracking of
+ current transaction info for a particular connection.
+*/
+
+class Transaction_state_tracker : public State_tracker
+{
+ /** Helper function: turn table info into table access flag */
+ enum_tx_state calc_trx_state(THD *thd, thr_lock_type l, bool has_trx);
+public:
+
+ bool enable(THD *thd)
+ {
+ m_enabled= false;
+ tx_changed= TX_CHG_NONE;
+ tx_curr_state= TX_EMPTY;
+ tx_reported_state= TX_EMPTY;
+ tx_read_flags= TX_READ_INHERIT;
+ tx_isol_level= TX_ISOL_INHERIT;
+ return State_tracker::enable(thd);
+ }
+
+ bool update(THD *thd, set_var *var);
+ bool store(THD *thd, String *buf);
+
+ /** Change transaction characteristics */
+ void set_read_flags(THD *thd, enum enum_tx_read_flags flags);
+ void set_isol_level(THD *thd, enum enum_tx_isol_level level);
+
+ /** Change transaction state */
+ void clear_trx_state(THD *thd, uint clear);
+ void add_trx_state(THD *thd, uint add);
+ void inline add_trx_state(THD *thd, thr_lock_type l, bool has_trx)
+ {
+ add_trx_state(thd, calc_trx_state(thd, l, has_trx));
+ }
+ void add_trx_state_from_thd(THD *thd);
+ void end_trx(THD *thd);
+
+
+private:
+ enum enum_tx_changed {
+ TX_CHG_NONE = 0, ///< no changes from previous stmt
+ TX_CHG_STATE = 1, ///< state has changed from previous stmt
+ TX_CHG_CHISTICS = 2 ///< characteristics have changed from previous stmt
+ };
+
+ /** any trackable changes caused by this statement? */
+ uint tx_changed;
+
+ /** transaction state */
+ uint tx_curr_state, tx_reported_state;
+
+ /** r/w or r/o set? session default? */
+ enum enum_tx_read_flags tx_read_flags;
+
+ /** isolation level */
+ enum enum_tx_isol_level tx_isol_level;
+
+ inline void update_change_flags(THD *thd)
+ {
+ tx_changed &= uint(~TX_CHG_STATE);
+ tx_changed |= (tx_curr_state != tx_reported_state) ? TX_CHG_STATE : 0;
+ if (tx_changed != TX_CHG_NONE)
+ set_changed(thd);
+ }
+};
+
+#define TRANSACT_TRACKER(X) \
+ do { if (thd->variables.session_track_transaction_info > TX_TRACK_NONE) \
+ thd->session_tracker.transaction_info.X; } while(0)
+
+
+/**
+ User_variables_tracker
+
+ This is a tracker class that enables & manages the tracking of user variables.
+*/
+
+#ifdef USER_VAR_TRACKING
+class User_variables_tracker: public State_tracker
+{
+ Hash_set<const user_var_entry> m_changed_user_variables;
+public:
+ User_variables_tracker():
+ m_changed_user_variables(PSI_INSTRUMENT_ME, &my_charset_bin, 0, 0,
+ sizeof(const user_var_entry*), 0, 0, HASH_UNIQUE |
+ mysqld_server_initialized ? HASH_THREAD_SPECIFIC : 0) {}
+ bool update(THD *thd, set_var *var);
+ bool store(THD *thd, String *buf);
+ void mark_as_changed(THD *thd, const user_var_entry *var)
+ {
+ if (is_enabled())
+ {
+ m_changed_user_variables.insert(var);
+ set_changed(thd);
+ }
+ }
+ void deinit() { m_changed_user_variables.~Hash_set(); }
+};
+#endif // USER_VAR_TRACKING
+
+
+/**
+ Session_tracker
+
+ This class holds an object each for all tracker classes and provides
+ methods necessary for systematic detection and generation of session
+ state change information.
+*/
+
+class Session_tracker
+{
+ State_tracker *m_trackers[SESSION_TRACKER_END];
+
+ /* The following two functions are private to disable copying. */
+ Session_tracker(Session_tracker const &other)
+ {
+ DBUG_ASSERT(FALSE);
+ }
+ Session_tracker& operator= (Session_tracker const &rhs)
+ {
+ DBUG_ASSERT(FALSE);
+ return *this;
+ }
+
+public:
+ Current_schema_tracker current_schema;
+ Session_state_change_tracker state_change;
+ Transaction_state_tracker transaction_info;
+ Session_sysvars_tracker sysvars;
+#ifdef USER_VAR_TRACKING
+ User_variables_tracker user_variables;
+#endif // USER_VAR_TRACKING
+
+ Session_tracker()
+ {
+ m_trackers[SESSION_SYSVARS_TRACKER]= &sysvars;
+ m_trackers[CURRENT_SCHEMA_TRACKER]= &current_schema;
+ m_trackers[SESSION_STATE_CHANGE_TRACKER]= &state_change;
+ m_trackers[TRANSACTION_INFO_TRACKER]= &transaction_info;
+#ifdef USER_VAR_TRACKING
+ m_trackers[USER_VARIABLES_TRACKER]= &user_variables;
+#endif // USER_VAR_TRACKING
+ }
+
+ void enable(THD *thd)
+ {
+ for (int i= 0; i < SESSION_TRACKER_END; i++)
+ m_trackers[i]->enable(thd);
+ }
+
+ void store(THD *thd, String *main_buf);
+};
+
+
+int session_tracker_init();
+#else
+
+#define TRANSACT_TRACKER(X) do{}while(0)
+
+class Session_tracker
+{
+ class Dummy_tracker
+ {
+ public:
+ void mark_as_changed(THD *thd) {}
+ void mark_as_changed(THD *thd, const sys_var *var) {}
+ };
+public:
+ Dummy_tracker current_schema;
+ Dummy_tracker state_change;
+ Dummy_tracker sysvars;
+};
+
+#endif //EMBEDDED_LIBRARY
+
+#endif /* SESSION_TRACKER_INCLUDED */