diff options
author | Jan Lindström <jan.lindstrom@mariadb.com> | 2016-08-12 11:17:45 +0300 |
---|---|---|
committer | Jan Lindström <jan.lindstrom@mariadb.com> | 2016-09-02 13:22:28 +0300 |
commit | 2e814d4702d71a04388386a9f591d14a35980bfe (patch) | |
tree | f3f9b48d116a3738c5e71f3a360ca61f16cfb632 /storage/innobase/include/ut0lst.h | |
parent | 848d211c5c4df00b819cd84d7530cf7d29bb0524 (diff) | |
download | mariadb-git-2e814d4702d71a04388386a9f591d14a35980bfe.tar.gz |
Merge InnoDB 5.7 from mysql-5.7.9.
Contains also
MDEV-10547: Test multi_update_innodb fails with InnoDB 5.7
The failure happened because 5.7 has changed the signature of
the bool handler::primary_key_is_clustered() const
virtual function ("const" was added). InnoDB was using the old
signature which caused the function not to be used.
MDEV-10550: Parallel replication lock waits/deadlock handling does not work with InnoDB 5.7
Fixed mutexing problem on lock_trx_handle_wait. Note that
rpl_parallel and rpl_optimistic_parallel tests still
fail.
MDEV-10156 : Group commit tests fail on 10.2 InnoDB (branch bb-10.2-jan)
Reason: incorrect merge
MDEV-10550: Parallel replication can't sync with master in InnoDB 5.7 (branch bb-10.2-jan)
Reason: incorrect merge
Diffstat (limited to 'storage/innobase/include/ut0lst.h')
-rw-r--r-- | storage/innobase/include/ut0lst.h | 585 |
1 files changed, 362 insertions, 223 deletions
diff --git a/storage/innobase/include/ut0lst.h b/storage/innobase/include/ut0lst.h index b53e7ade4c1..371e6457a9e 100644 --- a/storage/innobase/include/ut0lst.h +++ b/storage/innobase/include/ut0lst.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2015, 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 @@ -21,122 +21,150 @@ this program; if not, write to the Free Software Foundation, Inc., List utilities Created 9/10/1995 Heikki Tuuri +Rewritten by Sunny Bains Dec 2011. ***********************************************************************/ #ifndef ut0lst_h #define ut0lst_h -#include "univ.i" +/* Do not include univ.i because univ.i includes this. */ + +#include "ut0dbg.h" + +/* This module implements the two-way linear list. Note that a single +list node may belong to two or more lists, but is only on one list +at a time. */ /*******************************************************************//** -Return offset of F in POD T. -@param T - POD pointer -@param F - Field in T */ -#define IB_OFFSETOF(T, F) \ - (reinterpret_cast<byte*>(&(T)->F) - reinterpret_cast<byte*>(T)) +The two way list node. +@param TYPE the list node type name */ +template <typename Type> +struct ut_list_node { + Type* prev; /*!< pointer to the previous + node, NULL if start of list */ + Type* next; /*!< pointer to next node, + NULL if end of list */ + + void reverse() + { + Type* tmp = prev; + prev = next; + next = tmp; + } +}; -/* This module implements the two-way linear list which should be used -if a list is used in the database. Note that a single struct may belong -to two or more lists, provided that the list are given different names. -An example of the usage of the lists can be found in fil0fil.cc. */ +/** Macro used for legacy reasons */ +#define UT_LIST_NODE_T(t) ut_list_node<t> /*******************************************************************//** -This macro expands to the unnamed type definition of a struct which acts -as the two-way list base node. The base node contains pointers -to both ends of the list and a count of nodes in the list (excluding -the base node from the count). -@param TYPE the name of the list node data type */ -template <typename TYPE> +The two-way list base node. The base node contains pointers to both ends +of the list and a count of nodes in the list (excluding the base node +from the count). We also store a pointer to the member field so that it +doesn't have to be specified when doing list operations. +@param Type the type of the list element +@param NodePtr field member pointer that points to the list node */ +template <typename Type, typename NodePtr> struct ut_list_base { - typedef TYPE elem_type; - - ulint count; /*!< count of nodes in list */ - TYPE* start; /*!< pointer to list start, NULL if empty */ - TYPE* end; /*!< pointer to list end, NULL if empty */ + typedef Type elem_type; + typedef NodePtr node_ptr; + typedef ut_list_node<Type> node_type; + + ulint count; /*!< count of nodes in list */ + elem_type* start; /*!< pointer to list start, + NULL if empty */ + elem_type* end; /*!< pointer to list end, + NULL if empty */ + node_ptr node; /*!< Pointer to member field + that is used as a link node */ +#ifdef UNIV_DEBUG + ulint init; /*!< UT_LIST_INITIALISED if + the list was initialised with + UT_LIST_INIT() */ +#endif /* UNIV_DEBUG */ + + void reverse() + { + Type* tmp = start; + start = end; + end = tmp; + } }; -#define UT_LIST_BASE_NODE_T(TYPE) ut_list_base<TYPE> +#define UT_LIST_BASE_NODE_T(t) ut_list_base<t, ut_list_node<t> t::*> + +#ifdef UNIV_DEBUG +# define UT_LIST_INITIALISED 0xCAFE +# define UT_LIST_INITIALISE(b) (b).init = UT_LIST_INITIALISED +# define UT_LIST_IS_INITIALISED(b) ut_a(((b).init == UT_LIST_INITIALISED)) +#else +# define UT_LIST_INITIALISE(b) +# define UT_LIST_IS_INITIALISED(b) +#endif /* UNIV_DEBUG */ /*******************************************************************//** -This macro expands to the unnamed type definition of a struct which -should be embedded in the nodes of the list, the node type must be a struct. -This struct contains the pointers to next and previous nodes in the list. -The name of the field in the node struct should be the name given -to the list. -@param TYPE the list node type name */ -/* Example: -struct LRU_node_t { - UT_LIST_NODE_T(LRU_node_t) LRU_list; - ... +Note: This is really the list constructor. We should be able to use +placement new here. +Initializes the base node of a two-way list. +@param b the list base node +@param pmf point to member field that will be used as the link node */ +#define UT_LIST_INIT(b, pmf) \ +{ \ + (b).count = 0; \ + (b).start = 0; \ + (b).end = 0; \ + (b).node = pmf; \ + UT_LIST_INITIALISE(b); \ } -The example implements an LRU list of name LRU_list. Its nodes are of type -LRU_node_t. */ -template <typename TYPE> -struct ut_list_node { - TYPE* prev; /*!< pointer to the previous node, - NULL if start of list */ - TYPE* next; /*!< pointer to next node, NULL if end of list */ -}; +/** Functor for accessing the embedded node within a list element. This is +required because some lists can have the node emebedded inside a nested +struct/union. See lock0priv.h (table locks) for an example. It provides a +specialised functor to grant access to the list node. */ +template <typename Type> +struct GenericGetNode { -#define UT_LIST_NODE_T(TYPE) ut_list_node<TYPE> + typedef ut_list_node<Type> node_type; -/*******************************************************************//** -Get the list node at offset. -@param elem - list element -@param offset - offset within element. -@return reference to list node. */ -template <typename Type> -ut_list_node<Type>& -ut_elem_get_node(Type& elem, size_t offset) -{ - ut_a(offset < sizeof(elem)); + GenericGetNode(node_type Type::* node) : m_node(node) {} - return(*reinterpret_cast<ut_list_node<Type>*>( - reinterpret_cast<byte*>(&elem) + offset)); -} + node_type& operator() (Type& elem) + { + return(elem.*m_node); + } -/*******************************************************************//** -Initializes the base node of a two-way list. -@param BASE the list base node -*/ -#define UT_LIST_INIT(BASE)\ -{\ - (BASE).count = 0;\ - (BASE).start = NULL;\ - (BASE).end = NULL;\ -}\ + node_type Type::*m_node; +}; /*******************************************************************//** Adds the node as the first element in a two-way linked list. -@param list the base node (not a pointer to it) -@param elem the element to add -@param offset offset of list node in elem. */ -template <typename List, typename Type> +@param list the base node (not a pointer to it) +@param elem the element to add */ +template <typename List> void ut_list_prepend( - List& list, - Type& elem, - size_t offset) + List& list, + typename List::elem_type* elem) { - ut_list_node<Type>& elem_node = ut_elem_get_node(elem, offset); + typename List::node_type& elem_node = elem->*list.node; + + UT_LIST_IS_INITIALISED(list); - elem_node.prev = 0; - elem_node.next = list.start; + elem_node.prev = 0; + elem_node.next = list.start; if (list.start != 0) { - ut_list_node<Type>& base_node = - ut_elem_get_node(*list.start, offset); + typename List::node_type& base_node = + list.start->*list.node; - ut_ad(list.start != &elem); + ut_ad(list.start != elem); - base_node.prev = &elem; + base_node.prev = elem; } - list.start = &elem; + list.start = elem; if (list.end == 0) { - list.end = &elem; + list.end = elem; } ++list.count; @@ -144,42 +172,41 @@ ut_list_prepend( /*******************************************************************//** Adds the node as the first element in a two-way linked list. -@param NAME list name -@param LIST the base node (not a pointer to it) -@param ELEM the element to add */ -#define UT_LIST_ADD_FIRST(NAME, LIST, ELEM) \ - ut_list_prepend(LIST, *ELEM, IB_OFFSETOF(ELEM, NAME)) +@param LIST the base node (not a pointer to it) +@param ELEM the element to add */ +#define UT_LIST_ADD_FIRST(LIST, ELEM) ut_list_prepend(LIST, ELEM) /*******************************************************************//** Adds the node as the last element in a two-way linked list. -@param list list -@param elem the element to add -@param offset offset of list node in elem */ -template <typename List, typename Type> +@param list list +@param elem the element to add +@param get_node to get the list node for that element */ +template <typename List, typename Functor> void ut_list_append( - List& list, - Type& elem, - size_t offset) + List& list, + typename List::elem_type* elem, + Functor get_node) { - ut_list_node<Type>& elem_node = ut_elem_get_node(elem, offset); + typename List::node_type& node = get_node(*elem); + + UT_LIST_IS_INITIALISED(list); - elem_node.next = 0; - elem_node.prev = list.end; + node.next = 0; + node.prev = list.end; if (list.end != 0) { - ut_list_node<Type>& base_node = - ut_elem_get_node(*list.end, offset); + typename List::node_type& base_node = get_node(*list.end); - ut_ad(list.end != &elem); + ut_ad(list.end != elem); - base_node.next = &elem; + base_node.next = elem; } - list.end = &elem; + list.end = elem; if (list.start == 0) { - list.start = &elem; + list.start = elem; } ++list.count; @@ -187,45 +214,57 @@ ut_list_append( /*******************************************************************//** Adds the node as the last element in a two-way linked list. -@param NAME list name -@param LIST list -@param ELEM the element to add */ -#define UT_LIST_ADD_LAST(NAME, LIST, ELEM)\ - ut_list_append(LIST, *ELEM, IB_OFFSETOF(ELEM, NAME)) +@param list list +@param elem the element to add */ +template <typename List> +void +ut_list_append( + List& list, + typename List::elem_type* elem) +{ + ut_list_append( + list, elem, + GenericGetNode<typename List::elem_type>(list.node)); +} + +/*******************************************************************//** +Adds the node as the last element in a two-way linked list. +@param LIST list base node (not a pointer to it) +@param ELEM the element to add */ +#define UT_LIST_ADD_LAST(LIST, ELEM) ut_list_append(LIST, ELEM) /*******************************************************************//** Inserts a ELEM2 after ELEM1 in a list. -@param list the base node -@param elem1 node after which ELEM2 is inserted -@param elem2 node being inserted after NODE1 -@param offset offset of list node in elem1 and elem2 */ -template <typename List, typename Type> +@param list the base node +@param elem1 node after which ELEM2 is inserted +@param elem2 node being inserted after ELEM1 */ +template <typename List> void ut_list_insert( - List& list, - Type& elem1, - Type& elem2, - size_t offset) + List& list, + typename List::elem_type* elem1, + typename List::elem_type* elem2) { - ut_ad(&elem1 != &elem2); + ut_ad(elem1 != elem2); + UT_LIST_IS_INITIALISED(list); - ut_list_node<Type>& elem1_node = ut_elem_get_node(elem1, offset); - ut_list_node<Type>& elem2_node = ut_elem_get_node(elem2, offset); + typename List::node_type& elem1_node = elem1->*list.node; + typename List::node_type& elem2_node = elem2->*list.node; - elem2_node.prev = &elem1; + elem2_node.prev = elem1; elem2_node.next = elem1_node.next; if (elem1_node.next != NULL) { - ut_list_node<Type>& next_node = - ut_elem_get_node(*elem1_node.next, offset); + typename List::node_type& next_node = + elem1_node.next->*list.node; - next_node.prev = &elem2; + next_node.prev = elem2; } - elem1_node.next = &elem2; + elem1_node.next = elem2; - if (list.end == &elem1) { - list.end = &elem2; + if (list.end == elem1) { + list.end = elem2; } ++list.count; @@ -233,132 +272,180 @@ ut_list_insert( /*******************************************************************//** Inserts a ELEM2 after ELEM1 in a list. -@param NAME list name -@param LIST the base node -@param ELEM1 node after which ELEM2 is inserted -@param ELEM2 node being inserted after ELEM1 */ -#define UT_LIST_INSERT_AFTER(NAME, LIST, ELEM1, ELEM2)\ - ut_list_insert(LIST, *ELEM1, *ELEM2, IB_OFFSETOF(ELEM1, NAME)) - -#ifdef UNIV_LIST_DEBUG -/** Invalidate the pointers in a list node. -@param NAME list name -@param N pointer to the node that was removed */ -# define UT_LIST_REMOVE_CLEAR(N) \ - (N).next = (Type*) -1; \ - (N).prev = (N).next -#else -/** Invalidate the pointers in a list node. -@param NAME list name -@param N pointer to the node that was removed */ -# define UT_LIST_REMOVE_CLEAR(N) -#endif /* UNIV_LIST_DEBUG */ +@param LIST list base node (not a pointer to it) +@param ELEM1 node after which ELEM2 is inserted +@param ELEM2 node being inserted after ELEM1 */ +#define UT_LIST_INSERT_AFTER(LIST, ELEM1, ELEM2) \ + ut_list_insert(LIST, ELEM1, ELEM2) + +/*******************************************************************//** +Inserts a ELEM2 after ELEM1 in a list. +@param list the base node +@param elem1 node after which ELEM2 is inserted +@param elem2 node being inserted after ELEM1 +@param get_node to get the list node for that element */ + +template <typename List, typename Functor> +void +ut_list_insert( + List& list, + typename List::elem_type* elem1, + typename List::elem_type* elem2, + Functor get_node) +{ + ut_ad(elem1 != elem2); + UT_LIST_IS_INITIALISED(list); + + typename List::node_type& elem1_node = get_node(*elem1); + typename List::node_type& elem2_node = get_node(*elem2); + + elem2_node.prev = elem1; + elem2_node.next = elem1_node.next; + + if (elem1_node.next != NULL) { + typename List::node_type& next_node = + get_node(*elem1_node.next); + + next_node.prev = elem2; + } + + elem1_node.next = elem2; + + if (list.end == elem1) { + list.end = elem2; + } + + ++list.count; + +} /*******************************************************************//** Removes a node from a two-way linked list. -@param list the base node (not a pointer to it) -@param elem node to be removed from the list -@param offset offset of list node within elem */ -template <typename List, typename Type> +@param list the base node (not a pointer to it) +@param node member node within list element that is to be removed +@param get_node functor to get the list node from elem */ +template <typename List, typename Functor> void ut_list_remove( - List& list, - Type& elem, - size_t offset) + List& list, + typename List::node_type& node, + Functor get_node) { - ut_list_node<Type>& elem_node = ut_elem_get_node(elem, offset); - ut_a(list.count > 0); + UT_LIST_IS_INITIALISED(list); - if (elem_node.next != NULL) { - ut_list_node<Type>& next_node = - ut_elem_get_node(*elem_node.next, offset); + if (node.next != NULL) { + typename List::node_type& next_node = + get_node(*node.next); - next_node.prev = elem_node.prev; + next_node.prev = node.prev; } else { - list.end = elem_node.prev; + list.end = node.prev; } - if (elem_node.prev != NULL) { - ut_list_node<Type>& prev_node = - ut_elem_get_node(*elem_node.prev, offset); + if (node.prev != NULL) { + typename List::node_type& prev_node = + get_node(*node.prev); - prev_node.next = elem_node.next; + prev_node.next = node.next; } else { - list.start = elem_node.next; + list.start = node.next; } - UT_LIST_REMOVE_CLEAR(elem_node); + node.next = 0; + node.prev = 0; --list.count; } /*******************************************************************//** Removes a node from a two-way linked list. - aram NAME list name -@param LIST the base node (not a pointer to it) -@param ELEM node to be removed from the list */ -#define UT_LIST_REMOVE(NAME, LIST, ELEM) \ - ut_list_remove(LIST, *ELEM, IB_OFFSETOF(ELEM, NAME)) +@param list the base node (not a pointer to it) +@param elem element to be removed from the list +@param get_node functor to get the list node from elem */ +template <typename List, typename Functor> +void +ut_list_remove( + List& list, + typename List::elem_type* elem, + Functor get_node) +{ + ut_list_remove(list, get_node(*elem), get_node); +} + +/*******************************************************************//** +Removes a node from a two-way linked list. +@param list the base node (not a pointer to it) +@param elem element to be removed from the list */ +template <typename List> +void +ut_list_remove( + List& list, + typename List::elem_type* elem) +{ + ut_list_remove( + list, elem->*list.node, + GenericGetNode<typename List::elem_type>(list.node)); +} + +/*******************************************************************//** +Removes a node from a two-way linked list. +@param LIST the base node (not a pointer to it) +@param ELEM node to be removed from the list */ +#define UT_LIST_REMOVE(LIST, ELEM) ut_list_remove(LIST, ELEM) /********************************************************************//** Gets the next node in a two-way list. -@param NAME list name -@param N pointer to a node -@return the successor of N in NAME, or NULL */ -#define UT_LIST_GET_NEXT(NAME, N)\ - (((N)->NAME).next) +@param NAME list name +@param N pointer to a node +@return the successor of N in NAME, or NULL */ +#define UT_LIST_GET_NEXT(NAME, N) (((N)->NAME).next) /********************************************************************//** Gets the previous node in a two-way list. -@param NAME list name -@param N pointer to a node -@return the predecessor of N in NAME, or NULL */ -#define UT_LIST_GET_PREV(NAME, N)\ - (((N)->NAME).prev) +@param NAME list name +@param N pointer to a node +@return the predecessor of N in NAME, or NULL */ +#define UT_LIST_GET_PREV(NAME, N) (((N)->NAME).prev) /********************************************************************//** Alternative macro to get the number of nodes in a two-way list, i.e., its length. -@param BASE the base node (not a pointer to it). -@return the number of nodes in the list */ -#define UT_LIST_GET_LEN(BASE)\ - (BASE).count +@param BASE the base node (not a pointer to it). +@return the number of nodes in the list */ +#define UT_LIST_GET_LEN(BASE) (BASE).count /********************************************************************//** Gets the first node in a two-way list. -@param BASE the base node (not a pointer to it) -@return first node, or NULL if the list is empty */ -#define UT_LIST_GET_FIRST(BASE)\ - (BASE).start +@param BASE the base node (not a pointer to it) +@return first node, or NULL if the list is empty */ +#define UT_LIST_GET_FIRST(BASE) (BASE).start /********************************************************************//** Gets the last node in a two-way list. -@param BASE the base node (not a pointer to it) -@return last node, or NULL if the list is empty */ -#define UT_LIST_GET_LAST(BASE)\ - (BASE).end +@param BASE the base node (not a pointer to it) +@return last node, or NULL if the list is empty */ +#define UT_LIST_GET_LAST(BASE) (BASE).end struct NullValidate { void operator()(const void* elem) { } }; /********************************************************************//** Iterate over all the elements and call the functor for each element. -@param list base node (not a pointer to it) -@param functor Functor that is called for each element in the list -@parm node pointer to member node within list element */ +@param[in] list base node (not a pointer to it) +@param[in,out] functor Functor that is called for each element in the list */ template <typename List, class Functor> void ut_list_map( - List& list, - ut_list_node<typename List::elem_type> - List::elem_type::*node, - Functor functor) + const List& list, + Functor& functor) { ulint count = 0; + UT_LIST_IS_INITIALISED(list); + for (typename List::elem_type* elem = list.start; elem != 0; - elem = (elem->*node).next, ++count) { + elem = (elem->*list.node).next, ++count) { functor(elem); } @@ -366,43 +453,95 @@ ut_list_map( ut_a(count == list.count); } +template <typename List> +void +ut_list_reverse(List& list) +{ + UT_LIST_IS_INITIALISED(list); + + for (typename List::elem_type* elem = list.start; + elem != 0; + elem = (elem->*list.node).prev) { + (elem->*list.node).reverse(); + } + + list.reverse(); +} + +#define UT_LIST_REVERSE(LIST) ut_list_reverse(LIST) + /********************************************************************//** Checks the consistency of a two-way list. -@param list base node (not a pointer to it) -@param functor Functor that is called for each element in the list -@parm node pointer to member node within list element */ +@param[in] list base node (not a pointer to it) +@param[in,out] functor Functor that is called for each element in the list */ template <typename List, class Functor> void ut_list_validate( - List& list, - ut_list_node<typename List::elem_type> - List::elem_type::*node, - Functor functor = NullValidate()) + const List& list, + Functor& functor) { - ut_list_map(list, node, functor); + ut_list_map(list, functor); + /* Validate the list backwards. */ ulint count = 0; for (typename List::elem_type* elem = list.end; elem != 0; - elem = (elem->*node).prev, ++count) { - - functor(elem); + elem = (elem->*list.node).prev) { + ++count; } ut_a(count == list.count); } -/********************************************************************//** -Checks the consistency of a two-way list. -@param NAME the name of the list -@param TYPE node type -@param LIST base node (not a pointer to it) -@param FUNCTOR called for each list element */ -#define UT_LIST_VALIDATE(NAME, TYPE, LIST, FUNCTOR) \ - ut_list_validate(LIST, &TYPE::NAME, FUNCTOR) - -#define UT_LIST_CHECK(NAME, TYPE, LIST) \ - ut_list_validate(LIST, &TYPE::NAME, NullValidate()) +/** Check the consistency of a two-way list. +@param[in] LIST base node reference */ +#define UT_LIST_CHECK(LIST) do { \ + NullValidate nullV; \ + ut_list_validate(LIST, nullV); \ +} while (0) + +/** Move the given element to the beginning of the list. +@param[in,out] list the list object +@param[in] elem the element of the list which will be moved + to the beginning of the list. */ +template <typename List> +void +ut_list_move_to_front( + List& list, + typename List::elem_type* elem) +{ + ut_ad(ut_list_exists(list, elem)); + + if (UT_LIST_GET_FIRST(list) != elem) { + ut_list_remove(list, elem); + ut_list_prepend(list, elem); + } +} + +#ifdef UNIV_DEBUG +/** Check if the given element exists in the list. +@param[in,out] list the list object +@param[in] elem the element of the list which will be checked */ +template <typename List> +bool +ut_list_exists( + List& list, + typename List::elem_type* elem) +{ + typename List::elem_type* e1; + + for (e1 = UT_LIST_GET_FIRST(list); e1 != NULL; + e1 = (e1->*list.node).next) { + if (elem == e1) { + return(true); + } + } + return(false); +} +#endif + +#define UT_LIST_MOVE_TO_FRONT(LIST, ELEM) \ + ut_list_move_to_front(LIST, ELEM) #endif /* ut0lst.h */ |