mirror of
https://github.com/MariaDB/server.git
synced 2025-01-31 11:01:52 +01:00
911c673edf
------------------------------------------------------------ revno: 2617.23.18 committer: Davi Arnaut <Davi.Arnaut@Sun.COM> branch nick: 4284-6.0 timestamp: Mon 2009-03-02 18:18:26 -0300 message: Bug#989: If DROP TABLE while there's an active transaction, wrong binlog order WL#4284: Transactional DDL locking This is a prerequisite patch: These changes are intended to split lock requests from granted locks and to allow the memory and lifetime of granted locks to be managed within the MDL subsystem. Furthermore, tickets can now be shared and therefore are used to satisfy multiple lock requests, but only shared locks can be recursive. The problem is that the MDL subsystem morphs lock requests into granted locks locks but does not manage the memory and lifetime of lock requests, and hence, does not manage the memory of granted locks either. This can be problematic because it puts the burden of tracking references on the users of the subsystem and it can't be easily done in transactional contexts where the locks have to be kept around for the duration of a transaction. Another issue is that recursive locks (when the context trying to acquire a lock already holds a lock on the same object) requires that each time the lock is granted, a unique lock request/granted lock structure structure must be kept around until the lock is released. This can lead to memory leaks in transactional contexts as locks taken during the transaction should only be released at the end of the transaction. This also leads to unnecessary wake ups (broadcasts) in the MDL subsystem if the context still holds a equivalent of the lock being released. These issues are exacerbated due to the fact that WL#4284 low-level design says that the implementation should "2) Store metadata locks in transaction memory root, rather than statement memory root" but this is not possible because a memory root, as implemented in mysys, requires all objects allocated from it to be freed all at once. This patch combines review input and significant code contributions from Konstantin Osipov (kostja) and Dmitri Lenev (dlenev).
126 lines
3.1 KiB
C++
126 lines
3.1 KiB
C++
#ifndef SQL_PLIST_H
|
|
#define SQL_PLIST_H
|
|
/* Copyright (C) 2008 MySQL AB
|
|
|
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
|
|
|
|
#include <my_global.h>
|
|
|
|
template <typename T, typename B> class I_P_List_iterator;
|
|
|
|
|
|
/**
|
|
Intrusive parameterized list.
|
|
|
|
Unlike I_List does not require its elements to be descendant of ilink
|
|
class and therefore allows them to participate in several such lists
|
|
simultaneously.
|
|
|
|
Unlike List is doubly-linked list and thus supports efficient deletion
|
|
of element without iterator.
|
|
|
|
@param T Type of elements which will belong to list.
|
|
@param B Class which via its methods specifies which members
|
|
of T should be used for participating in this list.
|
|
Here is typical layout of such class:
|
|
|
|
struct B
|
|
{
|
|
static inline T **next_ptr(T *el)
|
|
{
|
|
return &el->next;
|
|
}
|
|
static inline T ***prev_ptr(T *el)
|
|
{
|
|
return &el->prev;
|
|
}
|
|
};
|
|
*/
|
|
|
|
template <typename T, typename B>
|
|
class I_P_List
|
|
{
|
|
T *first;
|
|
|
|
/*
|
|
Do not prohibit copying of I_P_List object to simplify their usage in
|
|
backup/restore scenarios. Note that performing any operations on such
|
|
is a bad idea.
|
|
*/
|
|
public:
|
|
I_P_List() : first(NULL) { };
|
|
inline void empty() { first= NULL; }
|
|
inline bool is_empty() const { return (first == NULL); }
|
|
inline void push_front(T* a)
|
|
{
|
|
*B::next_ptr(a)= first;
|
|
if (first)
|
|
*B::prev_ptr(first)= B::next_ptr(a);
|
|
first= a;
|
|
*B::prev_ptr(a)= &first;
|
|
}
|
|
inline void remove(T *a)
|
|
{
|
|
T *next= *B::next_ptr(a);
|
|
if (next)
|
|
*B::prev_ptr(next)= *B::prev_ptr(a);
|
|
**B::prev_ptr(a)= next;
|
|
}
|
|
inline T* head() { return first; }
|
|
void swap(I_P_List<T,B> &rhs)
|
|
{
|
|
swap_variables(T *, first, rhs.first);
|
|
if (first)
|
|
*B::prev_ptr(first)= &first;
|
|
if (rhs.first)
|
|
*B::prev_ptr(rhs.first)= &rhs.first;
|
|
}
|
|
#ifndef _lint
|
|
friend class I_P_List_iterator<T, B>;
|
|
#endif
|
|
typedef I_P_List_iterator<T, B> Iterator;
|
|
};
|
|
|
|
|
|
/**
|
|
Iterator for I_P_List.
|
|
*/
|
|
|
|
template <typename T, typename B>
|
|
class I_P_List_iterator
|
|
{
|
|
I_P_List<T, B> *list;
|
|
T *current;
|
|
public:
|
|
I_P_List_iterator(I_P_List<T, B> &a) : list(&a), current(a.first) {}
|
|
inline void init(I_P_List<T, B> &a)
|
|
{
|
|
list= &a;
|
|
current= a.first;
|
|
}
|
|
inline T* operator++(int)
|
|
{
|
|
T *result= current;
|
|
if (result)
|
|
current= *B::next_ptr(current);
|
|
return result;
|
|
}
|
|
inline void rewind()
|
|
{
|
|
current= list->first;
|
|
}
|
|
};
|
|
|
|
#endif
|