~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/innobase/log/log0log.c

  • Committer: Brian Aker
  • Date: 2009-05-11 17:50:22 UTC
  • Revision ID: brian@gaz-20090511175022-y35q9ky6uh9ldcjt
Replacing Sun employee copyright headers (aka... anything done by a Sun
employee is copyright by Sun).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/******************************************************
2
 
Database log
3
 
 
4
 
(c) 1995-1997 Innobase Oy
5
 
 
6
 
Created 12/9/1995 Heikki Tuuri
7
 
*******************************************************/
8
 
 
9
 
#include "log0log.h"
10
 
 
11
 
#ifdef UNIV_NONINL
12
 
#include "log0log.ic"
13
 
#endif
14
 
 
15
 
#include "mem0mem.h"
16
 
#include "buf0buf.h"
17
 
#include "buf0flu.h"
18
 
#include "srv0srv.h"
19
 
#include "log0recv.h"
20
 
#include "fil0fil.h"
21
 
#include "dict0boot.h"
22
 
#include "srv0srv.h"
23
 
#include "srv0start.h"
24
 
#include "trx0sys.h"
25
 
#include "trx0trx.h"
26
 
 
27
 
/*
28
 
General philosophy of InnoDB redo-logs:
29
 
 
30
 
1) Every change to a contents of a data page must be done
31
 
through mtr, which in mtr_commit() writes log records
32
 
to the InnoDB redo log.
33
 
 
34
 
2) Normally these changes are performed using a mlog_write_ulint()
35
 
or similar function.
36
 
 
37
 
3) In some page level operations only a code number of a
38
 
c-function and its parameters are written to the log to
39
 
reduce the size of the log.
40
 
 
41
 
  3a) You should not add parameters to these kind of functions
42
 
  (e.g. trx_undo_header_create(), trx_undo_insert_header_reuse())
43
 
 
44
 
  3b) You should not add such functionality which either change
45
 
  working when compared with the old or are dependent on data
46
 
  outside of the page. These kind of functions should implement
47
 
  self-contained page transformation and it should be unchanged
48
 
  if you don't have very essential reasons to change log
49
 
  semantics or format.
50
 
 
51
 
*/
52
 
 
53
 
/* Current free limit of space 0; protected by the log sys mutex; 0 means
54
 
uninitialized */
55
 
ulint   log_fsp_current_free_limit              = 0;
56
 
 
57
 
/* Global log system variable */
58
 
log_t*  log_sys = NULL;
59
 
 
60
 
#ifdef UNIV_DEBUG
61
 
ibool   log_do_write = TRUE;
62
 
 
63
 
ibool   log_debug_writes = FALSE;
64
 
#endif /* UNIV_DEBUG */
65
 
 
66
 
/* These control how often we print warnings if the last checkpoint is too
67
 
old */
68
 
ibool   log_has_printed_chkp_warning = FALSE;
69
 
time_t  log_last_warning_time;
70
 
 
71
 
#ifdef UNIV_LOG_ARCHIVE
72
 
/* Pointer to this variable is used as the i/o-message when we do i/o to an
73
 
archive */
74
 
byte    log_archive_io;
75
 
#endif /* UNIV_LOG_ARCHIVE */
76
 
 
77
 
/* A margin for free space in the log buffer before a log entry is catenated */
78
 
#define LOG_BUF_WRITE_MARGIN    (4 * OS_FILE_LOG_BLOCK_SIZE)
79
 
 
80
 
/* Margins for free space in the log buffer after a log entry is catenated */
81
 
#define LOG_BUF_FLUSH_RATIO     2
82
 
#define LOG_BUF_FLUSH_MARGIN    (LOG_BUF_WRITE_MARGIN + 4 * UNIV_PAGE_SIZE)
83
 
 
84
 
/* Margin for the free space in the smallest log group, before a new query
85
 
step which modifies the database, is started */
86
 
 
87
 
#define LOG_CHECKPOINT_FREE_PER_THREAD  (4 * UNIV_PAGE_SIZE)
88
 
#define LOG_CHECKPOINT_EXTRA_FREE       (8 * UNIV_PAGE_SIZE)
89
 
 
90
 
/* This parameter controls asynchronous making of a new checkpoint; the value
91
 
should be bigger than LOG_POOL_PREFLUSH_RATIO_SYNC */
92
 
 
93
 
#define LOG_POOL_CHECKPOINT_RATIO_ASYNC 32
94
 
 
95
 
/* This parameter controls synchronous preflushing of modified buffer pages */
96
 
#define LOG_POOL_PREFLUSH_RATIO_SYNC    16
97
 
 
98
 
/* The same ratio for asynchronous preflushing; this value should be less than
99
 
the previous */
100
 
#define LOG_POOL_PREFLUSH_RATIO_ASYNC   8
101
 
 
102
 
/* Extra margin, in addition to one log file, used in archiving */
103
 
#define LOG_ARCHIVE_EXTRA_MARGIN        (4 * UNIV_PAGE_SIZE)
104
 
 
105
 
/* This parameter controls asynchronous writing to the archive */
106
 
#define LOG_ARCHIVE_RATIO_ASYNC         16
107
 
 
108
 
/* Codes used in unlocking flush latches */
109
 
#define LOG_UNLOCK_NONE_FLUSHED_LOCK    1
110
 
#define LOG_UNLOCK_FLUSH_LOCK           2
111
 
 
112
 
/* States of an archiving operation */
113
 
#define LOG_ARCHIVE_READ        1
114
 
#define LOG_ARCHIVE_WRITE       2
115
 
 
116
 
/**********************************************************
117
 
Completes a checkpoint write i/o to a log file. */
118
 
static
119
 
void
120
 
log_io_complete_checkpoint(void);
121
 
/*============================*/
122
 
#ifdef UNIV_LOG_ARCHIVE
123
 
/**********************************************************
124
 
Completes an archiving i/o. */
125
 
static
126
 
void
127
 
log_io_complete_archive(void);
128
 
/*=========================*/
129
 
#endif /* UNIV_LOG_ARCHIVE */
130
 
 
131
 
/********************************************************************
132
 
Sets the global variable log_fsp_current_free_limit. Also makes a checkpoint,
133
 
so that we know that the limit has been written to a log checkpoint field
134
 
on disk. */
135
 
 
136
 
void
137
 
log_fsp_current_free_limit_set_and_checkpoint(
138
 
/*==========================================*/
139
 
        ulint   limit)  /* in: limit to set */
140
 
{
141
 
        ibool   success;
142
 
 
143
 
        mutex_enter(&(log_sys->mutex));
144
 
 
145
 
        log_fsp_current_free_limit = limit;
146
 
 
147
 
        mutex_exit(&(log_sys->mutex));
148
 
 
149
 
        /* Try to make a synchronous checkpoint */
150
 
 
151
 
        success = FALSE;
152
 
 
153
 
        while (!success) {
154
 
                success = log_checkpoint(TRUE, TRUE);
155
 
        }
156
 
}
157
 
 
158
 
/********************************************************************
159
 
Returns the oldest modified block lsn in the pool, or log_sys->lsn if none
160
 
exists. */
161
 
static
162
 
dulint
163
 
log_buf_pool_get_oldest_modification(void)
164
 
/*======================================*/
165
 
{
166
 
        dulint  lsn;
167
 
 
168
 
        ut_ad(mutex_own(&(log_sys->mutex)));
169
 
 
170
 
        lsn = buf_pool_get_oldest_modification();
171
 
 
172
 
        if (ut_dulint_is_zero(lsn)) {
173
 
 
174
 
                lsn = log_sys->lsn;
175
 
        }
176
 
 
177
 
        return(lsn);
178
 
}
179
 
 
180
 
/****************************************************************
181
 
Opens the log for log_write_low. The log must be closed with log_close and
182
 
released with log_release. */
183
 
 
184
 
dulint
185
 
log_reserve_and_open(
186
 
/*=================*/
187
 
                        /* out: start lsn of the log record */
188
 
        ulint   len)    /* in: length of data to be catenated */
189
 
{
190
 
        log_t*  log                     = log_sys;
191
 
        ulint   len_upper_limit;
192
 
#ifdef UNIV_LOG_ARCHIVE
193
 
        ulint   archived_lsn_age;
194
 
        ulint   dummy;
195
 
#endif /* UNIV_LOG_ARCHIVE */
196
 
#ifdef UNIV_DEBUG
197
 
        ulint   count                   = 0;
198
 
#endif /* UNIV_DEBUG */
199
 
 
200
 
        ut_a(len < log->buf_size / 2);
201
 
loop:
202
 
        mutex_enter(&(log->mutex));
203
 
 
204
 
        /* Calculate an upper limit for the space the string may take in the
205
 
        log buffer */
206
 
 
207
 
        len_upper_limit = LOG_BUF_WRITE_MARGIN + (5 * len) / 4;
208
 
 
209
 
        if (log->buf_free + len_upper_limit > log->buf_size) {
210
 
 
211
 
                mutex_exit(&(log->mutex));
212
 
 
213
 
                /* Not enough free space, do a syncronous flush of the log
214
 
                buffer */
215
 
 
216
 
                log_buffer_flush_to_disk();
217
 
 
218
 
                srv_log_waits++;
219
 
 
220
 
                ut_ad(++count < 50);
221
 
 
222
 
                goto loop;
223
 
        }
224
 
 
225
 
#ifdef UNIV_LOG_ARCHIVE
226
 
        if (log->archiving_state != LOG_ARCH_OFF) {
227
 
 
228
 
                archived_lsn_age = ut_dulint_minus(log->lsn,
229
 
                                                   log->archived_lsn);
230
 
                if (archived_lsn_age + len_upper_limit
231
 
                    > log->max_archived_lsn_age) {
232
 
                        /* Not enough free archived space in log groups: do a
233
 
                        synchronous archive write batch: */
234
 
 
235
 
                        mutex_exit(&(log->mutex));
236
 
 
237
 
                        ut_ad(len_upper_limit <= log->max_archived_lsn_age);
238
 
 
239
 
                        log_archive_do(TRUE, &dummy);
240
 
 
241
 
                        ut_ad(++count < 50);
242
 
 
243
 
                        goto loop;
244
 
                }
245
 
        }
246
 
#endif /* UNIV_LOG_ARCHIVE */
247
 
 
248
 
#ifdef UNIV_LOG_DEBUG
249
 
        log->old_buf_free = log->buf_free;
250
 
        log->old_lsn = log->lsn;
251
 
#endif
252
 
        return(log->lsn);
253
 
}
254
 
 
255
 
/****************************************************************
256
 
Writes to the log the string given. It is assumed that the caller holds the
257
 
log mutex. */
258
 
 
259
 
void
260
 
log_write_low(
261
 
/*==========*/
262
 
        byte*   str,            /* in: string */
263
 
        ulint   str_len)        /* in: string length */
264
 
{
265
 
        log_t*  log     = log_sys;
266
 
        ulint   len;
267
 
        ulint   data_len;
268
 
        byte*   log_block;
269
 
 
270
 
        ut_ad(mutex_own(&(log->mutex)));
271
 
part_loop:
272
 
        /* Calculate a part length */
273
 
 
274
 
        data_len = (log->buf_free % OS_FILE_LOG_BLOCK_SIZE) + str_len;
275
 
 
276
 
        if (data_len <= OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE) {
277
 
 
278
 
                /* The string fits within the current log block */
279
 
 
280
 
                len = str_len;
281
 
        } else {
282
 
                data_len = OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE;
283
 
 
284
 
                len = OS_FILE_LOG_BLOCK_SIZE
285
 
                        - (log->buf_free % OS_FILE_LOG_BLOCK_SIZE)
286
 
                        - LOG_BLOCK_TRL_SIZE;
287
 
        }
288
 
 
289
 
        ut_memcpy(log->buf + log->buf_free, str, len);
290
 
 
291
 
        str_len -= len;
292
 
        str = str + len;
293
 
 
294
 
        log_block = ut_align_down(log->buf + log->buf_free,
295
 
                                  OS_FILE_LOG_BLOCK_SIZE);
296
 
        log_block_set_data_len(log_block, data_len);
297
 
 
298
 
        if (data_len == OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE) {
299
 
                /* This block became full */
300
 
                log_block_set_data_len(log_block, OS_FILE_LOG_BLOCK_SIZE);
301
 
                log_block_set_checkpoint_no(log_block,
302
 
                                            log_sys->next_checkpoint_no);
303
 
                len += LOG_BLOCK_HDR_SIZE + LOG_BLOCK_TRL_SIZE;
304
 
 
305
 
                log->lsn = ut_dulint_add(log->lsn, len);
306
 
 
307
 
                /* Initialize the next block header */
308
 
                log_block_init(log_block + OS_FILE_LOG_BLOCK_SIZE, log->lsn);
309
 
        } else {
310
 
                log->lsn = ut_dulint_add(log->lsn, len);
311
 
        }
312
 
 
313
 
        log->buf_free += len;
314
 
 
315
 
        ut_ad(log->buf_free <= log->buf_size);
316
 
 
317
 
        if (str_len > 0) {
318
 
                goto part_loop;
319
 
        }
320
 
 
321
 
        srv_log_write_requests++;
322
 
}
323
 
 
324
 
/****************************************************************
325
 
Closes the log. */
326
 
 
327
 
dulint
328
 
log_close(void)
329
 
/*===========*/
330
 
                        /* out: lsn */
331
 
{
332
 
        byte*   log_block;
333
 
        ulint   first_rec_group;
334
 
        dulint  oldest_lsn;
335
 
        dulint  lsn;
336
 
        log_t*  log     = log_sys;
337
 
        ulint   checkpoint_age;
338
 
 
339
 
        ut_ad(mutex_own(&(log->mutex)));
340
 
 
341
 
        lsn = log->lsn;
342
 
 
343
 
        log_block = ut_align_down(log->buf + log->buf_free,
344
 
                                  OS_FILE_LOG_BLOCK_SIZE);
345
 
        first_rec_group = log_block_get_first_rec_group(log_block);
346
 
 
347
 
        if (first_rec_group == 0) {
348
 
                /* We initialized a new log block which was not written
349
 
                full by the current mtr: the next mtr log record group
350
 
                will start within this block at the offset data_len */
351
 
 
352
 
                log_block_set_first_rec_group(
353
 
                        log_block, log_block_get_data_len(log_block));
354
 
        }
355
 
 
356
 
        if (log->buf_free > log->max_buf_free) {
357
 
 
358
 
                log->check_flush_or_checkpoint = TRUE;
359
 
        }
360
 
 
361
 
        checkpoint_age = ut_dulint_minus(lsn, log->last_checkpoint_lsn);
362
 
 
363
 
        if (checkpoint_age >= log->log_group_capacity) {
364
 
                /* TODO: split btr_store_big_rec_extern_fields() into small
365
 
                steps so that we can release all latches in the middle, and
366
 
                call log_free_check() to ensure we never write over log written
367
 
                after the latest checkpoint. In principle, we should split all
368
 
                big_rec operations, but other operations are smaller. */
369
 
 
370
 
                if (!log_has_printed_chkp_warning
371
 
                    || difftime(time(NULL), log_last_warning_time) > 15) {
372
 
 
373
 
                        log_has_printed_chkp_warning = TRUE;
374
 
                        log_last_warning_time = time(NULL);
375
 
 
376
 
                        ut_print_timestamp(stderr);
377
 
                        fprintf(stderr,
378
 
                                "  InnoDB: ERROR: the age of the last"
379
 
                                " checkpoint is %lu,\n"
380
 
                                "InnoDB: which exceeds the log group"
381
 
                                " capacity %lu.\n"
382
 
                                "InnoDB: If you are using big"
383
 
                                " BLOB or TEXT rows, you must set the\n"
384
 
                                "InnoDB: combined size of log files"
385
 
                                " at least 10 times bigger than the\n"
386
 
                                "InnoDB: largest such row.\n",
387
 
                                (ulong) checkpoint_age,
388
 
                                (ulong) log->log_group_capacity);
389
 
                }
390
 
        }
391
 
 
392
 
        if (checkpoint_age <= log->max_modified_age_async) {
393
 
 
394
 
                goto function_exit;
395
 
        }
396
 
 
397
 
        oldest_lsn = buf_pool_get_oldest_modification();
398
 
 
399
 
        if (ut_dulint_is_zero(oldest_lsn)
400
 
            || (ut_dulint_minus(lsn, oldest_lsn)
401
 
                > log->max_modified_age_async)
402
 
            || checkpoint_age > log->max_checkpoint_age_async) {
403
 
 
404
 
                log->check_flush_or_checkpoint = TRUE;
405
 
        }
406
 
function_exit:
407
 
 
408
 
#ifdef UNIV_LOG_DEBUG
409
 
        log_check_log_recs(log->buf + log->old_buf_free,
410
 
                           log->buf_free - log->old_buf_free, log->old_lsn);
411
 
#endif
412
 
 
413
 
        return(lsn);
414
 
}
415
 
 
416
 
#ifdef UNIV_LOG_ARCHIVE
417
 
/**********************************************************
418
 
Pads the current log block full with dummy log records. Used in producing
419
 
consistent archived log files. */
420
 
static
421
 
void
422
 
log_pad_current_log_block(void)
423
 
/*===========================*/
424
 
{
425
 
        byte    b               = MLOG_DUMMY_RECORD;
426
 
        ulint   pad_length;
427
 
        ulint   i;
428
 
        dulint  lsn;
429
 
 
430
 
        /* We retrieve lsn only because otherwise gcc crashed on HP-UX */
431
 
        lsn = log_reserve_and_open(OS_FILE_LOG_BLOCK_SIZE);
432
 
 
433
 
        pad_length = OS_FILE_LOG_BLOCK_SIZE
434
 
                - (log_sys->buf_free % OS_FILE_LOG_BLOCK_SIZE)
435
 
                - LOG_BLOCK_TRL_SIZE;
436
 
 
437
 
        for (i = 0; i < pad_length; i++) {
438
 
                log_write_low(&b, 1);
439
 
        }
440
 
 
441
 
        lsn = log_sys->lsn;
442
 
 
443
 
        log_close();
444
 
        log_release();
445
 
 
446
 
        ut_a((ut_dulint_get_low(lsn) % OS_FILE_LOG_BLOCK_SIZE)
447
 
             == LOG_BLOCK_HDR_SIZE);
448
 
}
449
 
