194 lines
5.4 KiB
C++
194 lines
5.4 KiB
C++
/* Copyright (c) 2011, 2017, 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 */
|
|
|
|
#include "rpl_gtid.h"
|
|
|
|
#include "mysqld_error.h" // ER_*
|
|
|
|
|
|
Owned_gtids::Owned_gtids(Checkable_rwlock *_sid_lock)
|
|
: sid_lock(_sid_lock), sidno_to_hash(key_memory_Owned_gtids_sidno_to_hash)
|
|
{
|
|
/*
|
|
my_hash_init(>id_to_owner, &my_charset_bin, 20,
|
|
offsetof(Node, group), sizeof(Group), NULL,
|
|
my_free, 0);
|
|
*/
|
|
}
|
|
|
|
|
|
Owned_gtids::~Owned_gtids()
|
|
{
|
|
// destructor should only be called when no other thread may access object
|
|
//sid_lock->assert_no_lock();
|
|
// need to hold lock before calling get_max_sidno
|
|
sid_lock->rdlock();
|
|
rpl_sidno max_sidno= get_max_sidno();
|
|
for (int sidno= 1; sidno <= max_sidno; sidno++)
|
|
{
|
|
HASH *hash= get_hash(sidno);
|
|
my_hash_free(hash);
|
|
my_free(hash);
|
|
}
|
|
sid_lock->unlock();
|
|
//sid_lock->assert_no_lock();
|
|
}
|
|
|
|
|
|
enum_return_status Owned_gtids::ensure_sidno(rpl_sidno sidno)
|
|
{
|
|
DBUG_ENTER("Owned_gtids::ensure_sidno");
|
|
sid_lock->assert_some_wrlock();
|
|
rpl_sidno max_sidno= get_max_sidno();
|
|
if (sidno > max_sidno || get_hash(sidno) == NULL)
|
|
{
|
|
for (int i= max_sidno; i < sidno; i++)
|
|
{
|
|
HASH *hash= (HASH *)my_malloc(key_memory_Owned_gtids_sidno_to_hash,
|
|
sizeof(HASH), MYF(MY_WME));
|
|
if (hash == NULL)
|
|
goto error;
|
|
my_hash_init(hash, &my_charset_bin, 20,
|
|
offsetof(Node, gno), sizeof(rpl_gno), NULL,
|
|
my_free, 0,
|
|
key_memory_Owned_gtids_sidno_to_hash);
|
|
sidno_to_hash.push_back(hash);
|
|
}
|
|
}
|
|
RETURN_OK;
|
|
error:
|
|
BINLOG_ERROR(("Out of memory."), (ER_OUT_OF_RESOURCES, MYF(0)));
|
|
RETURN_REPORTED_ERROR;
|
|
}
|
|
|
|
|
|
enum_return_status Owned_gtids::add_gtid_owner(const Gtid >id,
|
|
my_thread_id owner)
|
|
{
|
|
DBUG_ENTER("Owned_gtids::add_gtid_owner(Gtid, my_thread_id)");
|
|
DBUG_ASSERT(gtid.sidno <= get_max_sidno());
|
|
Node *n= (Node *)my_malloc(key_memory_Sid_map_Node,
|
|
sizeof(Node), MYF(MY_WME));
|
|
if (n == NULL)
|
|
RETURN_REPORTED_ERROR;
|
|
n->gno= gtid.gno;
|
|
n->owner= owner;
|
|
/*
|
|
printf("Owned_gtids(%p)::add sidno=%d gno=%lld n=%p n->owner=%u\n",
|
|
this, sidno, gno, n, n?n->owner:0);
|
|
*/
|
|
if (my_hash_insert(get_hash(gtid.sidno), (const uchar *)n) != 0)
|
|
{
|
|
my_free(n);
|
|
BINLOG_ERROR(("Out of memory."), (ER_OUT_OF_RESOURCES, MYF(0)));
|
|
RETURN_REPORTED_ERROR;
|
|
}
|
|
RETURN_OK;
|
|
}
|
|
|
|
|
|
void Owned_gtids::remove_gtid(const Gtid >id, const my_thread_id owner)
|
|
{
|
|
DBUG_ENTER("Owned_gtids::remove_gtid(Gtid)");
|
|
//printf("Owned_gtids::remove(sidno=%d gno=%lld)\n", sidno, gno);
|
|
//DBUG_ASSERT(contains_gtid(sidno, gno)); // allow group not owned
|
|
HASH_SEARCH_STATE state;
|
|
HASH *hash= get_hash(gtid.sidno);
|
|
DBUG_ASSERT(hash != NULL);
|
|
|
|
for (Node *node= (Node *)my_hash_search(hash, (const uchar *)>id.gno, sizeof(rpl_gno));
|
|
node != NULL;
|
|
node= (Node*) my_hash_next(hash, (const uchar *)>id.gno, sizeof(rpl_gno), &state))
|
|
{
|
|
if (node->owner == owner)
|
|
{
|
|
#ifdef DBUG_OFF
|
|
my_hash_delete(hash, (uchar *)node);
|
|
#else
|
|
// my_hash_delete returns nonzero if the element does not exist
|
|
DBUG_ASSERT(my_hash_delete(hash, (uchar *)node) == 0);
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
bool Owned_gtids::is_intersection_nonempty(const Gtid_set *other) const
|
|
{
|
|
DBUG_ENTER("Owned_gtids::is_intersection_nonempty(Gtid_set *)");
|
|
if (sid_lock != NULL)
|
|
sid_lock->assert_some_wrlock();
|
|
Gtid_iterator git(this);
|
|
Gtid g= git.get();
|
|
while (g.sidno != 0)
|
|
{
|
|
if (other->contains_gtid(g.sidno, g.gno))
|
|
DBUG_RETURN(true);
|
|
git.next();
|
|
g= git.get();
|
|
}
|
|
DBUG_RETURN(false);
|
|
}
|
|
|
|
void Owned_gtids::get_gtids(Gtid_set >id_set) const
|
|
{
|
|
DBUG_ENTER("Owned_gtids::get_gtids");
|
|
|
|
if (sid_lock != NULL)
|
|
sid_lock->assert_some_wrlock();
|
|
|
|
Gtid_iterator git(this);
|
|
Gtid g= git.get();
|
|
while (g.sidno != 0)
|
|
{
|
|
gtid_set._add_gtid(g);
|
|
git.next();
|
|
g= git.get();
|
|
}
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
bool Owned_gtids::contains_gtid(const Gtid >id) const
|
|
{
|
|
HASH *hash= get_hash(gtid.sidno);
|
|
DBUG_ASSERT(hash != NULL);
|
|
sid_lock->assert_some_lock();
|
|
|
|
return my_hash_search(hash, (const uchar *)>id.gno, sizeof(rpl_gno)) != NULL;
|
|
}
|
|
|
|
bool Owned_gtids::is_owned_by(const Gtid >id, const my_thread_id thd_id) const
|
|
{
|
|
HASH_SEARCH_STATE state;
|
|
HASH *hash= get_hash(gtid.sidno);
|
|
DBUG_ASSERT(hash != NULL);
|
|
Node *node= (Node*) my_hash_first(hash, (const uchar *)>id.gno,
|
|
sizeof(rpl_gno), &state);
|
|
if (thd_id == 0)
|
|
return node == NULL;
|
|
while (node)
|
|
{
|
|
if (node->owner == thd_id)
|
|
return true;
|
|
node= (Node*) my_hash_next(hash, (const uchar *)>id.gno,
|
|
sizeof(rpl_gno), &state);
|
|
}
|
|
return false;
|
|
}
|