Merge lp:~ihanick/percona-server/5.1-innodb-log_archiving into lp:percona-server/5.1
- 5.1-innodb-log_archiving
- Merge into 5.1
Status: | Work in progress |
---|---|
Proposed branch: | lp:~ihanick/percona-server/5.1-innodb-log_archiving |
Merge into: | lp:percona-server/5.1 |
Diff against target: |
2050 lines (+1499/-19) 26 files modified
Percona-Server/mysql-test/r/percona_server_variables_debug.result (+4/-0) Percona-Server/mysql-test/r/percona_server_variables_release.result (+4/-0) Percona-Server/mysql-test/suite/innodb_plugin/r/percona_log_archiving.result (+45/-0) Percona-Server/mysql-test/suite/innodb_plugin/t/percona_log_archiving-master.opt (+1/-0) Percona-Server/mysql-test/suite/innodb_plugin/t/percona_log_archiving.test (+191/-0) Percona-Server/sql/handler.cc (+42/-0) Percona-Server/sql/handler.h (+7/-0) Percona-Server/sql/lex.h (+1/-0) Percona-Server/sql/mysqld.cc (+2/-0) Percona-Server/sql/sql_lex.h (+2/-0) Percona-Server/sql/sql_parse.cc (+44/-1) Percona-Server/sql/sql_yacc.yy (+20/-0) Percona-Server/storage/innodb_plugin/fil/fil0fil.c (+222/-0) Percona-Server/storage/innodb_plugin/handler/ha_innodb.cc (+130/-0) Percona-Server/storage/innodb_plugin/include/fil0fil.h (+14/-1) Percona-Server/storage/innodb_plugin/include/log0log.h (+28/-0) Percona-Server/storage/innodb_plugin/include/log0log.ic (+4/-0) Percona-Server/storage/innodb_plugin/include/os0file.h (+14/-0) Percona-Server/storage/innodb_plugin/include/srv0srv.h (+22/-0) Percona-Server/storage/innodb_plugin/include/srv0start.h (+22/-0) Percona-Server/storage/innodb_plugin/log/log0log.c (+90/-3) Percona-Server/storage/innodb_plugin/os/os0file.c (+152/-0) Percona-Server/storage/innodb_plugin/srv/srv0srv.c (+366/-0) Percona-Server/storage/innodb_plugin/srv/srv0start.c (+12/-14) doc/source/index.rst (+1/-0) doc/source/management/innodb_log_archiving.rst (+59/-0) |
To merge this branch: | bzr merge lp:~ihanick/percona-server/5.1-innodb-log_archiving |
Related bugs: | |
Related blueprints: |
Log Archiving for XtraDB
(High)
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Laurynas Biveinis (community) | Needs Fixing | ||
Alexey Kopytov (community) | Needs Fixing | ||
Review via email: mp+103578@code.launchpad.net |
This proposal supersedes a proposal from 2012-04-03.
Commit message
Description of the change
https:/
Based on original Yasufumi work: ~percona-
How it works:
1) Additional log archiving thread created inside innodb if log archiving is enabled
2) new transaction log file is created by log archiving script at the start or right after finishing archiving process
3) If active innodb transaction log file is full empty transaction log swapped with the earliest used transaction log file
4) If we have innodb_
5) if innodb_
6) test case now not using temporary file names and not affected by slow testing environment
7) fixed problems from last MP
8) cross-filesystem archived log renaming
Additionally the patch contains PURGE ARCHIVED LOGS {BEFORE|TO} command and a new handlerton call: purge_archive_logs
Apr 4th:
Fixed problems from last MP:
- Added debug code to check file size on separate filesystem
- use 64bit offsets to copy archived logs
- Implemented and tested IO throttling
- Added innodb variable to control throttling
- use posix_fadvise to prevent caching
Apr 26th:
- fixed indentation and code line lengths
- fixed posix_fadvise usage
- fixed deadlock if archiving enabled dynamically
- Max checkpoint age now increased/decreased on archiving stop/start
Latest test run:
http://
Laurynas Biveinis (laurynas-biveinis) wrote : Posted in a previous version of this proposal | # |
Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal | # |
Nickolay,
I didn't review everything. Just thought it would be more efficient to do it iteratively.
Generally, I first suggest trying to make a debug build with your patch (I had a few issues see below), and then trying to run the percona_
So the comments I have so far:
- percona_
- compiler warning in srv0srv.c. I suggest replacing
if(expire_sec <= 0 || (ut_time() - fileinfo.mtime) <= expire_sec) {
with
if (ut_time() <= (ib_time_t)
- there is a compile-time assertion in debug builds, because the
patch introduces 2 new SQLCOM_ commands, but does not add the
corresponding SHOW STATUS variables to com_status_vars.
- there are unused 'protocol' variables in ha_purge_
and ha_purge_
- after fixing the above issues with debug builds, I got a runtime
assertion failure when trying to run the percona_log_archive
test. The reason is that PURGE ARCHIVED LOGS sends neither OK nor
error packet to the client. You should either call my_ok() and set
res to FALSE in mysql_execute_
res to TRUE, see purge_master_logs() for an example
- there are main.percona_
http://
- I think it's better to add the test to the innodb_plugin suite
rather than main one
- a more common way to pass test-specific options to mysqld is an
.opt file, not a .cnf file. there are lots of examples in existing
tests
- the test case does "drop table if exists t1;" but then creates and
uses table with the name 't'
- some unnecessary changes:
> @@ -645,5 +646,5 @@
> { "TRIM", SYM(TRIM)},
> { "VARIANCE", SYM(VARIANCE_SYM)},
> { "VAR_POP", SYM(VARIANCE_SYM)},
> - { "VAR_SAMP", SYM(VAR_SAMP_SYM)},
> + { "VAR_SAMP", SYM(VAR_SAMP_SYM)}
> };
>
and
> @@ -4560,6 +4560,8 @@
> return FALSE;
> }
>
> +
> +
> bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat)
> {
> List<Item> field_list;
>
and
> @@ -10709,9 +10710,12 @@ select_var_ident:
> ;
>
> purge_options:
> + ARCHIVED_SYM LOGS_SYM purge_archive_
> + |
> master_or_binary LOGS_SYM purge_option
> ;
>
> +
> purge_option:
> TO_SYM TEXT_STRING_sys
> {
>
- please remove commented code, e.g.:
> + //res = purge_master_
> + //fprintf(stderr, "purge archive logs command called %s\n", lex->to_log);
>
- SLEEPs in test cases almost never work. They definitely don't work
for synchronization, but unfortunately there's no way to
synchronize between mtr and InnoDB, especially when a background
InnoDB thread has to be executed synchronously. Which means we have
to modify tests to remove SLEEP()s possibly at the cost of test
covera...
Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal | # |
Nickolay,
The patch looks generally good to me, but I have a bunch of relatively minor comments:
- the patch makes ARCHIVED a reserved keyword (so, for example,
"CREATE TABLE archived(...)" succeeds in upstream server, but fails
in PS). Please add ARCHIVED_SYM to the keyword_sp rule in sql_yacc.yy
- innobase_
something odd. So innobase_
time up to which logs must be purged as its 'before_date'
argument. Basically, all we need to do is to traverse all files in
the archived logs directory and delete those with mtime <
before_date, right? Here's what actually happens:
- innobase_
before_date and passes that as the expire_sec argument to
- expire_sec argument is unsigned. So if you specify a point in
time in the future, i.e. "PURGE ARCHIVED LOGS BEFORE NOW() +
INTERVAL 1 MONTH" an overflow occurs and unexpected things may
happen depending on sizeof(time_t) in the OS
- purge_archived_
adds expire_sec and compares it with _current_ time again. So the
exact cut-off time is drifting, which may become a problem when
file deletion takes a long time (which is quite possible)
- on a side note, purge_archive_
expired_sec is 0. Why?
So why not just pass before_date to purge_archived_
compare mtime with it directly?
- I think fil_swap_file() does too much unnecessary work on POSIX
systems. It flushes the file being swapped, then waits for flush to
complete, then closes the file, just because allegedly "we do not
trust the operating systems can rename an open file". Well, they
actually can. It is in the POSIX standard. Windows can do that too,
but that requires a special flag when opening the file. Since
Windows is not a priority for us, I suggest enclosing the
unnecessary for POSIX code in #ifdef __WIN__. We can fix Windows
later and remove that code in fil_swap_file() completely.
- fil_swap_file() could use some descriptive comments for the
function itself and its arguments. Also, fil_rotate_file() would
probably be a bit more descriptive name.
- innobase_
function body must be protected by log_sys-
otherwise multiple concurrent threads calling that function can
result in multiple log archive threads being created.
- in innobase_
innobase_
rather than innodb_* variables directly. The comment "where the
formal string goes" in the var_ptr comment looks to be copy-pasted
and not applicable to those 2 functions?
- please don't use the Yoda notation, as in "if (FALSE ==
log_
- please use OS_FILE_MAX_PATH instead of 10000 in
purge_
- there are 2 open_or_...
Nickolay Ihalainen (ihanick) wrote : Posted in a previous version of this proposal | # |
jenkins build for revision 435
http://
Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal | # |
Nickolay,
If I'm not mistaken, the only change since my previous review comments is revision 435 with some changes to tests. It doesn't look like any of my comments have been addressed yet. Is that correct, or I am missing something? Just trying to understand if the patch is ready for review.
Nickolay Ihalainen (ihanick) wrote : Posted in a previous version of this proposal | # |
Alexey,
Sorry, just have found your comments at 2012-02-19.
I'm going to fix these problems today and tomorrow.
In lastest MP was fixed only 2012-02-13 problems.
Nickolay Ihalainen (ihanick) wrote : Posted in a previous version of this proposal | # |
Laurynas Biveinis (laurynas-biveinis) wrote : Posted in a previous version of this proposal | # |
percona_
of have_innodb.inc.
I second Alexey's comments that SLEEP in a testcase will not work
reliably. We can discuss alternatives on IRC.
sql/handler.cc changes are inconsistent in "foo = " vs "foo=". It
should be the latter in all cases.
Replace if (foo) return TRUE; else return FALSE; constructs with
return foo; (purge_
purge_
Replace (CONSTANT == var) with (var == CONSTANT) (same functions).
Diff line 365: s/data/date ?
Line 379: remove commented-out code
fil_rotate_file can be simplified greatly taking into account
Alexey's comment that we can rename open files.
innobase_
passed (i.e. no LSN in the file name), strtoll will return 0,
calling purge_archived_logs with before_lsn == 0, purging all the
files, which is probably not the best action. A testcase should be
added for this case and strtoll errors handled.
Similar issue is in purge_archived_
that is named like archive log file but malformed (no LSN) in the
archived log directory, strtoll will return 0 there to and the
correctness of purge_archived_logs needs to be checked.
The option descriptions:
Line 805: s/"Set to 1 if you want to have logs archived"/"Enables
log archiving".
Line 809: s/"Where full logs should be archived."/"Path to
archived logs directory"
Line 813: s/expire time/expiration time
fil_rotate_file declaration in fil0fil should have comments for
arguments too, as does the definition.
I have commented previously that new fields in log_sys struct
should be commented. I think a better name for archived_mutex
would be arch_sys_mutex or similar.
I have asked previously, why do the log_sys->lsn increases need to
be protected by the log_sys-
purge_
comment if both args should not be set at the same time or what
would happen if they are.
os_
redundant (the casted-to type is identical to the original type)
The header comment for open_or_
("Creates or opens the next log file and closes that")
srv_
comment before)
I am not sure I understand the error message in
srv_
be created. The above errors should be fixed
will retry 10 seconds later again.". What does it mean "should be
fixed"? Should a DBA be continuously monitoring the error log and
fixing something in 10 seconds?
Please use snprintf instead of sprintf everywhere to avoid buffer
overflows (except maybe in purge_archived_
could be safe, but I'm not sure and erring on the side of snprintf
is always safer).
Documentation will need some more work, maybe with Hrvoje's
help. It's OK fo...
Nickolay Ihalainen (ihanick) wrote : Posted in a previous version of this proposal | # |
> Documentation will need some more work, maybe with Hrvoje's
> help. It's OK for documentation changes to be in a separate MP.
Things should be discussed:
>
> I second Alexey's comments that SLEEP in a testcase will not work
> reliably. We can discuss alternatives on IRC.
> I am not sure I understand the error message in
> srv_log_
> be created. The above errors should be fixed
> will retry 10 seconds later again.". What does it mean "should be
> fixed"? Should a DBA be continuously monitoring the error log and
> fixing something in 10 seconds?
If logging is enabled we should guarantee that there is no missing files.
What we can do in disk full or invalid permissions situation?
> percona_
> of have_innodb.inc.
Done
> sql/handler.cc changes are inconsistent in "foo = " vs "foo=". It
> should be the latter in all cases.
done
> Replace if (foo) return TRUE; else return FALSE; constructs with
> return foo; (purge_
> purge_archive_
done
>
> Replace (CONSTANT == var) with (var == CONSTANT) (same functions).
> Diff line 365: s/data/date ?
> Line 379: remove commented-out code
done
>
> fil_rotate_file can be simplified greatly taking into account
> Alexey's comment that we can rename open files.
We should flush all blocks and close file before finishing archiving.
Should I split this function or this one will be fine?
> innobase_
> passed (i.e. no LSN in the file name), strtoll will return 0,
> calling purge_archived_logs with before_lsn == 0, purging all the
> files, which is probably not the best action. A testcase should be
> added for this case and strtoll errors handled.
Fixed, Should I add some error message/produce an warning?
>
> Similar issue is in purge_archived_
> that is named like archive log file but malformed (no LSN) in the
> archived log directory, strtoll will return 0 there to and the
> correctness of purge_archived_logs needs to be checked.
fixed
>
> The option descriptions:
> Line 805: s/"Set to 1 if you want to have logs archived"/"Enables
> log archiving".
> Line 809: s/"Where full logs should be archived."/"Path to
> archived logs directory"
> Line 813: s/expire time/expiration time
> fil_rotate_file declaration in fil0fil should have comments for
> arguments too, as does the definition.
done
>
> I have commented previously that new fields in log_sys struct
> should be commented. I think a better name for archived_mutex
> would be arch_sys_mutex or similar.
done
>
> I have asked previously, why do the log_sys->lsn increases need to
> be protected by the log_sys-
In srv_log_
archived_lsn value is also used to understand if we have enough space in logs inside log_write_low.
E.g. If two or more...
Nickolay Ihalainen (ihanick) wrote : Posted in a previous version of this proposal | # |
Laurynas Biveinis (laurynas-biveinis) wrote : Posted in a previous version of this proposal | # |
I only have cosmetic comments for this MP:
Re. current SLEEP in testsuite. As previously discussed, I believe
that it is "almost safe", but I wonder if the following may happen
on very busy testing servers: around the SLEEP(1) time, the log
archiving thread is starved (not scheduled to run), SLEEP(1)
completes, then log archiving thread executes and rotates the log,
failing the next list_files test. I don't know if that's maybe
just a theoretical case, and we cannot do much about it anyway
currently.
The handler entry purge_archive_logs perhaps could be better
named purge_archived_
have to resubmit the MP. Likewise for the new functions in handler.h|cc
The typo fix s/data/date in sql_parse.cc should be made in own
code, not in otherwise untouched upstream code (i.e. in
SQLCOM_
s/arhiving/
comments.
"0 == strcmp(
in srv_log_
Since my comments are so minor, I suggest to wait for Alexey's review before submitting a new MP.
Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal | # |
Nickolay,
I didn't have time to review everything, but the following code in os_file_
> + success = os_file_
> + ut_a(success);
> +
> + for (offset_high = 0; offset_
> + for (offset = 0; offset<
I see the following problems with it:
1. when size_high == 0 (i.e. the file size is < 4 GB), we will have 0 loop iterations, i.e. we won't copy anything.
2. when size_high = 2 and size_low = 1024*1024 (i.e. the file size is 8 GB + 1 MB), we will have 2 iterations, each copying 1 MB, so we'll copy 2 MB in total.
Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal | # |
Oops, it looks like I reviewed and commented on a superseded proposal. But that code is the same with the current MP, so my previous comment still holds.
Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal | # |
Nickolay,
- I think the implementation of file copying in os_file_
- I don't understand this code:
+ if (max_iops > 100 && ((offset_
+ os_thread_
So what value does the max_iops argument actually has? The comment says "number of I/O operations per second", but looking at the code above, that doesn't seem to be the case.
- max_iops doesn't have any effect, because the caller of os_file_
Nickolay Ihalainen (ihanick) wrote : Posted in a previous version of this proposal | # |
Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal | # |
Nickolay,
- please follow the InnoDB code style and limit the line
width to 80 characters at least in your code
- excessive indentation. instead of having:
if (ret != 0) {
long indented block;
}
return(TRUE);
wouldn't it be better to have:
if (ret == 0) {
return(TRUE); // or "goto end;"
}
// long block with less indentation
return(TRUE);
- the above also applies to the "if (err == EXDEV)" block
- POSIX_FADV_DONTNEED is used in a wrong way, see XtraBackup
bug #925441
- I think the following for loop:
for (offset = 0; offset <= file_size-
is equivalent to:
for (offset = 0; offset < file_size; offset += block_size) {
but is a bit easier to read.
Alexey Kopytov (akopytov) wrote : | # |
- as we discussed previously, the major problem with the current
approach is that when log archiving is enabled the maximum
checkpoint age is reduced by 1 log file size, which in the most
common configuration with 2 log files means the available log space
is reduced in half. but we will get to this issue later after
implementing the XtraBackup part of the task;
- another major problem that I discovered is that log archiving is
not crash-safe: a crash may lead to 1) partially written archive
files and 2) log archiving itself not being able to recover without
user intervention; We should fix that, let's discuss the details later;
Less significant problems:
- no error handling in innobase_
comment says "@return non-zero if error", but it always
returns zero. The same applies to purge_archived_
return an error code. Not having error handling in those functions
is bad because it's currently impossible for a user to know after
running PURGE ARCHIVED LOGS whether it was successful or not
without looking at the error log. Instead, the PURGE statement
itself should return an error to the client.
- while you're fixing innobase_
replace strstr() with is_prefix() and
strlen(
e.g. IB_ARCHIVED_
- as Laurynas wrote, the following change fixes a comment typo in the
upstream comment. please revert it:
> === modified file 'Percona-
> --- Percona-
> +++ Percona-
> @@ -2491,7 +2491,7 @@ mysql_execute_
>
> if (check_
> goto error;
> - /* PURGE MASTER LOGS BEFORE 'data' */
> + /* PURGE MASTER LOGS BEFORE 'date' */
> it= (Item *)lex->
> if ((!it->fixed && it->fix_
> it->check_cols(1))
>
- another change in the upstream code for no apparent reasons. Note
that it changes code inside #ifdef UNIV_LOG_ARCHIVE which is never
(and in fact, cannot be) enabled in Percona Server:
> @@ -852,7 +897,7 @@ log_init(void)
> #ifdef UNIV_LOG_ARCHIVE
> /* Under MySQL, log archiving is always off */
> log_sys-
> - log_sys-
> + log_sys-
> log_sys-
>
> log_sys-
>
that initialization should probably be outside of #ifdef UNIV_LOG_ARCHIVE?
- I wonder if we a failure in os_file_
result in a fatal error, i.e. an assertion failure. Currently, we
do crash if a read or a write fail on a throttled cross-device
copy. However, when rename() fails, we just return FALSE, which
only results in a "Note:" message in the error log. Which looks
inconsistent to me. E.g. if the destination directory does not
exist, or we have insufficient privileges to write to it, logs will
not be a...
Laurynas Biveinis (laurynas-biveinis) wrote : | # |
Due to log archiving running in a separate thread we need DBUG_SYNC in code/testcase at least between any places that produce log and check the archived log files, i.e. between last INSERT and following list_files_
In the code the sync point should be around os_event_
Unmerged revisions
- 449. By Nickolay Ihalainen
-
merge with 5.1 trunk
- 448. By Nickolay Ihalainen
-
Fixed deadlock if innodb_
xtra_log_ archive enabled dynamically. Correct posix_fadvise usage, indentation - 447. By Nickolay Ihalainen
-
Add log archiving copy throttle variable to percona server variables test results
- 446. By Nickolay Ihalainen
-
fix file copy for archived log located on separate disks: prevent caching cleanup
- 445. By Nickolay Ihalainen
-
log archiving, copy log to separate disk, increase chunk to 64 innodb pages.
- 444. By Nickolay Ihalainen
-
log archiving, copy log to separate disk: copy now uses 64bit offset, implemented throttling
- 443. By Nickolay Ihalainen
-
pull changes from 5.1 trunk
- 442. By Nickolay Ihalainen
-
fix file copy for archived log located on separate disks
- 441. By Nickolay Ihalainen
-
code standards, comments, test for invalid purge archived logs to filename
- 440. By Nickolay Ihalainen
-
Added missing comments
Preview Diff
1 | === modified file 'Percona-Server/mysql-test/r/percona_server_variables_debug.result' |
2 | --- Percona-Server/mysql-test/r/percona_server_variables_debug.result 2012-01-30 04:30:33 +0000 |
3 | +++ Percona-Server/mysql-test/r/percona_server_variables_debug.result 2012-04-25 22:22:24 +0000 |
4 | @@ -161,6 +161,10 @@ |
5 | INNODB_USE_SYS_STATS_TABLE |
6 | INNODB_VERSION |
7 | INNODB_WRITE_IO_THREADS |
8 | +INNODB_XTRA_EXPIRE_ARCHIVE_LOGS_SEC |
9 | +INNODB_XTRA_LOG_ARCHIVE |
10 | +INNODB_XTRA_LOG_ARCHIVE_DIR |
11 | +INNODB_XTRA_LOG_ARCHIVE_THROTTLE |
12 | INSERT_ID |
13 | INTERACTIVE_TIMEOUT |
14 | JOIN_BUFFER_SIZE |
15 | |
16 | === modified file 'Percona-Server/mysql-test/r/percona_server_variables_release.result' |
17 | --- Percona-Server/mysql-test/r/percona_server_variables_release.result 2011-11-24 02:01:33 +0000 |
18 | +++ Percona-Server/mysql-test/r/percona_server_variables_release.result 2012-04-25 22:22:24 +0000 |
19 | @@ -159,6 +159,10 @@ |
20 | INNODB_USE_SYS_STATS_TABLE |
21 | INNODB_VERSION |
22 | INNODB_WRITE_IO_THREADS |
23 | +INNODB_XTRA_EXPIRE_ARCHIVE_LOGS_SEC |
24 | +INNODB_XTRA_LOG_ARCHIVE |
25 | +INNODB_XTRA_LOG_ARCHIVE_DIR |
26 | +INNODB_XTRA_LOG_ARCHIVE_THROTTLE |
27 | INSERT_ID |
28 | INTERACTIVE_TIMEOUT |
29 | JOIN_BUFFER_SIZE |
30 | |
31 | === added file 'Percona-Server/mysql-test/suite/innodb_plugin/r/percona_log_archiving.result' |
32 | --- Percona-Server/mysql-test/suite/innodb_plugin/r/percona_log_archiving.result 1970-01-01 00:00:00 +0000 |
33 | +++ Percona-Server/mysql-test/suite/innodb_plugin/r/percona_log_archiving.result 2012-04-25 22:22:24 +0000 |
34 | @@ -0,0 +1,45 @@ |
35 | +drop table if exists t; |
36 | +create table t (a int not null) ENGINE=InnoDB; |
37 | +insert into t values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13); |
38 | +insert into t values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13); |
39 | +insert into t values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13); |
40 | +insert into t values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13); |
41 | +insert into t values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13); |
42 | +insert into t values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13); |
43 | +insert into t values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13); |
44 | +insert into t values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13); |
45 | +insert into t values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13); |
46 | +insert into t values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13); |
47 | +insert into t values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13); |
48 | +insert into t (a) select t1.a from t t1, t t2, t t3 LIMIT 100000; |
49 | +SELECT sleep(1); |
50 | +sleep(1) |
51 | +0 |
52 | +PURGE ARCHIVED LOGS BEFORE ("tmpval" + INTERVAL 1 SECOND); |
53 | +insert into t (a) select t1.a from t t1, t t2, t t3 LIMIT 100000; |
54 | +PURGE ARCHIVED LOGS TO "last_log_file_next"; |
55 | +insert into t (a) select t1.a from t t1, t t2, t t3 LIMIT 100000; |
56 | +PURGE ARCHIVED LOGS TO "ib_log_archive_#invalid"; |
57 | +last_log_file |
58 | +SET GLOBAL innodb_xtra_log_archive = OFF; |
59 | +SELECT @@innodb_xtra_log_archive; |
60 | +@@innodb_xtra_log_archive |
61 | +0 |
62 | +insert into t (a) select t1.a from t t1, t t2, t t3 LIMIT 100000; |
63 | +SET GLOBAL innodb_xtra_log_archive = ON; |
64 | +insert into t (a) select t1.a from t t1, t t2, t t3 LIMIT 100000; |
65 | +SELECT sleep(1); |
66 | +sleep(1) |
67 | +0 |
68 | +SET @saved_innodb_xtra_expire_archive_logs_sec = @@innodb_xtra_expire_archive_logs_sec; |
69 | +SET GLOBAL innodb_xtra_expire_archive_logs_sec = 1; |
70 | +insert into t (a) select t1.a from t t1, t t2, t t3 LIMIT 100000; |
71 | +SET GLOBAL innodb_xtra_expire_archive_logs_sec = @saved_innodb_xtra_expire_archive_logs_sec; |
72 | +SET @saved_innodb_xtra_log_archive_throttle = @@innodb_xtra_log_archive_throttle; |
73 | +SET GLOBAL innodb_xtra_log_archive_throttle = 10; |
74 | +insert into t (a) select t1.a from t t1, t t2, t t3 LIMIT 100000; |
75 | +SET GLOBAL innodb_xtra_log_archive_throttle = @saved_innodb_xtra_log_archive_throttle; |
76 | +last_log_file |
77 | +create table archived(id int); |
78 | +drop table archived; |
79 | +DROP TABLE t; |
80 | |
81 | === added file 'Percona-Server/mysql-test/suite/innodb_plugin/t/percona_log_archiving-master.opt' |
82 | --- Percona-Server/mysql-test/suite/innodb_plugin/t/percona_log_archiving-master.opt 1970-01-01 00:00:00 +0000 |
83 | +++ Percona-Server/mysql-test/suite/innodb_plugin/t/percona_log_archiving-master.opt 2012-04-25 22:22:24 +0000 |
84 | @@ -0,0 +1,1 @@ |
85 | +--innodb_xtra_log_archive=1 --innodb_xtra_log_archive_dir=logs_archive --innodb_xtra_expire_archive_logs_sec=3600 --innodb_log_file_size=2M |
86 | |
87 | === added file 'Percona-Server/mysql-test/suite/innodb_plugin/t/percona_log_archiving.test' |
88 | --- Percona-Server/mysql-test/suite/innodb_plugin/t/percona_log_archiving.test 1970-01-01 00:00:00 +0000 |
89 | +++ Percona-Server/mysql-test/suite/innodb_plugin/t/percona_log_archiving.test 2012-04-25 22:22:24 +0000 |
90 | @@ -0,0 +1,191 @@ |
91 | +--source include/have_innodb_plugin.inc |
92 | +--disable_warnings |
93 | +drop table if exists t; |
94 | +--enable_warnings |
95 | + |
96 | +let $MYSQLD_DATADIR= `SELECT @@datadir`; |
97 | +let $MYSQLD_ARCHIVEDIR= `SELECT IF( locate('/', @@innodb_xtra_log_archive_dir) = 1, @@innodb_xtra_log_archive_dir, CONCAT(@@datadir, @@innodb_xtra_log_archive_dir))`; |
98 | +let MYSQLD_ARCHIVEDIR = $MYSQLD_ARCHIVEDIR; |
99 | +--mkdir $MYSQLD_ARCHIVEDIR |
100 | + |
101 | +create table t (a int not null) ENGINE=InnoDB; |
102 | + |
103 | +insert into t values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13); |
104 | +insert into t values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13); |
105 | +insert into t values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13); |
106 | +insert into t values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13); |
107 | +insert into t values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13); |
108 | +insert into t values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13); |
109 | +insert into t values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13); |
110 | +insert into t values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13); |
111 | +insert into t values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13); |
112 | +insert into t values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13); |
113 | +insert into t values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13); |
114 | +insert into t (a) select t1.a from t t1, t t2, t t3 LIMIT 100000; |
115 | + |
116 | +--list_files_append_file $MYSQLTEST_VARDIR/tmp/archived_transaction_logs.list $MYSQLD_ARCHIVEDIR ib_log_archive_* |
117 | +# Set the purge time 1 second after the last modify time of last ib_log_archive_* |
118 | +perl; |
119 | +open FSRC, "<".$ENV{'MYSQLTEST_VARDIR'}.'/tmp/archived_transaction_logs.list' or die "Tmp file archived_transaction_logs.list not found"; |
120 | +open F, ">>".$ENV{'MYSQLTEST_VARDIR'}.'/tmp/percona_archived_logs.tmp' or die "Tmp file percona_archived_logs.tmp not found"; |
121 | +my $line; |
122 | +while(<FSRC>) { |
123 | + chomp; |
124 | + if( index( $_,'ib_log_archive_') >= 0 ) { |
125 | + $line = $_; |
126 | + } |
127 | +} |
128 | + |
129 | +my $binlogpath = $ENV{'MYSQLD_ARCHIVEDIR'}.'/'.$line; |
130 | +my @array = stat($binlogpath); |
131 | +my $filemodifytime = $array[9]; |
132 | +my @t = localtime $filemodifytime; |
133 | +my $modifytime = sprintf "%04u-%02u-%02u %02u:%02u:%02u",$t[5]+1900,$t[4]+1,$t[3],$t[2],$t[1],$t[0]; |
134 | +printf F ("let \$last_log_file = %s;\n", $line); |
135 | +printf F ("let \$tmpval = %s;\n", $modifytime); |
136 | +close F; |
137 | +EOF |
138 | + |
139 | +--source $MYSQLTEST_VARDIR/tmp/percona_archived_logs.tmp |
140 | +remove_file $MYSQLTEST_VARDIR/tmp/percona_archived_logs.tmp; |
141 | +remove_file $MYSQLTEST_VARDIR/tmp/archived_transaction_logs.list; |
142 | + |
143 | +SELECT sleep(1); |
144 | + |
145 | +--replace_result $tmpval tmpval |
146 | +--eval PURGE ARCHIVED LOGS BEFORE ("$tmpval" + INTERVAL 1 SECOND) |
147 | +--list_files $MYSQLD_ARCHIVEDIR $last_log_file |
148 | + |
149 | +insert into t (a) select t1.a from t t1, t t2, t t3 LIMIT 100000; |
150 | + |
151 | +--list_files_append_file $MYSQLTEST_VARDIR/tmp/archived_transaction_logs.list $MYSQLD_ARCHIVEDIR ib_log_archive_* |
152 | +# get last archived transaction log file |
153 | +perl; |
154 | +open FSRC, "<".$ENV{'MYSQLTEST_VARDIR'}.'/tmp/archived_transaction_logs.list' or die "Tmp file archived_transaction_logs.list not found"; |
155 | +open F, ">>".$ENV{'MYSQLTEST_VARDIR'}.'/tmp/percona_archived_logs.tmp' or die "Tmp file percona_archived_logs.tmp not found"; |
156 | +my $line; |
157 | +my $next_lsn_file; |
158 | +while(<FSRC>) { |
159 | + chomp; |
160 | + if( m/ib_log_archive_(\d+)$/ ) { $line = $_;$next_lsn_file = sprintf "ib_log_archive_%016d", ($1+1); } |
161 | +} |
162 | + |
163 | +printf F ("let \$last_log_file = %s;\n", $line); |
164 | +printf F ("let \$last_log_file_next = %s;\n", $next_lsn_file); |
165 | +close F; |
166 | +EOF |
167 | + |
168 | +--source $MYSQLTEST_VARDIR/tmp/percona_archived_logs.tmp |
169 | +remove_file $MYSQLTEST_VARDIR/tmp/percona_archived_logs.tmp; |
170 | +remove_file $MYSQLTEST_VARDIR/tmp/archived_transaction_logs.list; |
171 | + |
172 | +--replace_result $last_log_file_next last_log_file_next |
173 | +--eval PURGE ARCHIVED LOGS TO "$last_log_file_next" |
174 | +--list_files $MYSQLD_ARCHIVEDIR $last_log_file |
175 | + |
176 | +# check invalid filename |
177 | +insert into t (a) select t1.a from t t1, t t2, t t3 LIMIT 100000; |
178 | + |
179 | +--list_files_append_file $MYSQLTEST_VARDIR/tmp/archived_transaction_logs.list $MYSQLD_ARCHIVEDIR ib_log_archive_* |
180 | +# get last archived transaction log file |
181 | +perl; |
182 | +open FSRC, "<".$ENV{'MYSQLTEST_VARDIR'}.'/tmp/archived_transaction_logs.list' or die "Tmp file archived_transaction_logs.list not found"; |
183 | +open F, ">>".$ENV{'MYSQLTEST_VARDIR'}.'/tmp/percona_archived_logs.tmp' or die "Tmp file percona_archived_logs.tmp not found"; |
184 | +my $line; |
185 | +my $next_lsn_file; |
186 | +while(<FSRC>) { |
187 | + chomp; |
188 | + if( m/ib_log_archive_(\d+)$/ ) { $line = $_;$next_lsn_file = sprintf "ib_log_archive_%016d", ($1+1); } |
189 | +} |
190 | + |
191 | +printf F ("let \$last_log_file = %s;\n", $line); |
192 | +printf F ("let \$last_log_file_next = %s;\n", $next_lsn_file); |
193 | +close F; |
194 | +EOF |
195 | + |
196 | +--source $MYSQLTEST_VARDIR/tmp/percona_archived_logs.tmp |
197 | +remove_file $MYSQLTEST_VARDIR/tmp/percona_archived_logs.tmp; |
198 | +remove_file $MYSQLTEST_VARDIR/tmp/archived_transaction_logs.list; |
199 | + |
200 | +--eval PURGE ARCHIVED LOGS TO "ib_log_archive_#invalid" |
201 | +--replace_result $last_log_file last_log_file |
202 | +--list_files $MYSQLD_ARCHIVEDIR $last_log_file |
203 | +--remove_files_wildcard $MYSQLD_ARCHIVEDIR ib_log_archive_* |
204 | + |
205 | +# Check enable-disable |
206 | +SET GLOBAL innodb_xtra_log_archive = OFF; |
207 | +SELECT @@innodb_xtra_log_archive; |
208 | +insert into t (a) select t1.a from t t1, t t2, t t3 LIMIT 100000; |
209 | +--list_files $MYSQLD_ARCHIVEDIR ib_log_archive_* |
210 | +SET GLOBAL innodb_xtra_log_archive = ON; |
211 | + |
212 | + |
213 | +insert into t (a) select t1.a from t t1, t t2, t t3 LIMIT 100000; |
214 | + |
215 | +--list_files_append_file $MYSQLTEST_VARDIR/tmp/archived_transaction_logs.list $MYSQLD_ARCHIVEDIR ib_log_archive_* |
216 | +perl; |
217 | +open FSRC, "<".$ENV{'MYSQLTEST_VARDIR'}.'/tmp/archived_transaction_logs.list' or die "Tmp file archived_transaction_logs.list not found"; |
218 | +open F, ">>".$ENV{'MYSQLTEST_VARDIR'}.'/tmp/percona_archived_logs.tmp' or die "Tmp file percona_archived_logs.tmp not found"; |
219 | +my $line; |
220 | +while(<FSRC>) { |
221 | + chomp; |
222 | + if( index( $_,'ib_log_archive_') >= 0 ) { $line = $_; } |
223 | +} |
224 | + |
225 | +printf F ("let \$last_log_file = %s;", $line); |
226 | +close F; |
227 | +EOF |
228 | + |
229 | +--source $MYSQLTEST_VARDIR/tmp/percona_archived_logs.tmp |
230 | +remove_file $MYSQLTEST_VARDIR/tmp/percona_archived_logs.tmp; |
231 | +remove_file $MYSQLTEST_VARDIR/tmp/archived_transaction_logs.list; |
232 | + |
233 | +SELECT sleep(1); |
234 | + |
235 | +SET @saved_innodb_xtra_expire_archive_logs_sec = @@innodb_xtra_expire_archive_logs_sec; |
236 | +SET GLOBAL innodb_xtra_expire_archive_logs_sec = 1; |
237 | +insert into t (a) select t1.a from t t1, t t2, t t3 LIMIT 100000; |
238 | +--list_files $MYSQLD_ARCHIVEDIR $last_log_file |
239 | +SET GLOBAL innodb_xtra_expire_archive_logs_sec = @saved_innodb_xtra_expire_archive_logs_sec; |
240 | + |
241 | + |
242 | + |
243 | +# check throttle |
244 | +SET @saved_innodb_xtra_log_archive_throttle = @@innodb_xtra_log_archive_throttle; |
245 | +SET GLOBAL innodb_xtra_log_archive_throttle = 10; |
246 | +insert into t (a) select t1.a from t t1, t t2, t t3 LIMIT 100000; |
247 | +SET GLOBAL innodb_xtra_log_archive_throttle = @saved_innodb_xtra_log_archive_throttle; |
248 | + |
249 | +--list_files_append_file $MYSQLTEST_VARDIR/tmp/archived_transaction_logs.list $MYSQLD_ARCHIVEDIR ib_log_archive_* |
250 | +# get last archived transaction log file |
251 | +perl; |
252 | +open FSRC, "<".$ENV{'MYSQLTEST_VARDIR'}.'/tmp/archived_transaction_logs.list' or die "Tmp file archived_transaction_logs.list not found"; |
253 | +open F, ">>".$ENV{'MYSQLTEST_VARDIR'}.'/tmp/percona_archived_logs.tmp' or die "Tmp file percona_archived_logs.tmp not found"; |
254 | +my $line; |
255 | +my $next_lsn_file; |
256 | +while(<FSRC>) { |
257 | + chomp; |
258 | + if( m/ib_log_archive_(\d+)$/ ) { $line = $_;$next_lsn_file = sprintf "ib_log_archive_%016d", ($1+1); } |
259 | +} |
260 | + |
261 | +printf F ("let \$last_log_file = %s;\n", $line); |
262 | +printf F ("let \$last_log_file_next = %s;\n", $next_lsn_file); |
263 | +close F; |
264 | +EOF |
265 | + |
266 | +--source $MYSQLTEST_VARDIR/tmp/percona_archived_logs.tmp |
267 | +remove_file $MYSQLTEST_VARDIR/tmp/percona_archived_logs.tmp; |
268 | +remove_file $MYSQLTEST_VARDIR/tmp/archived_transaction_logs.list; |
269 | + |
270 | + |
271 | +--replace_result $last_log_file last_log_file |
272 | +--list_files $MYSQLD_ARCHIVEDIR $last_log_file |
273 | + |
274 | + |
275 | +create table archived(id int); |
276 | +drop table archived; |
277 | + |
278 | +DROP TABLE t; |
279 | + |
280 | +--remove_files_wildcard $MYSQLD_ARCHIVEDIR ib_log_archive_* |
281 | +--rmdir $MYSQLD_ARCHIVEDIR |
282 | |
283 | === modified file 'Percona-Server/sql/handler.cc' |
284 | --- Percona-Server/sql/handler.cc 2011-11-24 16:33:30 +0000 |
285 | +++ Percona-Server/sql/handler.cc 2012-04-25 22:22:24 +0000 |
286 | @@ -4597,6 +4597,48 @@ |
287 | return result; |
288 | } |
289 | |
290 | +static my_bool purge_archive_logs_handlerton(THD *thd, plugin_ref plugin, |
291 | + void *arg) |
292 | +{ |
293 | + ulong before_timestamp= *(ulong*) arg; |
294 | + handlerton *hton= plugin_data(plugin, handlerton *); |
295 | + |
296 | + if (hton->purge_archive_logs == NULL) |
297 | + return TRUE; |
298 | + |
299 | + return hton->purge_archive_logs(hton, before_timestamp, NULL); |
300 | +} |
301 | + |
302 | +bool ha_purge_archive_logs(THD *thd, handlerton *db_type, void* args) |
303 | +{ |
304 | + if (db_type == NULL) |
305 | + return plugin_foreach(thd, purge_archive_logs_handlerton, |
306 | + MYSQL_STORAGE_ENGINE_PLUGIN, args); |
307 | + |
308 | + return false; |
309 | +} |
310 | + |
311 | +static my_bool purge_archive_logs_to_handlerton(THD *thd, plugin_ref plugin, |
312 | + void *arg) |
313 | +{ |
314 | + const char* to_filename= (const char*) arg; |
315 | + handlerton *hton= plugin_data(plugin, handlerton *); |
316 | + |
317 | + if (hton->purge_archive_logs == NULL) |
318 | + return TRUE; |
319 | + |
320 | + return hton->purge_archive_logs(hton, 0, to_filename); |
321 | +} |
322 | + |
323 | +bool ha_purge_archive_logs_to(THD *thd, handlerton *db_type, void* args) |
324 | +{ |
325 | + if (db_type == NULL) |
326 | + return plugin_foreach(thd, purge_archive_logs_to_handlerton, |
327 | + MYSQL_STORAGE_ENGINE_PLUGIN, args); |
328 | + |
329 | + return false; |
330 | +} |
331 | + |
332 | /* |
333 | Function to check if the conditions for row-based binlogging is |
334 | correct for the table. |
335 | |
336 | === modified file 'Percona-Server/sql/handler.h' |
337 | --- Percona-Server/sql/handler.h 2012-01-17 14:05:16 +0000 |
338 | +++ Percona-Server/sql/handler.h 2012-04-25 22:22:24 +0000 |
339 | @@ -693,6 +693,8 @@ |
340 | int (*fill_files_table)(handlerton *hton, THD *thd, |
341 | TABLE_LIST *tables, |
342 | class Item *cond); |
343 | + int (*purge_archive_logs)(handlerton *hton, time_t before_date, const char* to_filename); |
344 | + |
345 | uint32 flags; /* global handler flags */ |
346 | /* |
347 | Those handlerton functions below are properly initialized at handler |
348 | @@ -2074,6 +2076,11 @@ |
349 | int ha_prepare(THD *thd); |
350 | int ha_recover(HASH *commit_list); |
351 | |
352 | +/* remove old archived transaction logs files */ |
353 | +bool ha_purge_archive_logs(THD *thd, handlerton *db_type, void* args); |
354 | +bool ha_purge_archive_logs_to(THD *thd, handlerton *db_type, void* args); |
355 | + |
356 | + |
357 | /* transactions: these functions never call handlerton functions directly */ |
358 | int ha_commit_trans(THD *thd, bool all); |
359 | int ha_autocommit_or_rollback(THD *thd, int error); |
360 | |
361 | === modified file 'Percona-Server/sql/lex.h' |
362 | --- Percona-Server/sql/lex.h 2011-11-24 02:01:23 +0000 |
363 | +++ Percona-Server/sql/lex.h 2012-04-25 22:22:24 +0000 |
364 | @@ -68,6 +68,7 @@ |
365 | { "ANALYZE", SYM(ANALYZE_SYM)}, |
366 | { "AND", SYM(AND_SYM)}, |
367 | { "ANY", SYM(ANY_SYM)}, |
368 | + { "ARCHIVED", SYM(ARCHIVED_SYM)}, |
369 | { "AS", SYM(AS)}, |
370 | { "ASC", SYM(ASC)}, |
371 | { "ASCII", SYM(ASCII_SYM)}, |
372 | |
373 | === modified file 'Percona-Server/sql/mysqld.cc' |
374 | --- Percona-Server/sql/mysqld.cc 2012-03-16 09:07:44 +0000 |
375 | +++ Percona-Server/sql/mysqld.cc 2012-04-25 22:22:24 +0000 |
376 | @@ -3070,6 +3070,8 @@ |
377 | {"prepare_sql", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_PREPARE]), SHOW_LONG_STATUS}, |
378 | {"purge", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_PURGE]), SHOW_LONG_STATUS}, |
379 | {"purge_before_date", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_PURGE_BEFORE]), SHOW_LONG_STATUS}, |
380 | + {"purge_archived", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_PURGE_ARCHIVE]), SHOW_LONG_STATUS}, |
381 | + {"purge_archived_before_date", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_PURGE_ARCHIVE_BEFORE]), SHOW_LONG_STATUS}, |
382 | {"release_savepoint", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_RELEASE_SAVEPOINT]), SHOW_LONG_STATUS}, |
383 | {"rename_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_RENAME_TABLE]), SHOW_LONG_STATUS}, |
384 | {"rename_user", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_RENAME_USER]), SHOW_LONG_STATUS}, |
385 | |
386 | === modified file 'Percona-Server/sql/sql_lex.h' |
387 | --- Percona-Server/sql/sql_lex.h 2011-11-24 02:01:33 +0000 |
388 | +++ Percona-Server/sql/sql_lex.h 2012-04-25 22:22:24 +0000 |
389 | @@ -130,6 +130,8 @@ |
390 | // TODO(mcallaghan): update status_vars in mysqld to export these |
391 | SQLCOM_SHOW_USER_STATS, SQLCOM_SHOW_TABLE_STATS, SQLCOM_SHOW_INDEX_STATS, |
392 | SQLCOM_SHOW_CLIENT_STATS, SQLCOM_SHOW_THREAD_STATS, |
393 | + SQLCOM_PURGE_ARCHIVE, |
394 | + SQLCOM_PURGE_ARCHIVE_BEFORE, |
395 | /* This should be the last !!! */ |
396 | SQLCOM_END |
397 | }; |
398 | |
399 | === modified file 'Percona-Server/sql/sql_parse.cc' |
400 | --- Percona-Server/sql/sql_parse.cc 2011-11-24 16:33:30 +0000 |
401 | +++ Percona-Server/sql/sql_parse.cc 2012-04-25 22:22:24 +0000 |
402 | @@ -2491,7 +2491,7 @@ |
403 | |
404 | if (check_global_access(thd, SUPER_ACL)) |
405 | goto error; |
406 | - /* PURGE MASTER LOGS BEFORE 'data' */ |
407 | + /* PURGE MASTER LOGS BEFORE 'date' */ |
408 | it= (Item *)lex->value_list.head(); |
409 | if ((!it->fixed && it->fix_fields(lex->thd, &it)) || |
410 | it->check_cols(1)) |
411 | @@ -2508,6 +2508,49 @@ |
412 | res = purge_master_logs_before_date(thd, (ulong)it->val_int()); |
413 | break; |
414 | } |
415 | + case SQLCOM_PURGE_ARCHIVE: |
416 | + { |
417 | + if (check_global_access(thd, SUPER_ACL)) |
418 | + goto error; |
419 | + /* PURGE ARCHIVED LOGS TO 'file' */ |
420 | + if (ha_purge_archive_logs_to(NULL, NULL, lex->to_log)) { |
421 | + my_ok(thd); |
422 | + } else { |
423 | + my_error(ER_LOG_PURGE_UNKNOWN_ERR, MYF(0), "PURGE ARCHIVE LOGS TO"); |
424 | + goto error; |
425 | + } |
426 | + |
427 | + break; |
428 | + } |
429 | + case SQLCOM_PURGE_ARCHIVE_BEFORE: |
430 | + { |
431 | + Item *it; |
432 | + |
433 | + if (check_global_access(thd, SUPER_ACL)) |
434 | + goto error; |
435 | + /* PURGE ARCHIVE LOGS BEFORE 'data' */ |
436 | + it= (Item *)lex->value_list.head(); |
437 | + if ((!it->fixed && it->fix_fields(lex->thd, &it)) || |
438 | + it->check_cols(1)) |
439 | + { |
440 | + my_error(ER_WRONG_ARGUMENTS, MYF(0), "PURGE ARCHIVE LOGS BEFORE"); |
441 | + goto error; |
442 | + } |
443 | + it= new Item_func_unix_timestamp(it); |
444 | + /* |
445 | + it is OK only emulate fix_fieds, because we need only |
446 | + value of constant |
447 | + */ |
448 | + it->quick_fix_field(); |
449 | + ulong before_timestamp = (ulong)it->val_int(); |
450 | + if (ha_purge_archive_logs(NULL, NULL, &before_timestamp )) { |
451 | + my_ok(thd); |
452 | + } else { |
453 | + my_error(ER_LOG_PURGE_UNKNOWN_ERR, MYF(0), "PURGE ARCHIVE LOGS BEFORE"); |
454 | + goto error; |
455 | + } |
456 | + break; |
457 | + } |
458 | #endif |
459 | case SQLCOM_SHOW_WARNS: |
460 | { |
461 | |
462 | === modified file 'Percona-Server/sql/sql_yacc.yy' |
463 | --- Percona-Server/sql/sql_yacc.yy 2012-04-02 02:09:15 +0000 |
464 | +++ Percona-Server/sql/sql_yacc.yy 2012-04-25 22:22:24 +0000 |
465 | @@ -714,6 +714,7 @@ |
466 | %token AND_AND_SYM /* OPERATOR */ |
467 | %token AND_SYM /* SQL-2003-R */ |
468 | %token ANY_SYM /* SQL-2003-R */ |
469 | +%token ARCHIVED_SYM /* MYSQL */ |
470 | %token AS /* SQL-2003-R */ |
471 | %token ASC /* SQL-2003-N */ |
472 | %token ASCII_SYM /* MYSQL-FUNC */ |
473 | @@ -10715,6 +10716,8 @@ |
474 | ; |
475 | |
476 | purge_options: |
477 | + ARCHIVED_SYM LOGS_SYM purge_archive_option |
478 | + | |
479 | master_or_binary LOGS_SYM purge_option |
480 | ; |
481 | |
482 | @@ -10732,6 +10735,22 @@ |
483 | } |
484 | ; |
485 | |
486 | +purge_archive_option: |
487 | + TO_SYM TEXT_STRING_sys |
488 | + { |
489 | + Lex->to_log = $2.str; |
490 | + Lex->sql_command= SQLCOM_PURGE_ARCHIVE; |
491 | + } |
492 | + | BEFORE_SYM expr |
493 | + { |
494 | + LEX *lex= Lex; |
495 | + lex->value_list.empty(); |
496 | + lex->value_list.push_front($2); |
497 | + lex->sql_command= SQLCOM_PURGE_ARCHIVE_BEFORE; |
498 | + } |
499 | + ; |
500 | + |
501 | + |
502 | /* kill threads */ |
503 | |
504 | kill: |
505 | @@ -11776,6 +11795,7 @@ |
506 | | AGGREGATE_SYM {} |
507 | | ALGORITHM_SYM {} |
508 | | ANY_SYM {} |
509 | + | ARCHIVED_SYM {} |
510 | | AT_SYM {} |
511 | | AUTHORS_SYM {} |
512 | | AUTO_INC {} |
513 | |
514 | === modified file 'Percona-Server/storage/innodb_plugin/fil/fil0fil.c' |
515 | --- Percona-Server/storage/innodb_plugin/fil/fil0fil.c 2012-04-02 02:09:15 +0000 |
516 | +++ Percona-Server/storage/innodb_plugin/fil/fil0fil.c 2012-04-25 22:22:24 +0000 |
517 | @@ -2658,6 +2658,228 @@ |
518 | return(success); |
519 | } |
520 | |
521 | +/********************************************************************//** |
522 | +Rotates tablespace like logrotate does: renames tablespace file, |
523 | +new tablespace file is created with the same name and tablespace header |
524 | +as original tablespace |
525 | +@return TRUE if success */ |
526 | +UNIV_INTERN |
527 | +ibool |
528 | +fil_rotate_file( |
529 | +/*==========*/ |
530 | + ulint id, /*!< in: space id */ |
531 | + ulint block_offset_in, /*!< in: header offset in a tablespace */ |
532 | + const char* old_file_rename_to, /*!< in: src tablespace file name */ |
533 | + const char* new_file_rename_from, /*!< in: dst tablespace file name */ |
534 | + ulint hdr_size) /*!< in: tablespace header size */ |
535 | + |
536 | +{ |
537 | + ibool success; |
538 | + fil_space_t* space; |
539 | + fil_node_t* node; |
540 | + ulint block_offset; |
541 | + os_file_t file; |
542 | + ulint size; |
543 | + ulint size_high; |
544 | + ulint count = 0; |
545 | + |
546 | + byte* buf_ptr = NULL; |
547 | + byte* buf = NULL; |
548 | + |
549 | + ut_a(id != 0); |
550 | + |
551 | +retry: |
552 | + block_offset = block_offset_in; |
553 | + count++; |
554 | + |
555 | + if (count > 1000) { |
556 | + ut_print_timestamp(stderr); |
557 | + fputs(" InnoDB: Warning: problems renaming ", stderr); |
558 | + ut_print_filename(stderr, old_file_rename_to); |
559 | + fputs(" or ", stderr); |
560 | + ut_print_filename(stderr, new_file_rename_from); |
561 | + fprintf(stderr, ", %lu iterations\n", (ulong) count); |
562 | + } |
563 | + |
564 | + mutex_enter(&fil_system->mutex); |
565 | + |
566 | + space = fil_space_get_by_id(id); |
567 | + |
568 | + if (space == NULL) { |
569 | + fprintf(stderr, |
570 | + "InnoDB: Error: cannot find space id %lu" |
571 | + " in the tablespace memory cache\n", |
572 | + (ulong) id); |
573 | + mutex_exit(&fil_system->mutex); |
574 | + |
575 | + return(FALSE); |
576 | + } |
577 | + |
578 | + if (count > 25000) { |
579 | +error_exit: |
580 | + space->stop_ios = FALSE; |
581 | + mutex_exit(&fil_system->mutex); |
582 | + |
583 | + if (buf_ptr) { |
584 | + ut_free(buf_ptr); |
585 | + } |
586 | + |
587 | + return(FALSE); |
588 | + } |
589 | + |
590 | + /* We temporarily close the .ibd file because we do not trust that |
591 | + operating systems can rename an open file. For the closing we have to |
592 | + wait until there are no pending i/o's or flushes on the file. */ |
593 | + |
594 | + space->stop_ios = TRUE; |
595 | + |
596 | + node = UT_LIST_GET_FIRST(space->chain); |
597 | + |
598 | + for (;;) { |
599 | + if (UNIV_UNLIKELY(node == NULL)) { |
600 | + fprintf(stderr, |
601 | + "InnoDB: Error: The specified block_offset %lu" |
602 | + " in space %lu,\n" |
603 | + "InnoDB: space name %s, which is outside the tablespace bounds.\n", |
604 | + (ulong) block_offset, (ulong) id, |
605 | + space->name); |
606 | + |
607 | + goto error_exit; |
608 | + } |
609 | + |
610 | + ut_a(node->size != 0); |
611 | + |
612 | + if (node->size > block_offset) { |
613 | + /* Found! */ |
614 | + break; |
615 | + } else { |
616 | + block_offset -= node->size; |
617 | + node = UT_LIST_GET_NEXT(chain, node); |
618 | + } |
619 | + } |
620 | + |
621 | + if (node->n_pending > 0 || node->n_pending_flushes > 0) { |
622 | + /* There are pending i/o's or flushes, sleep for a while and |
623 | + retry */ |
624 | + |
625 | + mutex_exit(&fil_system->mutex); |
626 | + |
627 | + os_thread_sleep(20000); |
628 | + |
629 | + goto retry; |
630 | + |
631 | + } else if (node->modification_counter > node->flush_counter) { |
632 | + /* Flush the space */ |
633 | + |
634 | + mutex_exit(&fil_system->mutex); |
635 | + |
636 | + os_thread_sleep(20000); |
637 | + |
638 | + fil_flush(id, TRUE); |
639 | + |
640 | + goto retry; |
641 | + |
642 | + } else if (node->open) { |
643 | + /* Close the file */ |
644 | + |
645 | + fil_node_close_file(node, fil_system); |
646 | + } |
647 | + |
648 | + /* store old header */ |
649 | + if (hdr_size > 0) { |
650 | + buf_ptr = ut_malloc(2 * hdr_size); |
651 | + buf = ut_align(buf_ptr, hdr_size); |
652 | + |
653 | + file = os_file_create(node->name, OS_FILE_OPEN, OS_FILE_NORMAL, |
654 | + OS_LOG_FILE, &success); |
655 | + ut_a(success); |
656 | + |
657 | + success = os_file_read(file, buf, 0, 0, hdr_size); |
658 | + ut_a(success); |
659 | + |
660 | + os_file_close(file); |
661 | + } |
662 | + |
663 | + /* check size of the new file */ |
664 | + file = os_file_create(new_file_rename_from, OS_FILE_OPEN, OS_FILE_NORMAL, |
665 | + OS_LOG_FILE, &success); |
666 | + if (!success) { |
667 | + fprintf(stderr, |
668 | + "InnoDB: Error in opening %s\n", new_file_rename_from); |
669 | + goto error_exit; |
670 | + } |
671 | + |
672 | + success = os_file_get_size(file, &size, &size_high); |
673 | + ut_a(success); |
674 | + |
675 | + if (size != (0xFFFFFFFFUL & (node->size << UNIV_PAGE_SIZE_SHIFT)) |
676 | + || size_high != (node->size >> (32 - UNIV_PAGE_SIZE_SHIFT))) { |
677 | + fprintf(stderr, |
678 | + "InnoDB: Error: file %s is" |
679 | + " of different size %lu %lu bytes\n" |
680 | + "InnoDB: than intended %lu %lu bytes!\n", |
681 | + new_file_rename_from, (ulong) size_high, (ulong) size, |
682 | + (ulong) (node->size >> (32 - UNIV_PAGE_SIZE_SHIFT)), |
683 | + (ulong) (0xFFFFFFFFUL & (node->size << UNIV_PAGE_SIZE_SHIFT))); |
684 | + os_file_close(file); |
685 | + goto error_exit; |
686 | + } |
687 | + |
688 | + /* copy stored header */ |
689 | + if (hdr_size > 0) { |
690 | + success = os_file_write(new_file_rename_from, file, buf, 0, 0, hdr_size); |
691 | + if (!success) { |
692 | + fprintf(stderr, |
693 | + "InnoDB: Error: failed to initialize" |
694 | + " header of %s\n", |
695 | + new_file_rename_from); |
696 | + os_file_close(file); |
697 | + goto error_exit; |
698 | + } |
699 | + success = os_file_flush(file, TRUE); |
700 | + if (!success) { |
701 | + fprintf(stderr, |
702 | + "InnoDB: Error: failed to initialize" |
703 | + " header of %s\n", |
704 | + new_file_rename_from); |
705 | + os_file_close(file); |
706 | + goto error_exit; |
707 | + } |
708 | + } |
709 | + |
710 | + success = os_file_close(file); |
711 | + ut_a(success); |
712 | + |
713 | + /* Rename the tablespace and the node in the memory cache */ |
714 | + success = os_file_rename(node->name, old_file_rename_to); |
715 | + |
716 | + if (success) { |
717 | + success = os_file_rename(new_file_rename_from, node->name); |
718 | + |
719 | + if (!success) { |
720 | + ut_a(os_file_rename(old_file_rename_to, node->name)); |
721 | + } |
722 | + } |
723 | + |
724 | + if (success) { |
725 | + fprintf(stderr, |
726 | + "InnoDB: file %s was renamed to %s\n" |
727 | + "InnoDB: file %s was renamed to %s\n", |
728 | + node->name, old_file_rename_to, |
729 | + new_file_rename_from, node->name); |
730 | + } |
731 | + |
732 | + space->stop_ios = FALSE; |
733 | + |
734 | + mutex_exit(&fil_system->mutex); |
735 | + |
736 | + if (buf_ptr) { |
737 | + ut_free(buf_ptr); |
738 | + } |
739 | + |
740 | + return(success); |
741 | +} |
742 | + |
743 | /*******************************************************************//** |
744 | Creates a new single-table tablespace to a database directory of MySQL. |
745 | Database directories are under the 'datadir' of MySQL. The datadir is the |
746 | |
747 | === modified file 'Percona-Server/storage/innodb_plugin/handler/ha_innodb.cc' |
748 | --- Percona-Server/storage/innodb_plugin/handler/ha_innodb.cc 2012-04-02 02:09:15 +0000 |
749 | +++ Percona-Server/storage/innodb_plugin/handler/ha_innodb.cc 2012-04-25 22:22:24 +0000 |
750 | @@ -186,6 +186,10 @@ |
751 | static my_bool innobase_log_archive = FALSE; |
752 | static char* innobase_log_arch_dir = NULL; |
753 | #endif /* UNIV_LOG_ARCHIVE */ |
754 | +static my_bool innobase_xtra_log_archive = FALSE; |
755 | +static char* innobase_xtra_log_archive_dir = NULL; |
756 | +static ulong innodb_xtra_expire_archive_logs_sec = 0; |
757 | +static uint innodb_xtra_archive_logs_throttle = 0; |
758 | static my_bool innobase_use_doublewrite = TRUE; |
759 | static my_bool innobase_use_checksums = TRUE; |
760 | static my_bool innobase_fast_checksum = FALSE; |
761 | @@ -316,6 +320,31 @@ |
762 | static const char innobase_hton_name[]= "InnoDB"; |
763 | |
764 | /*************************************************************//** |
765 | +Removes old archived transaction log files. |
766 | +@return non-zero if error */ |
767 | +static int innobase_purge_archive_logs( |
768 | + handlerton *hton, /*!< in: InnoDB handlerton */ |
769 | + time_t before_date, /*!< in: all files modified |
770 | + before timestamp should be removed */ |
771 | + const char* to_filename) /*!< in: this and earler files |
772 | + should be removed */ |
773 | +{ |
774 | + if (before_date > 0) { |
775 | + purge_archived_logs(before_date, 0); |
776 | + } else if (to_filename) { |
777 | + if (strstr(to_filename, IB_ARCHIVED_LOGS_PREFIX) == to_filename) { |
778 | + unsigned long long log_file_lsn = strtoll(to_filename |
779 | + + strlen(IB_ARCHIVED_LOGS_PREFIX), |
780 | + NULL, 10); |
781 | + if (log_file_lsn > 0) { |
782 | + purge_archived_logs(0, log_file_lsn); |
783 | + } |
784 | + } |
785 | + } |
786 | + return 0; |
787 | +} |
788 | + |
789 | +/*************************************************************//** |
790 | Check for a valid value of innobase_commit_concurrency. |
791 | @return 0 for valid innodb_commit_concurrency */ |
792 | static |
793 | @@ -2134,6 +2163,7 @@ |
794 | innobase_hton->flags=HTON_NO_FLAGS; |
795 | innobase_hton->release_temporary_latches=innobase_release_temporary_latches; |
796 | innobase_hton->alter_table_flags = innobase_alter_table_flags; |
797 | + innobase_hton->purge_archive_logs = innobase_purge_archive_logs; |
798 | |
799 | ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR); |
800 | |
801 | @@ -2503,6 +2533,15 @@ |
802 | #ifdef UNIV_LOG_ARCHIVE |
803 | srv_log_archive_on = (ulint) innobase_log_archive; |
804 | #endif /* UNIV_LOG_ARCHIVE */ |
805 | + log_xtra_log_archive_on = (ulint) innobase_xtra_log_archive; |
806 | + log_xtra_log_arch_expire_sec = (ulint) innodb_xtra_expire_archive_logs_sec; |
807 | + log_xtra_log_arch_throttle = (ulint) innodb_xtra_archive_logs_throttle; |
808 | + |
809 | + if (innobase_xtra_log_archive_dir && strlen(innobase_xtra_log_archive_dir) > 0) { |
810 | + log_xtra_log_archive_dir = innobase_xtra_log_archive_dir; |
811 | + } else { |
812 | + log_xtra_log_archive_dir = innobase_log_group_home_dir; |
813 | + } |
814 | srv_log_buffer_size = (ulint) innobase_log_buffer_size; |
815 | |
816 | srv_buf_pool_size = (ulint) innobase_buffer_pool_size; |
817 | @@ -11320,6 +11359,75 @@ |
818 | } |
819 | |
820 | /****************************************************************//** |
821 | +Update the system variable innobase_log_archive using the "saved" |
822 | +value. This function is registered as a callback with MySQL. */ |
823 | +static |
824 | +void |
825 | +innobase_log_archive_update( |
826 | +/*==============================*/ |
827 | + THD* thd, /*!< in: thread handle */ |
828 | + struct st_mysql_sys_var* var, /*!< in: pointer to |
829 | + system variable */ |
830 | + void* var_ptr, /*!< out: unused */ |
831 | + const void* save) /*!< in: immediate result |
832 | + from check function */ |
833 | +{ |
834 | + mutex_enter(&(log_sys->arch_sys_mutex)); |
835 | + if (*(my_bool*) save) { |
836 | + if (log_xtra_log_archive_on == FALSE) { |
837 | + log_sys->archived_lsn=0; |
838 | + innobase_xtra_log_archive=TRUE; |
839 | + log_xtra_log_archive_on=TRUE; |
840 | + os_thread_create(&srv_log_archive_thread, NULL, NULL); |
841 | + } |
842 | + } else { |
843 | + if (log_xtra_log_archive_on == TRUE) { |
844 | + innobase_xtra_log_archive=FALSE; |
845 | + log_xtra_log_archive_on=FALSE; |
846 | + os_event_set(log_sys->arch_event_rotate_start); |
847 | + } |
848 | + } |
849 | + mutex_exit(&(log_sys->arch_sys_mutex)); |
850 | +} |
851 | + |
852 | +/****************************************************************//** |
853 | +Update the system variable innodb_xtra_expire_archive_logs_sec using |
854 | +the "saved" value. This function is registered as a callback with MySQL. */ |
855 | +static |
856 | +void |
857 | +innobase_log_archive_expire_update( |
858 | +/*==============================*/ |
859 | + THD* thd, /*!< in: thread handle */ |
860 | + struct st_mysql_sys_var* var, /*!< in: pointer to |
861 | + system variable */ |
862 | + void* var_ptr, /*!< out: unused */ |
863 | + const void* save) /*!< in: immediate result |
864 | + from check function */ |
865 | +{ |
866 | + mutex_enter(&(log_sys->arch_sys_mutex)); |
867 | + log_xtra_log_arch_expire_sec = innodb_xtra_expire_archive_logs_sec = *(ulint*) save; |
868 | + mutex_exit(&(log_sys->arch_sys_mutex)); |
869 | +} |
870 | +/****************************************************************//** |
871 | +Update the system variable innodb_xtra_expire_archive_logs_sec using |
872 | +the "saved" value. This function is registered as a callback with MySQL. */ |
873 | +static |
874 | +void |
875 | +innobase_log_archive_throttle_update( |
876 | +/*==============================*/ |
877 | + THD* thd, /*!< in: thread handle */ |
878 | + struct st_mysql_sys_var* var, /*!< in: pointer to |
879 | + system variable */ |
880 | + void* var_ptr, /*!< out: unused */ |
881 | + const void* save) /*!< in: immediate result |
882 | + from check function */ |
883 | +{ |
884 | + mutex_enter(&(log_sys->arch_sys_mutex)); |
885 | + log_xtra_log_arch_throttle = innodb_xtra_archive_logs_throttle = *static_cast<const uint*>(save); |
886 | + mutex_exit(&(log_sys->arch_sys_mutex)); |
887 | +} |
888 | + |
889 | +/****************************************************************//** |
890 | Update the system variable innodb_old_blocks_pct using the "saved" |
891 | value. This function is registered as a callback with MySQL. */ |
892 | static |
893 | @@ -11680,6 +11788,24 @@ |
894 | "Set to 1 if you want to have logs archived.", NULL, NULL, FALSE); |
895 | #endif /* UNIV_LOG_ARCHIVE */ |
896 | |
897 | +static MYSQL_SYSVAR_BOOL(xtra_log_archive, innobase_xtra_log_archive, |
898 | + PLUGIN_VAR_OPCMDARG, |
899 | + "Enables log archiving.", NULL, innobase_log_archive_update, FALSE); |
900 | + |
901 | +static MYSQL_SYSVAR_STR(xtra_log_archive_dir, innobase_xtra_log_archive_dir, |
902 | + PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, |
903 | + "Path to archived logs directory.", NULL, NULL, NULL); |
904 | + |
905 | +static MYSQL_SYSVAR_ULONG(xtra_expire_archive_logs_sec, innodb_xtra_expire_archive_logs_sec, |
906 | + PLUGIN_VAR_OPCMDARG, |
907 | + "Expiration time for archived innodb transaction logs.", |
908 | + NULL, innobase_log_archive_expire_update, 0, 0, ~0L, 0); |
909 | + |
910 | +static MYSQL_SYSVAR_UINT(xtra_log_archive_throttle, innodb_xtra_archive_logs_throttle, |
911 | + PLUGIN_VAR_OPCMDARG, |
912 | + "number of read+write pairs of operations per second for archived innodb transaction logs cross device copy operation.", |
913 | + NULL, innobase_log_archive_throttle_update, 0, 0, ~0L, 0); |
914 | + |
915 | static MYSQL_SYSVAR_STR(log_group_home_dir, innobase_log_group_home_dir, |
916 | PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, |
917 | "Path to InnoDB log files.", NULL, NULL, NULL); |
918 | @@ -12121,6 +12247,10 @@ |
919 | MYSQL_SYSVAR(log_arch_dir), |
920 | MYSQL_SYSVAR(log_archive), |
921 | #endif /* UNIV_LOG_ARCHIVE */ |
922 | + MYSQL_SYSVAR(xtra_log_archive), |
923 | + MYSQL_SYSVAR(xtra_log_archive_dir), |
924 | + MYSQL_SYSVAR(xtra_expire_archive_logs_sec), |
925 | + MYSQL_SYSVAR(xtra_log_archive_throttle), |
926 | MYSQL_SYSVAR(log_buffer_size), |
927 | MYSQL_SYSVAR(log_file_size), |
928 | MYSQL_SYSVAR(log_files_in_group), |
929 | |
930 | === modified file 'Percona-Server/storage/innodb_plugin/include/fil0fil.h' |
931 | --- Percona-Server/storage/innodb_plugin/include/fil0fil.h 2011-12-09 16:53:35 +0000 |
932 | +++ Percona-Server/storage/innodb_plugin/include/fil0fil.h 2012-04-25 22:22:24 +0000 |
933 | @@ -426,7 +426,20 @@ |
934 | const char* new_name); /*!< in: new table name in the standard |
935 | databasename/tablename format |
936 | of InnoDB */ |
937 | - |
938 | +/********************************************************************//** |
939 | +Rotates tablespace like logrotate does: renames tablespace file, |
940 | +new tablespace file is created with the same name and tablespace header |
941 | +as original tablespace |
942 | +@return TRUE if success */ |
943 | +UNIV_INTERN |
944 | +ibool |
945 | +fil_rotate_file( |
946 | +/*==========*/ |
947 | + ulint id, /*!< in: space id */ |
948 | + ulint block_offset_in, /*!< in: header offset in a tablespace */ |
949 | + const char* old_file_rename_to, /*!< in: src tablespace file name */ |
950 | + const char* new_file_rename_from, /*!< in: dst tablespace file name */ |
951 | + ulint hdr_size); /*!< in: tablespace header size */ |
952 | /*******************************************************************//** |
953 | Creates a new single-table tablespace to a database directory of MySQL. |
954 | Database directories are under the 'datadir' of MySQL. The datadir is the |
955 | |
956 | === modified file 'Percona-Server/storage/innodb_plugin/include/log0log.h' |
957 | --- Percona-Server/storage/innodb_plugin/include/log0log.h 2012-04-02 02:09:15 +0000 |
958 | +++ Percona-Server/storage/innodb_plugin/include/log0log.h 2012-04-25 22:22:24 +0000 |
959 | @@ -56,6 +56,10 @@ |
960 | # define log_do_write TRUE |
961 | #endif /* UNIV_DEBUG */ |
962 | |
963 | +extern ibool log_xtra_log_archive_on; |
964 | +extern const char* log_xtra_log_archive_dir; |
965 | +extern time_t log_xtra_log_arch_expire_sec; |
966 | +extern uint log_xtra_log_arch_throttle; |
967 | /** Wait modes for log_write_up_to @{ */ |
968 | #define LOG_NO_WAIT 91 |
969 | #define LOG_WAIT_ONE_GROUP 92 |
970 | @@ -75,6 +79,26 @@ |
971 | /*==========================================*/ |
972 | ulint limit); /*!< in: limit to set */ |
973 | #endif /* !UNIV_HOTBACKUP */ |
974 | +/******************************************************//** |
975 | +Calculates the offset of an lsn within a log group. |
976 | +@return offset within the log group */ |
977 | +UNIV_INTERN |
978 | +ulint |
979 | +log_group_calc_lsn_offset( |
980 | +/*======================*/ |
981 | + ib_uint64_t lsn, /*!< in: lsn, must be within 4 GB of |
982 | + group->lsn */ |
983 | + const log_group_t* group); /*!< in: log group */ |
984 | + |
985 | +/*****************************************************************//** |
986 | +Calculates the recommended highest values for lsn - last_checkpoint_lsn, |
987 | +lsn - buf_get_oldest_modification(), and lsn - max_archive_lsn_age. |
988 | +@return error value FALSE if the smallest log group is too small to |
989 | +accommodate the number of OS threads in the database server */ |
990 | +ibool |
991 | +log_calc_max_ages(void); |
992 | +/*===================*/ |
993 | + |
994 | /*******************************************************************//** |
995 | Calculates where in log files we find a specified lsn. |
996 | @return log file number */ |
997 | @@ -953,6 +977,10 @@ |
998 | become signaled */ |
999 | /* @} */ |
1000 | #endif /* UNIV_LOG_ARCHIVE */ |
1001 | + os_event_t arch_event_rotate_start; /*!< initiates transaction log archiving */ |
1002 | + os_event_t arch_event_rotate_done; /*!< logging thread can continue normal work after receiving this event */ |
1003 | + mutex_t arch_sys_mutex; /*!< protects LSN and archiving thread manipulations */ |
1004 | + ib_uint64_t archived_lsn; /*!< LSN of last archived transaction log file */ |
1005 | }; |
1006 | |
1007 | #ifdef UNIV_LOG_ARCHIVE |
1008 | |
1009 | === modified file 'Percona-Server/storage/innodb_plugin/include/log0log.ic' |
1010 | --- Percona-Server/storage/innodb_plugin/include/log0log.ic 2010-06-10 14:31:28 +0000 |
1011 | +++ Percona-Server/storage/innodb_plugin/include/log0log.ic 2012-04-25 22:22:24 +0000 |
1012 | @@ -372,7 +372,11 @@ |
1013 | |
1014 | ut_ad(log_sys->buf_free <= log_sys->buf_size); |
1015 | |
1016 | + if (log_xtra_log_archive_on) |
1017 | + mutex_enter(&(log_sys->arch_sys_mutex)); |
1018 | log_sys->lsn += len; |
1019 | + if (log_xtra_log_archive_on) |
1020 | + mutex_exit(&(log_sys->arch_sys_mutex)); |
1021 | |
1022 | #ifdef UNIV_LOG_DEBUG |
1023 | log_check_log_recs(log_sys->buf + log_sys->old_buf_free, |
1024 | |
1025 | === modified file 'Percona-Server/storage/innodb_plugin/include/os0file.h' |
1026 | --- Percona-Server/storage/innodb_plugin/include/os0file.h 2011-11-24 02:00:47 +0000 |
1027 | +++ Percona-Server/storage/innodb_plugin/include/os0file.h 2012-04-25 22:22:24 +0000 |
1028 | @@ -403,6 +403,20 @@ |
1029 | const char* oldpath, /*!< in: old file path as a |
1030 | null-terminated string */ |
1031 | const char* newpath); /*!< in: new file path */ |
1032 | +/*************************************************************************** |
1033 | +Renames a file (can also move it to another directory and another drive). |
1034 | +If file should be placed to a different disks throttle will applied. |
1035 | +@return TRUE if success */ |
1036 | +ibool |
1037 | +os_file_rename_throttled( |
1038 | +/*===========*/ |
1039 | + const char* oldpath, /* in: old file path as a |
1040 | + null-terminated |
1041 | + string */ |
1042 | + const char* newpath, /* in: new file path */ |
1043 | + unsigned int throttle); /* in: number of read+write pairs of |
1044 | + operations per second. */ |
1045 | + |
1046 | /***********************************************************************//** |
1047 | Closes a file handle. In case of error, error number can be retrieved with |
1048 | os_file_get_last_error. |
1049 | |
1050 | === modified file 'Percona-Server/storage/innodb_plugin/include/srv0srv.h' |
1051 | --- Percona-Server/storage/innodb_plugin/include/srv0srv.h 2011-11-24 02:01:25 +0000 |
1052 | +++ Percona-Server/storage/innodb_plugin/include/srv0srv.h 2012-04-25 22:22:24 +0000 |
1053 | @@ -185,6 +185,8 @@ |
1054 | extern dulint srv_archive_recovery_limit_lsn; |
1055 | #endif /* UNIV_LOG_ARCHIVE */ |
1056 | |
1057 | +#define IB_ARCHIVED_LOGS_PREFIX "ib_log_archive_" |
1058 | + |
1059 | extern char* srv_file_flush_method_str; |
1060 | extern ulint srv_unix_file_flush_method; |
1061 | extern ulint srv_win_file_flush_method; |
1062 | @@ -445,6 +447,7 @@ |
1063 | #endif |
1064 | SRV_PURGE, /* thread purging undo records */ |
1065 | SRV_PURGE_WORKER, /* thread purging undo records */ |
1066 | + SRV_ARCHIVE, |
1067 | SRV_MASTER /**< the master thread, (whose type number must |
1068 | be biggest) */ |
1069 | }; |
1070 | @@ -643,6 +646,13 @@ |
1071 | /*====================*/ |
1072 | void* arg); /*!< in: a dummy parameter required by |
1073 | os_thread_create */ |
1074 | +/********************************************************************//** |
1075 | +A thread which controls archiving transaction log files */ |
1076 | +UNIV_INTERN |
1077 | +os_thread_ret_t |
1078 | +srv_log_archive_thread( |
1079 | +/*===================*/ |
1080 | + void* arg); |
1081 | /******************************************************************//** |
1082 | Outputs to a file the output of the InnoDB Monitor. |
1083 | @return FALSE if not all information printed |
1084 | @@ -665,6 +675,18 @@ |
1085 | srv_export_innodb_status(void); |
1086 | /*==========================*/ |
1087 | |
1088 | +/*************************************************************//** |
1089 | +Removes old archived transaction log files. |
1090 | +Both parameters couldn't be provided at the same time */ |
1091 | +UNIV_INTERN |
1092 | +void |
1093 | +purge_archived_logs( |
1094 | + time_t before_date, /*!< in: all files modified |
1095 | + before timestamp should be removed */ |
1096 | + unsigned long long before_lsn); /*!< in: files with this lsn in name |
1097 | + and earler should be removed */ |
1098 | +/*==========================*/ |
1099 | + |
1100 | /** Thread slot in the thread table */ |
1101 | typedef struct srv_slot_struct srv_slot_t; |
1102 | |
1103 | |
1104 | === modified file 'Percona-Server/storage/innodb_plugin/include/srv0start.h' |
1105 | --- Percona-Server/storage/innodb_plugin/include/srv0start.h 2011-11-24 02:00:36 +0000 |
1106 | +++ Percona-Server/storage/innodb_plugin/include/srv0start.h 2012-04-25 22:22:24 +0000 |
1107 | @@ -37,6 +37,22 @@ |
1108 | /*=======================*/ |
1109 | char* str); /*!< in/out: null-terminated character string */ |
1110 | /*********************************************************************//** |
1111 | +Calculates the low 32 bits when a file size which is given as a number |
1112 | +database pages is converted to the number of bytes. |
1113 | +@return low 32 bytes of file size when expressed in bytes */ |
1114 | +ulint |
1115 | +srv_calc_low32( |
1116 | +/*===========*/ |
1117 | + ulint file_size); /*!< in: file size in database pages */ |
1118 | +/*********************************************************************//** |
1119 | +Calculates the high 32 bits when a file size which is given as a number |
1120 | +database pages is converted to the number of bytes. |
1121 | +@return high 32 bytes of file size when expressed in bytes */ |
1122 | +ulint |
1123 | +srv_calc_high32( |
1124 | +/*============*/ |
1125 | + ulint file_size); /*!< in: file size in database pages */ |
1126 | +/*********************************************************************//** |
1127 | Reads the data files and their sizes from a character string given in |
1128 | the .cnf file. |
1129 | @return TRUE if ok, FALSE on parse error */ |
1130 | @@ -134,4 +150,10 @@ |
1131 | /** reserved for extra system tables */ |
1132 | #define SRV_EXTRA_SYS_SPACE_FIRST_ID 0xFFFFFFE0UL |
1133 | |
1134 | +#ifdef __WIN__ |
1135 | +#define SRV_PATH_SEPARATOR '\\' |
1136 | +#else |
1137 | +#define SRV_PATH_SEPARATOR '/' |
1138 | +#endif |
1139 | + |
1140 | #endif |
1141 | |
1142 | === modified file 'Percona-Server/storage/innodb_plugin/log/log0log.c' |
1143 | --- Percona-Server/storage/innodb_plugin/log/log0log.c 2012-04-02 02:09:15 +0000 |
1144 | +++ Percona-Server/storage/innodb_plugin/log/log0log.c 2012-04-25 22:22:24 +0000 |
1145 | @@ -97,6 +97,11 @@ |
1146 | UNIV_INTERN byte log_archive_io; |
1147 | #endif /* UNIV_LOG_ARCHIVE */ |
1148 | |
1149 | +UNIV_INTERN ibool log_xtra_log_archive_on = FALSE; |
1150 | + |
1151 | +UNIV_INTERN const char* log_xtra_log_archive_dir = NULL; |
1152 | +UNIV_INTERN time_t log_xtra_log_arch_expire_sec; |
1153 | +UNIV_INTERN uint log_xtra_log_arch_throttle = 0; |
1154 | /* A margin for free space in the log buffer before a log entry is catenated */ |
1155 | #define LOG_BUF_WRITE_MARGIN (4 * OS_FILE_LOG_BLOCK_SIZE) |
1156 | |
1157 | @@ -287,10 +292,13 @@ |
1158 | ulint str_len) /*!< in: string length */ |
1159 | { |
1160 | log_t* log = log_sys; |
1161 | + log_group_t* group; |
1162 | ulint len; |
1163 | ulint data_len; |
1164 | byte* log_block; |
1165 | |
1166 | + group = UT_LIST_GET_FIRST(log->log_groups); |
1167 | + |
1168 | ut_ad(mutex_own(&(log->mutex))); |
1169 | part_loop: |
1170 | ut_ad(!recv_no_log_write); |
1171 | @@ -311,6 +319,30 @@ |
1172 | - LOG_BLOCK_TRL_SIZE; |
1173 | } |
1174 | |
1175 | + /* If the log write is across file border, |
1176 | + should check the archive was done. */ |
1177 | + if (log_xtra_log_archive_on) { |
1178 | + if ((log_group_calc_lsn_offset(log->lsn, group) |
1179 | + / group->file_size) |
1180 | + != (log_group_calc_lsn_offset(log->lsn + len, group) |
1181 | + / group->file_size)) { |
1182 | + os_event_set(log_sys->arch_event_rotate_start); |
1183 | + } |
1184 | +wait_for_archived: |
1185 | + mutex_enter(&(log_sys->arch_sys_mutex)); |
1186 | + if ( !(log_sys->archived_lsn) || |
1187 | + log->lsn + len <= log_sys->archived_lsn |
1188 | + + log_group_get_capacity(group)) { |
1189 | + mutex_exit(&(log_sys->arch_sys_mutex)); |
1190 | + } else { |
1191 | + os_event_reset(log_sys->arch_event_rotate_done); |
1192 | + mutex_exit(&(log_sys->arch_sys_mutex)); |
1193 | + os_event_set(log_sys->arch_event_rotate_start); /* for safety */ |
1194 | + os_event_wait(log_sys->arch_event_rotate_done); |
1195 | + goto wait_for_archived; |
1196 | + } |
1197 | + } |
1198 | + |
1199 | ut_memcpy(log->buf + log->buf_free, str, len); |
1200 | |
1201 | str_len -= len; |
1202 | @@ -327,12 +359,20 @@ |
1203 | log_sys->next_checkpoint_no); |
1204 | len += LOG_BLOCK_HDR_SIZE + LOG_BLOCK_TRL_SIZE; |
1205 | |
1206 | + if (log_xtra_log_archive_on) |
1207 | + mutex_enter(&(log_sys->arch_sys_mutex)); |
1208 | log->lsn += len; |
1209 | + if (log_xtra_log_archive_on) |
1210 | + mutex_exit(&(log_sys->arch_sys_mutex)); |
1211 | |
1212 | /* Initialize the next block header */ |
1213 | log_block_init(log_block + OS_FILE_LOG_BLOCK_SIZE, log->lsn); |
1214 | } else { |
1215 | + if (log_xtra_log_archive_on) |
1216 | + mutex_enter(&(log_sys->arch_sys_mutex)); |
1217 | log->lsn += len; |
1218 | + if (log_xtra_log_archive_on) |
1219 | + mutex_exit(&(log_sys->arch_sys_mutex)); |
1220 | } |
1221 | |
1222 | log->buf_free += len; |
1223 | @@ -552,7 +592,7 @@ |
1224 | /******************************************************//** |
1225 | Calculates the offset of an lsn within a log group. |
1226 | @return offset within the log group */ |
1227 | -static |
1228 | +UNIV_INTERN |
1229 | ulint |
1230 | log_group_calc_lsn_offset( |
1231 | /*======================*/ |
1232 | @@ -670,7 +710,6 @@ |
1233 | lsn - buf_get_oldest_modification(), and lsn - max_archive_lsn_age. |
1234 | @return error value FALSE if the smallest log group is too small to |
1235 | accommodate the number of OS threads in the database server */ |
1236 | -static |
1237 | ibool |
1238 | log_calc_max_ages(void) |
1239 | /*===================*/ |
1240 | @@ -710,6 +749,11 @@ |
1241 | group = UT_LIST_GET_NEXT(log_groups, group); |
1242 | } |
1243 | |
1244 | + /* log_archive needs over 1 file margin */ |
1245 | + if (log_xtra_log_archive_on) { |
1246 | + smallest_capacity = smallest_archive_margin; |
1247 | + } |
1248 | + |
1249 | /* Add extra safety */ |
1250 | smallest_capacity = smallest_capacity - smallest_capacity / 10; |
1251 | |
1252 | @@ -786,6 +830,7 @@ |
1253 | log_sys = mem_alloc(sizeof(log_t)); |
1254 | |
1255 | mutex_create(&log_sys->mutex, SYNC_LOG); |
1256 | + mutex_create(&log_sys->arch_sys_mutex, SYNC_NO_ORDER_CHECK); |
1257 | |
1258 | mutex_enter(&(log_sys->mutex)); |
1259 | |
1260 | @@ -852,7 +897,7 @@ |
1261 | #ifdef UNIV_LOG_ARCHIVE |
1262 | /* Under MySQL, log archiving is always off */ |
1263 | log_sys->archiving_state = LOG_ARCH_OFF; |
1264 | - log_sys->archived_lsn = log_sys->lsn; |
1265 | + log_sys->archived_lsn = 0; |
1266 | log_sys->next_archived_lsn = 0; |
1267 | |
1268 | log_sys->n_pending_archive_ios = 0; |
1269 | @@ -872,6 +917,11 @@ |
1270 | log_sys->archiving_on = os_event_create(NULL); |
1271 | #endif /* UNIV_LOG_ARCHIVE */ |
1272 | |
1273 | + log_sys->arch_event_rotate_start = os_event_create(NULL); |
1274 | + os_event_set(log_sys->arch_event_rotate_start); |
1275 | + log_sys->arch_event_rotate_done = os_event_create(NULL); |
1276 | + os_event_set(log_sys->arch_event_rotate_done); |
1277 | + |
1278 | /*----------------------------*/ |
1279 | |
1280 | log_block_init(log_sys->buf, log_sys->lsn); |
1281 | @@ -1693,13 +1743,29 @@ |
1282 | log_complete_checkpoint(void) |
1283 | /*=========================*/ |
1284 | { |
1285 | + log_group_t* group; |
1286 | + |
1287 | ut_ad(mutex_own(&(log_sys->mutex))); |
1288 | ut_ad(log_sys->n_pending_checkpoint_writes == 0); |
1289 | |
1290 | + group = UT_LIST_GET_FIRST(log_sys->log_groups); |
1291 | + |
1292 | + if (log_xtra_log_archive_on) { |
1293 | + mutex_enter(&(log_sys->arch_sys_mutex)); |
1294 | + |
1295 | + if ((log_group_calc_lsn_offset(log_sys->next_checkpoint_lsn, group) / group->file_size) |
1296 | + != (log_group_calc_lsn_offset(log_sys->last_checkpoint_lsn, group) / group->file_size)) { |
1297 | + os_event_set(log_sys->arch_event_rotate_start); |
1298 | + } |
1299 | + } |
1300 | + |
1301 | log_sys->next_checkpoint_no++; |
1302 | |
1303 | log_sys->last_checkpoint_lsn = log_sys->next_checkpoint_lsn; |
1304 | |
1305 | + if (log_xtra_log_archive_on) |
1306 | + mutex_exit(&(log_sys->arch_sys_mutex)); |
1307 | + |
1308 | rw_lock_x_unlock_gen(&(log_sys->checkpoint_lock), LOG_CHECKPOINT); |
1309 | } |
1310 | |
1311 | @@ -3158,6 +3224,15 @@ |
1312 | goto loop; |
1313 | } |
1314 | |
1315 | + if (log_xtra_log_archive_on |
1316 | + && srv_n_threads_active[SRV_ARCHIVE] != 0) { |
1317 | + |
1318 | + mutex_exit(&kernel_mutex); |
1319 | + os_event_set(log_sys->arch_event_rotate_start); |
1320 | + |
1321 | + goto loop; |
1322 | + } |
1323 | + |
1324 | /* Check that the purge threads ended */ |
1325 | if (srv_use_purge_thread |
1326 | && (srv_n_threads_active[SRV_PURGE] != 0 |
1327 | @@ -3375,6 +3450,14 @@ |
1328 | log_sys->flushed_to_disk_lsn, |
1329 | log_sys->last_checkpoint_lsn); |
1330 | |
1331 | + if (log_xtra_log_archive_on) { |
1332 | + mutex_enter(&(log_sys->arch_sys_mutex)); |
1333 | + fprintf(file, |
1334 | + "Log archived until %llu\n", |
1335 | + log_sys->archived_lsn); |
1336 | + mutex_exit(&(log_sys->arch_sys_mutex)); |
1337 | + } |
1338 | + |
1339 | fprintf(file, |
1340 | "Max checkpoint age %lu\n" |
1341 | "Checkpoint age target %lu\n" |
1342 | @@ -3479,12 +3562,16 @@ |
1343 | rw_lock_free(&log_sys->checkpoint_lock); |
1344 | |
1345 | mutex_free(&log_sys->mutex); |
1346 | + mutex_free(&log_sys->arch_sys_mutex); |
1347 | |
1348 | #ifdef UNIV_LOG_ARCHIVE |
1349 | rw_lock_free(&log_sys->archive_lock); |
1350 | os_event_create(log_sys->archiving_on); |
1351 | #endif /* UNIV_LOG_ARCHIVE */ |
1352 | |
1353 | + os_event_free(log_sys->arch_event_rotate_start); |
1354 | + os_event_free(log_sys->arch_event_rotate_done); |
1355 | + |
1356 | #ifdef UNIV_LOG_DEBUG |
1357 | recv_sys_debug_free(); |
1358 | #endif |
1359 | |
1360 | === modified file 'Percona-Server/storage/innodb_plugin/os/os0file.c' |
1361 | --- Percona-Server/storage/innodb_plugin/os/os0file.c 2011-12-15 15:27:38 +0000 |
1362 | +++ Percona-Server/storage/innodb_plugin/os/os0file.c 2012-04-25 22:22:24 +0000 |
1363 | @@ -1685,6 +1685,158 @@ |
1364 | return(TRUE); |
1365 | #endif |
1366 | } |
1367 | +/*************************************************************************** |
1368 | +Renames a file (can also move it to another directory and another drive). |
1369 | +If file should be placed to a different disks throttle will applied. |
1370 | +@return TRUE if success */ |
1371 | +ibool |
1372 | +os_file_rename_throttled( |
1373 | +/*===========*/ |
1374 | + const char* oldpath, /* in: old file path as a |
1375 | + null-terminated string */ |
1376 | + const char* newpath, /* in: new file path */ |
1377 | + unsigned int throttle) /* in: number of read+write pairs of |
1378 | + operations per second. */ |
1379 | +{ |
1380 | +#ifdef __WIN__ |
1381 | + return os_file_rename(oldpath, newpath); |
1382 | +#else |
1383 | + int ret; |
1384 | + ulint err; |
1385 | + ulint block_size = 64*UNIV_PAGE_SIZE; |
1386 | + os_file_t file; |
1387 | + os_file_t new_file; |
1388 | + byte* buf_ptr = NULL; |
1389 | + byte* buf = NULL; |
1390 | + ibool success; |
1391 | + ib_int64_t file_size; |
1392 | + ib_int64_t offset; |
1393 | + ulint prev_time = 0 , cur_time = 0; |
1394 | + int num_io = 0; |
1395 | + |
1396 | + ret = rename(oldpath, newpath); |
1397 | + |
1398 | + if (ret == 0) { |
1399 | + return(TRUE); |
1400 | + } |
1401 | + |
1402 | + err = (ulint) errno; |
1403 | + |
1404 | + if (err != EXDEV) { |
1405 | + os_file_handle_error_no_exit(oldpath, "rename"); |
1406 | + return(FALSE); |
1407 | + } |
1408 | + |
1409 | + buf_ptr = ut_malloc(2*block_size); |
1410 | + buf = ut_align(buf_ptr, block_size); |
1411 | + |
1412 | + file = os_file_create(oldpath, OS_FILE_OPEN, OS_FILE_NORMAL, |
1413 | + OS_LOG_FILE, &success); |
1414 | + ut_a(success); |
1415 | + new_file = os_file_create(newpath, OS_FILE_CREATE, OS_FILE_NORMAL, |
1416 | + OS_LOG_FILE, &success); |
1417 | + ut_a(success); |
1418 | + |
1419 | +#ifndef USE_POSIX_FADVISE |
1420 | +#ifdef POSIX_FADV_NORMAL |
1421 | +#define USE_POSIX_FADVISE |
1422 | +#endif |
1423 | +#endif |
1424 | + |
1425 | +#ifdef USE_POSIX_FADVISE |
1426 | + posix_fadvise(new_file, 0, 0, POSIX_FADV_SEQUENTIAL); |
1427 | + posix_fadvise(file, 0, 0, POSIX_FADV_SEQUENTIAL); |
1428 | +#endif |
1429 | + file_size = os_file_get_size_as_iblonglong(file); |
1430 | + ut_a(file_size != -1); |
1431 | + |
1432 | + if (throttle) { |
1433 | + prev_time = ut_time_ms(); |
1434 | + } |
1435 | + |
1436 | + for (offset = 0; offset < file_size; offset += block_size) { |
1437 | + success = os_file_read(file, buf, |
1438 | + (ulint)(offset & 0xFFFFFFFFUL), |
1439 | + (ulint)(offset >> 32), |
1440 | + block_size); |
1441 | + ut_a(success); |
1442 | + success = os_file_write(newpath, new_file, buf, |
1443 | + (ulint)(offset & 0xFFFFFFFFUL), |
1444 | + (ulint)(offset >> 32), |
1445 | + block_size); |
1446 | + ut_a(success); |
1447 | + |
1448 | + if (!throttle) { |
1449 | + continue; |
1450 | + } |
1451 | + |
1452 | + ++num_io; |
1453 | + cur_time = ut_time_ms(); |
1454 | + |
1455 | + if ((cur_time - prev_time) > 0 && |
1456 | + num_io*1000/(cur_time - prev_time) <= throttle) { |
1457 | + continue; |
1458 | + } |
1459 | + |
1460 | + os_thread_sleep(1000000/throttle |
1461 | + - 1000*(cur_time - prev_time)/num_io); |
1462 | + |
1463 | + prev_time = cur_time; |
1464 | + num_io = 0; |
1465 | + } |
1466 | + |
1467 | + if (file_size - offset > 0) { |
1468 | + success = os_file_read(file, buf, |
1469 | + (ulint)(offset & 0xFFFFFFFFUL), |
1470 | + (ulint)(offset >> 32), |
1471 | + file_size - offset); |
1472 | + ut_a(success); |
1473 | + success = os_file_write(newpath, new_file, buf, |
1474 | + (ulint)(offset & 0xFFFFFFFFUL), |
1475 | + (ulint)(offset >> 32), |
1476 | + file_size - offset); |
1477 | + ut_a(success); |
1478 | + } |
1479 | + |
1480 | + success = os_file_flush(new_file, TRUE); |
1481 | + ut_a(success); |
1482 | + |
1483 | +#ifdef UNIV_DEBUG |
1484 | + { |
1485 | + ib_int64_t new_file_size; |
1486 | + |
1487 | + new_file_size = os_file_get_size_as_iblonglong(new_file); |
1488 | + ut_a(new_file_size != -1); |
1489 | + |
1490 | + if (new_file_size != file_size) { |
1491 | + fputs( " InnoDB: Warning: problems moving " |
1492 | + "to different disk: wrong file size", stderr); |
1493 | + ut_print_filename(stderr, newpath); |
1494 | + fputs("\n",stderr); |
1495 | + } |
1496 | + } |
1497 | +#endif |
1498 | + |
1499 | +#ifdef USE_POSIX_FADVISE |
1500 | + posix_fadvise(new_file, 0, 0, POSIX_FADV_DONTNEED); |
1501 | + posix_fadvise(file, 0, 0, POSIX_FADV_DONTNEED); |
1502 | +#endif |
1503 | + |
1504 | + |
1505 | + os_file_close(file); |
1506 | + os_file_close(new_file); |
1507 | + success = os_file_delete_if_exists(oldpath); |
1508 | + ut_a(success); |
1509 | + |
1510 | + if (buf_ptr) { |
1511 | + ut_free(buf_ptr); |
1512 | + } |
1513 | + |
1514 | + return(TRUE); |
1515 | +#endif |
1516 | +} |
1517 | + |
1518 | + |
1519 | |
1520 | /***********************************************************************//** |
1521 | Closes a file handle. In case of error, error number can be retrieved with |
1522 | |
1523 | === modified file 'Percona-Server/storage/innodb_plugin/srv/srv0srv.c' |
1524 | --- Percona-Server/storage/innodb_plugin/srv/srv0srv.c 2011-11-24 02:01:25 +0000 |
1525 | +++ Percona-Server/storage/innodb_plugin/srv/srv0srv.c 2012-04-25 22:22:24 +0000 |
1526 | @@ -2674,6 +2674,372 @@ |
1527 | OS_THREAD_DUMMY_RETURN; |
1528 | } |
1529 | |
1530 | +/*********************************************************************//** |
1531 | +Creates or opens the next log file. The file will be closed after the call */ |
1532 | +static |
1533 | +ulint |
1534 | +open_or_create_new_log_file( |
1535 | +/*========================*/ |
1536 | + const char* name) |
1537 | +{ |
1538 | + ibool ret; |
1539 | + ulint size; |
1540 | + ulint size_high; |
1541 | + os_file_t new_file; |
1542 | + |
1543 | + new_file = os_file_create(name, OS_FILE_CREATE, OS_FILE_NORMAL, |
1544 | + OS_LOG_FILE, &ret); |
1545 | + if (ret == FALSE) { |
1546 | + if (os_file_get_last_error(FALSE) != OS_FILE_ALREADY_EXISTS) { |
1547 | + fprintf(stderr, |
1548 | + "InnoDB: Error in creating" |
1549 | + " or opening %s\n", name); |
1550 | + |
1551 | + return(DB_ERROR); |
1552 | + } |
1553 | + |
1554 | + new_file = os_file_create(name, OS_FILE_OPEN, OS_FILE_AIO, |
1555 | + OS_LOG_FILE, &ret); |
1556 | + if (!ret) { |
1557 | + fprintf(stderr, |
1558 | + "InnoDB: Error in opening %s\n", name); |
1559 | + return(DB_ERROR); |
1560 | + } |
1561 | + |
1562 | + ret = os_file_get_size(new_file, &size, &size_high); |
1563 | + ut_a(ret); |
1564 | + |
1565 | + if (size != srv_calc_low32(srv_log_file_size) |
1566 | + || size_high != srv_calc_high32(srv_log_file_size)) { |
1567 | + |
1568 | + fprintf(stderr, |
1569 | + "InnoDB: Error: log file %s is" |
1570 | + " of different size %lu %lu bytes\n" |
1571 | + "InnoDB: than specified in the .cnf" |
1572 | + " file %lu %lu bytes! Rename or remove the file.\n", |
1573 | + name, (ulong) size_high, (ulong) size, |
1574 | + (ulong) srv_calc_high32(srv_log_file_size), |
1575 | + (ulong) srv_calc_low32(srv_log_file_size)); |
1576 | + |
1577 | + return(DB_ERROR); |
1578 | + } |
1579 | + } else { |
1580 | + ut_print_timestamp(stderr); |
1581 | + |
1582 | + fprintf(stderr, |
1583 | + " InnoDB: Log file %s did not exist:" |
1584 | + " new to be created\n", |
1585 | + name); |
1586 | + |
1587 | + fprintf(stderr, "InnoDB: Setting log file %s size to %lu MB\n", |
1588 | + name, (ulong) srv_log_file_size |
1589 | + >> (20 - UNIV_PAGE_SIZE_SHIFT)); |
1590 | + |
1591 | + fprintf(stderr, |
1592 | + "InnoDB: Database physically writes the file" |
1593 | + " full: wait...\n"); |
1594 | + |
1595 | + ret = os_file_set_size(name, new_file, |
1596 | + srv_calc_low32(srv_log_file_size), |
1597 | + srv_calc_high32(srv_log_file_size)); |
1598 | + if (!ret) { |
1599 | + fprintf(stderr, |
1600 | + "InnoDB: Error in creating %s:" |
1601 | + " probably out of disk space\n", |
1602 | + name); |
1603 | + |
1604 | + return(DB_ERROR); |
1605 | + } |
1606 | + |
1607 | + fprintf(stderr, |
1608 | + "InnoDB: Setting log file was done\n"); |
1609 | + } |
1610 | + |
1611 | + ret = os_file_close(new_file); |
1612 | + ut_a(ret); |
1613 | + |
1614 | + return(DB_SUCCESS); |
1615 | +} |
1616 | + |
1617 | +/*************************************************************//** |
1618 | +Removes old archived transaction log files. |
1619 | +Both parameters couldn't be provided at the same time */ |
1620 | +void |
1621 | +purge_archived_logs( |
1622 | + time_t before_date, /*!< in: all files modified |
1623 | + before timestamp should be removed */ |
1624 | + unsigned long long before_lsn) /*!< in: files with this lsn in name |
1625 | + and earler should be removed */ |
1626 | +{ |
1627 | + os_file_dir_t dir; |
1628 | + os_file_stat_t fileinfo; |
1629 | + char archived_log_filename[OS_FILE_MAX_PATH]; |
1630 | + ulint dirnamelen; |
1631 | + |
1632 | + if (log_xtra_log_archive_dir) { |
1633 | + dir = os_file_opendir(log_xtra_log_archive_dir, FALSE); |
1634 | + if (!dir) { |
1635 | + fprintf(stderr, |
1636 | + "InnoDB: Note: opening archived log directory " |
1637 | + "%s was failed. " |
1638 | + "Purge archived logs are not available\n", |
1639 | + log_xtra_log_archive_dir); |
1640 | + return; |
1641 | + } |
1642 | + } else { |
1643 | + return; |
1644 | + } |
1645 | + |
1646 | + dirnamelen = strlen(log_xtra_log_archive_dir); |
1647 | + |
1648 | + memcpy(archived_log_filename, log_xtra_log_archive_dir, dirnamelen); |
1649 | + if (dirnamelen && |
1650 | + archived_log_filename[dirnamelen - 1] != SRV_PATH_SEPARATOR) { |
1651 | + archived_log_filename[dirnamelen++] = SRV_PATH_SEPARATOR; |
1652 | + } |
1653 | + |
1654 | + memset(&fileinfo, 0, sizeof(fileinfo)); |
1655 | + while(!os_file_readdir_next_file(log_xtra_log_archive_dir, dir, |
1656 | + &fileinfo) ) { |
1657 | + if (fileinfo.name != strstr(fileinfo.name, |
1658 | + IB_ARCHIVED_LOGS_PREFIX)) { |
1659 | + } |
1660 | + if (dirnamelen + strlen(fileinfo.name) + 2 > OS_FILE_MAX_PATH) |
1661 | + continue; |
1662 | + |
1663 | + snprintf(archived_log_filename + dirnamelen, OS_FILE_MAX_PATH, |
1664 | + "%s", fileinfo.name); |
1665 | + |
1666 | + if (before_lsn) { |
1667 | + ib_uint64_t log_file_lsn = strtoll(fileinfo.name + |
1668 | + strlen(IB_ARCHIVED_LOGS_PREFIX), |
1669 | + NULL, 10); |
1670 | + if (log_file_lsn == 0 || before_lsn <= log_file_lsn) { |
1671 | + continue; |
1672 | + } |
1673 | + } else { |
1674 | + fileinfo.mtime = 0; |
1675 | + if (os_file_get_status(archived_log_filename, |
1676 | + &fileinfo) == FALSE || |
1677 | + fileinfo.mtime == 0) { |
1678 | + fprintf(stderr, |
1679 | + "InnoDB: Note: read archived log last" |
1680 | + " modification date for: %s.\n", |
1681 | + archived_log_filename); |
1682 | + continue; |
1683 | + } |
1684 | + |
1685 | + if (before_date == 0 || fileinfo.mtime > before_date) { |
1686 | + continue; |
1687 | + } |
1688 | + } |
1689 | + |
1690 | + if (os_file_delete(archived_log_filename) == FALSE) { |
1691 | + fprintf(stderr, |
1692 | + "InnoDB: Note: can't delete archived log file" |
1693 | + " %s.\n", archived_log_filename); |
1694 | + } |
1695 | + } |
1696 | + |
1697 | + os_file_closedir(dir); |
1698 | +} |
1699 | + |
1700 | + |
1701 | +/*********************************************************************//** |
1702 | +A thread which controls archiving transaction log files */ |
1703 | +UNIV_INTERN |
1704 | +os_thread_ret_t |
1705 | +srv_log_archive_thread( |
1706 | +/*===================*/ |
1707 | + void* arg __attribute__((unused))) |
1708 | +{ |
1709 | + log_group_t* group = UT_LIST_GET_FIRST(log_sys->log_groups); |
1710 | + ibool next_is_prepared; |
1711 | + ulint err; |
1712 | + char new_file_name[OS_FILE_MAX_PATH]; |
1713 | + char archive_file_name[OS_FILE_MAX_PATH]; |
1714 | + char final_file_name[OS_FILE_MAX_PATH]; |
1715 | + ulint dirnamelen; |
1716 | + ulint final_dirnamelen; |
1717 | + |
1718 | + ut_a(log_xtra_log_archive_on); |
1719 | + |
1720 | + mutex_enter(&kernel_mutex); |
1721 | + srv_table_reserve_slot(SRV_ARCHIVE); |
1722 | + srv_n_threads_active[SRV_ARCHIVE]++; |
1723 | + mutex_exit(&kernel_mutex); |
1724 | + |
1725 | + log_calc_max_ages(); |
1726 | + log_check_margins(); |
1727 | + |
1728 | + /* initialization */ |
1729 | + /* assume before the current file was archived already */ |
1730 | + mutex_enter(&(log_sys->arch_sys_mutex)); |
1731 | + log_sys->archived_lsn = log_sys->lsn |
1732 | + - ((log_group_calc_lsn_offset(log_sys->lsn - 1, group) |
1733 | + % group->file_size) + 1 - LOG_FILE_HDR_SIZE); |
1734 | + os_event_set(log_sys->arch_event_rotate_done); |
1735 | + mutex_exit(&(log_sys->arch_sys_mutex)); |
1736 | + |
1737 | + fprintf(stderr, "InnoDB: Note: " |
1738 | + "transaction log archiving thread started.\n"); |
1739 | + |
1740 | + /* confirm new file and create if needed */ |
1741 | + dirnamelen = strlen(srv_log_group_home_dirs[0]); |
1742 | + ut_a(dirnamelen < (sizeof new_file_name) - 31 - sizeof "ib_logfile"); |
1743 | + |
1744 | + if (log_xtra_log_archive_dir && |
1745 | + strcmp(log_xtra_log_archive_dir, |
1746 | + srv_log_group_home_dirs[0]) != 0 |
1747 | + ) { |
1748 | + final_dirnamelen = strlen(log_xtra_log_archive_dir); |
1749 | + memcpy(final_file_name, log_xtra_log_archive_dir, |
1750 | + final_dirnamelen); |
1751 | + if (final_dirnamelen && |
1752 | + final_file_name[final_dirnamelen - 1] |
1753 | + != SRV_PATH_SEPARATOR) { |
1754 | + final_file_name[final_dirnamelen++] |
1755 | + = SRV_PATH_SEPARATOR; |
1756 | + } |
1757 | + } else { |
1758 | + final_dirnamelen = 0; |
1759 | + } |
1760 | + |
1761 | + memcpy(new_file_name, srv_log_group_home_dirs[0], dirnamelen); |
1762 | + if (dirnamelen && new_file_name[dirnamelen - 1] != SRV_PATH_SEPARATOR) { |
1763 | + new_file_name[dirnamelen++] = SRV_PATH_SEPARATOR; |
1764 | + } |
1765 | + memcpy(archive_file_name, new_file_name, dirnamelen); |
1766 | + |
1767 | + snprintf(new_file_name + dirnamelen, |
1768 | + OS_FILE_MAX_PATH, "%s", "ib_next_logfile"); |
1769 | + |
1770 | + next_is_prepared = FALSE; |
1771 | + |
1772 | +loop: |
1773 | + os_event_reset(log_sys->arch_event_rotate_start); |
1774 | + |
1775 | +/* NOTICE: waiting the event log_sys->arch_event_rotate_done is done with |
1776 | + log_sys->mutex holding. |
1777 | + So, we cannot obtain log_sys->mutex in this thread. |
1778 | + The values shared with the other threads should be protected by |
1779 | + log_sys->arch_sys_mutex */ |
1780 | + |
1781 | +retry_create_file: |
1782 | + if (!next_is_prepared) { |
1783 | + err = open_or_create_new_log_file(new_file_name); |
1784 | + if (err == DB_SUCCESS) { |
1785 | + next_is_prepared = TRUE; |
1786 | + } else { |
1787 | + next_is_prepared = FALSE; |
1788 | + fprintf(stderr, "InnoDB: Warning: " |
1789 | + "The new log file cannot be created. " |
1790 | + "The above errors should be fixed\n" |
1791 | + "will retry 10 seconds later again.\n"); |
1792 | + os_thread_sleep(10000000); |
1793 | + goto retry_create_file; |
1794 | + } |
1795 | + } |
1796 | + |
1797 | + ut_a(next_is_prepared); |
1798 | + |
1799 | + mutex_enter(&(log_sys->arch_sys_mutex)); |
1800 | + if (log_sys->last_checkpoint_lsn |
1801 | + >= log_sys->archived_lsn + (group->file_size - LOG_FILE_HDR_SIZE)) { |
1802 | + ulint hdr_offset; |
1803 | + ibool success; |
1804 | + |
1805 | + mutex_exit(&(log_sys->arch_sys_mutex)); |
1806 | + trx_sys_print_mysql_binlog_offset(); |
1807 | + |
1808 | + snprintf(archive_file_name + dirnamelen, |
1809 | + OS_FILE_MAX_PATH, "%s%016lld", |
1810 | + IB_ARCHIVED_LOGS_PREFIX, |
1811 | + log_sys->archived_lsn); |
1812 | + |
1813 | + if (final_dirnamelen) { |
1814 | + snprintf(final_file_name + final_dirnamelen, |
1815 | + OS_FILE_MAX_PATH, "%s%016lld", |
1816 | + IB_ARCHIVED_LOGS_PREFIX, |
1817 | + log_sys->archived_lsn); |
1818 | + } |
1819 | + |
1820 | + hdr_offset = log_group_calc_lsn_offset( |
1821 | + log_sys->archived_lsn, group) |
1822 | + / group->file_size * group->file_size / UNIV_PAGE_SIZE; |
1823 | + |
1824 | + success = fil_rotate_file(group->space_id, hdr_offset, |
1825 | + archive_file_name, new_file_name, |
1826 | + LOG_FILE_HDR_SIZE); |
1827 | + |
1828 | + if (success) { |
1829 | + mutex_enter(&(log_sys->arch_sys_mutex)); |
1830 | + log_sys->archived_lsn += group->file_size |
1831 | + - LOG_FILE_HDR_SIZE; |
1832 | + os_event_set(log_sys->arch_event_rotate_done); |
1833 | + mutex_exit(&(log_sys->arch_sys_mutex)); |
1834 | + next_is_prepared = FALSE; |
1835 | + |
1836 | + if (log_xtra_log_archive_dir && |
1837 | + !os_file_rename_throttled( |
1838 | + archive_file_name, |
1839 | + final_file_name, |
1840 | + log_xtra_log_arch_throttle) |
1841 | + |
1842 | + ) { |
1843 | + fprintf(stderr, "InnoDB: Note: " |
1844 | + "moving archived log to " |
1845 | + "%s was failed\n", |
1846 | + final_file_name); |
1847 | + } |
1848 | + |
1849 | + if (log_xtra_log_arch_expire_sec) { |
1850 | + purge_archived_logs(ut_time() |
1851 | + - log_xtra_log_arch_expire_sec, |
1852 | + 0); |
1853 | + } |
1854 | + |
1855 | + |
1856 | + goto retry_create_file; |
1857 | + } else { |
1858 | + fprintf(stderr, |
1859 | + "InnoDB: Error: archiving %s was failed\n" |
1860 | + " will retry 10 seconds later again.\n", |
1861 | + archive_file_name); |
1862 | + os_thread_sleep(10000000); |
1863 | + goto retry_create_file; |
1864 | + } |
1865 | + } else { |
1866 | + mutex_exit(&(log_sys->arch_sys_mutex)); |
1867 | + } |
1868 | + |
1869 | + if (srv_shutdown_state > 0 || log_xtra_log_archive_on == FALSE) { |
1870 | + fprintf(stderr, |
1871 | + "InnoDB: stopping transaction log archiving\n" |
1872 | + ); |
1873 | + goto exit_func; |
1874 | + } |
1875 | + |
1876 | + os_event_wait(log_sys->arch_event_rotate_start); |
1877 | + |
1878 | + goto loop; |
1879 | + |
1880 | +exit_func: |
1881 | + os_event_set(log_sys->arch_event_rotate_done); |
1882 | + |
1883 | + if(srv_shutdown_state == 0) { |
1884 | + log_calc_max_ages(); |
1885 | + log_check_margins(); |
1886 | + } |
1887 | + |
1888 | + mutex_enter(&kernel_mutex); |
1889 | + srv_n_threads_active[SRV_ARCHIVE]--; |
1890 | + mutex_exit(&kernel_mutex); |
1891 | + os_thread_exit(NULL); |
1892 | + |
1893 | + OS_THREAD_DUMMY_RETURN; /* srv_log_archive_thread() */ |
1894 | +} |
1895 | + |
1896 | /*******************************************************************//** |
1897 | Tells the InnoDB server that there has been activity in the database |
1898 | and wakes up the master thread if it is suspended (not sleeping). Used |
1899 | |
1900 | === modified file 'Percona-Server/storage/innodb_plugin/srv/srv0start.c' |
1901 | --- Percona-Server/storage/innodb_plugin/srv/srv0start.c 2011-11-24 02:00:47 +0000 |
1902 | +++ Percona-Server/storage/innodb_plugin/srv/srv0start.c 2012-04-25 22:22:24 +0000 |
1903 | @@ -127,9 +127,9 @@ |
1904 | static ulint ios; |
1905 | |
1906 | /** io_handler_thread parameters for thread identification */ |
1907 | -static ulint n[SRV_MAX_N_IO_THREADS + 7 + UNIV_MAX_PARALLELISM]; |
1908 | +static ulint n[SRV_MAX_N_IO_THREADS + 8 + UNIV_MAX_PARALLELISM]; |
1909 | /** io_handler_thread identifiers */ |
1910 | -static os_thread_id_t thread_ids[SRV_MAX_N_IO_THREADS + 7 + UNIV_MAX_PARALLELISM]; |
1911 | +static os_thread_id_t thread_ids[SRV_MAX_N_IO_THREADS + 8 + UNIV_MAX_PARALLELISM]; |
1912 | |
1913 | /** We use this mutex to test the return value of pthread_mutex_trylock |
1914 | on successful locking. HP-UX does NOT return 0, though Linux et al do. */ |
1915 | @@ -490,12 +490,6 @@ |
1916 | } |
1917 | #endif /* !UNIV_HOTBACKUP */ |
1918 | |
1919 | -#ifdef __WIN__ |
1920 | -#define SRV_PATH_SEPARATOR '\\' |
1921 | -#else |
1922 | -#define SRV_PATH_SEPARATOR '/' |
1923 | -#endif |
1924 | - |
1925 | /*********************************************************************//** |
1926 | Normalizes a directory path for Windows: converts slashes to backslashes. */ |
1927 | UNIV_INTERN |
1928 | @@ -520,7 +514,6 @@ |
1929 | Calculates the low 32 bits when a file size which is given as a number |
1930 | database pages is converted to the number of bytes. |
1931 | @return low 32 bytes of file size when expressed in bytes */ |
1932 | -static |
1933 | ulint |
1934 | srv_calc_low32( |
1935 | /*===========*/ |
1936 | @@ -533,7 +526,6 @@ |
1937 | Calculates the high 32 bits when a file size which is given as a number |
1938 | database pages is converted to the number of bytes. |
1939 | @return high 32 bytes of file size when expressed in bytes */ |
1940 | -static |
1941 | ulint |
1942 | srv_calc_high32( |
1943 | /*============*/ |
1944 | @@ -1880,6 +1872,12 @@ |
1945 | os_thread_create(&srv_LRU_dump_restore_thread, NULL, |
1946 | thread_ids + 5 + SRV_MAX_N_IO_THREADS); |
1947 | |
1948 | + /* Create the thread which archives transaction log files */ |
1949 | + if (log_xtra_log_archive_on) { |
1950 | + os_thread_create(&srv_log_archive_thread, NULL, |
1951 | + thread_ids + 6 + SRV_MAX_N_IO_THREADS); |
1952 | + } |
1953 | + |
1954 | /* If srv_blocking_lru_restore is TRUE, load buffer pool contents |
1955 | synchronously */ |
1956 | if (srv_auto_lru_dump && srv_blocking_lru_restore) |
1957 | @@ -1909,13 +1907,13 @@ |
1958 | ulint i; |
1959 | |
1960 | os_thread_create(&srv_purge_thread, NULL, thread_ids |
1961 | - + (6 + SRV_MAX_N_IO_THREADS)); |
1962 | + + (7 + SRV_MAX_N_IO_THREADS)); |
1963 | |
1964 | for (i = 0; i < srv_use_purge_thread - 1; i++) { |
1965 | - n[7 + i + SRV_MAX_N_IO_THREADS] = i; /* using as index for arrays in purge_sys */ |
1966 | + n[8 + i + SRV_MAX_N_IO_THREADS] = i; /* using as index for arrays in purge_sys */ |
1967 | os_thread_create(&srv_purge_worker_thread, |
1968 | - n + (7 + i + SRV_MAX_N_IO_THREADS), |
1969 | - thread_ids + (7 + i + SRV_MAX_N_IO_THREADS)); |
1970 | + n + (8 + i + SRV_MAX_N_IO_THREADS), |
1971 | + thread_ids + (8 + i + SRV_MAX_N_IO_THREADS)); |
1972 | } |
1973 | } |
1974 | #ifdef UNIV_DEBUG |
1975 | |
1976 | === modified file 'doc/source/index.rst' |
1977 | --- doc/source/index.rst 2012-04-02 09:36:37 +0000 |
1978 | +++ doc/source/index.rst 2012-04-25 22:22:24 +0000 |
1979 | @@ -126,6 +126,7 @@ |
1980 | management/udf_maatkit |
1981 | management/innodb_fake_changes |
1982 | management/innodb_kill_idle_trx |
1983 | + management/innodb_log_archiving |
1984 | |
1985 | Diagnostics Improvements |
1986 | ======================== |
1987 | |
1988 | === added file 'doc/source/management/innodb_log_archiving.rst' |
1989 | --- doc/source/management/innodb_log_archiving.rst 1970-01-01 00:00:00 +0000 |
1990 | +++ doc/source/management/innodb_log_archiving.rst 2012-04-25 22:22:24 +0000 |
1991 | @@ -0,0 +1,59 @@ |
1992 | +.. _innodb_fast_index_creation: |
1993 | + |
1994 | +===================== |
1995 | + Innodb Log archiving |
1996 | +===================== |
1997 | + |
1998 | +The purpose of archiving logs is to be able to use them as a form of incremental backup. |
1999 | + |
2000 | +By replaying archived logs since the last backup taken with xtrabackup, you can get an online incremental backup. |
2001 | + |
2002 | +When log archiving is enabled, instead of rotating through log files, XtraDB will create a new one. There should always be one spare log file so that transactions are never stalled at log file rotation. |
2003 | + |
2004 | +``PURGE ARCHIVE LOGS`` |
2005 | +================ |
2006 | + |
2007 | +Syntax: |
2008 | + |
2009 | +PURGE ARCHIVED LOGS { TO 'filename' | BEFORE `datetime`} |
2010 | + |
2011 | +Examples: |
2012 | + |
2013 | +PURGE ARCHIVED LOGS TO 'ib_log_archive_000262325167341'; |
2014 | + |
2015 | +PURGE ARCHIVED LOGS BEFORE '2008-04-02 22:46:26'; |
2016 | + |
2017 | + |
2018 | + |
2019 | +System Variables |
2020 | +================ |
2021 | + |
2022 | +.. variable:: innodb_xtra_log_archive |
2023 | + |
2024 | + :cli: Yes |
2025 | + :conf: Yes |
2026 | + :scope: Global |
2027 | + :dyn: Yes |
2028 | + :vartype: Boolean |
2029 | + :default: OFF |
2030 | + :range: ON/OFF |
2031 | + |
2032 | +.. variable:: innodb_xtra_log_archive_dir |
2033 | + |
2034 | + :cli: Yes |
2035 | + :conf: Yes |
2036 | + :scope: Global |
2037 | + :dyn: No |
2038 | + :vartype: String |
2039 | + :default: '' |
2040 | + |
2041 | +.. variable:: innodb_xtra_expire_archive_logs_sec |
2042 | + |
2043 | + :cli: Yes |
2044 | + :conf: Yes |
2045 | + :scope: Global |
2046 | + :dyn: Yes |
2047 | + :vartype: Integer |
2048 | + :default: 0 |
2049 | + :range: 0- |
2050 | + |
Nickolay -
Overall impression looks good. I have some comments/questions:
What we are going to do when/if UNIV_LOG_ARCHIVE InnoDB log archiving
is enabled upstream? The implementations are not drop-in replacements
for each other (see below), so maybe it's good to prevent potential
user confusion by inventing another name for the XtraDB one?
What is the difference between this implementation and
UNIV_LOG_ARCHIVE anyway? As I see it:
1) this one is simpler and more parallel.
2) UNIV_LOG_ARCHIVE is able to archive up to the last checkpoint,
while this one is able to archive up to the last log file change.
Are there any other differences?
I am not sure about the archive file naming convention, i.e. including
the LSN in the file name instead of sequence number. With sequence
number it is easier to detect continuity errors when some file gets
lost. Perhaps include both?
SLEEP 4 in the test may result in non-deterministic behaviour on
loaded test machines. It's better to use DEBUG_SYNC facilities.
Why does log_sys->lsn need to be protected by log_sys- >archived_ mutex
too? I see no need to stop it advancing while the archiving is going
on as far as the log_write_low check is in place.
fil_swap_file does not have a header comment.
Please document the new fields in log_sys struct. I think a better
name for archived_mutex would be arch_sys_mutex or similar.
purge_archived_logs should have an InnoDB style header comment.
Please move SRV_PATH_SEPARATOR, srv_calc_low32, srv_calc_high32
definitions from srv0start.c to srv0start.h instead of copying them to
srv0srv.c
s/archivation/ archiving
s/"Log archived until"/"Log archived up to" in log_print()
Diff line 315: whitespace mismatch
Inconsistent code formatting: occurences of "if(foo)" or even
"if( foo)". Should be "if (foo)" everywhere.
I'd try to pretend to support multiple log groups with >log_groups, but I guess that's
UT_LIST_GET_NEXT loop over the log_sys-
strictly optional.