1 : /* Copyright (C) 2007 MySQL AB & Guilhem Bichot & Michael Widenius
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 :
16 : /*
17 : WL#3234 Maria control file
18 : First version written by Guilhem Bichot on 2006-04-27.
19 : */
20 :
21 : #ifndef EXTRACT_DEFINITIONS
22 : #include "maria_def.h"
23 : #include "ma_checkpoint.h"
24 : #endif
25 :
26 : /*
27 : A control file contains the following objects:
28 :
29 : Start of create time variables (at start of file):
30 : - Magic string (including version number of Maria control file)
31 : - Uuid
32 : - Size of create time part
33 : - Size of dynamic part
34 : - Maria block size
35 : ..... Here we can add new variables without changing format
36 : - Checksum of create time part (last of block)
37 :
38 : Start of changeable part:
39 : - Checksum of changeable part
40 : - LSN of last checkpoint
41 : - Number of last log file
42 : - Max trid in control file (since Maria 1.5 May 2008)
43 : - Number of consecutive recovery failures (since Maria 1.5 May 2008)
44 : ..... Here we can add new variables without changing format
45 :
46 : The idea is that one can add new variables to the control file and still
47 : use it with old program versions. If one needs to do an incompatible change
48 : one should increment the control file version number.
49 : */
50 :
51 : /* Total size should be < sector size for atomic write operation */
52 : #define CF_MAX_SIZE 512
53 : #define CF_MIN_SIZE (CF_BLOCKSIZE_OFFSET + CF_BLOCKSIZE_SIZE + \
54 : CF_CHECKSUM_SIZE * 2 + CF_LSN_SIZE + CF_FILENO_SIZE)
55 :
56 : /* Create time variables */
57 : #define CF_MAGIC_STRING "\xfe\xfe\xc"
58 : #define CF_MAGIC_STRING_OFFSET 0
59 : #define CF_MAGIC_STRING_SIZE (sizeof(CF_MAGIC_STRING)-1)
60 : #define CF_VERSION_OFFSET (CF_MAGIC_STRING_OFFSET + CF_MAGIC_STRING_SIZE)
61 : #define CF_VERSION_SIZE 1
62 : #define CF_UUID_OFFSET (CF_VERSION_OFFSET + CF_VERSION_SIZE)
63 : #define CF_UUID_SIZE MY_UUID_SIZE
64 : #define CF_CREATE_TIME_SIZE_OFFSET (CF_UUID_OFFSET + CF_UUID_SIZE)
65 : #define CF_SIZE_SIZE 2
66 : #define CF_CHANGEABLE_SIZE_OFFSET (CF_CREATE_TIME_SIZE_OFFSET + CF_SIZE_SIZE)
67 : #define CF_BLOCKSIZE_OFFSET (CF_CHANGEABLE_SIZE_OFFSET + CF_SIZE_SIZE)
68 : #define CF_BLOCKSIZE_SIZE 2
69 :
70 : #define CF_CREATE_TIME_TOTAL_SIZE (CF_BLOCKSIZE_OFFSET + CF_BLOCKSIZE_SIZE + \
71 : CF_CHECKSUM_SIZE)
72 :
73 : /*
74 : Start of the part that changes during execution
75 : This is stored at offset uint2korr(file[CF_CHANGEABLE_SIZE])
76 : */
77 : #define CF_CHECKSUM_OFFSET 0
78 : #define CF_CHECKSUM_SIZE 4
79 : #define CF_LSN_OFFSET (CF_CHECKSUM_OFFSET + CF_CHECKSUM_SIZE)
80 : #define CF_LSN_SIZE LSN_STORE_SIZE
81 : #define CF_FILENO_OFFSET (CF_LSN_OFFSET + CF_LSN_SIZE)
82 : #define CF_FILENO_SIZE 4
83 : #define CF_MAX_TRID_OFFSET (CF_FILENO_OFFSET + CF_FILENO_SIZE)
84 : #define CF_MAX_TRID_SIZE TRANSID_SIZE
85 : #define CF_RECOV_FAIL_OFFSET (CF_MAX_TRID_OFFSET + CF_MAX_TRID_SIZE)
86 : #define CF_RECOV_FAIL_SIZE 1
87 : #define CF_CHANGEABLE_TOTAL_SIZE (CF_RECOV_FAIL_OFFSET + CF_RECOV_FAIL_SIZE)
88 :
89 : /*
90 : The following values should not be changed, except when changing version
91 : number of the maria control file. These are the minimum sizes of the
92 : parts the code can handle.
93 : */
94 :
95 : #define CF_MIN_CREATE_TIME_TOTAL_SIZE \
96 : (CF_BLOCKSIZE_OFFSET + CF_BLOCKSIZE_SIZE + CF_CHECKSUM_SIZE)
97 : #define CF_MIN_CHANGEABLE_TOTAL_SIZE \
98 : (CF_FILENO_OFFSET + CF_FILENO_SIZE)
99 :
100 : #ifndef EXTRACT_DEFINITIONS
101 :
102 : /* This module owns these two vars. */
103 : /**
104 : This LSN serves for the two-checkpoint rule, and also to find the
105 : checkpoint record when doing a recovery.
106 : */
107 : LSN last_checkpoint_lsn= LSN_IMPOSSIBLE;
108 : uint32 last_logno= FILENO_IMPOSSIBLE;
109 : /**
110 : The maximum transaction id given to a transaction. It is only updated at
111 : clean shutdown (in case of crash, logs have better information).
112 : */
113 : TrID max_trid_in_control_file= 0;
114 :
115 : /**
116 : Number of consecutive log or recovery failures. Reset to 0 after recovery's
117 : success.
118 : */
119 : uint8 recovery_failures= 0;
120 :
121 : /**
122 : @brief If log's lock should be asserted when writing to control file.
123 :
124 : Can be re-used by any function which needs to be thread-safe except when
125 : it is called at startup.
126 : */
127 : my_bool maria_multi_threaded= FALSE;
128 : /** @brief if currently doing a recovery */
129 : my_bool maria_in_recovery= FALSE;
130 :
131 : /**
132 : Control file is less then 512 bytes (a disk sector),
133 : to be as atomic as possible
134 : */
135 : static int control_file_fd= -1;
136 :
137 : static uint cf_create_time_size;
138 : static uint cf_changeable_size;
139 :
140 : /**
141 : @brief Create Maria control file
142 : */
143 :
144 : static CONTROL_FILE_ERROR create_control_file(const char *name,
145 : int open_flags)
146 443 : {
147 : uint32 sum;
148 : uchar buffer[CF_CREATE_TIME_TOTAL_SIZE];
149 443 : DBUG_ENTER("maria_create_control_file");
150 :
151 443 : if ((control_file_fd= my_create(name, 0,
152 : open_flags,
153 : MYF(MY_SYNC_DIR | MY_WME))) < 0)
154 0 : DBUG_RETURN(CONTROL_FILE_UNKNOWN_ERROR);
155 :
156 : /* Reset variables, as we are creating the file */
157 443 : cf_create_time_size= CF_CREATE_TIME_TOTAL_SIZE;
158 443 : cf_changeable_size= CF_CHANGEABLE_TOTAL_SIZE;
159 :
160 : /* Create unique uuid for the control file */
161 443 : my_uuid_init((ulong) &buffer, (ulong) &maria_uuid);
162 443 : my_uuid(maria_uuid);
163 :
164 : /* Prepare and write the file header */
165 443 : memcpy(buffer, CF_MAGIC_STRING, CF_MAGIC_STRING_SIZE);
166 443 : buffer[CF_VERSION_OFFSET]= CONTROL_FILE_VERSION;
167 443 : memcpy(buffer + CF_UUID_OFFSET, maria_uuid, CF_UUID_SIZE);
168 443 : int2store(buffer + CF_CREATE_TIME_SIZE_OFFSET, cf_create_time_size);
169 443 : int2store(buffer + CF_CHANGEABLE_SIZE_OFFSET, cf_changeable_size);
170 :
171 : /* Write create time variables */
172 443 : int2store(buffer + CF_BLOCKSIZE_OFFSET, maria_block_size);
173 :
174 : /* Store checksum for create time parts */
175 443 : sum= (uint32) my_checksum(0, buffer, cf_create_time_size -
176 : CF_CHECKSUM_SIZE);
177 443 : int4store(buffer + cf_create_time_size - CF_CHECKSUM_SIZE, sum);
178 :
179 443 : if (my_pwrite(control_file_fd, buffer, cf_create_time_size,
180 : 0, MYF(MY_FNABP | MY_WME)))
181 0 : DBUG_RETURN(CONTROL_FILE_UNKNOWN_ERROR);
182 :
183 : /*
184 : To be safer we should make sure that there are no logs or data/index
185 : files around (indeed it could be that the control file alone was deleted
186 : or not restored, and we should not go on with life at this point).
187 :
188 : Things should still be relatively safe as if someone tries to use
189 : an old table with a new control file the different uuid:s between
190 : the files will cause ma_open() to generate an HA_ERR_OLD_FILE
191 : error. When used from mysqld this will cause the table to be open
192 : in repair mode which will remove all dependencies between the
193 : table and the old control file.
194 :
195 : We could have a tool which can rebuild the control file, by reading the
196 : directory of logs, finding the newest log, reading it to find last
197 : checkpoint... Slow but can save your db. For this to be possible, we
198 : must always write to the control file right after writing the checkpoint
199 : log record, and do nothing in between (i.e. the checkpoint must be
200 : usable as soon as it has been written to the log).
201 : */
202 :
203 : /* init the file with these "undefined" values */
204 443 : DBUG_RETURN(ma_control_file_write_and_force(LSN_IMPOSSIBLE,
205 : FILENO_IMPOSSIBLE, 0, 0));
206 : }
207 :
208 :
209 : /**
210 : Locks control file exclusively. This is kept for the duration of the engine
211 : process, to prevent another Maria instance to write to our logs or control
212 : file.
213 : */
214 :
215 : static int lock_control_file(const char *name)
216 2557 : {
217 2557 : uint retry= 0;
218 : /*
219 : On Windows, my_lock() uses locking() which is mandatory locking and so
220 : prevents maria-recovery.test from copying the control file. And in case of
221 : crash, it may take a while for Windows to unlock file, causing downtime.
222 : */
223 : /**
224 : @todo BUG We should explore my_sopen(_SH_DENYWRD) to open or create the
225 : file under Windows.
226 : */
227 : #ifndef __WIN__
228 : /*
229 : We can't here use the automatic wait in my_lock() as the alarm thread
230 : may not yet exists.
231 : */
232 5114 : while (my_lock(control_file_fd, F_WRLCK, 0L, F_TO_EOF,
233 : MYF(MY_SEEK_NOT_DONE | MY_FORCE_LOCK | MY_NO_WAIT)))
234 : {
235 0 : if (retry == 0)
236 0 : my_printf_error(HA_ERR_INITIALIZATION,
237 : "Can't lock maria control file '%s' for exclusive use, "
238 : "error: %d. Will retry for %d seconds", 0,
239 : name, my_errno, MARIA_MAX_CONTROL_FILE_LOCK_RETRY);
240 0 : if (retry++ > MARIA_MAX_CONTROL_FILE_LOCK_RETRY)
241 0 : return 1;
242 0 : sleep(1);
243 : }
244 : #endif
245 2557 : return 0;
246 : }
247 :
248 :
249 : /*
250 : @brief Initialize control file subsystem
251 :
252 : Looks for the control file. If none and creation is requested, creates file.
253 : If present, reads it to find out last checkpoint's LSN and last log, updates
254 : the last_checkpoint_lsn and last_logno global variables.
255 : Called at engine's start.
256 :
257 : @note
258 : The format of the control file is defined in the comments and defines
259 : at the start of this file.
260 :
261 : @param create_if_missing create file if not found
262 :
263 : @return Operation status
264 : @retval 0 OK
265 : @retval 1 Error (in which case the file is left closed)
266 : */
267 :
268 : CONTROL_FILE_ERROR ma_control_file_open(my_bool create_if_missing,
269 : my_bool print_error)
270 2558 : {
271 : uchar buffer[CF_MAX_SIZE];
272 : char name[FN_REFLEN], errmsg_buff[256];
273 : const char *errmsg, *lock_failed_errmsg= "Could not get an exclusive lock;"
274 2558 : " file is probably in use by another process";
275 : uint new_cf_create_time_size, new_cf_changeable_size, new_block_size;
276 : my_off_t file_size;
277 2558 : int open_flags= O_BINARY | /*O_DIRECT |*/ O_RDWR;
278 2558 : int error= CONTROL_FILE_UNKNOWN_ERROR;
279 2558 : DBUG_ENTER("ma_control_file_open");
280 :
281 : /*
282 : If you change sizes in the #defines, you at least have to change the
283 : "*store" and "*korr" calls in this file, and can even create backward
284 : compatibility problems. Beware!
285 : */
286 : DBUG_ASSERT(CF_LSN_SIZE == (3+4));
287 : DBUG_ASSERT(CF_FILENO_SIZE == 4);
288 :
289 2558 : if (control_file_fd >= 0) /* already open */
290 1 : DBUG_RETURN(0);
291 :
292 2557 : if (fn_format(name, CONTROL_FILE_BASE_NAME,
293 : maria_data_root, "", MYF(MY_WME)) == NullS)
294 0 : DBUG_RETURN(CONTROL_FILE_UNKNOWN_ERROR);
295 :
296 2557 : if (my_access(name,F_OK))
297 : {
298 : CONTROL_FILE_ERROR create_error;
299 443 : if (!create_if_missing)
300 : {
301 0 : error= CONTROL_FILE_MISSING;
302 0 : errmsg= "Can't find file";
303 0 : goto err;
304 : }
305 443 : if ((create_error= create_control_file(name, open_flags)))
306 : {
307 0 : error= create_error;
308 0 : errmsg= "Can't create file";
309 0 : goto err;
310 : }
311 443 : if (lock_control_file(name))
312 : {
313 0 : errmsg= lock_failed_errmsg;
314 0 : goto err;
315 : }
316 : goto ok;
317 : }
318 :
319 : /* Otherwise, file exists */
320 :
321 2114 : if ((control_file_fd= my_open(name, open_flags, MYF(MY_WME))) < 0)
322 : {
323 0 : errmsg= "Can't open file";
324 0 : goto err;
325 : }
326 :
327 2114 : if (lock_control_file(name)) /* lock it before reading content */
328 : {
329 0 : errmsg= lock_failed_errmsg;
330 0 : goto err;
331 : }
332 :
333 2114 : file_size= my_seek(control_file_fd, 0, SEEK_END, MYF(MY_WME));
334 2114 : if (file_size == MY_FILEPOS_ERROR)
335 : {
336 0 : errmsg= "Can't read size";
337 0 : goto err;
338 : }
339 2114 : if (file_size < CF_MIN_SIZE)
340 : {
341 : /*
342 : Given that normally we write only a sector and it's atomic, the only
343 : possibility for a file to be of too short size is if we crashed at the
344 : very first startup, between file creation and file write. Quite unlikely
345 : (and can be made even more unlikely by doing this: create a temp file,
346 : write it, and then rename it to be the control file).
347 : What's more likely is if someone forgot to restore the control file,
348 : just did a "touch control" to try to get Maria to start, or if the
349 : disk/filesystem has a problem.
350 : So let's be rigid.
351 : */
352 1 : error= CONTROL_FILE_TOO_SMALL;
353 1 : errmsg= "Size of control file is smaller than expected";
354 1 : goto err;
355 : }
356 :
357 : /* Check if control file is unexpectedly big */
358 2113 : if (file_size > CF_MAX_SIZE)
359 : {
360 1 : error= CONTROL_FILE_TOO_BIG;
361 1 : errmsg= "File size bigger than expected";
362 1 : goto err;
363 : }
364 :
365 2112 : if (my_pread(control_file_fd, buffer, (size_t)file_size, 0, MYF(MY_FNABP)))
366 : {
367 0 : errmsg= "Can't read file";
368 0 : goto err;
369 : }
370 :
371 2112 : if (memcmp(buffer + CF_MAGIC_STRING_OFFSET,
372 : CF_MAGIC_STRING, CF_MAGIC_STRING_SIZE))
373 : {
374 1 : error= CONTROL_FILE_BAD_MAGIC_STRING;
375 1 : errmsg= "Missing valid id at start of file. File is not a valid maria control file";
376 1 : goto err;
377 : }
378 :
379 2111 : if (buffer[CF_VERSION_OFFSET] > CONTROL_FILE_VERSION)
380 : {
381 0 : error= CONTROL_FILE_BAD_VERSION;
382 0 : sprintf(errmsg_buff, "File is from a future maria system: %d. Current version is: %d",
383 : (int) buffer[CF_VERSION_OFFSET], CONTROL_FILE_VERSION);
384 0 : errmsg= errmsg_buff;
385 0 : goto err;
386 : }
387 :
388 2111 : new_cf_create_time_size= uint2korr(buffer + CF_CREATE_TIME_SIZE_OFFSET);
389 2111 : new_cf_changeable_size= uint2korr(buffer + CF_CHANGEABLE_SIZE_OFFSET);
390 :
391 2111 : if (new_cf_create_time_size < CF_MIN_CREATE_TIME_TOTAL_SIZE ||
392 : new_cf_changeable_size < CF_MIN_CHANGEABLE_TOTAL_SIZE ||
393 : new_cf_create_time_size + new_cf_changeable_size != file_size)
394 : {
395 0 : error= CONTROL_FILE_INCONSISTENT_INFORMATION;
396 0 : errmsg= "Sizes stored in control file are inconsistent";
397 0 : goto err;
398 : }
399 :
400 2111 : new_block_size= uint2korr(buffer + CF_BLOCKSIZE_OFFSET);
401 2111 : if (new_block_size != maria_block_size)
402 : {
403 11 : error= CONTROL_FILE_WRONG_BLOCKSIZE;
404 11 : sprintf(errmsg_buff,
405 : "Block size in control file (%u) is different than given maria_block_size: %u",
406 : new_block_size, (uint) maria_block_size);
407 11 : errmsg= errmsg_buff;
408 11 : goto err;
409 : }
410 :
411 2100 : if (my_checksum(0, buffer, new_cf_create_time_size - CF_CHECKSUM_SIZE) !=
412 : uint4korr(buffer + new_cf_create_time_size - CF_CHECKSUM_SIZE))
413 : {
414 1 : error= CONTROL_FILE_BAD_HEAD_CHECKSUM;
415 1 : errmsg= "Fixed part checksum mismatch";
416 1 : goto err;
417 : }
418 :
419 2099 : if (my_checksum(0, buffer + new_cf_create_time_size + CF_CHECKSUM_SIZE,
420 : new_cf_changeable_size - CF_CHECKSUM_SIZE) !=
421 : uint4korr(buffer + new_cf_create_time_size))
422 : {
423 1 : error= CONTROL_FILE_BAD_CHECKSUM;
424 1 : errmsg= "Changeable part (end of control file) checksum mismatch";
425 1 : goto err;
426 : }
427 :
428 2098 : memcpy(maria_uuid, buffer + CF_UUID_OFFSET, CF_UUID_SIZE);
429 2098 : cf_create_time_size= new_cf_create_time_size;
430 2098 : cf_changeable_size= new_cf_changeable_size;
431 2098 : last_checkpoint_lsn= lsn_korr(buffer + new_cf_create_time_size +
432 : CF_LSN_OFFSET);
433 2098 : last_logno= uint4korr(buffer + new_cf_create_time_size + CF_FILENO_OFFSET);
434 2098 : if (new_cf_changeable_size >= (CF_MAX_TRID_OFFSET + CF_MAX_TRID_SIZE))
435 2098 : max_trid_in_control_file=
436 : transid_korr(buffer + new_cf_create_time_size + CF_MAX_TRID_OFFSET);
437 2098 : if (new_cf_changeable_size >= (CF_RECOV_FAIL_OFFSET + CF_RECOV_FAIL_SIZE))
438 2098 : recovery_failures=
439 : (buffer + new_cf_create_time_size + CF_RECOV_FAIL_OFFSET)[0];
440 :
441 2541 : ok:
442 2541 : DBUG_RETURN(0);
443 :
444 16 : err:
445 16 : if (print_error)
446 6 : my_printf_error(HA_ERR_INITIALIZATION,
447 : "Got error '%s' when trying to use maria control file "
448 : "'%s'", 0, errmsg, name);
449 16 : ma_control_file_end(); /* will unlock file if needed */
450 16 : DBUG_RETURN(error);
451 : }
452 :
453 :
454 : /*
455 : Write information durably to the control file; stores this information into
456 : the last_checkpoint_lsn, last_logno, max_trid_in_control_file,
457 : recovery_failures global variables.
458 : Called when we have created a new log (after syncing this log's creation),
459 : when we have written a checkpoint (after syncing this log record), at
460 : shutdown (for storing trid in case logs are soon removed by user), and
461 : before and after recovery (to store recovery_failures).
462 : Variables last_checkpoint_lsn and last_logno must be protected by caller
463 : using log's lock, unless this function is called at startup.
464 :
465 : SYNOPSIS
466 : ma_control_file_write_and_force()
467 : last_checkpoint_lsn_arg LSN of last checkpoint
468 : last_logno_arg last log file number
469 : max_trid_arg maximum transaction longid
470 : recovery_failures_arg consecutive recovery failures
471 :
472 : NOTE
473 : We always want to do one single my_pwrite() here to be as atomic as
474 : possible.
475 :
476 : RETURN
477 : 0 - OK
478 : 1 - Error
479 : */
480 :
481 : int ma_control_file_write_and_force(LSN last_checkpoint_lsn_arg,
482 : uint32 last_logno_arg,
483 : TrID max_trid_arg,
484 : uint8 recovery_failures_arg)
485 1297 : {
486 : uchar buffer[CF_MAX_SIZE];
487 : uint32 sum;
488 : my_bool no_need_sync;
489 1297 : DBUG_ENTER("ma_control_file_write_and_force");
490 :
491 : /*
492 : We don't need to sync if this is just an increase of
493 : recovery_failures: it's even good if that counter is not increased on disk
494 : in case of power or hardware failure (less false positives when removing
495 : logs).
496 : */
497 1297 : no_need_sync= ((last_checkpoint_lsn == last_checkpoint_lsn_arg) &&
498 : (last_logno == last_logno_arg) &&
499 : (max_trid_in_control_file == max_trid_arg) &&
500 : (recovery_failures_arg > 0));
501 :
502 1297 : if (control_file_fd < 0)
503 0 : DBUG_RETURN(1);
504 :
505 : #ifndef DBUG_OFF
506 1297 : if (maria_multi_threaded)
507 0 : translog_lock_handler_assert_owner();
508 : #endif
509 :
510 1297 : lsn_store(buffer + CF_LSN_OFFSET, last_checkpoint_lsn_arg);
511 1297 : int4store(buffer + CF_FILENO_OFFSET, last_logno_arg);
512 1297 : transid_store(buffer + CF_MAX_TRID_OFFSET, max_trid_arg);
513 1297 : (buffer + CF_RECOV_FAIL_OFFSET)[0]= recovery_failures_arg;
514 :
515 1297 : if (cf_changeable_size > CF_CHANGEABLE_TOTAL_SIZE)
516 : {
517 : /*
518 : More room than needed for us. Must be a newer version. Clear part which
519 : we cannot maintain, so that any future version notices we didn't
520 : maintain its extra data.
521 : */
522 0 : uint zeroed= cf_changeable_size - CF_CHANGEABLE_TOTAL_SIZE;
523 : char msg[150];
524 0 : bzero(buffer + CF_CHANGEABLE_TOTAL_SIZE, zeroed);
525 0 : my_snprintf(msg, sizeof(msg),
526 : "Control file must be from a newer version; zero-ing out %u"
527 : " unknown bytes in control file at offset %u", zeroed,
528 : cf_changeable_size + cf_create_time_size);
529 0 : ma_message_no_user(ME_JUST_WARNING, msg);
530 : }
531 : else
532 : {
533 : /* not enough room for what we need to store: enlarge */
534 1297 : cf_changeable_size= CF_CHANGEABLE_TOTAL_SIZE;
535 : }
536 : /* Note that the create-time portion is not touched */
537 :
538 : /* Checksum is stored first */
539 : compile_time_assert(CF_CHECKSUM_OFFSET == 0);
540 1297 : sum= my_checksum(0, buffer + CF_CHECKSUM_SIZE,
541 : cf_changeable_size - CF_CHECKSUM_SIZE);
542 1297 : int4store(buffer, sum);
543 :
544 1297 : if (my_pwrite(control_file_fd, buffer, cf_changeable_size,
545 : cf_create_time_size, MYF(MY_FNABP | MY_WME)) ||
546 : (!no_need_sync && my_sync(control_file_fd, MYF(MY_WME))))
547 0 : DBUG_RETURN(1);
548 :
549 1297 : last_checkpoint_lsn= last_checkpoint_lsn_arg;
550 1297 : last_logno= last_logno_arg;
551 1297 : max_trid_in_control_file= max_trid_arg;
552 1297 : recovery_failures= recovery_failures_arg;
553 :
554 1297 : cf_changeable_size= CF_CHANGEABLE_TOTAL_SIZE; /* no more warning */
555 1297 : DBUG_RETURN(0);
556 : }
557 :
558 :
559 : /*
560 : Free resources taken by control file subsystem
561 :
562 : SYNOPSIS
563 : ma_control_file_end()
564 : */
565 :
566 : int ma_control_file_end(void)
567 2499 : {
568 : int close_error;
569 2499 : DBUG_ENTER("ma_control_file_end");
570 :
571 2499 : if (control_file_fd < 0) /* already closed */
572 41 : DBUG_RETURN(0);
573 :
574 : #ifndef __WIN__
575 2458 : (void) my_lock(control_file_fd, F_UNLCK, 0L, F_TO_EOF,
576 : MYF(MY_SEEK_NOT_DONE | MY_FORCE_LOCK));
577 : #endif
578 :
579 2458 : close_error= my_close(control_file_fd, MYF(MY_WME));
580 : /*
581 : As my_close() frees structures even if close() fails, we do the same,
582 : i.e. we mark the file as closed in all cases.
583 : */
584 2458 : control_file_fd= -1;
585 : /*
586 : As this module owns these variables, closing the module forbids access to
587 : them (just a safety):
588 : */
589 2458 : last_checkpoint_lsn= LSN_IMPOSSIBLE;
590 2458 : last_logno= FILENO_IMPOSSIBLE;
591 2458 : max_trid_in_control_file= recovery_failures= 0;
592 :
593 2458 : DBUG_RETURN(close_error);
594 : }
595 :
596 :
597 : /**
598 : Tells if control file is initialized.
599 : */
600 :
601 : my_bool ma_control_file_inited(void)
602 785 : {
603 785 : return (control_file_fd >= 0);
604 : }
605 :
606 : #endif /* EXTRACT_DEFINITIONS */
|