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