#endif /* UNIV_LOG_ARCHIVE */
450
 
 
451
 
/**********************************************************
452
 
Calculates the data capacity of a log group, when the log file headers are not
453
 
included. */
454
 
 
455
 
ulint
456
 
log_group_get_capacity(
457
 
/*===================*/
458
 
                                /* out: capacity in bytes */
459
 
        log_group_t*    group)  /* in: log group */
460
 
{
461
 
        ut_ad(mutex_own(&(log_sys->mutex)));
462
 
 
463
 
        return((group->file_size - LOG_FILE_HDR_SIZE) * group->n_files);
464
 
}
465
 
 
466
 
/**********************************************************
467
 
Calculates the offset within a log group, when the log file headers are not
468
 
included. */
469
 
UNIV_INLINE
470
 
ulint
471
 
log_group_calc_size_offset(
472
 
/*=======================*/
473
 
                                /* out: size offset (<= offset) */
474
 
        ulint           offset, /* in: real offset within the log group */
475
 
        log_group_t*    group)  /* in: log group */
476
 
{
477
 
        ut_ad(mutex_own(&(log_sys->mutex)));
478
 
 
479
 
        return(offset - LOG_FILE_HDR_SIZE * (1 + offset / group->file_size));
480
 
}
481
 
 
482
 
/**********************************************************
483
 
Calculates the offset within a log group, when the log file headers are
484
 
included. */
485
 
UNIV_INLINE
486
 
ulint
487
 
log_group_calc_real_offset(
488
 
/*=======================*/
489
 
                                /* out: real offset (>= offset) */
490
 
        ulint           offset, /* in: size offset within the log group */
491
 
        log_group_t*    group)  /* in: log group */
492
 
{
493
 
        ut_ad(mutex_own(&(log_sys->mutex)));
494
 
 
495
 
        return(offset + LOG_FILE_HDR_SIZE
496
 
               * (1 + offset / (group->file_size - LOG_FILE_HDR_SIZE)));
497
 
}
498
 
 
499
 
/**********************************************************
500
 
Calculates the offset of an lsn within a log group. */
501
 
static
502
 
ulint
503
 
log_group_calc_lsn_offset(
504
 
/*======================*/
505
 
                                /* out: offset within the log group */
506
 
        dulint          lsn,    /* in: lsn, must be within 4 GB of
507
 
                                group->lsn */
508
 
        log_group_t*    group)  /* in: log group */
509
 
{
510
 
        dulint          gr_lsn;
511
 
        ib_longlong     gr_lsn_size_offset;
512
 
        ib_longlong     difference;
513
 
        ib_longlong     group_size;
514
 
        ib_longlong     offset;
515
 
 
516
 
        ut_ad(mutex_own(&(log_sys->mutex)));
517
 
 
518
 
        /* If total log file size is > 2 GB we can easily get overflows
519
 
        with 32-bit integers. Use 64-bit integers instead. */
520
 
 
521
 
        gr_lsn = group->lsn;
522
 
 
523
 
        gr_lsn_size_offset = (ib_longlong)
524
 
                log_group_calc_size_offset(group->lsn_offset, group);
525
 
 
526
 
        group_size = (ib_longlong) log_group_get_capacity(group);
527
 
 
528
 
        if (ut_dulint_cmp(lsn, gr_lsn) >= 0) {
529
 
 
530
 
                difference = (ib_longlong) ut_dulint_minus(lsn, gr_lsn);
531
 
        } else {
532
 
                difference = (ib_longlong) ut_dulint_minus(gr_lsn, lsn);
533
 
 
534
 
                difference = difference % group_size;
535
 
 
536
 
                difference = group_size - difference;
537
 
        }
538
 
 
539
 
        offset = (gr_lsn_size_offset + difference) % group_size;
540
 
 
541
 
        ut_a(offset < (((ib_longlong) 1) << 32)); /* offset must be < 4 GB */
542
 
 
543
 
        /* fprintf(stderr,
544
 
        "Offset is %lu gr_lsn_offset is %lu difference is %lu\n",
545
 
        (ulint)offset,(ulint)gr_lsn_size_offset, (ulint)difference);
546
 
        */
547
 
 
548
 
        return(log_group_calc_real_offset((ulint)offset, group));
549
 
}
550
 
 
551
 
/***********************************************************************
552
 
Calculates where in log files we find a specified lsn. */
553
 
 
554
 
ulint
555
 
log_calc_where_lsn_is(
556
 
/*==================*/
557
 
                                                /* out: log file number */
558
 
        ib_longlong*    log_file_offset,        /* out: offset in that file
559
 
                                                (including the header) */
560
 
        dulint          first_header_lsn,       /* in: first log file start
561
 
                                                lsn */
562
 
        dulint          lsn,                    /* in: lsn whose position to
563
 
                                                determine */
564
 
        ulint           n_log_files,            /* in: total number of log
565
 
                                                files */
566
 
        ib_longlong     log_file_size)          /* in: log file size
567
 
                                                (including the header) */
568
 
{
569
 
        ib_longlong     ib_lsn;
570
 
        ib_longlong     ib_first_header_lsn;
571
 
        ib_longlong     capacity        = log_file_size - LOG_FILE_HDR_SIZE;
572
 
        ulint           file_no;
573
 
        ib_longlong     add_this_many;
574
 
 
575
 
        ib_lsn = ut_conv_dulint_to_longlong(lsn);
576
 
        ib_first_header_lsn = ut_conv_dulint_to_longlong(first_header_lsn);
577
 
 
578
 
        if (ib_lsn < ib_first_header_lsn) {
579
 
                add_this_many = 1 + (ib_first_header_lsn - ib_lsn)
580
 
                        / (capacity * (ib_longlong)n_log_files);
581
 
                ib_lsn += add_this_many
582
 
                        * capacity * (ib_longlong)n_log_files;
583
 
        }
584
 
 
585
 
        ut_a(ib_lsn >= ib_first_header_lsn);
586
 
 
587
 
        file_no = ((ulint)((ib_lsn - ib_first_header_lsn) / capacity))
588
 
                % n_log_files;
589
 
        *log_file_offset = (ib_lsn - ib_first_header_lsn) % capacity;
590
 
 
591
 
        *log_file_offset = *log_file_offset + LOG_FILE_HDR_SIZE;
592
 
 
593
 
        return(file_no);
594
 
}
595
 
 
596
 
/************************************************************
597
 
Sets the field values in group to correspond to a given lsn. For this function
598
 
to work, the values must already be correctly initialized to correspond to
599
 
some lsn, for instance, a checkpoint lsn. */
600
 
 
601
 
void
602
 
log_group_set_fields(
603
 
/*=================*/
604
 
        log_group_t*    group,  /* in: group */
605
 
        dulint          lsn)    /* in: lsn for which the values should be
606
 
                                set */
607
 
{
608
 
        group->lsn_offset = log_group_calc_lsn_offset(lsn, group);
609
 
        group->lsn = lsn;
610
 
}
611
 
 
612
 
/*********************************************************************
613
 
Calculates the recommended highest values for lsn - last_checkpoint_lsn,
614
 
lsn - buf_get_oldest_modification(), and lsn - max_archive_lsn_age. */
615
 
static
616
 
ibool
617
 
log_calc_max_ages(void)
618
 
/*===================*/
619
 
                        /* out: error value FALSE if the smallest log group is
620
 
                        too small to accommodate the number of OS threads in
621
 
                        the database server */
622
 
{
623
 
        log_group_t*    group;
624
 
        ulint           margin;
625
 
        ulint           free;
626
 
        ibool           success         = TRUE;
627
 
        ulint           smallest_capacity;
628
 
        ulint           archive_margin;
629
 
        ulint           smallest_archive_margin;
630
 
 
631
 
        ut_ad(!mutex_own(&(log_sys->mutex)));
632
 
 
633
 
        mutex_enter(&(log_sys->mutex));
634
 
 
635
 
        group = UT_LIST_GET_FIRST(log_sys->log_groups);
636
 
 
637
 
        ut_ad(group);
638
 
 
639
 
        smallest_capacity = ULINT_MAX;
640
 
        smallest_archive_margin = ULINT_MAX;
641
 
 
642
 
        while (group) {
643
 
                if (log_group_get_capacity(group) < smallest_capacity) {
644
 
 
645
 
                        smallest_capacity = log_group_get_capacity(group);
646
 
                }
647
 
 
648
 
                archive_margin = log_group_get_capacity(group)
649
 
                        - (group->file_size - LOG_FILE_HDR_SIZE)
650
 
                        - LOG_ARCHIVE_EXTRA_MARGIN;
651
 
 
652
 
                if (archive_margin < smallest_archive_margin) {
653
 
 
654
 
                        smallest_archive_margin = archive_margin;
655
 
                }
656
 
 
657
 
                group = UT_LIST_GET_NEXT(log_groups, group);
658
 
        }
659
 
 
660
 
        /* Add extra safety */
661
 
        smallest_capacity = smallest_capacity - smallest_capacity / 10;
662
 
 
663
 
        /* For each OS thread we must reserve so much free space in the
664
 
        smallest log group that it can accommodate the log entries produced
665
 
        by single query steps: running out of free log space is a serious
666
 
        system error which requires rebooting the database. */
667
 
 
668
 
        free = LOG_CHECKPOINT_FREE_PER_THREAD * (10 + srv_thread_concurrency)
669
 
                + LOG_CHECKPOINT_EXTRA_FREE;
670
 
        if (free >= smallest_capacity / 2) {
671
 
                success = FALSE;
672
 
 
673
 
                goto failure;
674
 
        } else {
675
 
                margin = smallest_capacity - free;
676
 
        }
677
 
 
678
 
        margin = ut_min(margin, log_sys->adm_checkpoint_interval);
679
 
 
680
 
        margin = margin - margin / 10;  /* Add still some extra safety */
681
 
 
682
 
        log_sys->log_group_capacity = smallest_capacity;
683
 
 
684
 
        log_sys->max_modified_age_async = margin
685
 
                - margin / LOG_POOL_PREFLUSH_RATIO_ASYNC;
686
 
        log_sys->max_modified_age_sync = margin
687
 
                - margin / LOG_POOL_PREFLUSH_RATIO_SYNC;
688
 
 
689
 
        log_sys->max_checkpoint_age_async = margin - margin
690
 
                / LOG_POOL_CHECKPOINT_RATIO_ASYNC;
691
 
        log_sys->max_checkpoint_age = margin;
692
 
 
693
 
#ifdef UNIV_LOG_ARCHIVE
694
 
        log_sys->max_archived_lsn_age = smallest_archive_margin;
695
 
 
696
 
        log_sys->max_archived_lsn_age_async = smallest_archive_margin
697
 
                - smallest_archive_margin / LOG_ARCHIVE_RATIO_ASYNC;
698
 
#endif /* UNIV_LOG_ARCHIVE */
699
 
failure:
700
 
        mutex_exit(&(log_sys->mutex));
701
 
 
702
 
        if (!success) {
703
 
                fprintf(stderr,
704
 
                        "InnoDB: Error: ib_logfiles are too small"
705
 
                        " for innodb_thread_concurrency %lu.\n"
706
 
                        "InnoDB: The combined size of ib_logfiles"
707
 
                        " should be bigger than\n"
708
 
                        "InnoDB: 200 kB * innodb_thread_concurrency.\n"
709
 
                        "InnoDB: To get mysqld to start up, set"
710
 
                        " innodb_thread_concurrency in my.cnf\n"
711
 
                        "InnoDB: to a lower value, for example, to 8."
712
 
                        " After an ERROR-FREE shutdown\n"
713
 
                        "InnoDB: of mysqld you can adjust the size of"
714
 
                        " ib_logfiles, as explained in\n"
715
 
                        "InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
716
 
                        "adding-and-removing.html\n"
717
 
                        "InnoDB: Cannot continue operation."
718
 
                        " Calling exit(1).\n",
719
 
                        (ulong)srv_thread_concurrency);
720
 
 
721
 
                exit(1);
722
 
        }
723
 
 
724
 
        return(success);
725
 
}
726
 
 
727
 
/**********************************************************
728
 
Initializes the log. */
729
 
 
730
 
void
731
 
log_init(void)
732
 
/*==========*/
733
 
{
734
 
        byte*   buf;
735
 
 
736
 
        log_sys = mem_alloc(sizeof(log_t));
737
 
 
738
 
        mutex_create(&log_sys->mutex, SYNC_LOG);
739
 
 
740
 
        mutex_enter(&(log_sys->mutex));
741
 
 
742
 
        /* Start the lsn from one log block from zero: this way every
743
 
        log record has a start lsn != zero, a fact which we will use */
744
 
 
745
 
        log_sys->lsn = LOG_START_LSN;
746
 
 
747
 
        ut_a(LOG_BUFFER_SIZE >= 16 * OS_FILE_LOG_BLOCK_SIZE);
748
 
        ut_a(LOG_BUFFER_SIZE >= 4 * UNIV_PAGE_SIZE);
749
 
 
750
 
        buf = ut_malloc(LOG_BUFFER_SIZE + OS_FILE_LOG_BLOCK_SIZE);
751
 
        log_sys->buf = ut_align(buf, OS_FILE_LOG_BLOCK_SIZE);
752
 
 
753
 
        log_sys->buf_size = LOG_BUFFER_SIZE;
754
 
 
755
 
        memset(log_sys->buf, '\0', LOG_BUFFER_SIZE);
756
 
 
757
 
        log_sys->max_buf_free = log_sys->buf_size / LOG_BUF_FLUSH_RATIO
758
 
                - LOG_BUF_FLUSH_MARGIN;
759
 
        log_sys->check_flush_or_checkpoint = TRUE;
760
 
        UT_LIST_INIT(log_sys->log_groups);
761
 
 
762
 
        log_sys->n_log_ios = 0;
763
 
 
764
 
        log_sys->n_log_ios_old = log_sys->n_log_ios;
765
 
        log_sys->last_printout_time = time(NULL);
766
 
        /*----------------------------*/
767
 
 
768
 
        log_sys->buf_next_to_write = 0;
769
 
 
770
 
        log_sys->write_lsn = ut_dulint_zero;
771
 
        log_sys->current_flush_lsn = ut_dulint_zero;
772
 
        log_sys->flushed_to_disk_lsn = ut_dulint_zero;
773
 
 
774
 
        log_sys->written_to_some_lsn = log_sys->lsn;
775
 
        log_sys->written_to_all_lsn = log_sys->lsn;
776
 
 
777
 
        log_sys->n_pending_writes = 0;
778
 
 
779
 
        log_sys->no_flush_event = os_event_create(NULL);
780
 
 
781
 
        os_event_set(log_sys->no_flush_event);
782
 
 
783
 
        log_sys->one_flushed_event = os_event_create(NULL);
784
 
 
785
 
        os_event_set(log_sys->one_flushed_event);
786
 
 
787
 
        /*----------------------------*/
788
 
        log_sys->adm_checkpoint_interval = ULINT_MAX;
789
 
 
790
 
        log_sys->next_checkpoint_no = ut_dulint_zero;
791
 
        log_sys->last_checkpoint_lsn = log_sys->lsn;
792
 
        log_sys->n_pending_checkpoint_writes = 0;
793
 
 
794
 
        rw_lock_create(&log_sys->checkpoint_lock, SYNC_NO_ORDER_CHECK);
795
 
 
796
 
        log_sys->checkpoint_buf
797
 
                = ut_align(mem_alloc(2 * OS_FILE_LOG_BLOCK_SIZE),
798
 
                           OS_FILE_LOG_BLOCK_SIZE);
799
 
        memset(log_sys->checkpoint_buf, '\0', OS_FILE_LOG_BLOCK_SIZE);
800
 
        /*----------------------------*/
801
 
 
802
 
#ifdef UNIV_LOG_ARCHIVE
803
 
        /* Under MySQL, log archiving is always off */
804
 
        log_sys->archiving_state = LOG_ARCH_OFF;
805
 
        log_sys->archived_lsn = log_sys->lsn;
806
 
        log_sys->next_archived_lsn = ut_dulint_zero;
807
 
 
808
 
        log_sys->n_pending_archive_ios = 0;
809
 
 
810
 
        rw_lock_create(&log_sys->archive_lock, SYNC_NO_ORDER_CHECK);
811
 
 
812
 
        log_sys->archive_buf = NULL;
813
 
 
814
 
        /* ut_align(
815
 
        ut_malloc(LOG_ARCHIVE_BUF_SIZE
816
 
        + OS_FILE_LOG_BLOCK_SIZE),
817
 
        OS_FILE_LOG_BLOCK_SIZE); */
818
 
        log_sys->archive_buf_size = 0;
819
 
 
820
 
        /* memset(log_sys->archive_buf, '\0', LOG_ARCHIVE_BUF_SIZE); */
821
 
 
822
 
        log_sys->archiving_on = os_event_create(NULL);
823
 
#endif /* UNIV_LOG_ARCHIVE */
824
 
 
825
 
        /*----------------------------*/
826
 
 
827
 
        log_block_init(log_sys->buf, log_sys->lsn);
828
 
        log_block_set_first_rec_group(log_sys->buf, LOG_BLOCK_HDR_SIZE);
829
 
 
830
 
        log_sys->buf_free = LOG_BLOCK_HDR_SIZE;
831
 
        log_sys->lsn = ut_dulint_add(LOG_START_LSN, LOG_BLOCK_HDR_SIZE);
832
 
 
833
 
        mutex_exit(&(log_sys->mutex));
834
 
 
835
 
#ifdef UNIV_LOG_DEBUG
836
 
        recv_sys_create();
837
 
        recv_sys_init(FALSE, buf_pool_get_curr_size());
838
 
 
839
 
        recv_sys->parse_start_lsn = log_sys->lsn;
840
 
        recv_sys->scanned_lsn = log_sys->lsn;
841
 
        recv_sys->scanned_checkpoint_no = 0;
842
 
        recv_sys->recovered_lsn = log_sys->lsn;
843
 
        recv_sys->limit_lsn = ut_dulint_max;
844
 
#endif
845
 
}
846
 
 
847
 
