1
by brian
clean slate |
1 |
/* Copyright (C) 2000-2003 MySQL AB
|
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 as published by
|
|
5 |
the Free Software Foundation; version 2 of the License.
|
|
6 |
||
7 |
This program is distributed in the hope that it will be useful,
|
|
8 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
9 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
10 |
GNU General Public License for more details.
|
|
11 |
||
12 |
You should have received a copy of the GNU General Public License
|
|
13 |
along with this program; if not, write to the Free Software
|
|
14 |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
15 |
||
243.1.17
by Jay Pipes
FINAL PHASE removal of mysql_priv.h (Bye, bye my friend.) |
16 |
#include <drizzled/server_includes.h> |
1
by brian
clean slate |
17 |
#include "rpl_mi.h" |
18 |
||
19 |
#ifdef HAVE_REPLICATION
|
|
20 |
||
21 |
#define DEFAULT_CONNECT_RETRY 60
|
|
22 |
||
23 |
// Defined in slave.cc
|
|
24 |
int init_intvar_from_file(int* var, IO_CACHE* f, int default_val); |
|
25 |
int init_strvar_from_file(char *var, int max_size, IO_CACHE *f, |
|
26 |
const char *default_val); |
|
27 |
int init_floatvar_from_file(float* var, IO_CACHE* f, float default_val); |
|
28 |
||
29 |
Master_info::Master_info() |
|
30 |
:Slave_reporting_capability("I/O"), |
|
301
by Brian Aker
Clean up port startup |
31 |
ssl(0), ssl_verify_server_cert(0), fd(-1), io_thd(0), port(DRIZZLE_PORT), |
1
by brian
clean slate |
32 |
connect_retry(DEFAULT_CONNECT_RETRY), heartbeat_period(0), |
33 |
received_heartbeats(0), inited(0), |
|
34 |
abort_slave(0), slave_running(0), slave_run_id(0) |
|
35 |
{
|
|
36 |
host[0] = 0; user[0] = 0; password[0] = 0; |
|
37 |
ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0; |
|
38 |
ssl_cipher[0]= 0; ssl_key[0]= 0; |
|
39 |
||
212.6.6
by Mats Kindahl
Removing redundant use of casts in drizzled/ for memcmp(), memcpy(), memset(), and memmove(). |
40 |
memset(&file, 0, sizeof(file)); |
1
by brian
clean slate |
41 |
pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST); |
42 |
pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST); |
|
43 |
pthread_cond_init(&data_cond, NULL); |
|
44 |
pthread_cond_init(&start_cond, NULL); |
|
45 |
pthread_cond_init(&stop_cond, NULL); |
|
46 |
}
|
|
47 |
||
48 |
Master_info::~Master_info() |
|
49 |
{
|
|
50 |
pthread_mutex_destroy(&run_lock); |
|
51 |
pthread_mutex_destroy(&data_lock); |
|
52 |
pthread_cond_destroy(&data_cond); |
|
53 |
pthread_cond_destroy(&start_cond); |
|
54 |
pthread_cond_destroy(&stop_cond); |
|
55 |
}
|
|
56 |
||
57 |
||
58 |
void init_master_log_pos(Master_info* mi) |
|
59 |
{
|
|
60 |
mi->master_log_name[0] = 0; |
|
61 |
mi->master_log_pos = BIN_LOG_HEADER_SIZE; // skip magic number |
|
62 |
/*
|
|
63 |
always request heartbeat unless master_heartbeat_period is set
|
|
64 |
explicitly zero. Here is the default value for heartbeat period
|
|
65 |
if CHANGE MASTER did not specify it. (no data loss in conversion
|
|
66 |
as hb period has a max)
|
|
67 |
*/
|
|
287.3.8
by Monty Taylor
Oy. Replaced max and min macros with std::max and std::min so that we get |
68 |
mi->heartbeat_period= (float) min((double)SLAVE_MAX_HEARTBEAT_PERIOD, |
1
by brian
clean slate |
69 |
(slave_net_timeout/2.0)); |
51.1.39
by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE |
70 |
assert(mi->heartbeat_period > (float) 0.001 |
1
by brian
clean slate |
71 |
|| mi->heartbeat_period == 0); |
51.1.39
by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE |
72 |
return; |
1
by brian
clean slate |
73 |
}
|
74 |
||
75 |
||
76 |
enum { |
|
77 |
LINES_IN_MASTER_INFO_WITH_SSL= 14, |
|
78 |
||
79 |
/* 5.1.16 added value of master_ssl_verify_server_cert */
|
|
80 |
LINE_FOR_MASTER_SSL_VERIFY_SERVER_CERT= 15, |
|
81 |
||
82 |
/* 6.0 added value of master_heartbeat_period */
|
|
83 |
LINE_FOR_MASTER_HEARTBEAT_PERIOD= 16, |
|
84 |
||
85 |
/* Number of lines currently used when saving master info file */
|
|
86 |
LINES_IN_MASTER_INFO= LINE_FOR_MASTER_HEARTBEAT_PERIOD |
|
87 |
};
|
|
88 |
||
89 |
||
90 |
int init_master_info(Master_info* mi, const char* master_info_fname, |
|
91 |
const char* slave_info_fname, |
|
92 |
bool abort_if_no_master_info_file, |
|
93 |
int thread_mask) |
|
94 |
{
|
|
95 |
int fd,error; |
|
96 |
char fname[FN_REFLEN+128]; |
|
97 |
||
98 |
if (mi->inited) |
|
99 |
{
|
|
100 |
/*
|
|
101 |
We have to reset read position of relay-log-bin as we may have
|
|
102 |
already been reading from 'hotlog' when the slave was stopped
|
|
103 |
last time. If this case pos_in_file would be set and we would
|
|
104 |
get a crash when trying to read the signature for the binary
|
|
105 |
relay log.
|
|
106 |
||
107 |
We only rewind the read position if we are starting the SQL
|
|
108 |
thread. The handle_slave_sql thread assumes that the read
|
|
109 |
position is at the beginning of the file, and will read the
|
|
110 |
"signature" and then fast-forward to the last position read.
|
|
111 |
*/
|
|
112 |
if (thread_mask & SLAVE_SQL) |
|
113 |
{
|
|
114 |
my_b_seek(mi->rli.cur_log, (my_off_t) 0); |
|
115 |
}
|
|
51.1.39
by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE |
116 |
return(0); |
1
by brian
clean slate |
117 |
}
|
118 |
||
206.3.1
by Patrick Galbraith
Most everything working with client rename |
119 |
mi->drizzle=0; |
1
by brian
clean slate |
120 |
mi->file_id=1; |
121 |
fn_format(fname, master_info_fname, mysql_data_home, "", 4+32); |
|
122 |
||
123 |
/*
|
|
124 |
We need a mutex while we are changing master info parameters to
|
|
125 |
keep other threads from reading bogus info
|
|
126 |
*/
|
|
127 |
||
128 |
pthread_mutex_lock(&mi->data_lock); |
|
129 |
fd = mi->fd; |
|
130 |
||
131 |
/* does master.info exist ? */
|
|
132 |
||
133 |
if (access(fname,F_OK)) |
|
134 |
{
|
|
135 |
if (abort_if_no_master_info_file) |
|
136 |
{
|
|
137 |
pthread_mutex_unlock(&mi->data_lock); |
|
51.1.39
by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE |
138 |
return(0); |
1
by brian
clean slate |
139 |
}
|
140 |
/*
|
|
141 |
if someone removed the file from underneath our feet, just close
|
|
142 |
the old descriptor and re-create the old file
|
|
143 |
*/
|
|
144 |
if (fd >= 0) |
|
145 |
my_close(fd, MYF(MY_WME)); |
|
146 |
if ((fd = my_open(fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0 ) |
|
147 |
{
|
|
261.3.4
by Monty Taylor
Added three more files worth of stuff. |
148 |
sql_print_error(_("Failed to create a new master info file (file '%s', errno %d)"), fname, my_errno); |
1
by brian
clean slate |
149 |
goto err; |
150 |
}
|
|
151 |
if (init_io_cache(&mi->file, fd, IO_SIZE*2, READ_CACHE, 0L,0, |
|
152 |
MYF(MY_WME))) |
|
153 |
{
|
|
261.3.4
by Monty Taylor
Added three more files worth of stuff. |
154 |
sql_print_error(_("Failed to create a cache on master info file (file '%s')"), fname); |
1
by brian
clean slate |
155 |
goto err; |
156 |
}
|
|
157 |
||
158 |
mi->fd = fd; |
|
159 |
init_master_log_pos(mi); |
|
160 |
||
161 |
}
|
|
162 |
else // file exists |
|
163 |
{
|
|
164 |
if (fd >= 0) |
|
165 |
reinit_io_cache(&mi->file, READ_CACHE, 0L,0,0); |
|
166 |
else
|
|
167 |
{
|
|
168 |
if ((fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0 ) |
|
169 |
{
|
|
261.3.4
by Monty Taylor
Added three more files worth of stuff. |
170 |
sql_print_error(_("Failed to open the existing master info file (file '%s', errno %d)"), fname, my_errno); |
1
by brian
clean slate |
171 |
goto err; |
172 |
}
|
|
173 |
if (init_io_cache(&mi->file, fd, IO_SIZE*2, READ_CACHE, 0L, |
|
174 |
0, MYF(MY_WME))) |
|
175 |
{
|
|
261.3.4
by Monty Taylor
Added three more files worth of stuff. |
176 |
sql_print_error(_("Failed to create a cache on master info file (file '%s')"), fname); |
1
by brian
clean slate |
177 |
goto err; |
178 |
}
|
|
179 |
}
|
|
180 |
||
181 |
mi->fd = fd; |
|
182 |
int port, connect_retry, master_log_pos, lines; |
|
183 |
int ssl= 0, ssl_verify_server_cert= 0; |
|
184 |
float master_heartbeat_period= 0.0; |
|
185 |
char *first_non_digit; |
|
186 |
||
187 |
/*
|
|
188 |
Starting from 4.1.x master.info has new format. Now its
|
|
189 |
first line contains number of lines in file. By reading this
|
|
190 |
number we will be always distinguish to which version our
|
|
191 |
master.info corresponds to. We can't simply count lines in
|
|
192 |
file since versions before 4.1.x could generate files with more
|
|
193 |
lines than needed.
|
|
194 |
If first line doesn't contain a number or contain number less than
|
|
195 |
LINES_IN_MASTER_INFO_WITH_SSL then such file is treated like file
|
|
196 |
from pre 4.1.1 version.
|
|
197 |
There is no ambiguity when reading an old master.info, as before
|
|
198 |
4.1.1, the first line contained the binlog's name, which is either
|
|
199 |
empty or has an extension (contains a '.'), so can't be confused
|
|
200 |
with an integer.
|
|
201 |
||
202 |
So we're just reading first line and trying to figure which version
|
|
203 |
is this.
|
|
204 |
*/
|
|
205 |
||
206 |
/*
|
|
207 |
The first row is temporarily stored in mi->master_log_name,
|
|
208 |
if it is line count and not binlog name (new format) it will be
|
|
209 |
overwritten by the second row later.
|
|
210 |
*/
|
|
211 |
if (init_strvar_from_file(mi->master_log_name, |
|
212 |
sizeof(mi->master_log_name), &mi->file, |
|
213 |
"")) |
|
214 |
goto errwithmsg; |
|
215 |
||
216 |
lines= strtoul(mi->master_log_name, &first_non_digit, 10); |
|
217 |
||
218 |
if (mi->master_log_name[0]!='\0' && |
|
219 |
*first_non_digit=='\0' && lines >= LINES_IN_MASTER_INFO_WITH_SSL) |
|
220 |
{
|
|
221 |
/* Seems to be new format => read master log name from next line */
|
|
222 |
if (init_strvar_from_file(mi->master_log_name, |
|
223 |
sizeof(mi->master_log_name), &mi->file, "")) |
|
224 |
goto errwithmsg; |
|
225 |
}
|
|
226 |
else
|
|
227 |
lines= 7; |
|
228 |
||
229 |
if (init_intvar_from_file(&master_log_pos, &mi->file, 4) || |
|
230 |
init_strvar_from_file(mi->host, sizeof(mi->host), &mi->file, 0) || |
|
231 |
init_strvar_from_file(mi->user, sizeof(mi->user), &mi->file, "test") || |
|
232 |
init_strvar_from_file(mi->password, SCRAMBLED_PASSWORD_CHAR_LENGTH+1, |
|
233 |
&mi->file, 0 ) || |
|
301
by Brian Aker
Clean up port startup |
234 |
init_intvar_from_file(&port, &mi->file, DRIZZLE_PORT) || |
1
by brian
clean slate |
235 |
init_intvar_from_file(&connect_retry, &mi->file, DEFAULT_CONNECT_RETRY)) |
236 |
goto errwithmsg; |
|
237 |
||
238 |
/*
|
|
239 |
If file has ssl part use it even if we have server without
|
|
240 |
SSL support. But these option will be ignored later when
|
|
241 |
slave will try connect to master, so in this case warning
|
|
242 |
is printed.
|
|
243 |
*/
|
|
244 |
if (lines >= LINES_IN_MASTER_INFO_WITH_SSL) |
|
245 |
{
|
|
246 |
if (init_intvar_from_file(&ssl, &mi->file, 0) || |
|
247 |
init_strvar_from_file(mi->ssl_ca, sizeof(mi->ssl_ca), |
|
248 |
&mi->file, 0) || |
|
249 |
init_strvar_from_file(mi->ssl_capath, sizeof(mi->ssl_capath), |
|
250 |
&mi->file, 0) || |
|
251 |
init_strvar_from_file(mi->ssl_cert, sizeof(mi->ssl_cert), |
|
252 |
&mi->file, 0) || |
|
253 |
init_strvar_from_file(mi->ssl_cipher, sizeof(mi->ssl_cipher), |
|
254 |
&mi->file, 0) || |
|
255 |
init_strvar_from_file(mi->ssl_key, sizeof(mi->ssl_key), |
|
256 |
&mi->file, 0)) |
|
257 |
goto errwithmsg; |
|
258 |
||
259 |
/*
|
|
260 |
Starting from 5.1.16 ssl_verify_server_cert might be
|
|
261 |
in the file
|
|
262 |
*/
|
|
263 |
if (lines >= LINE_FOR_MASTER_SSL_VERIFY_SERVER_CERT && |
|
264 |
init_intvar_from_file(&ssl_verify_server_cert, &mi->file, 0)) |
|
265 |
goto errwithmsg; |
|
266 |
/*
|
|
267 |
Starting from 6.0 master_heartbeat_period might be
|
|
268 |
in the file
|
|
269 |
*/
|
|
270 |
if (lines >= LINE_FOR_MASTER_HEARTBEAT_PERIOD && |
|
271 |
init_floatvar_from_file(&master_heartbeat_period, &mi->file, 0.0)) |
|
272 |
goto errwithmsg; |
|
273 |
}
|
|
274 |
||
275 |
if (ssl) |
|
261.3.4
by Monty Taylor
Added three more files worth of stuff. |
276 |
sql_print_warning(_("SSL information in the master info file " |
277 |
"('%s') are ignored because this MySQL slave was "
|
|
278 |
"compiled without SSL support."), fname); |
|
1
by brian
clean slate |
279 |
|
280 |
/*
|
|
281 |
This has to be handled here as init_intvar_from_file can't handle
|
|
282 |
my_off_t types
|
|
283 |
*/
|
|
284 |
mi->master_log_pos= (my_off_t) master_log_pos; |
|
285 |
mi->port= (uint) port; |
|
286 |
mi->connect_retry= (uint) connect_retry; |
|
149
by Brian Aker
More bool conversion. |
287 |
mi->ssl= (bool) ssl; |
1
by brian
clean slate |
288 |
mi->ssl_verify_server_cert= ssl_verify_server_cert; |
289 |
mi->heartbeat_period= master_heartbeat_period; |
|
290 |
}
|
|
291 |
||
292 |
mi->rli.mi = mi; |
|
293 |
if (init_relay_log_info(&mi->rli, slave_info_fname)) |
|
294 |
goto err; |
|
295 |
||
296 |
mi->inited = 1; |
|
297 |
// now change cache READ -> WRITE - must do this before flush_master_info
|
|
298 |
reinit_io_cache(&mi->file, WRITE_CACHE, 0L, 0, 1); |
|
299 |
if ((error=test(flush_master_info(mi, 1)))) |
|
261.3.4
by Monty Taylor
Added three more files worth of stuff. |
300 |
sql_print_error(_("Failed to flush master info file")); |
1
by brian
clean slate |
301 |
pthread_mutex_unlock(&mi->data_lock); |
51.1.39
by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE |
302 |
return(error); |
1
by brian
clean slate |
303 |
|
304 |
errwithmsg: |
|
261.3.4
by Monty Taylor
Added three more files worth of stuff. |
305 |
sql_print_error(_("Error reading master configuration")); |
1
by brian
clean slate |
306 |
|
307 |
err: |
|
308 |
if (fd >= 0) |
|
309 |
{
|
|
310 |
my_close(fd, MYF(0)); |
|
311 |
end_io_cache(&mi->file); |
|
312 |
}
|
|
313 |
mi->fd= -1; |
|
314 |
pthread_mutex_unlock(&mi->data_lock); |
|
51.1.39
by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE |
315 |
return(1); |
1
by brian
clean slate |
316 |
}
|
317 |
||
318 |
||
319 |
/*
|
|
320 |
RETURN
|
|
321 |
2 - flush relay log failed
|
|
322 |
1 - flush master info failed
|
|
323 |
0 - all ok
|
|
324 |
*/
|
|
325 |
int flush_master_info(Master_info* mi, bool flush_relay_log_cache) |
|
326 |
{
|
|
327 |
IO_CACHE* file = &mi->file; |
|
328 |
char lbuf[22]; |
|
329 |
||
330 |
/*
|
|
331 |
Flush the relay log to disk. If we don't do it, then the relay log while
|
|
332 |
have some part (its last kilobytes) in memory only, so if the slave server
|
|
333 |
dies now, with, say, from master's position 100 to 150 in memory only (not
|
|
334 |
on disk), and with position 150 in master.info, then when the slave
|
|
335 |
restarts, the I/O thread will fetch binlogs from 150, so in the relay log
|
|
336 |
we will have "[0, 100] U [150, infinity[" and nobody will notice it, so the
|
|
337 |
SQL thread will jump from 100 to 150, and replication will silently break.
|
|
338 |
||
339 |
When we come to this place in code, relay log may or not be initialized;
|
|
340 |
the caller is responsible for setting 'flush_relay_log_cache' accordingly.
|
|
341 |
*/
|
|
342 |
if (flush_relay_log_cache && |
|
343 |
flush_io_cache(mi->rli.relay_log.get_log_file())) |
|
51.1.39
by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE |
344 |
return(2); |
1
by brian
clean slate |
345 |
|
346 |
/*
|
|
347 |
We flushed the relay log BEFORE the master.info file, because if we crash
|
|
348 |
now, we will get a duplicate event in the relay log at restart. If we
|
|
349 |
flushed in the other order, we would get a hole in the relay log.
|
|
350 |
And duplicate is better than hole (with a duplicate, in later versions we
|
|
351 |
can add detection and scrap one event; with a hole there's nothing we can
|
|
352 |
do).
|
|
353 |
*/
|
|
354 |
||
355 |
/*
|
|
356 |
In certain cases this code may create master.info files that seems
|
|
357 |
corrupted, because of extra lines filled with garbage in the end
|
|
358 |
file (this happens if new contents take less space than previous
|
|
359 |
contents of file). But because of number of lines in the first line
|
|
360 |
of file we don't care about this garbage.
|
|
361 |
*/
|
|
362 |
char heartbeat_buf[sizeof(mi->heartbeat_period) * 4]; // buffer to suffice always |
|
171.1.1
by Patrick Galbraith
Dar, I forgot to commit this earlier. |
363 |
sprintf(heartbeat_buf, "%.3f", mi->heartbeat_period); |
1
by brian
clean slate |
364 |
my_b_seek(file, 0L); |
365 |
my_b_printf(file, |
|
366 |
"%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n%d\n%s\n", |
|
367 |
LINES_IN_MASTER_INFO, |
|
368 |
mi->master_log_name, llstr(mi->master_log_pos, lbuf), |
|
369 |
mi->host, mi->user, |
|
370 |
mi->password, mi->port, mi->connect_retry, |
|
371 |
(int)(mi->ssl), mi->ssl_ca, mi->ssl_capath, mi->ssl_cert, |
|
372 |
mi->ssl_cipher, mi->ssl_key, mi->ssl_verify_server_cert, |
|
373 |
heartbeat_buf); |
|
51.1.39
by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE |
374 |
return(-flush_io_cache(file)); |
1
by brian
clean slate |
375 |
}
|
376 |
||
377 |
||
378 |
void end_master_info(Master_info* mi) |
|
379 |
{
|
|
380 |
if (!mi->inited) |
|
51.1.39
by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE |
381 |
return; |
1
by brian
clean slate |
382 |
end_relay_log_info(&mi->rli); |
383 |
if (mi->fd >= 0) |
|
384 |
{
|
|
385 |
end_io_cache(&mi->file); |
|
386 |
(void)my_close(mi->fd, MYF(MY_WME)); |
|
387 |
mi->fd = -1; |
|
388 |
}
|
|
389 |
mi->inited = 0; |
|
390 |
||
51.1.39
by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE |
391 |
return; |
1
by brian
clean slate |
392 |
}
|
393 |
||
394 |
||
395 |
#endif /* HAVE_REPLICATION */ |