1 /* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
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
29 PSI_memory_key key_memory_Sid_map_Node;
30
Sid_map(Checkable_rwlock * _sid_lock)31 Sid_map::Sid_map(Checkable_rwlock *_sid_lock)
32 : sid_lock(_sid_lock),
33 _sidno_to_sid(key_memory_Sid_map_Node), _sorted(key_memory_Sid_map_Node)
34 {
35 DBUG_ENTER("Sid_map::Sid_map");
36 my_hash_init(&_sid_to_sidno, &my_charset_bin, 20,
37 offsetof(Node, sid.bytes), binary_log::Uuid::BYTE_LENGTH, NULL,
38 my_free, 0,
39 key_memory_Sid_map_Node);
40 DBUG_VOID_RETURN;
41 }
42
43
~Sid_map()44 Sid_map::~Sid_map()
45 {
46 DBUG_ENTER("Sid_map::~Sid_map");
47 my_hash_free(&_sid_to_sidno);
48 DBUG_VOID_RETURN;
49 }
50
51
52 /*
53 This code is not being used but we will keep it as it may be
54 useful to optimize gtids by avoiding sharing mappings from
55 sid to sidno. For instance, the IO Thread and the SQL Thread
56 may have different mappings in the future.
57 */
58 #ifdef NON_DISABLED_GTID
clear()59 enum_return_status Sid_map::clear()
60 {
61 DBUG_ENTER("Sid_map::clear");
62 my_hash_free(&_sid_to_sidno);
63 my_hash_init(&_sid_to_sidno, &my_charset_bin, 20,
64 offsetof(Node, sid.bytes), binary_log::Uuid::BYTE_LENGTH, NULL,
65 my_free, 0);
66 _sidno_to_sid.clear();
67 _sorted.clear();
68 RETURN_OK;
69 }
70 #endif
71
add_sid(const rpl_sid & sid)72 rpl_sidno Sid_map::add_sid(const rpl_sid &sid)
73 {
74 DBUG_ENTER("Sid_map::add_sid(const rpl_sid *)");
75 #ifndef DBUG_OFF
76 char buf[binary_log::Uuid::TEXT_LENGTH + 1];
77 sid.to_string(buf);
78 DBUG_PRINT("info", ("SID=%s", buf));
79 #endif
80 if (sid_lock)
81 sid_lock->assert_some_lock();
82 Node *node= (Node *)my_hash_search(&_sid_to_sidno, sid.bytes,
83 binary_log::Uuid::BYTE_LENGTH);
84 if (node != NULL)
85 {
86 DBUG_PRINT("info", ("existed as sidno=%d", node->sidno));
87 DBUG_RETURN(node->sidno);
88 }
89
90 bool is_wrlock= false;
91 if (sid_lock)
92 {
93 is_wrlock= sid_lock->is_wrlock();
94 if (!is_wrlock)
95 {
96 sid_lock->unlock();
97 sid_lock->wrlock();
98 }
99 }
100 DBUG_PRINT("info", ("is_wrlock=%d sid_lock=%p", is_wrlock, sid_lock));
101 rpl_sidno sidno;
102 node= (Node *)my_hash_search(&_sid_to_sidno, sid.bytes,
103 binary_log::Uuid::BYTE_LENGTH);
104 if (node != NULL)
105 sidno= node->sidno;
106 else
107 {
108 sidno= get_max_sidno() + 1;
109 if (add_node(sidno, sid) != RETURN_STATUS_OK)
110 sidno= -1;
111 }
112
113 if (sid_lock)
114 {
115 if (!is_wrlock)
116 {
117 sid_lock->unlock();
118 sid_lock->rdlock();
119 }
120 }
121 DBUG_RETURN(sidno);
122 }
123
add_node(rpl_sidno sidno,const rpl_sid & sid)124 enum_return_status Sid_map::add_node(rpl_sidno sidno, const rpl_sid &sid)
125 {
126 DBUG_ENTER("Sid_map::add_node(rpl_sidno, const rpl_sid *)");
127 if (sid_lock)
128 sid_lock->assert_some_wrlock();
129 Node *node= (Node *)my_malloc(key_memory_Sid_map_Node,
130 sizeof(Node), MYF(MY_WME));
131 if (node == NULL)
132 RETURN_REPORTED_ERROR;
133
134 node->sidno= sidno;
135 node->sid= sid;
136 if (!_sidno_to_sid.push_back(node))
137 {
138 if (!_sorted.push_back(sidno))
139 {
140 if (my_hash_insert(&_sid_to_sidno, (uchar *)node) == 0)
141 {
142 #ifdef MYSQL_SERVER
143 /*
144 If this is the global_sid_map, we take the opportunity to
145 resize all arrays in gtid_state while holding the wrlock.
146 */
147 if (this != global_sid_map ||
148 gtid_state->ensure_sidno() == RETURN_STATUS_OK)
149 #endif
150 {
151 // We have added one element to the end of _sorted. Now we
152 // bubble it down to the sorted position.
153 int sorted_i= sidno - 1;
154 rpl_sidno *prev_sorted_p= &_sorted[sorted_i];
155 sorted_i--;
156 while (sorted_i >= 0)
157 {
158 rpl_sidno *sorted_p= &_sorted[sorted_i];
159 const rpl_sid &other_sid= sidno_to_sid(*sorted_p);
160 if (memcmp(sid.bytes, other_sid.bytes,
161 binary_log::Uuid::BYTE_LENGTH) >= 0)
162 break;
163 memcpy(prev_sorted_p, sorted_p, sizeof(rpl_sidno));
164 sorted_i--;
165 prev_sorted_p= sorted_p;
166 }
167 memcpy(prev_sorted_p, &sidno, sizeof(rpl_sidno));
168 RETURN_OK;
169 }
170 }
171 _sorted.pop_back();
172 }
173 _sidno_to_sid.pop_back();
174 }
175 my_free(node);
176
177 BINLOG_ERROR(("Out of memory."), (ER_OUT_OF_RESOURCES, MYF(0)));
178 RETURN_REPORTED_ERROR;
179 }
180
181
copy(Sid_map * dest)182 enum_return_status Sid_map::copy(Sid_map *dest)
183 {
184 DBUG_ENTER("Sid_map::copy(Sid_map)");
185 enum_return_status return_status= RETURN_STATUS_OK;
186
187 rpl_sidno max_sidno= get_max_sidno();
188 for (rpl_sidno sidno= 1;
189 sidno <= max_sidno && return_status == RETURN_STATUS_OK;
190 sidno++)
191 {
192 rpl_sid sid;
193 sid.copy_from(sidno_to_sid(sidno));
194 return_status= dest->add_node(sidno, sid);
195 }
196
197 DBUG_RETURN(return_status);
198 }
199