/**********************************************************************
848
 
Inits a log group to the log system. */
849
 
 
850
 
void
851
 
log_group_init(
852
 
/*===========*/
853
 
        ulint   id,                     /* in: group id */
854
 
        ulint   n_files,                /* in: number of log files */
855
 
        ulint   file_size,              /* in: log file size in bytes */
856
 
        ulint   space_id,               /* in: space id of the file space
857
 
                                        which contains the log files of this
858
 
                                        group */
859
 
        ulint   archive_space_id __attribute__((unused)))
860
 
                                        /* in: space id of the file space
861
 
                                        which contains some archived log
862
 
                                        files for this group; currently, only
863
 
                                        for the first log group this is
864
 
                                        used */
865
 
{
866
 
        ulint   i;
867
 
 
868
 
        log_group_t*    group;
869
 
 
870
 
        group = mem_alloc(sizeof(log_group_t));
871
 
 
872
 
        group->id = id;
873
 
        group->n_files = n_files;
874
 
        group->file_size = file_size;
875
 
        group->space_id = space_id;
876
 
        group->state = LOG_GROUP_OK;
877
 
        group->lsn = LOG_START_LSN;
878
 
        group->lsn_offset = LOG_FILE_HDR_SIZE;
879
 
        group->n_pending_writes = 0;
880
 
 
881
 
        group->file_header_bufs = mem_alloc(sizeof(byte*) * n_files);
882
 
#ifdef UNIV_LOG_ARCHIVE
883
 
        group->archive_file_header_bufs = mem_alloc(sizeof(byte*) * n_files);
884
 
#endif /* UNIV_LOG_ARCHIVE */
885
 
 
886
 
        for (i = 0; i < n_files; i++) {
887
 
                *(group->file_header_bufs + i) = ut_align(
888
 
                        mem_alloc(LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE),
889
 
                        OS_FILE_LOG_BLOCK_SIZE);
890
 
 
891
 
                memset(*(group->file_header_bufs + i), '\0',
892
 
                       LOG_FILE_HDR_SIZE);
893
 
 
894
 
#ifdef UNIV_LOG_ARCHIVE
895
 
                *(group->archive_file_header_bufs + i) = ut_align(
896
 
                        mem_alloc(LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE),
897
 
                        OS_FILE_LOG_BLOCK_SIZE);
898
 
                memset(*(group->archive_file_header_bufs + i), '\0',
899
 
                       LOG_FILE_HDR_SIZE);
900
 
#endif /* UNIV_LOG_ARCHIVE */
901
 
        }
902
 
 
903
 
#ifdef UNIV_LOG_ARCHIVE
904
 
        group->archive_space_id = archive_space_id;
905
 
 
906
 
        group->archived_file_no = 0;
907
 
        group->archived_offset = 0;
908
 
#endif /* UNIV_LOG_ARCHIVE */
909
 
 
910
 
        group->checkpoint_buf = ut_align(
911
 
                mem_alloc(2 * OS_FILE_LOG_BLOCK_SIZE), OS_FILE_LOG_BLOCK_SIZE);
912
 
 
913
 
        memset(group->checkpoint_buf, '\0', OS_FILE_LOG_BLOCK_SIZE);
914
 
 
915
 
        UT_LIST_ADD_LAST(log_groups, log_sys->log_groups, group);
916
 
 
917
 
        ut_a(log_calc_max_ages());
918
 
}
919
 
 
920
 
/**********************************************************************
921
 
Does the unlockings needed in flush i/o completion. */
922
 
UNIV_INLINE
923
 
void
924
 
log_flush_do_unlocks(
925
 
/*=================*/
926
 
        ulint   code)   /* in: any ORed combination of LOG_UNLOCK_FLUSH_LOCK
927
 
                        and LOG_UNLOCK_NONE_FLUSHED_LOCK */
928
 
{
929
 
        ut_ad(mutex_own(&(log_sys->mutex)));
930
 
 
931
 
        /* NOTE that we must own the log mutex when doing the setting of the
932
 
        events: this is because transactions will wait for these events to
933
 
        be set, and at that moment the log flush they were waiting for must
934
 
        have ended. If the log mutex were not reserved here, the i/o-thread
935
 
        calling this function might be preempted for a while, and when it
936
 
        resumed execution, it might be that a new flush had been started, and
937
 
        this function would erroneously signal the NEW flush as completed.
938
 
        Thus, the changes in the state of these events are performed
939
 
        atomically in conjunction with the changes in the state of
940
 
        log_sys->n_pending_writes etc. */
941
 
 
942
 
        if (code & LOG_UNLOCK_NONE_FLUSHED_LOCK) {
943
 
                os_event_set(log_sys->one_flushed_event);
944
 
        }
945
 
 
946
 
        if (code & LOG_UNLOCK_FLUSH_LOCK) {
947
 
                os_event_set(log_sys->no_flush_event);
948
 
        }
949
 
}
950
 
 
951
 
/**********************************************************************
952
 
Checks if a flush is completed for a log group and does the completion
953
 
routine if yes. */
954
 
UNIV_INLINE
955
 
ulint
956
 
log_group_check_flush_completion(
957
 
/*=============================*/
958
 
                                /* out: LOG_UNLOCK_NONE_FLUSHED_LOCK or 0 */
959
 
        log_group_t*    group)  /* in: log group */
960
 
{
961
 
        ut_ad(mutex_own(&(log_sys->mutex)));
962
 
 
963
 
        if (!log_sys->one_flushed && group->n_pending_writes == 0) {
964
 
#ifdef UNIV_DEBUG
965
 
                if (log_debug_writes) {
966
 
                        fprintf(stderr,
967
 
                                "Log flushed first to group %lu\n",
968
 
                                (ulong) group->id);
969
 
                }
970
 
#endif /* UNIV_DEBUG */
971
 
                log_sys->written_to_some_lsn = log_sys->write_lsn;
972
 
                log_sys->one_flushed = TRUE;
973
 
 
974
 
                return(LOG_UNLOCK_NONE_FLUSHED_LOCK);
975
 
        }
976
 
 
977
 
#ifdef UNIV_DEBUG
978
 
        if (log_debug_writes && (group->n_pending_writes == 0)) {
979
 
 
980
 
                fprintf(stderr, "Log flushed to group %lu\n",
981
 
                        (ulong) group->id);
982
 
        }
983
 
#endif /* UNIV_DEBUG */
984
 
        return(0);
985
 
}
986
 
 
987
 
/**********************************************************
988
 
Checks if a flush is completed and does the completion routine if yes. */
989
 
static
990
 
ulint
991
 
log_sys_check_flush_completion(void)
992
 
/*================================*/
993
 
                        /* out: LOG_UNLOCK_FLUSH_LOCK or 0 */
994
 
{
995
 
        ulint   move_start;
996
 
        ulint   move_end;
997
 
 
998
 
        ut_ad(mutex_own(&(log_sys->mutex)));
999
 
 
1000
 
        if (log_sys->n_pending_writes == 0) {
1001
 
 
1002
 
                log_sys->written_to_all_lsn = log_sys->write_lsn;
1003
 
                log_sys->buf_next_to_write = log_sys->write_end_offset;
1004
 
 
1005
 
                if (log_sys->write_end_offset > log_sys->max_buf_free / 2) {
1006
 
                        /* Move the log buffer content to the start of the
1007
 
                        buffer */
1008
 
 
1009
 
                        move_start = ut_calc_align_down(
1010
 
                                log_sys->write_end_offset,
1011
 
                                OS_FILE_LOG_BLOCK_SIZE);
1012
 
                        move_end = ut_calc_align(log_sys->buf_free,
1013
 
                                                 OS_FILE_LOG_BLOCK_SIZE);
1014
 
 
1015
 
                        ut_memmove(log_sys->buf, log_sys->buf + move_start,
1016
 
                                   move_end - move_start);
1017
 
                        log_sys->buf_free -= move_start;
1018
 
 
1019
 
                        log_sys->buf_next_to_write -= move_start;
1020
 
                }
1021
 
 
1022
 
                return(LOG_UNLOCK_FLUSH_LOCK);
1023
 
        }
1024
 
 
1025
 
        return(0);
1026
 
}
1027
 
 
1028
 
/**********************************************************
1029
 
Completes an i/o to a log file. */
1030
 
 
1031
 
void
1032
 
log_io_complete(
1033
 
/*============*/
1034
 
        log_group_t*    group)  /* in: log group or a dummy pointer */
1035
 
{
1036
 
        ulint   unlock;
1037
 
 
1038
 
#ifdef UNIV_LOG_ARCHIVE
1039
 
        if ((byte*)group == &log_archive_io) {
1040
 
                /* It was an archive write */
1041
 
 
1042
 
                log_io_complete_archive();
1043
 
 
1044
 
                return;
1045
 
        }
1046
 
#endif /* UNIV_LOG_ARCHIVE */
1047
 
 
1048
 
        if ((ulint)group & 0x1UL) {
1049
 
                /* It was a checkpoint write */
1050
 
                group = (log_group_t*)((ulint)group - 1);
1051
 
 
1052
 
                if (srv_unix_file_flush_method != SRV_UNIX_O_DSYNC
1053
 
                    && srv_unix_file_flush_method != SRV_UNIX_NOSYNC) {
1054
 
 
1055
 
                        fil_flush(group->space_id);
1056
 
                }
1057
 
 
1058
 
#ifdef UNIV_DEBUG
1059
 
                if (log_debug_writes) {
1060
 
                        fprintf(stderr,
1061
 
                                "Checkpoint info written to group %lu\n",
1062
 
                                group->id);
1063
 
                }
1064
 
#endif /* UNIV_DEBUG */
1065
 
                log_io_complete_checkpoint();
1066
 
 
1067
 
                return;
1068
 
        }
1069
 
 
1070
 
        ut_error;       /* We currently use synchronous writing of the
1071
 
                        logs and cannot end up here! */
1072
 
 
1073
 
        if (srv_unix_file_flush_method != SRV_UNIX_O_DSYNC
1074
 
            && srv_unix_file_flush_method != SRV_UNIX_NOSYNC
1075
 
            && srv_flush_log_at_trx_commit != 2) {
1076
 
 
1077
 
                fil_flush(group->space_id);
1078
 
        }
1079
 
 
1080
 
        mutex_enter(&(log_sys->mutex));
1081
 
 
1082
 
        ut_a(group->n_pending_writes > 0);
1083
 
        ut_a(log_sys->n_pending_writes > 0);
1084
 
 
1085
 
        group->n_pending_writes--;
1086
 
        log_sys->n_pending_writes--;
1087
 
 
1088
 
        unlock = log_group_check_flush_completion(group);
1089
 
        unlock = unlock | log_sys_check_flush_completion();
1090
 
 
1091
 
        log_flush_do_unlocks(unlock);
1092
 
 
1093
 
        mutex_exit(&(log_sys->mutex));
1094
 
}
1095
 
 
1096
 
/**********************************************************
1097
 
Writes a log file header to a log file space. */
1098
 
static
1099
 
void
1100
 
log_group_file_header_flush(
1101
 
/*========================*/
1102
 
        log_group_t*    group,          /* in: log group */
1103
 
        ulint           nth_file,       /* in: header to the nth file in the
1104
 
                                        log file space */
1105
 
        dulint          start_lsn)      /* in: log file data starts at this
1106
 
                                        lsn */
1107
 
{
1108
 
        byte*   buf;
1109
 
        ulint   dest_offset;
1110
 
 
1111
 
        ut_ad(mutex_own(&(log_sys->mutex)));
1112
 
        ut_a(nth_file < group->n_files);
1113
 
 
1114
 
        buf = *(group->file_header_bufs + nth_file);
1115
 
 
1116
 
        mach_write_to_4(buf + LOG_GROUP_ID, group->id);
1117
 
        mach_write_to_8(buf + LOG_FILE_START_LSN, start_lsn);
1118
 
 
1119
 
        /* Wipe over possible label of ibbackup --restore */
1120
 
        memcpy(buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, "    ", 4);
1121
 
 
1122
 
        dest_offset = nth_file * group->file_size;
1123
 
 
1124
 
#ifdef UNIV_DEBUG
1125
 
        if (log_debug_writes) {
1126
 
                fprintf(stderr,
1127
 
                        "Writing log file header to group %lu file %lu\n",
1128
 
                        (ulong) group->id, (ulong) nth_file);
1129
 
        }
1130
 
#endif /* UNIV_DEBUG */
1131
 
        if (log_do_write) {
1132
 
                log_sys->n_log_ios++;
1133
 
 
1134
 
                srv_os_log_pending_writes++;
1135
 
 
1136
 
                fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE, group->space_id,
1137
 
                       dest_offset / UNIV_PAGE_SIZE,
1138
 
                       dest_offset % UNIV_PAGE_SIZE,
1139
 
                       OS_FILE_LOG_BLOCK_SIZE,
1140
 
                       buf, group);
1141
 
 
1142
 
                srv_os_log_pending_writes--;
1143
 
        }
1144
 
}
1145
 
 
1146
 
/**********************************************************
1147
 
Stores a 4-byte checksum to the trailer checksum field of a log block
1148
 
before writing it to a log file. This checksum is used in recovery to
1149
 
check the consistency of a log block. */
1150
 
static
1151
 
void
1152
 
log_block_store_checksum(
1153
 
/*=====================*/
1154
 
        byte*   block)  /* in/out: pointer to a log block */
1155
 
{
1156
 
        log_block_set_checksum(block, log_block_calc_checksum(block));
1157
 
}
1158
 
 
1159
 
/**********************************************************
1160
 
Writes a buffer to a log file group. */
1161
 
 
1162
 
void
1163
 
log_group_write_buf(
1164
 
/*================*/
1165
 
        log_group_t*    group,          /* in: log group */
1166
 
        byte*           buf,            /* in: buffer */
1167
 
        ulint           len,            /* in: buffer len; must be divisible
1168
 
                                        by OS_FILE_LOG_BLOCK_SIZE */
1169
 
        dulint          start_lsn,      /* in: start lsn of the buffer; must
1170
 
                                        be divisible by
1171
 
                                        OS_FILE_LOG_BLOCK_SIZE */
1172
 
        ulint           new_data_offset)/* in: start offset of new data in
1173
 
                                        buf: this parameter is used to decide
1174
 
                                        if we have to write a new log file
1175
 
                                        header */
1176
 
{
1177
 
        ulint   write_len;
1178
 
        ibool   write_header;
1179
 
        ulint   next_offset;
1180
 
        ulint   i;
1181
 
 
1182
 
        ut_ad(mutex_own(&(log_sys->mutex)));
1183
 
        ut_a(len % OS_FILE_LOG_BLOCK_SIZE == 0);
1184
 
        ut_a(ut_dulint_get_low(start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0);
1185
 
 
1186
 
        if (new_data_offset == 0) {
1187
 
                write_header = TRUE;
1188
 
        } else {
1189
 
                write_header = FALSE;
1190
 
        }
1191
 
loop:
1192
 
        if (len == 0) {
1193
 
 
1194
 
                return;
1195
 
        }
1196
 
 
1197
 
        next_offset = log_group_calc_lsn_offset(start_lsn, group);
1198
 
 
1199
 
        if ((next_offset % group->file_size == LOG_FILE_HDR_SIZE)
1200
 
            && write_header) {
1201
 
                /* We start to write a new log file instance in the group */
1202
 
 
1203
 
                log_group_file_header_flush(group,
1204
 
                                            next_offset / group->file_size,
1205
 
                                            start_lsn);
1206
 
                srv_os_log_written+= OS_FILE_LOG_BLOCK_SIZE;
1207
 
                srv_log_writes++;
1208
 
        }
1209
 
 
1210
 
        if ((next_offset % group->file_size) + len > group->file_size) {
1211
 
 
1212
 
                write_len = group->file_size
1213
 
                        - (next_offset % group->file_size);
1214
 
        } else {
1215
 
                write_len = len;
1216
 
        }
1217
 
 
1218
 
#ifdef UNIV_DEBUG
1219
 
        if (log_debug_writes) {
1220
 
 
1221
 
                fprintf(stderr,
1222
 
                        "Writing log file segment to group %lu"
1223
 
                        " offset %lu len %lu\n"
1224
 
                        "start lsn %lu %lu\n"
1225
 
                        "First block n:o %lu last block n:o %lu\n",
1226
 
                        (ulong) group->id, (ulong) next_offset,
1227
 
                        (ulong) write_len,
1228
 
                        (ulong) ut_dulint_get_high(start_lsn),
1229
 
                        (ulong) ut_dulint_get_low(start_lsn),
1230
 
                        (ulong) log_block_get_hdr_no(buf),
1231
 
                        (ulong) log_block_get_hdr_no(
1232
 
                                buf + write_len - OS_FILE_LOG_BLOCK_SIZE));
1233
 
                ut_a(log_block_get_hdr_no(buf)
1234
 
                     == log_block_convert_lsn_to_no(start_lsn));
1235
 
 
1236
 
                for (i = 0; i < write_len / OS_FILE_LOG_BLOCK_SIZE; i++) {
1237
 
 
1238
 
                        ut_a(log_block_get_hdr_no(buf) + i
1239
 
                             == log_block_get_hdr_no(
1240
 
                                     buf + i * OS_FILE_LOG_BLOCK_SIZE));
1241
 
                }
1242
 
        }
1243
 
#endif /* UNIV_DEBUG */
1244
 
        /* Calculate the checksums for each log block and write them to
1245
 
        the trailer fields of the log blocks */
1246
 
 
1247
 
        for (i = 0; i < write_len / OS_FILE_LOG_BLOCK_SIZE; i++) {
1248
 
                log_block_store_checksum(buf + i * OS_FILE_LOG_BLOCK_SIZE);
1249
 
        }
1250
 
 
1251
 
        if (log_do_write) {
1252
 
                log_sys->n_log_ios++;
1253
 
 
1254
 
                srv_os_log_pending_writes++;
1255
 
 
1256
 
                fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE, group->space_id,
1257
 
                       next_offset / UNIV_PAGE_SIZE,
1258
 
                       next_offset % UNIV_PAGE_SIZE, write_len, buf, group);
1259
 
 
1260
 
                srv_os_log_pending_writes--;
1261
 
 
1262
 
                srv_os_log_written+= write_len;
1263
 
                srv_log_writes++;
1264
 
        }
1265
 
 
1266
 
        if (write_len < len) {
1267
 
                start_lsn = ut_dulint_add(start_lsn, write_len);
1268
 
                len -= write_len;
1269
 
                buf += write_len;
1270
 
 
1271
 
                write_header = TRUE;
1272
 
 
1273
 
                goto loop;
1274
 
        }
1275
 
}
1276
 
 
1277
 
