1 /* Copyright (c) 2011, 2021, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 02110-1301 USA */
23
24 #include "rpl_gtid.h"
25
26 #include "mysqld_error.h" // ER_*
27
28
Owned_gtids(Checkable_rwlock * _sid_lock)29 Owned_gtids::Owned_gtids(Checkable_rwlock *_sid_lock)
30 : sid_lock(_sid_lock), sidno_to_hash(key_memory_Owned_gtids_sidno_to_hash)
31 {
32 /*
33 my_hash_init(>id_to_owner, &my_charset_bin, 20,
34 offsetof(Node, group), sizeof(Group), NULL,
35 my_free, 0);
36 */
37 }
38
39
~Owned_gtids()40 Owned_gtids::~Owned_gtids()
41 {
42 // destructor should only be called when no other thread may access object
43 //sid_lock->assert_no_lock();
44 // need to hold lock before calling get_max_sidno
45 sid_lock->rdlock();
46 rpl_sidno max_sidno= get_max_sidno();
47 for (int sidno= 1; sidno <= max_sidno; sidno++)
48 {
49 HASH *hash= get_hash(sidno);
50 my_hash_free(hash);
51 my_free(hash);
52 }
53 sid_lock->unlock();
54 //sid_lock->assert_no_lock();
55 }
56
57
ensure_sidno(rpl_sidno sidno)58 enum_return_status Owned_gtids::ensure_sidno(rpl_sidno sidno)
59 {
60 DBUG_ENTER("Owned_gtids::ensure_sidno");
61 sid_lock->assert_some_wrlock();
62 rpl_sidno max_sidno= get_max_sidno();
63 if (sidno > max_sidno || get_hash(sidno) == NULL)
64 {
65 for (int i= max_sidno; i < sidno; i++)
66 {
67 HASH *hash= (HASH *)my_malloc(key_memory_Owned_gtids_sidno_to_hash,
68 sizeof(HASH), MYF(MY_WME));
69 if (hash == NULL)
70 goto error;
71 my_hash_init(hash, &my_charset_bin, 20,
72 offsetof(Node, gno), sizeof(rpl_gno), NULL,
73 my_free, 0,
74 key_memory_Owned_gtids_sidno_to_hash);
75 sidno_to_hash.push_back(hash);
76 }
77 }
78 RETURN_OK;
79 error:
80 BINLOG_ERROR(("Out of memory."), (ER_OUT_OF_RESOURCES, MYF(0)));
81 RETURN_REPORTED_ERROR;
82 }
83
84
add_gtid_owner(const Gtid & gtid,my_thread_id owner)85 enum_return_status Owned_gtids::add_gtid_owner(const Gtid >id,
86 my_thread_id owner)
87 {
88 DBUG_ENTER("Owned_gtids::add_gtid_owner(Gtid, my_thread_id)");
89 assert(gtid.sidno <= get_max_sidno());
90 assert(gtid.gno > 0);
91 assert(gtid.gno < GNO_END);
92 Node *n= (Node *)my_malloc(key_memory_Sid_map_Node,
93 sizeof(Node), MYF(MY_WME));
94 if (n == NULL)
95 RETURN_REPORTED_ERROR;
96 n->gno= gtid.gno;
97 n->owner= owner;
98 /*
99 printf("Owned_gtids(%p)::add sidno=%d gno=%lld n=%p n->owner=%u\n",
100 this, sidno, gno, n, n?n->owner:0);
101 */
102 if (my_hash_insert(get_hash(gtid.sidno), (const uchar *)n) != 0)
103 {
104 my_free(n);
105 BINLOG_ERROR(("Out of memory."), (ER_OUT_OF_RESOURCES, MYF(0)));
106 RETURN_REPORTED_ERROR;
107 }
108 RETURN_OK;
109 }
110
111
remove_gtid(const Gtid & gtid,const my_thread_id owner)112 void Owned_gtids::remove_gtid(const Gtid >id, const my_thread_id owner)
113 {
114 DBUG_ENTER("Owned_gtids::remove_gtid(Gtid)");
115 //printf("Owned_gtids::remove(sidno=%d gno=%lld)\n", sidno, gno);
116 //assert(contains_gtid(sidno, gno)); // allow group not owned
117 HASH_SEARCH_STATE state;
118 HASH *hash= get_hash(gtid.sidno);
119 assert(hash != NULL);
120
121 for (Node *node= (Node *)my_hash_search(hash, (const uchar *)>id.gno, sizeof(rpl_gno));
122 node != NULL;
123 node= (Node*) my_hash_next(hash, (const uchar *)>id.gno, sizeof(rpl_gno), &state))
124 {
125 if (node->owner == owner)
126 {
127 #ifdef NDEBUG
128 my_hash_delete(hash, (uchar *)node);
129 #else
130 // my_hash_delete returns nonzero if the element does not exist
131 assert(my_hash_delete(hash, (uchar *)node) == 0);
132 #endif
133 break;
134 }
135 }
136 DBUG_VOID_RETURN;
137 }
138
139
is_intersection_nonempty(const Gtid_set * other) const140 bool Owned_gtids::is_intersection_nonempty(const Gtid_set *other) const
141 {
142 DBUG_ENTER("Owned_gtids::is_intersection_nonempty(Gtid_set *)");
143 if (sid_lock != NULL)
144 sid_lock->assert_some_wrlock();
145 Gtid_iterator git(this);
146 Gtid g= git.get();
147 while (g.sidno != 0)
148 {
149 if (other->contains_gtid(g.sidno, g.gno))
150 DBUG_RETURN(true);
151 git.next();
152 g= git.get();
153 }
154 DBUG_RETURN(false);
155 }
156
get_gtids(Gtid_set & gtid_set) const157 void Owned_gtids::get_gtids(Gtid_set >id_set) const
158 {
159 DBUG_ENTER("Owned_gtids::get_gtids");
160
161 if (sid_lock != NULL)
162 sid_lock->assert_some_wrlock();
163
164 Gtid_iterator git(this);
165 Gtid g= git.get();
166 while (g.sidno != 0)
167 {
168 gtid_set._add_gtid(g);
169 git.next();
170 g= git.get();
171 }
172 DBUG_VOID_RETURN;
173 }
174
contains_gtid(const Gtid & gtid) const175 bool Owned_gtids::contains_gtid(const Gtid >id) const
176 {
177 HASH *hash= get_hash(gtid.sidno);
178 assert(hash != NULL);
179 sid_lock->assert_some_lock();
180
181 return my_hash_search(hash, (const uchar *)>id.gno, sizeof(rpl_gno)) != NULL;
182 }
183
is_owned_by(const Gtid & gtid,const my_thread_id thd_id) const184 bool Owned_gtids::is_owned_by(const Gtid >id, const my_thread_id thd_id) const
185 {
186 HASH_SEARCH_STATE state;
187 HASH *hash= get_hash(gtid.sidno);
188 assert(hash != NULL);
189 Node *node= (Node*) my_hash_first(hash, (const uchar *)>id.gno,
190 sizeof(rpl_gno), &state);
191 if (thd_id == 0)
192 return node == NULL;
193 while (node)
194 {
195 if (node->owner == thd_id)
196 return true;
197 node= (Node*) my_hash_next(hash, (const uchar *)>id.gno,
198 sizeof(rpl_gno), &state);
199 }
200 return false;
201 }
202