diff options
author | Sergei Golubchik <sergii@pisem.net> | 2011-07-02 22:08:51 +0200 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2011-07-02 22:08:51 +0200 |
commit | 9809f05199aeb0b67991fac41bd86f38730768dc (patch) | |
tree | fa2792ff86d0da014b535d743759810612338042 /sql/mdl.h | |
parent | 0accbd0364e0333e0b119aa9ce93e34ded9df6cb (diff) | |
parent | 5a0e7394a5ae0c7b6a1ea35b7ea3a8985325987a (diff) | |
download | mariadb-git-9809f05199aeb0b67991fac41bd86f38730768dc.tar.gz |
5.5-merge
Diffstat (limited to 'sql/mdl.h')
-rw-r--r-- | sql/mdl.h | 218 |
1 files changed, 119 insertions, 99 deletions
diff --git a/sql/mdl.h b/sql/mdl.h index b9dad0597da..2fa89ea2f55 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -151,6 +151,15 @@ enum enum_mdl_type { MDL_TYPE_END}; +/** Duration of metadata lock. */ + +enum enum_mdl_duration { MDL_STATEMENT= 0, + MDL_TRANSACTION, + MDL_EXPLICIT, + /* This should be the last ! */ + MDL_DURATION_END }; + + /** Maximal length of key for metadata locking subsystem. */ #define MAX_MDLKEY_LENGTH (1 + NAME_LEN + 1 + NAME_LEN + 1) @@ -168,13 +177,16 @@ class MDL_key { public: /** - Object namespaces + Object namespaces. + Sic: when adding a new member to this enum make sure to + update m_namespace_to_wait_state_name array in mdl.cc! Different types of objects exist in different namespaces - TABLE is for tables and views. - FUNCTION is for stored functions. - PROCEDURE is for stored procedures. - TRIGGER is for triggers. + - EVENT is for event scheduler events Note that although there isn't metadata locking on triggers, it's necessary to have a separate namespace for them since MDL_key is also used outside of the MDL subsystem. @@ -185,6 +197,8 @@ public: FUNCTION, PROCEDURE, TRIGGER, + EVENT, + COMMIT, /* This should be the last ! */ NAMESPACE_END }; @@ -239,7 +253,7 @@ public: character set is utf-8, we can safely assume that no character starts with a zero byte. */ - return memcmp(m_ptr, rhs->m_ptr, min(m_length, rhs->m_length)+1); + return memcmp(m_ptr, rhs->m_ptr, min(m_length, rhs->m_length)); } MDL_key(const MDL_key *rhs) @@ -273,21 +287,6 @@ private: }; - -/** - Hook class which via its methods specifies which members - of T should be used for participating in MDL lists. -*/ - -template <typename T, T* T::*next, T** T::*prev> -struct I_P_List_adapter -{ - static inline T **next_ptr(T *el) { return &(el->*next); } - - static inline T ***prev_ptr(T *el) { return &(el->*prev); } -}; - - /** A pending metadata lock request. @@ -306,6 +305,8 @@ class MDL_request public: /** Type of metadata lock. */ enum enum_mdl_type type; + /** Duration for requested lock. */ + enum enum_mdl_duration duration; /** Pointers for participating in the list of lock requests for this context. @@ -328,17 +329,16 @@ public: void init(MDL_key::enum_mdl_namespace namespace_arg, const char *db_arg, const char *name_arg, - enum_mdl_type mdl_type_arg); - void init(const MDL_key *key_arg, enum_mdl_type mdl_type_arg); + enum_mdl_type mdl_type_arg, + enum_mdl_duration mdl_duration_arg); + void init(const MDL_key *key_arg, enum_mdl_type mdl_type_arg, + enum_mdl_duration mdl_duration_arg); /** Set type of lock request. Can be only applied to pending locks. */ inline void set_type(enum_mdl_type type_arg) { DBUG_ASSERT(ticket == NULL); type= type_arg; } - static MDL_request *create(MDL_key::enum_mdl_namespace mdl_namespace, - const char *db, const char *name, - enum_mdl_type mdl_type, MEM_ROOT *root); /* This is to work around the ugliness of TABLE_LIST @@ -364,6 +364,7 @@ public: MDL_request(const MDL_request *rhs) :type(rhs->type), + duration(rhs->duration), ticket(NULL), key(&rhs->key) {} @@ -386,10 +387,7 @@ public: virtual bool inspect_edge(MDL_context *dest) = 0; virtual ~MDL_wait_for_graph_visitor(); - MDL_wait_for_graph_visitor() :m_lock_open_count(0), - m_current_search_depth(0) - { } - virtual void abort_traversal(MDL_context *node) = 0; + MDL_wait_for_graph_visitor() :m_lock_open_count(0) {} public: /** XXX, hack: During deadlock search, we may need to @@ -400,17 +398,6 @@ public: LOCK_open since it has significant performance impacts. */ uint m_lock_open_count; - /** - Set to the 0 at start. Increased whenever - we descend into another MDL context (aka traverse to the next - wait-for graph node). When MAX_SEARCH_DEPTH is reached, we - assume that a deadlock is found, even if we have not found a - loop. - - XXX: This member belongs to this class only temporarily until - bug #56405 is fixed. - */ - uint m_current_search_depth; }; /** @@ -499,17 +486,35 @@ public: private: friend class MDL_context; - MDL_ticket(MDL_context *ctx_arg, enum_mdl_type type_arg) + MDL_ticket(MDL_context *ctx_arg, enum_mdl_type type_arg +#ifndef DBUG_OFF + , enum_mdl_duration duration_arg +#endif + ) : m_type(type_arg), +#ifndef DBUG_OFF + m_duration(duration_arg), +#endif m_ctx(ctx_arg), m_lock(NULL) {} - static MDL_ticket *create(MDL_context *ctx_arg, enum_mdl_type type_arg); + static MDL_ticket *create(MDL_context *ctx_arg, enum_mdl_type type_arg +#ifndef DBUG_OFF + , enum_mdl_duration duration_arg +#endif + ); static void destroy(MDL_ticket *ticket); private: /** Type of metadata lock. Externally accessible. */ enum enum_mdl_type m_type; +#ifndef DBUG_OFF + /** + Duration of lock represented by this ticket. + Context private. Debug-only. + */ + enum_mdl_duration m_duration; +#endif /** Context of the owner of the metadata lock ticket. Externally accessible. */ @@ -527,6 +532,39 @@ private: /** + Savepoint for MDL context. + + Doesn't include metadata locks with explicit duration as + they are not released during rollback to savepoint. +*/ + +class MDL_savepoint +{ +public: + MDL_savepoint() {}; + +private: + MDL_savepoint(MDL_ticket *stmt_ticket, MDL_ticket *trans_ticket) + : m_stmt_ticket(stmt_ticket), m_trans_ticket(trans_ticket) + {} + + friend class MDL_context; + +private: + /** + Pointer to last lock with statement duration which was taken + before creation of savepoint. + */ + MDL_ticket *m_stmt_ticket; + /** + Pointer to last lock with transaction duration which was taken + before creation of savepoint. + */ + MDL_ticket *m_trans_ticket; +}; + + +/** A reliable way to wait on an MDL lock. */ @@ -574,9 +612,7 @@ public: typedef I_P_List<MDL_ticket, I_P_List_adapter<MDL_ticket, &MDL_ticket::next_in_context, - &MDL_ticket::prev_in_context>, - I_P_List_null_counter, - I_P_List_fast_push_back<MDL_ticket> > + &MDL_ticket::prev_in_context> > Ticket_list; typedef Ticket_list::Iterator Ticket_iterator; @@ -599,37 +635,28 @@ public: const char *db, const char *name, enum_mdl_type mdl_type); - bool has_lock(MDL_ticket *mdl_savepoint, MDL_ticket *mdl_ticket); + bool has_lock(const MDL_savepoint &mdl_savepoint, MDL_ticket *mdl_ticket); inline bool has_locks() const { - return !m_tickets.is_empty(); + return !(m_tickets[MDL_STATEMENT].is_empty() && + m_tickets[MDL_TRANSACTION].is_empty() && + m_tickets[MDL_EXPLICIT].is_empty()); } - MDL_ticket *mdl_savepoint() + MDL_savepoint mdl_savepoint() { - /* - NULL savepoint represents the start of the transaction. - Checking for m_trans_sentinel also makes sure we never - return a pointer to HANDLER ticket as a savepoint. - */ - return m_tickets.front() == m_trans_sentinel ? NULL : m_tickets.front(); + return MDL_savepoint(m_tickets[MDL_STATEMENT].front(), + m_tickets[MDL_TRANSACTION].front()); } - void set_trans_sentinel() - { - m_trans_sentinel= m_tickets.front(); - } - MDL_ticket *trans_sentinel() const { return m_trans_sentinel; } - - void reset_trans_sentinel(MDL_ticket *sentinel_arg) - { - m_trans_sentinel= sentinel_arg; - } - void move_ticket_after_trans_sentinel(MDL_ticket *mdl_ticket); + void set_explicit_duration_for_all_locks(); + void set_transaction_duration_for_all_locks(); + void set_lock_duration(MDL_ticket *mdl_ticket, enum_mdl_duration duration); + void release_statement_locks(); void release_transactional_locks(); - void rollback_to_savepoint(MDL_ticket *mdl_savepoint); + void rollback_to_savepoint(const MDL_savepoint &mdl_savepoint); inline THD *get_thd() const { return m_thd; } @@ -670,46 +697,43 @@ public: MDL_wait m_wait; private: /** - All MDL tickets acquired by this connection. - - The order of tickets in m_tickets list. - --------------------------------------- - The entire set of locks acquired by a connection - can be separated in two subsets: transactional and - non-transactional locks. - - Transactional locks are locks with automatic scope. They - are accumulated in the course of a transaction, and - released only on COMMIT, ROLLBACK or ROLLBACK TO SAVEPOINT. - They must not be (and never are) released manually, + Lists of all MDL tickets acquired by this connection. + + Lists of MDL tickets: + --------------------- + The entire set of locks acquired by a connection can be separated + in three subsets according to their: locks released at the end of + statement, at the end of transaction and locks are released + explicitly. + + Statement and transactional locks are locks with automatic scope. + They are accumulated in the course of a transaction, and released + either at the end of uppermost statement (for statement locks) or + on COMMIT, ROLLBACK or ROLLBACK TO SAVEPOINT (for transactional + locks). They must not be (and never are) released manually, i.e. with release_lock() call. - Non-transactional locks are taken for locks that span + Locks with explicit duration are taken for locks that span multiple transactions or savepoints. These are: HANDLER SQL locks (HANDLER SQL is transaction-agnostic), LOCK TABLES locks (you can COMMIT/etc under LOCK TABLES, and the locked tables stay locked), and - SET GLOBAL READ_ONLY=1 global shared lock. + locks implementing "global read lock". - Transactional locks are always prepended to the beginning - of the list. In other words, they are stored in reverse - temporal order. Thus, when we rollback to a savepoint, - we start popping and releasing tickets from the front - until we reach the last ticket acquired after the - savepoint. + Statement/transactional locks are always prepended to the + beginning of the appropriate list. In other words, they are + stored in reverse temporal order. Thus, when we rollback to + a savepoint, we start popping and releasing tickets from the + front until we reach the last ticket acquired after the savepoint. - Non-transactional locks are always stored after - transactional ones, and among each other can be - split into three sets: + Locks with explicit duration stored are not stored in any + particular order, and among each other can be split into + three sets: [LOCK TABLES locks] [HANDLER locks] [GLOBAL READ LOCK locks] The following is known about these sets: - * we can never have both HANDLER and LOCK TABLES locks - together -- HANDLER statements are prohibited under LOCK - TABLES, entering LOCK TABLES implicitly closes all open - HANDLERs. * GLOBAL READ LOCK locks are always stored after LOCK TABLES locks and after HANDLER locks. This is because one can't say SET GLOBAL read_only=1 or FLUSH TABLES WITH READ LOCK @@ -724,14 +748,9 @@ private: However, one can open a few HANDLERs after entering the read only mode. * LOCK TABLES locks include intention exclusive locks on - involved schemas. - */ - Ticket_list m_tickets; - /** - Separates transactional and non-transactional locks - in m_tickets list, @sa m_tickets. + involved schemas and global intention exclusive lock. */ - MDL_ticket *m_trans_sentinel; + Ticket_list m_tickets[MDL_DURATION_END]; THD *m_thd; /** TRUE - if for this context we will break protocol and try to @@ -762,8 +781,9 @@ private: MDL_wait_for_subgraph *m_waiting_for; private: MDL_ticket *find_ticket(MDL_request *mdl_req, - bool *is_transactional); - void release_locks_stored_before(MDL_ticket *sentinel); + enum_mdl_duration *duration); + void release_locks_stored_before(enum_mdl_duration duration, MDL_ticket *sentinel); + void release_lock(enum_mdl_duration duration, MDL_ticket *ticket); bool try_acquire_lock_impl(MDL_request *mdl_request, MDL_ticket **out_ticket); |