/**********************************************************
1278
 
This function is called, e.g., when a transaction wants to commit. It checks
1279
 
that the log has been written to the log file up to the last log entry written
1280
 
by the transaction. If there is a flush running, it waits and checks if the
1281
 
flush flushed enough. If not, starts a new flush. */
1282
 
 
1283
 
void
1284
 
log_write_up_to(
1285
 
/*============*/
1286
 
        dulint  lsn,    /* in: log sequence number up to which the log should
1287
 
                        be written, ut_dulint_max if not specified */
1288
 
        ulint   wait,   /* in: LOG_NO_WAIT, LOG_WAIT_ONE_GROUP,
1289
 
                        or LOG_WAIT_ALL_GROUPS */
1290
 
        ibool   flush_to_disk)
1291
 
                        /* in: TRUE if we want the written log also to be
1292
 
                        flushed to disk */
1293
 
{
1294
 
        log_group_t*    group;
1295
 
        ulint           start_offset;
1296
 
        ulint           end_offset;
1297
 
        ulint           area_start;
1298
 
        ulint           area_end;
1299
 
#ifdef UNIV_DEBUG
1300
 
        ulint           loop_count      = 0;
1301
 
#endif /* UNIV_DEBUG */
1302
 
        ulint           unlock;
1303
 
 
1304
 
        if (recv_no_ibuf_operations) {
1305
 
                /* Recovery is running and no operations on the log files are
1306
 
                allowed yet (the variable name .._no_ibuf_.. is misleading) */
1307
 
 
1308
 
                return;
1309
 
        }
1310
 
 
1311
 
loop:
1312
 
#ifdef UNIV_DEBUG
1313
 
        loop_count++;
1314
 
 
1315
 
        ut_ad(loop_count < 5);
1316
 
 
1317
 
# if 0
1318
 
        if (loop_count > 2) {
1319
 
                fprintf(stderr, "Log loop count %lu\n", loop_count);
1320
 
        }
1321
 
# endif
1322
 
#endif
1323
 
 
1324
 
        mutex_enter(&(log_sys->mutex));
1325
 
 
1326
 
        if (flush_to_disk
1327
 
            && ut_dulint_cmp(log_sys->flushed_to_disk_lsn, lsn) >= 0) {
1328
 
 
1329
 
                mutex_exit(&(log_sys->mutex));
1330
 
 
1331
 
                return;
1332
 
        }
1333
 
 
1334
 
        if (!flush_to_disk
1335
 
            && (ut_dulint_cmp(log_sys->written_to_all_lsn, lsn) >= 0
1336
 
                || (ut_dulint_cmp(log_sys->written_to_some_lsn, lsn)
1337
 
                    >= 0
1338
 
                    && wait != LOG_WAIT_ALL_GROUPS))) {
1339
 
 
1340
 
                mutex_exit(&(log_sys->mutex));
1341
 
 
1342
 
                return;
1343
 
        }
1344
 
 
1345
 
        if (log_sys->n_pending_writes > 0) {
1346
 
                /* A write (+ possibly flush to disk) is running */
1347
 
 
1348
 
                if (flush_to_disk
1349
 
                    && ut_dulint_cmp(log_sys->current_flush_lsn, lsn)
1350
 
                    >= 0) {
1351
 
                        /* The write + flush will write enough: wait for it to
1352
 
                        complete  */
1353
 
 
1354
 
                        goto do_waits;
1355
 
                }
1356
 
 
1357
 
                if (!flush_to_disk
1358
 
                    && ut_dulint_cmp(log_sys->write_lsn, lsn) >= 0) {
1359
 
                        /* The write will write enough: wait for it to
1360
 
                        complete  */
1361
 
 
1362
 
                        goto do_waits;
1363
 
                }
1364
 
 
1365
 
                mutex_exit(&(log_sys->mutex));
1366
 
 
1367
 
                /* Wait for the write to complete and try to start a new
1368
 
                write */
1369
 
 
1370
 
                os_event_wait(log_sys->no_flush_event);
1371
 
 
1372
 
                goto loop;
1373
 
        }
1374
 
 
1375
 
        if (!flush_to_disk
1376
 
            && log_sys->buf_free == log_sys->buf_next_to_write) {
1377
 
                /* Nothing to write and no flush to disk requested */
1378
 
 
1379
 
                mutex_exit(&(log_sys->mutex));
1380
 
 
1381
 
                return;
1382
 
        }
1383
 
 
1384
 
#ifdef UNIV_DEBUG
1385
 
        if (log_debug_writes) {
1386
 
                fprintf(stderr,
1387
 
                        "Writing log from %lu %lu up to lsn %lu %lu\n",
1388
 
                        (ulong) ut_dulint_get_high(
1389
 
                                log_sys->written_to_all_lsn),
1390
 
                        (ulong) ut_dulint_get_low(
1391
 
                                log_sys->written_to_all_lsn),
1392
 
                        (ulong) ut_dulint_get_high(log_sys->lsn),
1393
 
                        (ulong) ut_dulint_get_low(log_sys->lsn));
1394
 
        }
1395
 
#endif /* UNIV_DEBUG */
1396
 
        log_sys->n_pending_writes++;
1397
 
 
1398
 
        group = UT_LIST_GET_FIRST(log_sys->log_groups);
1399
 
        group->n_pending_writes++;      /* We assume here that we have only
1400
 
                                        one log group! */
1401
 
 
1402
 
        os_event_reset(log_sys->no_flush_event);
1403
 
        os_event_reset(log_sys->one_flushed_event);
1404
 
 
1405
 
        start_offset = log_sys->buf_next_to_write;
1406
 
        end_offset = log_sys->buf_free;
1407
 
 
1408
 
        area_start = ut_calc_align_down(start_offset, OS_FILE_LOG_BLOCK_SIZE);
1409
 
        area_end = ut_calc_align(end_offset, OS_FILE_LOG_BLOCK_SIZE);
1410
 
 
1411
 
        ut_ad(area_end - area_start > 0);
1412
 
 
1413
 
        log_sys->write_lsn = log_sys->lsn;
1414
 
 
1415
 
        if (flush_to_disk) {
1416
 
                log_sys->current_flush_lsn = log_sys->lsn;
1417
 
        }
1418
 
 
1419
 
        log_sys->one_flushed = FALSE;
1420
 
 
1421
 
        log_block_set_flush_bit(log_sys->buf + area_start, TRUE);
1422
 
        log_block_set_checkpoint_no(
1423
 
                log_sys->buf + area_end - OS_FILE_LOG_BLOCK_SIZE,
1424
 
                log_sys->next_checkpoint_no);
1425
 
 
1426
 
        /* Copy the last, incompletely written, log block a log block length
1427
 
        up, so that when the flush operation writes from the log buffer, the
1428
 
        segment to write will not be changed by writers to the log */
1429
 
 
1430
 
        ut_memcpy(log_sys->buf + area_end,
1431
 
                  log_sys->buf + area_end - OS_FILE_LOG_BLOCK_SIZE,
1432
 
                  OS_FILE_LOG_BLOCK_SIZE);
1433
 
 
1434
 
        log_sys->buf_free += OS_FILE_LOG_BLOCK_SIZE;
1435
 
        log_sys->write_end_offset = log_sys->buf_free;
1436
 
 
1437
 
        group = UT_LIST_GET_FIRST(log_sys->log_groups);
1438
 
 
1439
 
        /* Do the write to the log files */
1440
 
 
1441
 
        while (group) {
1442
 
                log_group_write_buf(
1443
 
                        group, log_sys->buf + area_start,
1444
 
                        area_end - area_start,
1445
 
                        ut_dulint_align_down(log_sys->written_to_all_lsn,
1446
 
                                             OS_FILE_LOG_BLOCK_SIZE),
1447
 
                        start_offset - area_start);
1448
 
 
1449
 
                log_group_set_fields(group, log_sys->write_lsn);
1450
 
 
1451
 
                group = UT_LIST_GET_NEXT(log_groups, group);
1452
 
        }
1453
 
 
1454
 
        mutex_exit(&(log_sys->mutex));
1455
 
 
1456
 
        if (srv_unix_file_flush_method == SRV_UNIX_O_DSYNC) {
1457
 
                /* O_DSYNC means the OS did not buffer the log file at all:
1458
 
                so we have also flushed to disk what we have written */
1459
 
 
1460
 
                log_sys->flushed_to_disk_lsn = log_sys->write_lsn;
1461
 
 
1462
 
        } else if (flush_to_disk) {
1463
 
 
1464
 
                group = UT_LIST_GET_FIRST(log_sys->log_groups);
1465
 
 
1466
 
                fil_flush(group->space_id);
1467
 
                log_sys->flushed_to_disk_lsn = log_sys->write_lsn;
1468
 
        }
1469
 
 
1470
 
        mutex_enter(&(log_sys->mutex));
1471
 
 
1472
 
        group = UT_LIST_GET_FIRST(log_sys->log_groups);
1473
 
 
1474
 
        ut_a(group->n_pending_writes == 1);
1475
 
        ut_a(log_sys->n_pending_writes == 1);
1476
 
 
1477
 
        group->n_pending_writes--;
1478
 
        log_sys->n_pending_writes--;
1479
 
 
1480
 
        unlock = log_group_check_flush_completion(group);
1481
 
        unlock = unlock | log_sys_check_flush_completion();
1482
 
 
1483
 
        log_flush_do_unlocks(unlock);
1484
 
 
1485
 
        mutex_exit(&(log_sys->mutex));
1486
 
 
1487
 
        return;
1488
 
 
1489
 
do_waits:
1490
 
        mutex_exit(&(log_sys->mutex));
1491
 
 
1492
 
        if (wait == LOG_WAIT_ONE_GROUP) {
1493
 
                os_event_wait(log_sys->one_flushed_event);
1494
 
        } else if (wait == LOG_WAIT_ALL_GROUPS) {
1495
 
                os_event_wait(log_sys->no_flush_event);
1496
 
        } else {
1497
 
                ut_ad(wait == LOG_NO_WAIT);
1498
 
        }
1499
 
}
1500
 
 
1501
 
/********************************************************************
1502
 
Does a syncronous flush of the log buffer to disk. */
1503
 
 
1504
 
void
1505
 
log_buffer_flush_to_disk(void)
1506
 
/*==========================*/
1507
 
{
1508
 
        dulint  lsn;
1509
 
 
1510
 
        mutex_enter(&(log_sys->mutex));
1511
 
 
1512
 
        lsn = log_sys->lsn;
1513
 
 
1514
 
        mutex_exit(&(log_sys->mutex));
1515
 
 
1516
 
        log_write_up_to(lsn, LOG_WAIT_ALL_GROUPS, TRUE);
1517
 
}
1518
 
 
1519
 
/********************************************************************
1520
 
Tries to establish a big enough margin of free space in the log buffer, such
1521
 
that a new log entry can be catenated without an immediate need for a flush. */
1522
 
static
1523
 
void
1524
 
log_flush_margin(void)
1525
 
/*==================*/
1526
 
{
1527
 
        ibool   do_flush        = FALSE;
1528
 
        log_t*  log             = log_sys;
1529
 
        dulint  lsn;
1530
 
 
1531
 
        mutex_enter(&(log->mutex));
1532
 
 
1533
 
        if (log->buf_free > log->max_buf_free) {
1534
 
 
1535
 
                if (log->n_pending_writes > 0) {
1536
 
                        /* A flush is running: hope that it will provide enough
1537
 
                        free space */
1538
 
                } else {
1539
 
                        do_flush = TRUE;
1540
 
                        lsn = log->lsn;
1541
 
                }
1542
 
        }
1543
 
 
1544
 
        mutex_exit(&(log->mutex));
1545
 
 
1546
 
        if (do_flush) {
1547
 
                log_write_up_to(lsn, LOG_NO_WAIT, FALSE);
1548
 
        }
1549
 
}
1550
 
 
1551
 
/********************************************************************
1552
 
Advances the smallest lsn for which there are unflushed dirty blocks in the
1553
 
buffer pool. NOTE: this function may only be called if the calling thread owns
1554
 
no synchronization objects! */
1555
 
 
1556
 
ibool
1557
 
log_preflush_pool_modified_pages(
1558
 
/*=============================*/
1559
 
                                /* out: FALSE if there was a flush batch of
1560
 
                                the same type running, which means that we
1561
 
                                could not start this flush batch */
1562
 
        dulint  new_oldest,     /* in: try to advance oldest_modified_lsn
1563
 
                                at least to this lsn */
1564
 
        ibool   sync)           /* in: TRUE if synchronous operation is
1565
 
                                desired */
1566
 
{
1567
 
        ulint   n_pages;
1568
 
 
1569
 
        if (recv_recovery_on) {
1570
 
                /* If the recovery is running, we must first apply all
1571
 
                log records to their respective file pages to get the
1572
 
                right modify lsn values to these pages: otherwise, there
1573
 
                might be pages on disk which are not yet recovered to the
1574
 
                current lsn, and even after calling this function, we could
1575
 
                not know how up-to-date the disk version of the database is,
1576
 
                and we could not make a new checkpoint on the basis of the
1577
 
                info on the buffer pool only. */
1578
 
 
1579
 
                recv_apply_hashed_log_recs(TRUE);
1580
 
        }
1581
 
 
1582
 
        n_pages = buf_flush_batch(BUF_FLUSH_LIST, ULINT_MAX, new_oldest);
1583
 
 
1584
 
        if (sync) {
1585
 
                buf_flush_wait_batch_end(BUF_FLUSH_LIST);
1586
 
        }
1587
 
 
1588
 
        if (n_pages == ULINT_UNDEFINED) {
1589
 
 
1590
 
                return(FALSE);
1591
 
        }
1592
 
 
1593
 
        return(TRUE);
1594
 
}
1595
 
 
1596
 
/**********************************************************
1597
 
Completes a checkpoint. */
1598
 
static
1599
 
void
1600
 
log_complete_checkpoint(void)
1601
 
/*=========================*/
1602
 
{
1603
 
        ut_ad(mutex_own(&(log_sys->mutex)));
1604
 
        ut_ad(log_sys->n_pending_checkpoint_writes == 0);
1605
 
 
1606
 
        log_sys->next_checkpoint_no
1607
 
                = ut_dulint_add(log_sys->next_checkpoint_no, 1);
1608
 
 
1609
 
        log_sys->last_checkpoint_lsn = log_sys->next_checkpoint_lsn;
1610
 
 
1611
 
        rw_lock_x_unlock_gen(&(log_sys->checkpoint_lock), LOG_CHECKPOINT);
1612
 
}
1613
 
 
1614
 
/**********************************************************
1615
 
Completes an asynchronous checkpoint info write i/o to a log file. */
1616
 
static
1617
 
void
1618
 
log_io_complete_checkpoint(void)
1619
 
/*============================*/
1620
 
{
1621
 
        mutex_enter(&(log_sys->mutex));
1622
 
 
1623
 
        ut_ad(log_sys->n_pending_checkpoint_writes > 0);
1624
 
 
1625
 
        log_sys->n_pending_checkpoint_writes--;
1626
 
 
1627
 
        if (log_sys->n_pending_checkpoint_writes == 0) {
1628
 
                log_complete_checkpoint();
1629
 
        }
1630
 
 
1631
 
        mutex_exit(&(log_sys->mutex));
1632
 
}
1633
 
 
1634
 
/***********************************************************************
1635
 
Writes info to a checkpoint about a log group. */
1636
 
static
1637
 
void
1638
 
log_checkpoint_set_nth_group_info(
1639
 
/*==============================*/
1640
 
        byte*   buf,    /* in: buffer for checkpoint info */
1641
 
        ulint   n,      /* in: nth slot */
1642
 
        ulint   file_no,/* in: archived file number */
1643
 
        ulint   offset) /* in: archived file offset */
1644
 
{
1645
 
        ut_ad(n < LOG_MAX_N_GROUPS);
1646
 
 
1647
 
        mach_write_to_4(buf + LOG_CHECKPOINT_GROUP_ARRAY
1648
 
                        + 8 * n + LOG_CHECKPOINT_ARCHIVED_FILE_NO, file_no);
1649
 
        mach_write_to_4(buf + LOG_CHECKPOINT_GROUP_ARRAY
1650
 
                        + 8 * n + LOG_CHECKPOINT_ARCHIVED_OFFSET, offset);
1651
 
}
1652
 
 
1653
 
/***********************************************************************
1654
 
Gets info from a checkpoint about a log group. */
1655
 
 
1656
 
void
1657
 
log_checkpoint_get_nth_group_info(
1658
 
/*==============================*/
1659
 
        byte*   buf,    /* in: buffer containing checkpoint info */
1660
 
        ulint   n,      /* in: nth slot */
1661
 
        ulint*  file_no,/* out: archived file number */
1662
 
        ulint*  offset) /* out: archived file offset */
1663
 
{
1664
 
        ut_ad(n < LOG_MAX_N_GROUPS);
1665
 
 
1666
 
        *file_no = mach_read_from_4(buf + LOG_CHECKPOINT_GROUP_ARRAY
1667
 
                                    + 8 * n + LOG_CHECKPOINT_ARCHIVED_FILE_NO);
1668
 
        *offset = mach_read_from_4(buf + LOG_CHECKPOINT_GROUP_ARRAY
1669
 
                                   + 8 * n + LOG_CHECKPOINT_ARCHIVED_OFFSET);
1670
 
}
1671
 
 
1672
 
/**********************************************************
1673
 
Writes the checkpoint info to a log group header. */
1674
 
static
1675
 
void
1676
 
log_group_checkpoint(
1677
 
/*=================*/
1678
 
        log_group_t*    group)  /* in: log group */
1679
 
{
1680
 
        log_group_t*    group2;
1681
 
#ifdef UNIV_LOG_ARCHIVE
1682
 
        dulint  archived_lsn;
1683
 
        dulint  next_archived_lsn;
1684
 
#endif /* UNIV_LOG_ARCHIVE */
1685
 
        ulint   write_offset;
1686
 
        ulint   fold;
1687
 
        byte*   buf;
1688
 
        ulint   i;
1689
 
 
1690
 
        ut_ad(mutex_own(&(log_sys->mutex)));
1691
 
#if LOG_CHECKPOINT_SIZE > OS_FILE_LOG_BLOCK_SIZE
1692
 
# error "LOG_CHECKPOINT_SIZE > OS_FILE_LOG_BLOCK_SIZE"
1693
 
#endif
1694
 
 
1695
 
        buf = group->checkpoint_buf;
1696
 
 
1697
 
        mach_write_to_8(buf + LOG_CHECKPOINT_NO, log_sys->next_checkpoint_no);
1698
 
        mach_write_to_8(buf + LOG_CHECKPOINT_LSN,
1699
 
                        log_sys->next_checkpoint_lsn);
1700
 
 
1701
 
        mach_write_to_4(buf + LOG_CHECKPOINT_OFFSET,
1702
 
                        log_group_calc_lsn_offset(
1703
 
                                log_sys->next_checkpoint_lsn, group));
1704
 
 
1705
 
        mach_write_to_4(buf + LOG_CHECKPOINT_LOG_BUF_SIZE, log_sys->buf_size);
1706
 
 
1707
 
#ifdef UNIV_LOG_ARCHIVE
1708
 
        if (log_sys->archiving_state == LOG_ARCH_OFF) {
1709
 
                archived_lsn = ut_dulint_max;
1710
 
        } else {
1711
 
                archived_lsn = log_sys->archived_lsn;
1712
 
 
1713
 
                if (0 != ut_dulint_cmp(archived_lsn,
1714
 
                                       log_sys->next_archived_lsn)) {
1715
 
                        next_archived_lsn = log_sys->next_archived_lsn;
1716
 
                        /* For debugging only */
1717
 
                }
1718
 
        }
1719
 
 
1720
 
        mach_write_to_8(buf + LOG_CHECKPOINT_ARCHIVED_LSN, archived_lsn);
1721
 
#else /* UNIV_LOG_ARCHIVE */
1722
 
        mach_write_to_8(buf + LOG_CHECKPOINT_ARCHIVED_LSN, ut_dulint_max);
1723
 
#endif /* UNIV_LOG_ARCHIVE */
1724
 
 
1725
 
        for (i = 0; i < LOG_MAX_N_GROUPS; i++) {
1726
 
                log_checkpoint_set_nth_group_info(buf, i, 0, 0);
1727
 
        }
1728
 
 
1729
 
        group2 = UT_LIST_GET_FIRST(log_sys->log_groups);
1730
 
 
1731
 
        while (group2) {
1732
 
                log_checkpoint_set_nth_group_info(buf, group2->id,
1733
 
#ifdef UNIV_LOG_ARCHIVE
1734
 
                                                  group2->archived_file_no,
1735
 
                                                  group2->archived_offset
1736
 
#else /* UNIV_LOG_ARCHIVE */
1737
 
                                                  0, 0
1738
 
#endif /* UNIV_LOG_ARCHIVE */
1739
 
                                                  );
1740
 
 
1741
 
                group2 = UT_LIST_GET_NEXT(log_groups, group2);
1742
 
        }
1743
 
 
1744
 
        fold = ut_fold_binary(buf, LOG_CHECKPOINT_CHECKSUM_1);
1745
 
        mach_write_to_4(buf + LOG_CHECKPOINT_CHECKSUM_1, fold);
1746
 
 
1747
 
        fold = ut_fold_binary(buf + LOG_CHECKPOINT_LSN,
1748
 
                              LOG_CHECKPOINT_CHECKSUM_2 - LOG_CHECKPOINT_LSN);
1749
 
        mach_write_to_4(buf + LOG_CHECKPOINT_CHECKSUM_2, fold);
1750
 
 
1751
 
        /* Starting from InnoDB-3.23.50, we also write info on allocated
1752
 
        size in the tablespace */
1753
 
 
1754
 
        mach_write_to_4(buf + LOG_CHECKPOINT_FSP_FREE_LIMIT,
1755
 
                        log_fsp_current_free_limit);
1756
 
 
1757
 
        mach_write_to_4(buf + LOG_CHECKPOINT_FSP_MAGIC_N,
1758
 
                        LOG_CHECKPOINT_FSP_MAGIC_N_VAL);
1759
 
 
1760
 
        /* We alternate the physical place of the checkpoint info in the first
1761
 
        log file */
1762
 
 
1763
 
        if (ut_dulint_get_low(log_sys->next_checkpoint_no) % 2 == 0) {
1764
 
                write_offset = LOG_CHECKPOINT_1;
1765
 
        } else {
1766
 
                write_offset = LOG_CHECKPOINT_2;
1767
 
        }
1768
 
 
1769
 
        if (log_do_write) {
1770
 
                if (log_sys->n_pending_checkpoint_writes == 0) {
1771
 
 
1772
 
                        rw_lock_x_lock_gen(&(log_sys->checkpoint_lock),
1773
 
                                           LOG_CHECKPOINT);
1774
 
                }
1775
 
 
1776
 
                log_sys->n_pending_checkpoint_writes++;
1777
 
 
1778
 
                log_sys->n_log_ios++;
1779
 
 
1780
 
                /* We send as the last parameter the group machine address
1781
 
                added with 1, as we want to distinguish between a normal log
1782
 
                file write and a checkpoint field write */
1783
 
 
1784
 
                fil_io(OS_FILE_WRITE | OS_FILE_LOG, FALSE, group->space_id,
1785
 
                       write_offset / UNIV_PAGE_SIZE,
1786
 
                       write_offset % UNIV_PAGE_SIZE,
1787
 
                       OS_FILE_LOG_BLOCK_SIZE,
1788
 
                       buf, ((byte*)group + 1));
1789
 
 
1790
 
                ut_ad(((ulint)group & 0x1UL) == 0);
1791
 
        }
1792
 
}
1793
 
 
1794
 
/**********************************************************
1795
 
Writes info to a buffer of a log group when log files are created in
1796
 
backup restoration. */
1797
 
 
1798
 
void
1799
 
log_reset_first_header_and_checkpoint(
1800
 
/*==================================*/
1801
 
        byte*   hdr_buf,/* in: buffer which will be written to the start
1802
 
                        of the first log file */
1803
 
        dulint  start)  /* in: lsn of the start of the first log file;
1804
 
                        we pretend that there is a checkpoint at
1805
 
                        start + LOG_BLOCK_HDR_SIZE */
1806
 
{
1807
 
        ulint   fold;
1808
 
        byte*   buf;
1809
 
        dulint  lsn;
1810
 
 
1811
 
        mach_write_to_4(hdr_buf + LOG_GROUP_ID, 0);
1812
 
        mach_write_to_8(hdr_buf + LOG_FILE_START_LSN, start);
1813
 
 
1814
 
        lsn = ut_dulint_add(start, LOG_BLOCK_HDR_SIZE);
1815
 
 
1816
 
        /* Write the label of ibbackup --restore */
1817
 
        strcpy((char*) hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP,
1818
 
               "ibbackup ");
1819
 
        ut_sprintf_timestamp((char*) hdr_buf
1820
 
                             + (LOG_FILE_WAS_CREATED_BY_HOT_BACKUP
1821
 
                                + (sizeof "ibbackup ") - 1));
1822
 
        buf = hdr_buf + LOG_CHECKPOINT_1;
1823
 
 
1824
 
        mach_write_to_8(buf + LOG_CHECKPOINT_NO, ut_dulint_zero);
1825
 
        mach_write_to_8(buf + LOG_CHECKPOINT_LSN, lsn);
1826
 
 
1827
 
        mach_write_to_4(buf + LOG_CHECKPOINT_OFFSET,
1828
 
                        LOG_FILE_HDR_SIZE + LOG_BLOCK_HDR_SIZE);
1829
 
 
1830
 
        mach_write_to_4(buf + LOG_CHECKPOINT_LOG_BUF_SIZE, 2 * 1024 * 1024);
1831
 
 
1832
 
        mach_write_to_8(buf + LOG_CHECKPOINT_ARCHIVED_LSN, ut_dulint_max);
1833
 
 
1834
 
        fold = ut_fold_binary(buf, LOG_CHECKPOINT_CHECKSUM_1);
1835
 
        mach_write_to_4(buf + LOG_CHECKPOINT_CHECKSUM_1, fold);
1836
 
 
1837
 
        fold = ut_fold_binary(buf + LOG_CHECKPOINT_LSN,
1838
 
                              LOG_CHECKPOINT_CHECKSUM_2 - LOG_CHECKPOINT_LSN);
1839
 
        mach_write_to_4(buf + LOG_CHECKPOINT_CHECKSUM_2, fold);
1840
 
 
1841
 
        /* Starting from InnoDB-3.23.50, we should also write info on
1842
 
        allocated size in the tablespace, but unfortunately we do not
1843
 
        know it here */
1844
 
}
1845
 
 
1846
 
/**********************************************************
1847
 
Reads a checkpoint info from a log group header to log_sys->checkpoint_buf. */
1848
 
 
1849
 
void
1850
 
log_group_read_checkpoint_info(
1851
 
/*===========================*/
1852
 
        log_group_t*    group,  /* in: log group */
1853
 
        ulint           field)  /* in: LOG_CHECKPOINT_1 or LOG_CHECKPOINT_2 */
1854
 
{
1855
 
        ut_ad(mutex_own(&(log_sys->mutex)));
1856
 
 
1857
 
        log_sys->n_log_ios++;
1858
 
 
1859
 
        fil_io(OS_FILE_READ | OS_FILE_LOG, TRUE, group->space_id,
1860
 
               field / UNIV_PAGE_SIZE, field % UNIV_PAGE_SIZE,
1861
 
               OS_FILE_LOG_BLOCK_SIZE, log_sys->checkpoint_buf, NULL);
1862
 
}
1863
 
 
1864
 
/**********************************************************
1865
 
Writes checkpoint info to groups. */
1866
 
 
1867
 
void
1868
 
log_groups_write_checkpoint_info(void)
1869
 
/*==================================*/
1870
 
{
1871
 
        log_group_t*    group;
1872
 
 
1873
 
        ut_ad(mutex_own(&(log_sys->mutex)));
1874
 
 
1875
 
        group = UT_LIST_GET_FIRST(log_sys->log_groups);
1876
 
 
1877
 
        while (group) {
1878
 
                log_group_checkpoint(group);
1879
 
 
1880
 
                group = UT_LIST_GET_NEXT(log_groups, group);
1881
 
        }
1882
 
}
1883
 
 
1884
 
/**********************************************************
1885
 
Makes a checkpoint. Note that this function does not flush dirty
1886
 
blocks from the buffer pool: it only checks what is lsn of the oldest
1887
 
modification in the pool, and writes information about the lsn in
1888
 
log files. Use log_make_checkpoint_at to flush also the pool. */
1889
 
 
1890
 
ibool
1891
 
log_checkpoint(
1892
 
/*===========*/
1893
 
                                /* out: TRUE if success, FALSE if a checkpoint
1894
 
                                write was already running */
1895
 
        ibool   sync,           /* in: TRUE if synchronous operation is
1896
 
                                desired */
1897
 
        ibool   write_always)   /* in: the function normally checks if the
1898
 
                                the new checkpoint would have a greater
1899
 
                                lsn than the previous one: if not, then no
1900
 
                                physical write is done; by setting this
1901
 
                                parameter TRUE, a physical write will always be
1902
 
                                made to log files */
1903
 
{
1904
 
        dulint  oldest_lsn;
1905
 
 
1906
 
        if (recv_recovery_is_on()) {
1907
 
                recv_apply_hashed_log_recs(TRUE);
1908
 
        }
1909
 
 
1910
 
        if (srv_unix_file_flush_method != SRV_UNIX_NOSYNC) {
1911
 
                fil_flush_file_spaces(FIL_TABLESPACE);
1912
 
        }
1913
 
 
1914
 
        mutex_enter(&(log_sys->mutex));
1915
 
 
1916
 
        oldest_lsn = log_buf_pool_get_oldest_modification();
1917
 
 
1918
 
        mutex_exit(&(log_sys->mutex));
1919
 
 
1920
 
        /* Because log also contains headers and dummy log records,
1921
 
        if the buffer pool contains no dirty buffers, oldest_lsn
1922
 
        gets the value log_sys->lsn from the previous function,
1923
 
        and we must make sure that the log is flushed up to that
1924
 
        lsn. If there are dirty buffers in the buffer pool, then our
1925
 
        write-ahead-logging algorithm ensures that the log has been flushed
1926
 
        up to oldest_lsn. */
1927
 
 
1928
 
        log_write_up_to(oldest_lsn, LOG_WAIT_ALL_GROUPS, TRUE);
1929
 
 
1930
 
        mutex_enter(&(log_sys->mutex));
1931
 
 
1932
 
        if (!write_always
1933
 
            && ut_dulint_cmp(log_sys->last_checkpoint_lsn, oldest_lsn) >= 0) {
1934
 
 
1935
 
                mutex_exit(&(log_sys->mutex));
1936
 
 
1937
 
                return(TRUE);
1938
 
        }
1939
 
 
1940
 
        ut_ad(ut_dulint_cmp(log_sys->written_to_all_lsn, oldest_lsn) >= 0);
1941
 
 
1942
 
        if (log_sys->n_pending_checkpoint_writes > 0) {
1943
 
                /* A checkpoint write is running */
1944
 
 
1945
 
                mutex_exit(&(log_sys->mutex));
1946
 
 
1947
 
                if (sync) {
1948
 
                        /* Wait for the checkpoint write to complete */
1949
 
                        rw_lock_s_lock(&(log_sys->checkpoint_lock));
1950
 
                        rw_lock_s_unlock(&(log_sys->checkpoint_lock));
1951
 
                }
1952
 
 
1953
 
                return(FALSE);
1954
 
        }
1955
 
 
1956
 
        log_sys->next_checkpoint_lsn = oldest_lsn;
1957
 
 
1958
 
#ifdef UNIV_DEBUG
1959
 
        if (log_debug_writes) {
1960
 
                fprintf(stderr, "Making checkpoint no %lu at lsn %lu %lu\n",
1961
 
                        (ulong) ut_dulint_get_low(log_sys->next_checkpoint_no),
1962
 
                        (ulong) ut_dulint_get_high(oldest_lsn),
1963
 
                        (ulong) ut_dulint_get_low(oldest_lsn));
1964
 
        }
1965
 
#endif /* UNIV_DEBUG */
1966
 
 
1967
 
        log_groups_write_checkpoint_info();
1968
 
 
1969
 
        mutex_exit(&(log_sys->mutex));
1970
 
 
1971
 
        if (sync) {
1972
 
                /* Wait for the checkpoint write to complete */
1973
 
                rw_lock_s_lock(&(log_sys->checkpoint_lock));
1974
 
                rw_lock_s_unlock(&(log_sys->checkpoint_lock));
1975
 
        }
1976
 
 
1977
 
        return(TRUE);
1978
 
}
1979
 
 
1980
 
/********************************************************************
1981
 
Makes a checkpoint at a given lsn or later. */
1982
 
 
1983
 
void
1984
 
log_make_checkpoint_at(
1985
 
/*===================*/
1986
 
        dulint  lsn,            /* in: make a checkpoint at this or a later
1987
 
                                lsn, if ut_dulint_max, makes a checkpoint at
1988
 
                                the latest lsn */
1989
 
        ibool   write_always)   /* in: the function normally checks if the
1990
 
                                the new checkpoint would have a greater
1991
 
                                lsn than the previous one: if not, then no
1992
 
                                physical write is done; by setting this
1993
 
                                parameter TRUE, a physical write will always be
1994
 
                                made to log files */
1995
 
{
1996
 
        ibool   success;
1997
 
 
1998
 
        /* Preflush pages synchronously */
1999
 
 
2000
 
        success = FALSE;
2001
 
 
2002
 
        while (!success) {
2003
 
                success = log_preflush_pool_modified_pages(lsn, TRUE);
2004
 
        }
2005
 
 
2006
 
        success = FALSE;
2007
 
 
2008
 
        while (!success) {
2009
 
                success = log_checkpoint(TRUE, write_always);
2010
 
        }
2011
 
}
2012
 
 
2013
 
/********************************************************************
2014
 
Tries to establish a big enough margin of free space in the log groups, such
2015
 
that a new log entry can be catenated without an immediate need for a
2016
 
checkpoint. NOTE: this function may only be called if the calling thread
2017
 
owns no synchronization objects! */
2018
 
static
2019
 
void
2020
 
log_checkpoint_margin(void)
2021
 
/*=======================*/
2022
 
{
2023
 
        log_t*  log             = log_sys;
2024
 
        ulint   age;
2025
 
        ulint   checkpoint_age;
2026
 
        ulint   advance;
2027
 
        dulint  oldest_lsn;
2028
 
        ibool   sync;
2029
 
        ibool   checkpoint_sync;
2030
 
        ibool   do_checkpoint;
2031
 
        ibool   success;
2032
 
loop:
2033
 
        sync = FALSE;
2034
 
        checkpoint_sync = FALSE;
2035
 
        do_checkpoint = FALSE;
2036
 
 
2037
 
        mutex_enter(&(log->mutex));
2038
 
 
2039
 
        if (log->check_flush_or_checkpoint == FALSE) {
2040
 
                mutex_exit(&(log->mutex));
2041
 
 
2042
 
                return;
2043
 
        }
2044
 
 
2045
 
        oldest_lsn = log_buf_pool_get_oldest_modification();
2046
 
 
2047
 
        age = ut_dulint_minus(log->lsn, oldest_lsn);
2048
 
 
2049
 
        if (age > log->max_modified_age_sync) {
2050
 
 
2051
 
                /* A flush is urgent: we have to do a synchronous preflush */
2052
 
 
2053
 
                sync = TRUE;
2054
 
                advance = 2 * (age - log->max_modified_age_sync);
2055
 
        } else if (age > log->max_modified_age_async) {
2056
 
 
2057
 
                /* A flush is not urgent: we do an asynchronous preflush */
2058
 
                advance = age - log->max_modified_age_async;
2059
 
        } else {
2060
 
                advance = 0;
2061
 
        }
2062
 
 
2063
 
        checkpoint_age = ut_dulint_minus(log->lsn, log->last_checkpoint_lsn);
2064
 
 
2065
 
        if (checkpoint_age > log->max_checkpoint_age) {
2066
 
                /* A checkpoint is urgent: we do it synchronously */
2067
 
 
2068
 
                checkpoint_sync = TRUE;
2069
 
 
2070
 
                do_checkpoint = TRUE;
2071
 
 
2072
 
        } else if (checkpoint_age > log->max_checkpoint_age_async) {
2073
 
                /* A checkpoint is not urgent: do it asynchronously */
2074
 
 
2075
 
                do_checkpoint = TRUE;
2076
 
 
2077
 
                log->check_flush_or_checkpoint = FALSE;
2078
 
        } else {
2079
 
                log->check_flush_or_checkpoint = FALSE;
2080
 
        }
2081
 
 
2082
 
        mutex_exit(&(log->mutex));
2083
 
 
2084
 
        if (advance) {
2085
 
                dulint  new_oldest = ut_dulint_add(oldest_lsn, advance);
2086
 
 
2087
 
                success = log_preflush_pool_modified_pages(new_oldest, sync);
2088
 
 
2089
 
                /* If the flush succeeded, this thread has done its part
2090
 
                and can proceed. If it did not succeed, there was another
2091
 
                thread doing a flush at the same time. If sync was FALSE,
2092
 
                the flush was not urgent, and we let this thread proceed.
2093
 
                Otherwise, we let it start from the beginning again. */
2094
 
 
2095
 
                if (sync && !success) {
2096
 
                        mutex_enter(&(log->mutex));
2097
 
 
2098
 
                        log->check_flush_or_checkpoint = TRUE;
2099
 
 
2100
 
                        mutex_exit(&(log->mutex));
2101
 
                        goto loop;
2102
 
                }
2103
 
        }
2104
 
 
2105
 
        if (do_checkpoint) {
2106
 
                log_checkpoint(checkpoint_sync, FALSE);
2107
 
 
2108
 
                if (checkpoint_sync) {
2109
 
 
2110
 
                        goto loop;
2111
 
                }
2112
 
        }
2113
 
}
2114
 
 
2115
 
/**********************************************************
2116
 
Reads a specified log segment to a buffer. */
2117
 
 
2118
 
void
2119
 
log_group_read_log_seg(
2120
 
/*===================*/
2121
 
        ulint           type,           /* in: LOG_ARCHIVE or LOG_RECOVER */
2122
 
        byte*           buf,            /* in: buffer where to read */
2123
 
        log_group_t*    group,          /* in: log group */
2124
 
        dulint          start_lsn,      /* in: read area start */
2125
 
        dulint          end_lsn)        /* in: read area end */
2126
 
{
2127
 
        ulint   len;
2128
 
        ulint   source_offset;
2129
 
        ibool   sync;
2130
 
 
2131
 
        ut_ad(mutex_own(&(log_sys->mutex)));
2132
 
 
2133
 
        sync = FALSE;
2134
 
 
2135
 
        if (type == LOG_RECOVER) {
2136
 
                sync = TRUE;
2137
 
        }
2138
 
loop:
2139
 
        source_offset = log_group_calc_lsn_offset(start_lsn, group);
2140
 
 
2141
 
        len = ut_dulint_minus(end_lsn, start_lsn);
2142
 
 
2143
 
        ut_ad(len != 0);
2144
 
 
2145
 
        if ((source_offset % group->file_size) + len > group->file_size) {
2146
 
 
2147
 
                len = group->file_size - (source_offset % group->file_size);
2148
 
        }
2149
 
 
2150
 
#ifdef UNIV_LOG_ARCHIVE
2151
 
        if (type == LOG_ARCHIVE) {
2152
 
 
2153
 
                log_sys->n_pending_archive_ios++;
2154
 
        }
2155
 
#endif /* UNIV_LOG_ARCHIVE */
2156
 
 
2157
 
        log_sys->n_log_ios++;
2158
 
 
2159
 
        fil_io(OS_FILE_READ | OS_FILE_LOG, sync, group->space_id,
2160
 
               source_offset / UNIV_PAGE_SIZE, source_offset % UNIV_PAGE_SIZE,
2161
 
               len, buf, NULL);
2162
 
 
2163
 
        start_lsn = ut_dulint_add(start_lsn, len);
2164
 
        buf += len;
2165
 
 
2166
 
        if (ut_dulint_cmp(start_lsn, end_lsn) != 0) {
2167
 
 
2168
 
                goto loop;
2169
 
        }
2170
 
}
2171
 
 
2172
 
#ifdef UNIV_LOG_ARCHIVE
2173
 
/**********************************************************
2174
 
Generates an archived log file name. */
2175
 
 
2176
 
void
2177
 
log_archived_file_name_gen(
2178
 
/*=======================*/
2179
 
        char*   buf,    /* in: buffer where to write */
2180
 
        ulint   id __attribute__((unused)),
2181
 
                        /* in: group id;
2182
 
                        currently we only archive the first group */
2183
 
        ulint   file_no)/* in: file number */
2184
 
{
2185
 
        sprintf(buf, "%sib_arch_log_%010lu", srv_arch_dir, (ulong) file_no);
2186
 
}
2187
 
 
2188
 
/**********************************************************
2189
 
Writes a log file header to a log file space. */
2190
 
static
2191
 
void
2192
 
log_group_archive_file_header_write(
2193
 
/*================================*/
2194
 
        log_group_t*    group,          /* in: log group */
2195
 
        ulint           nth_file,       /* in: header to the nth file in the
2196
 
                                        archive log file space */
2197
 
        ulint           file_no,        /* in: archived file number */
2198
 
        dulint          start_lsn)      /* in: log file data starts at this
2199
 
                                        lsn */
2200
 
{
2201
 
        byte*   buf;
2202
 
        ulint   dest_offset;
2203
 
 
2204
 
        ut_ad(mutex_own(&(log_sys->mutex)));
2205
 
 
2206
 
        ut_a(nth_file < group->n_files);
2207
 
 
2208
 
        buf = *(group->archive_file_header_bufs + nth_file);
2209
 
 
2210
 
        mach_write_to_4(buf + LOG_GROUP_ID, group->id);
2211
 
        mach_write_to_8(buf + LOG_FILE_START_LSN, start_lsn);
2212
 
        mach_write_to_4(buf + LOG_FILE_NO, file_no);
2213
 
 
2214
 
        mach_write_to_4(buf + LOG_FILE_ARCH_COMPLETED, FALSE);
2215
 
 
2216
 
        dest_offset = nth_file * group->file_size;
2217
 
 
2218
 
        log_sys->n_log_ios++;
2219
 
 
2220
 
        fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE, group->archive_space_id,
2221
 
               dest_offset / UNIV_PAGE_SIZE,
2222
 
               dest_offset % UNIV_PAGE_SIZE,
2223
 
               2 * OS_FILE_LOG_BLOCK_SIZE,
2224
 
               buf, &log_archive_io);
2225
 
}
2226
 
 
2227
 
/**********************************************************
2228
 
Writes a log file header to a completed archived log file. */
2229
 
static
2230
 
void
2231
 
log_group_archive_completed_header_write(
2232
 
/*=====================================*/
2233
 
        log_group_t*    group,          /* in: log group */
2234
 
        ulint           nth_file,       /* in: header to the nth file in the
2235
 
                                        archive log file space */
2236
 
        dulint          end_lsn)        /* in: end lsn of the file */
2237
 
{
2238
 
        byte*   buf;
2239
 
        ulint   dest_offset;
2240
 
 
2241
 
        ut_ad(mutex_own(&(log_sys->mutex)));
2242
 
        ut_a(nth_file < group->n_files);
2243
 
 
2244
 
        buf = *(group->archive_file_header_bufs + nth_file);
2245
 
 
2246
 
        mach_write_to_4(buf + LOG_FILE_ARCH_COMPLETED, TRUE);
2247
 
        mach_write_to_8(buf + LOG_FILE_END_LSN, end_lsn);
2248
 
 
2249
 
        dest_offset = nth_file * group->file_size + LOG_FILE_ARCH_COMPLETED;
2250
 
 
2251
 
        log_sys->n_log_ios++;
2252
 
 
2253
 
        fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE, group->archive_space_id,
2254
 
               dest_offset / UNIV_PAGE_SIZE,
2255
 
               dest_offset % UNIV_PAGE_SIZE,
2256
 
               OS_FILE_LOG_BLOCK_SIZE,
2257
 
               buf + LOG_FILE_ARCH_COMPLETED,
2258
 
               &log_archive_io);
2259
 
}
2260
 
 
2261
 
/**********************************************************
2262
 
Does the archive writes for a single log group. */
2263
 
static
2264
 
void
2265
 
log_group_archive(
2266
 
/*==============*/
2267
 
        log_group_t*    group)  /* in: log group */
2268
 
{
2269
 
        os_file_t file_handle;
2270
 
        dulint  start_lsn;
2271
 
        dulint  end_lsn;
2272
 
        char    name[1024];
2273
 
        byte*   buf;
2274
 
        ulint   len;
2275
 
        ibool   ret;
2276
 
        ulint   next_offset;
2277
 
        ulint   n_files;
2278
 
        ulint   open_mode;
2279
 
 
2280
 
        ut_ad(mutex_own(&(log_sys->mutex)));
2281
 
 
2282
 
        start_lsn = log_sys->archived_lsn;
2283
 
 
2284
 
        ut_a(ut_dulint_get_low(start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0);
2285
 
 
2286
 
        end_lsn = log_sys->next_archived_lsn;
2287
 
 
2288
 
        ut_a(ut_dulint_get_low(end_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0);
2289
 
 
2290
 
        buf = log_sys->archive_buf;
2291
 
 
2292
 
        n_files = 0;
2293
 
 
2294
 
        next_offset = group->archived_offset;
2295
 
loop:
2296
 
        if ((next_offset % group->file_size == 0)
2297
 
            || (fil_space_get_size(group->archive_space_id) == 0)) {
2298
 
 
2299
 
                /* Add the file to the archive file space; create or open the
2300
 
                file */
2301
 
 
2302
 
                if (next_offset % group->file_size == 0) {
2303
 
                        open_mode = OS_FILE_CREATE;
2304
 
                } else {
2305
 
                        open_mode = OS_FILE_OPEN;
2306
 
                }
2307
 
 
2308
 
                log_archived_file_name_gen(name, group->id,
2309
 
                                           group->archived_file_no + n_files);
2310
 
 
2311
 
                file_handle = os_file_create(name, open_mode, OS_FILE_AIO,
2312
 
                                             OS_DATA_FILE, &ret);
2313
 
 
2314
 
                if (!ret && (open_mode == OS_FILE_CREATE)) {
2315
 
                        file_handle = os_file_create(
2316
 
                                name, OS_FILE_OPEN, OS_FILE_AIO,
2317
 
                                OS_DATA_FILE, &ret);
2318
 
                }
2319
 
 
2320
 
                if (!ret) {
2321
 
                        fprintf(stderr,
2322
 
                                "InnoDB: Cannot create or open"
2323
 
                                " archive log file %s.\n"
2324
 
                                "InnoDB: Cannot continue operation.\n"
2325
 
                                "InnoDB: Check that the log archive"
2326
 
                                " directory exists,\n"
2327
 
                                "InnoDB: you have access rights to it, and\n"
2328
 
                                "InnoDB: there is space available.\n", name);
2329
 
                        exit(1);
2330
 
                }
2331
 
 
2332
 
#ifdef UNIV_DEBUG
2333
 
                if (log_debug_writes) {
2334
 
                        fprintf(stderr, "Created archive file %s\n", name);
2335
 
                }
2336
 
#endif /* UNIV_DEBUG */
2337
 
 
2338
 
                ret = os_file_close(file_handle);
2339
 
 
2340
 
                ut_a(ret);
2341
 
 
2342
 
                /* Add the archive file as a node to the space */
2343
 
 
2344
 
                fil_node_create(name, group->file_size / UNIV_PAGE_SIZE,
2345
 
                                group->archive_space_id, FALSE);
2346
 
 
2347
 
                if (next_offset % group->file_size == 0) {
2348
 
                        log_group_archive_file_header_write(
2349
 
                                group, n_files,
2350
 
                                group->archived_file_no + n_files,
2351
 
                                start_lsn);
2352
 
 
2353
 
                        next_offset += LOG_FILE_HDR_SIZE;
2354
 
                }
2355
 
        }
2356
 
 
2357
 
        len = ut_dulint_minus(end_lsn, start_lsn);
2358
 
 
2359
 
        if (group->file_size < (next_offset % group->file_size) + len) {
2360
 
 
2361
 
                len = group->file_size - (next_offset % group->file_size);
2362
 
        }
2363
 
 
2364
 
#ifdef UNIV_DEBUG
2365
 
        if (log_debug_writes) {
2366
 
                fprintf(stderr,
2367
 
                        "Archiving starting at lsn %lu %lu, len %lu"
2368
 
                        " to group %lu\n",
2369
 
                        (ulong) ut_dulint_get_high(start_lsn),
2370
 
                        (ulong) ut_dulint_get_low(start_lsn),
2371
 
                        (ulong) len, (ulong) group->id);
2372
 
        }
2373
 
#endif /* UNIV_DEBUG */
2374
 
 
2375
 
        log_sys->n_pending_archive_ios++;
2376
 
 
2377
 
        log_sys->n_log_ios++;
2378
 
 
2379
 
        fil_io(OS_FILE_WRITE | OS_FILE_LOG, FALSE, group->archive_space_id,
2380
 
               next_offset / UNIV_PAGE_SIZE, next_offset % UNIV_PAGE_SIZE,
2381
 
               ut_calc_align(len, OS_FILE_LOG_BLOCK_SIZE), buf,
2382
 
               &log_archive_io);
2383
 
 
2384
 
        start_lsn = ut_dulint_add(start_lsn, len);
2385
 
        next_offset += len;
2386
 
        buf += len;
2387
 
 
2388
 
        if (next_offset % group->file_size == 0) {
2389
 
                n_files++;
2390
 
        }
2391
 
 
2392
 
        if (ut_dulint_cmp(end_lsn, start_lsn) != 0) {
2393
 
 
2394
 
                goto loop;
2395
 
        }
2396
 
 
2397
 
        group->next_archived_file_no = group->archived_file_no + n_files;
2398
 
        group->next_archived_offset = next_offset % group->file_size;
2399
 
 
2400
 
        ut_a(group->next_archived_offset % OS_FILE_LOG_BLOCK_SIZE == 0);
2401
 
}
2402
 
 
2403
 
/*********************************************************
2404
 
(Writes to the archive of each log group.) Currently, only the first
2405
 
group is archived. */
2406
 
static
2407
 
void
2408
 
log_archive_groups(void)
2409
 
/*====================*/
2410
 
{
2411
 
        log_group_t*    group;
2412
 
 
2413
 
        ut_ad(mutex_own(&(log_sys->mutex)));
2414
 
 
2415
 
        group = UT_LIST_GET_FIRST(log_sys->log_groups);
2416
 
 
2417
 
        log_group_archive(group);
2418
 
}
2419
 
 
2420
 
/*********************************************************
2421
 
Completes the archiving write phase for (each log group), currently,
2422
 
the first log group. */
2423
 
static
2424
 
void
2425
 
log_archive_write_complete_groups(void)
2426
 
/*===================================*/
2427
 
{
2428
 
        log_group_t*    group;
2429
 
        ulint           end_offset;
2430
 
        ulint           trunc_files;
2431
 
        ulint           n_files;
2432
 
        dulint          start_lsn;
2433
 
        dulint          end_lsn;
2434
 
        ulint           i;
2435
 
 
2436
 
        ut_ad(mutex_own(&(log_sys->mutex)));
2437
 
 
2438
 
        group = UT_LIST_GET_FIRST(log_sys->log_groups);
2439
 
 
2440
 
        group->archived_file_no = group->next_archived_file_no;
2441
 
        group->archived_offset = group->next_archived_offset;
2442
 
 
2443
 
        /* Truncate from the archive file space all but the last
2444
 
        file, or if it has been written full, all files */
2445
 
 
2446
 
        n_files = (UNIV_PAGE_SIZE
2447
 
                   * fil_space_get_size(group->archive_space_id))
2448
 
                / group->file_size;
2449
 
        ut_ad(n_files > 0);
2450
 
 
2451
 
        end_offset = group->archived_offset;
2452
 
 
2453
 
        if (end_offset % group->file_size == 0) {
2454
 
 
2455
 
                trunc_files = n_files;
2456
 
        } else {
2457
 
                trunc_files = n_files - 1;
2458
 
        }
2459
 
 
2460
 
#ifdef UNIV_DEBUG
2461
 
        if (log_debug_writes && trunc_files) {
2462
 
                fprintf(stderr,
2463
 
                        "Complete file(s) archived to group %lu\n",
2464
 
                        (ulong) group->id);
2465
 
        }
2466
 
#endif /* UNIV_DEBUG */
2467
 
 
2468
 
        /* Calculate the archive file space start lsn */
2469
 
        start_lsn = ut_dulint_subtract(
2470
 
                log_sys->next_archived_lsn,
2471
 
                end_offset - LOG_FILE_HDR_SIZE + trunc_files
2472
 
                * (group->file_size - LOG_FILE_HDR_SIZE));
2473
 
        end_lsn = start_lsn;
2474
 
 
2475
 
        for (i = 0; i < trunc_files; i++) {
2476
 
 
2477
 
                end_lsn = ut_dulint_add(end_lsn,
2478
 
                                        group->file_size - LOG_FILE_HDR_SIZE);
2479
 
 
2480
 
                /* Write a notice to the headers of archived log
2481
 
                files that the file write has been completed */
2482
 
 
2483
 
                log_group_archive_completed_header_write(group, i, end_lsn);
2484
 
        }
2485
 
 
2486
 
        fil_space_truncate_start(group->archive_space_id,
2487
 
                                 trunc_files * group->file_size);
2488
 
 
2489
 
#ifdef UNIV_DEBUG
2490
 
        if (log_debug_writes) {
2491
 
                fputs("Archiving writes completed\n", stderr);
2492
 
        }
2493
 
#endif /* UNIV_DEBUG */
2494
 
}
2495
 
 
2496
 
/**********************************************************
2497
 
Completes an archiving i/o. */
2498
 
static
2499
 
void
2500
 
log_archive_check_completion_low(void)
2501
 
/*==================================*/
2502
 
{
2503
 
        ut_ad(mutex_own(&(log_sys->mutex)));
2504
 
 
2505
 
        if (log_sys->n_pending_archive_ios == 0
2506
 
            && log_sys->archiving_phase == LOG_ARCHIVE_READ) {
2507
 
 
2508
 
#ifdef UNIV_DEBUG
2509
 
                if (log_debug_writes) {
2510
 
                        fputs("Archiving read completed\n", stderr);
2511
 
                }
2512
 
#endif /* UNIV_DEBUG */
2513
 
 
2514
 
                /* Archive buffer has now been read in: start archive writes */
2515
 
 
2516
 
                log_sys->archiving_phase = LOG_ARCHIVE_WRITE;
2517
 
 
2518
 
                log_archive_groups();
2519
 
        }
2520
 
 
2521
 
        if (log_sys->n_pending_archive_ios == 0
2522
 
            && log_sys->archiving_phase == LOG_ARCHIVE_WRITE) {
2523
 
 
2524
 
                log_archive_write_complete_groups();
2525
 
 
2526
 
                log_sys->archived_lsn = log_sys->next_archived_lsn;
2527
 
 
2528
 
                rw_lock_x_unlock_gen(&(log_sys->archive_lock), LOG_ARCHIVE);
2529
 
        }
2530
 
}
2531
 
 
2532
 
/**********************************************************
2533
 
Completes an archiving i/o. */
2534
 
static
2535
 
void
2536
 
log_io_complete_archive(void)
2537
 
/*=========================*/
2538
 
{
2539
 
        log_group_t*    group;
2540
 
 
2541
 
        mutex_enter(&(log_sys->mutex));
2542
 
 
2543
 
        group = UT_LIST_GET_FIRST(log_sys->log_groups);
2544
 
 
2545
 
        mutex_exit(&(log_sys->mutex));
2546
 
 
2547
 
        fil_flush(group->archive_space_id);
2548
 
 
2549
 
        mutex_enter(&(log_sys->mutex));
2550
 
 
2551
 
        ut_ad(log_sys->n_pending_archive_ios > 0);
2552
 
 
2553
 
        log_sys->n_pending_archive_ios--;
2554
 
 
2555
 
        log_archive_check_completion_low();
2556
 
 
2557
 
        mutex_exit(&(log_sys->mutex));
2558
 
}
2559
 
 
2560
 
/************************************************************************
2561
 
Starts an archiving operation. */
2562
 
 
2563
 
ibool
2564
 
log_archive_do(
2565
 
/*===========*/
2566
 
                        /* out: TRUE if succeed, FALSE if an archiving
2567
 
                        operation was already running */
2568
 
        ibool   sync,   /* in: TRUE if synchronous operation is desired */
2569
 
        ulint*  n_bytes)/* out: archive log buffer size, 0 if nothing to
2570
 
                        archive */
2571
 
{
2572
 
        ibool   calc_new_limit;
2573
 
        dulint  start_lsn;
2574
 
        dulint  limit_lsn;
2575
 
 
2576
 
        calc_new_limit = TRUE;
2577
 
loop:
2578
 
        mutex_enter(&(log_sys->mutex));
2579
 
 
2580
 
        if (log_sys->archiving_state == LOG_ARCH_OFF) {
2581
 
                mutex_exit(&(log_sys->mutex));
2582
 
 
2583
 
                *n_bytes = 0;
2584
 
 
2585
 
                return(TRUE);
2586
 
 
2587
 
        } else if (log_sys->archiving_state == LOG_ARCH_STOPPED
2588
 
                   || log_sys->archiving_state == LOG_ARCH_STOPPING2) {
2589
 
 
2590
 
                mutex_exit(&(log_sys->mutex));
2591
 
 
2592
 
                os_event_wait(log_sys->archiving_on);
2593
 
 
2594
 
                mutex_enter(&(log_sys->mutex));
2595
 
 
2596
 
                goto loop;
2597
 
        }
2598
 
 
2599
 
        start_lsn = log_sys->archived_lsn;
2600
 
 
2601
 
        if (calc_new_limit) {
2602
 
                ut_a(log_sys->archive_buf_size % OS_FILE_LOG_BLOCK_SIZE == 0);
2603
 
                limit_lsn = ut_dulint_add(start_lsn,
2604
 
                                          log_sys->archive_buf_size);
2605
 
 
2606
 
                *n_bytes = log_sys->archive_buf_size;
2607
 
 
2608
 
                if (ut_dulint_cmp(limit_lsn, log_sys->lsn) >= 0) {
2609
 
 
2610
 
                        limit_lsn = ut_dulint_align_down(
2611
 
                                log_sys->lsn, OS_FILE_LOG_BLOCK_SIZE);
2612
 
                }
2613
 
        }
2614
 
 
2615
 
        if (ut_dulint_cmp(log_sys->archived_lsn, limit_lsn) >= 0) {
2616
 
 
2617
 
                mutex_exit(&(log_sys->mutex));
2618
 
 
2619
 
                *n_bytes = 0;
2620
 
 
2621
 
                return(TRUE);
2622
 
        }
2623
 
 
2624
 
        if (ut_dulint_cmp(log_sys->written_to_all_lsn, limit_lsn) < 0) {
2625
 
 
2626
 
                mutex_exit(&(log_sys->mutex));
2627
 
 
2628
 
                log_write_up_to(limit_lsn, LOG_WAIT_ALL_GROUPS, TRUE);
2629
 
 
2630
 
                calc_new_limit = FALSE;
2631
 
 
2632
 
                goto loop;
2633
 
        }
2634
 
 
2635
 
        if (log_sys->n_pending_archive_ios > 0) {
2636
 
                /* An archiving operation is running */
2637
 
 
2638
 
                mutex_exit(&(log_sys->mutex));
2639
 
 
2640
 
                if (sync) {
2641
 
                        rw_lock_s_lock(&(log_sys->archive_lock));
2642
 
                        rw_lock_s_unlock(&(log_sys->archive_lock));
2643
 
                }
2644
 
 
2645
 
                *n_bytes = log_sys->archive_buf_size;
2646
 
 
2647
 
                return(FALSE);
2648
 
        }
2649
 
 
2650
 
        rw_lock_x_lock_gen(&(log_sys->archive_lock), LOG_ARCHIVE);
2651
 
 
2652
 
        log_sys->archiving_phase = LOG_ARCHIVE_READ;
2653
 
 
2654
 
        log_sys->next_archived_lsn = limit_lsn;
2655
 
 
2656
 
#ifdef UNIV_DEBUG
2657
 
        if (log_debug_writes) {
2658
 
                fprintf(stderr,
2659
 
                        "Archiving from lsn %lu %lu to lsn %lu %lu\n",
2660
 
                        (ulong) ut_dulint_get_high(log_sys->archived_lsn),
2661
 
                        (ulong) ut_dulint_get_low(log_sys->archived_lsn),
2662
 
                        (ulong) ut_dulint_get_high(limit_lsn),
2663
 
                        (ulong) ut_dulint_get_low(limit_lsn));
2664
 
        }
2665
 
#endif /* UNIV_DEBUG */
2666
 
 
2667
 
        /* Read the log segment to the archive buffer */
2668
 
 
2669
 
        log_group_read_log_seg(LOG_ARCHIVE, log_sys->archive_buf,
2670
 
                               UT_LIST_GET_FIRST(log_sys->log_groups),
2671
 
                               start_lsn, limit_lsn);
2672
 
 
2673
 
        mutex_exit(&(log_sys->mutex));
2674
 
 
2675
 
        if (sync) {
2676
 
                rw_lock_s_lock(&(log_sys->archive_lock));
2677
 
                rw_lock_s_unlock(&(log_sys->archive_lock));
2678
 
        }
2679
 
 
2680
 
        *n_bytes = log_sys->archive_buf_size;
2681
 
 
2682
 
        return(TRUE);
2683
 
}
2684
 
 
2685
 
/********************************************************************
2686
 
Writes the log contents to the archive at least up to the lsn when this
2687
 
function was called. */
2688
 
static
2689
 
void
2690
 
log_archive_all(void)
2691
 
/*=================*/
2692
 
{
2693
 
        dulint  present_lsn;
2694
 
        ulint   dummy;
2695
 
 
2696
 
        mutex_enter(&(log_sys->mutex));
2697
 
 
2698
 
        if (log_sys->archiving_state == LOG_ARCH_OFF) {
2699
 
                mutex_exit(&(log_sys->mutex));
2700
 
 
2701
 
                return;
2702
 
        }
2703
 
 
2704
 
        present_lsn = log_sys->lsn;
2705
 
 
2706
 
        mutex_exit(&(log_sys->mutex));
2707
 
 
2708
 
        log_pad_current_log_block();
2709
 
 
2710
 
        for (;;) {
2711
 
                mutex_enter(&(log_sys->mutex));
2712
 
 
2713
 
                if (ut_dulint_cmp(present_lsn, log_sys->archived_lsn) <= 0) {
2714
 
 
2715
 
                        mutex_exit(&(log_sys->mutex));
2716
 
 
2717
 
                        return;
2718
 
                }
2719
 
 
2720
 
                mutex_exit(&(log_sys->mutex));
2721
 
 
2722
 
                log_archive_do(TRUE, &dummy);
2723
 
        }
2724
 
}
2725
 
 
2726
 
/*********************************************************
2727
 
Closes the possible open archive log file (for each group) the first group,
2728
 
and if it was open, increments the group file count by 2, if desired. */
2729
 
static
2730
 
void
2731
 
log_archive_close_groups(
2732
 
/*=====================*/
2733
 
        ibool   increment_file_count)   /* in: TRUE if we want to increment
2734
 
                                        the file count */
2735
 
{
2736
 
        log_group_t*    group;
2737
 
        ulint           trunc_len;
2738
 
 
2739
 
        ut_ad(mutex_own(&(log_sys->mutex)));
2740
 
 
2741
 
        if (log_sys->archiving_state == LOG_ARCH_OFF) {
2742
 
 
2743
 
                return;
2744
 
        }
2745
 
 
2746
 
        group = UT_LIST_GET_FIRST(log_sys->log_groups);
2747
 
 
2748
 
        trunc_len = UNIV_PAGE_SIZE
2749
 
                * fil_space_get_size(group->archive_space_id);
2750
 
        if (trunc_len > 0) {
2751
 
                ut_a(trunc_len == group->file_size);
2752
 
 
2753
 
                /* Write a notice to the headers of archived log
2754
 
                files that the file write has been completed */
2755
 
 
2756
 
                log_group_archive_completed_header_write(
2757
 
                        group, 0, log_sys->archived_lsn);
2758
 
 
2759
 
                fil_space_truncate_start(group->archive_space_id,
2760
 
                                         trunc_len);
2761
 
                if (increment_file_count) {
2762
 
                        group->archived_offset = 0;
2763
 
                        group->archived_file_no += 2;
2764
 
                }
2765
 
 
2766
 
#ifdef UNIV_DEBUG
2767
 
                if (log_debug_writes) {
2768
 
                        fprintf(stderr,
2769
 
                                "Incrementing arch file no to %lu"
2770
 
                                " in log group %lu\n",
2771
 
                                (ulong) group->archived_file_no + 2,
2772
 
                                (ulong) group->id);
2773
 
                }
2774
 
#endif /* UNIV_DEBUG */
2775
 
        }
2776
 
}
2777
 
 
2778
 
/********************************************************************
2779
 
Writes the log contents to the archive up to the lsn when this function was
2780
 
called, and stops the archiving. When archiving is started again, the archived
2781
 
log file numbers start from 2 higher, so that the archiving will not write
2782
 
again to the archived log files which exist when this function returns. */
2783
 
 
2784
 
ulint
2785
 
log_archive_stop(void)
2786
 
/*==================*/
2787
 
                        /* out: DB_SUCCESS or DB_ERROR */
2788
 
{
2789
 
        ibool   success;
2790
 
 
2791
 
        mutex_enter(&(log_sys->mutex));
2792
 
 
2793
 
        if (log_sys->archiving_state != LOG_ARCH_ON) {
2794
 
 
2795
 
                mutex_exit(&(log_sys->mutex));
2796
 
 
2797
 
                return(DB_ERROR);
2798
 
        }
2799
 
 
2800
 
        log_sys->archiving_state = LOG_ARCH_STOPPING;
2801
 
 
2802
 
        mutex_exit(&(log_sys->mutex));
2803
 
 
2804
 
        log_archive_all();
2805
 
 
2806
 
        mutex_enter(&(log_sys->mutex));
2807
 
 
2808
 
        log_sys->archiving_state = LOG_ARCH_STOPPING2;
2809
 
        os_event_reset(log_sys->archiving_on);
2810
 
 
2811
 
        mutex_exit(&(log_sys->mutex));
2812
 
 
2813
 
        /* Wait for a possible archiving operation to end */
2814
 
 
2815
 
        rw_lock_s_lock(&(log_sys->archive_lock));
2816
 
        rw_lock_s_unlock(&(log_sys->archive_lock));
2817
 
 
2818
 
        mutex_enter(&(log_sys->mutex));
2819
 
 
2820
 
        /* Close all archived log files, incrementing the file count by 2,
2821
 
        if appropriate */
2822
 
 
2823
 
        log_archive_close_groups(TRUE);
2824
 
 
2825
 
        mutex_exit(&(log_sys->mutex));
2826
 
 
2827
 
        /* Make a checkpoint, so that if recovery is needed, the file numbers
2828
 
        of new archived log files will start from the right value */
2829
 
 
2830
 
        success = FALSE;
2831
 
 
2832
 
        while (!success) {
2833
 
                success = log_checkpoint(TRUE, TRUE);
2834
 
        }
2835
 
 
2836
 
        mutex_enter(&(log_sys->mutex));
2837
 
 
2838
 
        log_sys->archiving_state = LOG_ARCH_STOPPED;
2839
 
 
2840
 
        mutex_exit(&(log_sys->mutex));
2841
 
 
2842
 
        return(DB_SUCCESS);
2843
 
}
2844
 
 
2845
 
/********************************************************************
2846
 
Starts again archiving which has been stopped. */
2847
 
 
2848
 
ulint
2849
 
log_archive_start(void)
2850
 
/*===================*/
2851
 
                        /* out: DB_SUCCESS or DB_ERROR */
2852
 
{
2853
 
        mutex_enter(&(log_sys->mutex));
2854
 
 
2855
 
        if (log_sys->archiving_state != LOG_ARCH_STOPPED) {
2856
 
 
2857
 
                mutex_exit(&(log_sys->mutex));
2858
 
 
2859
 
                return(DB_ERROR);
2860
 
        }
2861
 
 
2862
 
        log_sys->archiving_state = LOG_ARCH_ON;
2863
 
 
2864
 
        os_event_set(log_sys->archiving_on);
2865
 
 
2866
 
        mutex_exit(&(log_sys->mutex));
2867
 
 
2868
 
        return(DB_SUCCESS);
2869
 
}
2870
 
 
2871
 
/********************************************************************
2872
 
Stop archiving the log so that a gap may occur in the archived log files. */
2873
 
 
2874
 
ulint
2875
 
log_archive_noarchivelog(void)
2876
 
/*==========================*/
2877
 
                        /* out: DB_SUCCESS or DB_ERROR */
2878
 
{
2879
 
loop:
2880
 
        mutex_enter(&(log_sys->mutex));
2881
 
 
2882
 
        if (log_sys->archiving_state == LOG_ARCH_STOPPED
2883
 
            || log_sys->archiving_state == LOG_ARCH_OFF) {
2884
 
 
2885
 
                log_sys->archiving_state = LOG_ARCH_OFF;
2886
 
 
2887
 
                os_event_set(log_sys->archiving_on);
2888
 
 
2889
 
                mutex_exit(&(log_sys->mutex));
2890
 
 
2891
 
                return(DB_SUCCESS);
2892
 
        }
2893
 
 
2894
 
        mutex_exit(&(log_sys->mutex));
2895
 
 
2896
 
        log_archive_stop();
2897
 
 
2898
 
        os_thread_sleep(500000);
2899
 
 
2900
 
        goto loop;
2901
 
}
2902
 
 
2903
 
/********************************************************************
2904
 
Start archiving the log so that a gap may occur in the archived log files. */
2905
 
 
2906
 
ulint
2907
 
log_archive_archivelog(void)
2908
 
/*========================*/
2909
 
                        /* out: DB_SUCCESS or DB_ERROR */
2910
 
{
2911
 
        mutex_enter(&(log_sys->mutex));
2912
 
 
2913
 
        if (log_sys->archiving_state == LOG_ARCH_OFF) {
2914
 
 
2915
 
                log_sys->archiving_state = LOG_ARCH_ON;
2916
 
 
2917
 
                log_sys->archived_lsn
2918
 
                        = ut_dulint_align_down(log_sys->lsn,
2919
 
                                               OS_FILE_LOG_BLOCK_SIZE);
2920
 
                mutex_exit(&(log_sys->mutex));
2921
 
 
2922
 
                return(DB_SUCCESS);
2923
 
        }
2924
 
 
2925
 
        mutex_exit(&(log_sys->mutex));
2926
 
 
2927
 
        return(DB_ERROR);
2928
 
}
2929
 
 
2930
 
/********************************************************************
2931
 
Tries to establish a big enough margin of free space in the log groups, such
2932
 
that a new log entry can be catenated without an immediate need for
2933
 
archiving. */
2934
 
static
2935
 
void
2936
 
log_archive_margin(void)
2937
 
/*====================*/
2938
 
{
2939
 
        log_t*  log             = log_sys;
2940
 
        ulint   age;
2941
 
        ibool   sync;
2942
 
        ulint   dummy;
2943
 
loop:
2944
 
        mutex_enter(&(log->mutex));
2945
 
 
2946
 
        if (log->archiving_state == LOG_ARCH_OFF) {
2947
 
                mutex_exit(&(log->mutex));
2948
 
 
2949
 
                return;
2950
 
        }
2951
 
 
2952
 
        age = ut_dulint_minus(log->lsn, log->archived_lsn);
2953
 
 
2954
 
        if (age > log->max_archived_lsn_age) {
2955
 
 
2956
 
                /* An archiving is urgent: we have to do synchronous i/o */
2957
 
 
2958
 
                sync = TRUE;
2959
 
 
2960
 
        } else if (age > log->max_archived_lsn_age_async) {
2961
 
 
2962
 
                /* An archiving is not urgent: we do asynchronous i/o */
2963
 
 
2964
 
                sync = FALSE;
2965
 
        } else {
2966
 
                /* No archiving required yet */
2967
 
 
2968
 
                mutex_exit(&(log->mutex));
2969
 
 
2970
 
                return;
2971
 
        }
2972
 
 
2973
 
        mutex_exit(&(log->mutex));
2974
 
 
2975
 
        log_archive_do(sync, &dummy);
2976
 
 
2977
 
        if (sync == TRUE) {
2978
 
                /* Check again that enough was written to the archive */
2979
 
 
2980
 
                goto loop;
2981
 
        }
2982
 
}
2983
 
#endif /* UNIV_LOG_ARCHIVE */
2984
 
 
2985
 
/************************************************************************
2986
 
Checks that there is enough free space in the log to start a new query step.
2987
 
Flushes the log buffer or makes a new checkpoint if necessary. NOTE: this
2988
 
function may only be called if the calling thread owns no synchronization
2989
 
objects! */
2990
 
 
2991
 
void
2992
 
log_check_margins(void)
2993
 
/*===================*/
2994
 
{
2995
 
loop:
2996
 
        log_flush_margin();
2997
 
 
2998
 
        log_checkpoint_margin();
2999
 
 
3000
 
#ifdef UNIV_LOG_ARCHIVE
3001
 
        log_archive_margin();
3002
 
#endif /* UNIV_LOG_ARCHIVE */
3003
 
 
3004
 
        mutex_enter(&(log_sys->mutex));
3005
 
 
3006
 
        if (log_sys->check_flush_or_checkpoint) {
3007
 
 
3008
 
                mutex_exit(&(log_sys->mutex));
3009
 
 
3010
 
                goto loop;
3011
 
        }
3012
 
 
3013
 
        mutex_exit(&(log_sys->mutex));
3014
 
}
3015
 
 
3016
 
/********************************************************************
3017
 
Makes a checkpoint at the latest lsn and writes it to first page of each
3018
 
data file in the database, so that we know that the file spaces contain
3019
 
all modifications up to that lsn. This can only be called at database
3020
 
shutdown. This function also writes all log in log files to the log archive. */
3021
 
 
3022
 
void
3023
 
logs_empty_and_mark_files_at_shutdown(void)
3024
 
/*=======================================*/
3025
 
{
3026
 
        dulint  lsn;
3027
 
        ulint   arch_log_no;
3028
 
 
3029
 
        if (srv_print_verbose_log) {
3030
 
                ut_print_timestamp(stderr);
3031
 
                fprintf(stderr, "  InnoDB: Starting shutdown...\n");
3032
 
        }
3033
 
        /* Wait until the master thread and all other operations are idle: our
3034
 
        algorithm only works if the server is idle at shutdown */
3035
 
 
3036
 
        srv_shutdown_state = SRV_SHUTDOWN_CLEANUP;
3037
 
loop:
3038
 
        os_thread_sleep(100000);
3039
 
 
3040
 
        mutex_enter(&kernel_mutex);
3041
 
 
3042
 
        /* We need the monitor threads to stop before we proceed with a
3043
 
        normal shutdown. In case of very fast shutdown, however, we can
3044
 
        proceed without waiting for monitor threads. */
3045
 
 
3046
 
        if (srv_fast_shutdown < 2
3047
 
           && (srv_error_monitor_active
3048
 
              || srv_lock_timeout_and_monitor_active)) {
3049
 
 
3050
 
                mutex_exit(&kernel_mutex);
3051
 
 
3052
 
                goto loop;
3053
 
        }
3054
 
 
3055
 
        /* Check that there are no longer transactions. We need this wait even
3056
 
        for the 'very fast' shutdown, because the InnoDB layer may have
3057
 
        committed or prepared transactions and we don't want to lose them. */
3058
 
 
3059
 
        if (trx_n_mysql_transactions > 0
3060
 
            || UT_LIST_GET_LEN(trx_sys->trx_list) > 0) {
3061
 
 
3062
 
                mutex_exit(&kernel_mutex);
3063
 
 
3064
 
                goto loop;
3065
 
        }
3066
 
 
3067
 
        if (srv_fast_shutdown == 2) {
3068
 
                /* In this fastest shutdown we do not flush the buffer pool:
3069
 
                it is essentially a 'crash' of the InnoDB server. Make sure
3070
 
                that the log is all flushed to disk, so that we can recover
3071
 
                all committed transactions in a crash recovery. We must not
3072
 
                write the lsn stamps to the data files, since at a startup
3073
 
                InnoDB deduces from the stamps if the previous shutdown was
3074
 
                clean. */
3075
 
 
3076
 
                log_buffer_flush_to_disk();
3077
 
 
3078
 
                return; /* We SKIP ALL THE REST !! */
3079
 
        }
3080
 
 
3081
 
        /* Check that the master thread is suspended */
3082
 
 
3083
 
        if (srv_n_threads_active[SRV_MASTER] != 0) {
3084
 
 
3085
 
                mutex_exit(&kernel_mutex);
3086
 
 
3087
 
                goto loop;
3088
 
        }
3089
 
 
3090
 
        mutex_exit(&kernel_mutex);
3091
 
 
3092
 
        mutex_enter(&(log_sys->mutex));
3093
 
 
3094
 
        if (log_sys->n_pending_checkpoint_writes
3095
 
#ifdef UNIV_LOG_ARCHIVE
3096
 
            || log_sys->n_pending_archive_ios
3097
 
#endif /* UNIV_LOG_ARCHIVE */
3098
 
            || log_sys->n_pending_writes) {
3099
 
 
3100
 
                mutex_exit(&(log_sys->mutex));
3101
 
 
3102
 
                goto loop;
3103
 
        }
3104
 
 
3105
 
        mutex_exit(&(log_sys->mutex));
3106
 
 
3107
 
        if (!buf_pool_check_no_pending_io()) {
3108
 
 
3109
 
                goto loop;
3110
 
        }
3111
 
 
3112
 
#ifdef UNIV_LOG_ARCHIVE
3113
 
        log_archive_all();
3114
 
#endif /* UNIV_LOG_ARCHIVE */
3115
 
 
3116
 
        log_make_checkpoint_at(ut_dulint_max, TRUE);
3117
 
 
3118
 
        mutex_enter(&(log_sys->mutex));
3119
 
 
3120
 
        lsn = log_sys->lsn;
3121
 
 
3122
 
        if ((ut_dulint_cmp(lsn, log_sys->last_checkpoint_lsn) != 0)
3123
 
#ifdef UNIV_LOG_ARCHIVE
3124
 
            || (srv_log_archive_on
3125
 
                && ut_dulint_cmp(lsn,
3126
 
                                 ut_dulint_add(log_sys->archived_lsn,
3127
 
                                               LOG_BLOCK_HDR_SIZE))
3128
 
                != 0)
3129
 
#endif /* UNIV_LOG_ARCHIVE */
3130
 
            ) {
3131
 
 
3132
 
                mutex_exit(&(log_sys->mutex));
3133
 
 
3134
 
                goto loop;
3135
 
        }
3136
 
 
3137
 
        arch_log_no = 0;
3138
 
 
3139
 
#ifdef UNIV_LOG_ARCHIVE
3140
 
        UT_LIST_GET_FIRST(log_sys->log_groups)->archived_file_no;
3141
 
 
3142
 
        if (0 == UT_LIST_GET_FIRST(log_sys->log_groups)->archived_offset) {
3143
 
 
3144
 
                arch_log_no--;
3145
 
        }
3146
 
 
3147
 
        log_archive_close_groups(TRUE);
3148
 
#endif /* UNIV_LOG_ARCHIVE */
3149
 
 
3150
 
        mutex_exit(&(log_sys->mutex));
3151
 
 
3152
 
        mutex_enter(&kernel_mutex);
3153
 
        /* Check that the master thread has stayed suspended */
3154
 
        if (srv_n_threads_active[SRV_MASTER] != 0) {
3155
 
                fprintf(stderr,
3156
 
                        "InnoDB: Warning: the master thread woke up"
3157
 
                        " during shutdown\n");
3158
 
 
3159
 
                mutex_exit(&kernel_mutex);
3160
 
 
3161
 
                goto loop;
3162
 
        }
3163
 
        mutex_exit(&kernel_mutex);
3164
 
 
3165
 
        fil_flush_file_spaces(FIL_TABLESPACE);
3166
 
        fil_flush_file_spaces(FIL_LOG);
3167
 
 
3168
 
        /* The call fil_write_flushed_lsn_to_data_files() will pass the buffer
3169
 
        pool: therefore it is essential that the buffer pool has been
3170
 
        completely flushed to disk! (We do not call fil_write... if the
3171
 
        'very fast' shutdown is enabled.) */
3172
 
 
3173
 
        if (!buf_all_freed()) {
3174
 
 
3175
 
                goto loop;
3176
 
        }
3177
 
 
3178
 
        srv_shutdown_state = SRV_SHUTDOWN_LAST_PHASE;
3179
 
 
3180
 
        /* Make some checks that the server really is quiet */
3181
 
        ut_a(srv_n_threads_active[SRV_MASTER] == 0);
3182
 
        ut_a(buf_all_freed());
3183
 
        ut_a(0 == ut_dulint_cmp(lsn, log_sys->lsn));
3184
 
 
3185
 
        if (ut_dulint_cmp(lsn, srv_start_lsn) < 0) {
3186
 
                fprintf(stderr,
3187
 
                        "InnoDB: Error: log sequence number"
3188
 
                        " at shutdown %lu %lu\n"
3189
 
                        "InnoDB: is lower than at startup %lu %lu!\n",
3190
 
                        (ulong) ut_dulint_get_high(lsn),
3191
 
                        (ulong) ut_dulint_get_low(lsn),
3192
 
                        (ulong) ut_dulint_get_high(srv_start_lsn),
3193
 
                        (ulong) ut_dulint_get_low(srv_start_lsn));
3194
 
        }
3195
 
 
3196
 
        srv_shutdown_lsn = lsn;
3197
 
 
3198
 
        fil_write_flushed_lsn_to_data_files(lsn, arch_log_no);
3199
 
 
3200
 
        fil_flush_file_spaces(FIL_TABLESPACE);
3201
 
 
3202
 
        fil_close_all_files();
3203
 
 
3204
 
        /* Make some checks that the server really is quiet */
3205
 
        ut_a(srv_n_threads_active[SRV_MASTER] == 0);
3206
 
        ut_a(buf_all_freed());
3207
 
        ut_a(0 == ut_dulint_cmp(lsn, log_sys->lsn));
3208
 
}
3209
 
 
3210
 
/**********************************************************
3211
 
Checks by parsing that the catenated log segment for a single mtr is
3212
 
consistent. */
3213
 
 
3214
 
ibool
3215
 
log_check_log_recs(
3216
 
/*===============*/
3217
 
        byte*   buf,            /* in: pointer to the start of the log segment
3218
 
                                in the log_sys->buf log buffer */
3219
 
        ulint   len,            /* in: segment length in bytes */
3220
 
        dulint  buf_start_lsn)  /* in: buffer start lsn */
3221
 
{
3222
 
        dulint  contiguous_lsn;
3223
 
        dulint  scanned_lsn;
3224
 
        byte*   start;
3225
 
        byte*   end;
3226
 
        byte*   buf1;
3227
 
        byte*   scan_buf;
3228
 
 
3229
 
        ut_ad(mutex_own(&(log_sys->mutex)));
3230
 
 
3231
 
        if (len == 0) {
3232
 
 
3233
 
                return(TRUE);
3234
 
        }
3235
 
 
3236
 
        start = ut_align_down(buf, OS_FILE_LOG_BLOCK_SIZE);
3237
 
        end = ut_align(buf + len, OS_FILE_LOG_BLOCK_SIZE);
3238
 
 
3239
 
        buf1 = mem_alloc((end - start) + OS_FILE_LOG_BLOCK_SIZE);
3240
 
        scan_buf = ut_align(buf1, OS_FILE_LOG_BLOCK_SIZE);
3241
 
 
3242
 
        ut_memcpy(scan_buf, start, end - start);
3243
 
 
3244
 
        recv_scan_log_recs(TRUE,
3245
 
                           (buf_pool->n_frames
3246
 
                            - recv_n_pool_free_frames) * UNIV_PAGE_SIZE,
3247
 
                           FALSE, scan_buf, end - start,
3248
 
                           ut_dulint_align_down(buf_start_lsn,
3249
 
                                                OS_FILE_LOG_BLOCK_SIZE),
3250
 
                           &contiguous_lsn, &scanned_lsn);
3251
 
 
3252
 
        ut_a(ut_dulint_cmp(scanned_lsn, ut_dulint_add(buf_start_lsn, len))
3253
 
             == 0);
3254
 
        ut_a(ut_dulint_cmp(recv_sys->recovered_lsn, scanned_lsn) == 0);
3255
 
 
3256
 
        mem_free(buf1);
3257
 
 
3258
 
        return(TRUE);
3259
 
}
3260
 
 
3261
 
/**********************************************************
3262
 
Peeks the current lsn. */
3263
 
 
3264
 
ibool
3265
 
log_peek_lsn(
3266
 
/*=========*/
3267
 
                        /* out: TRUE if success, FALSE if could not get the
3268
 
                        log system mutex */
3269
 
        dulint* lsn)    /* out: if returns TRUE, current lsn is here */
3270
 
{
3271
 
        if (0 == mutex_enter_nowait(&(log_sys->mutex))) {
3272
 
                *lsn = log_sys->lsn;
3273
 
 
3274
 
                mutex_exit(&(log_sys->mutex));
3275
 
 
3276
 
                return(TRUE);
3277
 
        }
3278
 
 
3279
 
        return(FALSE);
3280
 
}
3281
 
 
3282
 
/**********************************************************
3283
 
Prints info of the log. */
3284
 
 
3285
 
void
3286
 
log_print(
3287
 
/*======*/
3288
 
        FILE*   file)   /* in: file where to print */
3289
 
{
3290
 
        double  time_elapsed;
3291
 
        time_t  current_time;
3292
 
 
3293
 
        mutex_enter(&(log_sys->mutex));
3294
 
 
3295
 
        fprintf(file,
3296
 
                "Log sequence number %lu %lu\n"
3297
 
                "Log flushed up to   %lu %lu\n"
3298
 
                "Last checkpoint at  %lu %lu\n",
3299
 
                (ulong) ut_dulint_get_high(log_sys->lsn),
3300
 
                (ulong) ut_dulint_get_low(log_sys->lsn),
3301
 
                (ulong) ut_dulint_get_high(log_sys->flushed_to_disk_lsn),
3302
 
                (ulong) ut_dulint_get_low(log_sys->flushed_to_disk_lsn),
3303
 
                (ulong) ut_dulint_get_high(log_sys->last_checkpoint_lsn),
3304
 
                (ulong) ut_dulint_get_low(log_sys->last_checkpoint_lsn));
3305
 
 
3306
 
        current_time = time(NULL);
3307
 
 
3308
 
        time_elapsed = 0.001 + difftime(current_time,
3309
 
                                        log_sys->last_printout_time);
3310
 
        fprintf(file,
3311
 
                "%lu pending log writes, %lu pending chkp writes\n"
3312
 
                "%lu log i/o's done, %.2f log i/o's/second\n",
3313
 
                (ulong) log_sys->n_pending_writes,
3314
 
                (ulong) log_sys->n_pending_checkpoint_writes,
3315
 
                (ulong) log_sys->n_log_ios,
3316
 
                ((log_sys->n_log_ios - log_sys->n_log_ios_old)
3317
 
                 / time_elapsed));
3318
 
 
3319
 
        log_sys->n_log_ios_old = log_sys->n_log_ios;
3320
 
        log_sys->last_printout_time = current_time;
3321
 
 
3322
 
        mutex_exit(&(log_sys->mutex));
3323
 
}
3324
 
 
3325
 
/**************************************************************************
3326
 
Refreshes the statistics used to print per-second averages. */
3327
 
 
3328
 
void
3329
 
log_refresh_stats(void)
3330
 
/*===================*/
3331
 
{
3332
 
        log_sys->n_log_ios_old = log_sys->n_log_ios;
3333
 
        log_sys->last_printout_time = time(NULL);
3334
 
}