Merge lp:~sergei.glushchenko/percona-xtrabackup/xb-tools into lp:percona-xtrabackup/2.1
- xb-tools
- Merge into 2.1
Status: | Work in progress |
---|---|
Proposed branch: | lp:~sergei.glushchenko/percona-xtrabackup/xb-tools |
Merge into: | lp:percona-xtrabackup/2.1 |
Diff against target: |
7189 lines (+6798/-18) (has conflicts) 19 files modified
patches/innodb51.patch (+342/-7) src/Makefile (+14/-5) src/api_log.c (+1493/-0) src/api_log.h (+213/-0) src/api_page.c (+3522/-0) src/api_page.h (+70/-0) src/fil_cur.c (+3/-1) src/fil_cur.h (+1/-0) src/innodb_int.c (+75/-0) src/innodb_int.h (+322/-2) src/percona-pprint.c (+146/-0) src/percona-redo.c (+216/-0) src/xtrabackup.c (+18/-0) test/inc/allpagetypes.sql (+147/-0) test/inc/allrectypes.sql (+154/-0) test/run.sh (+9/-1) test/t/percona-pprint.sh (+27/-0) test/t/percona-redo.sh (+20/-0) utils/build.sh (+6/-2) Text conflict in src/innodb_int.h |
To merge this branch: | bzr merge lp:~sergei.glushchenko/percona-xtrabackup/xb-tools |
Related bugs: | |
Related blueprints: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Laurynas Biveinis (community) | Needs Fixing | ||
Alexey Kopytov | Pending | ||
Review via email: mp+138331@code.launchpad.net |
This proposal supersedes a proposal from 2012-06-21.
Commit message
Description of the change
Log and printers are build inside XtraBackup tree. Following are how it been done:
innodb51-
innodb51-
api0internal.h - some innodb internals exposed
api0log.c - log printer code
api0page.c - page printer code
innodb_init.c - innodb initialization code needed for standalone utils
percona-pprint.cc - standalone page printer main function
percona-redo.cc - standalone log printer main function
to build standalone tools utils/build.sh utils
utils are also linked to xtrabackup_plugin
Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal | # |
Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal | # |
In addition to the above, I think api0internal.h has to be merged with
innodb_int.h, since the latter has the same purpose.
And api0log.c and api0print.c should have better name, I don't see a
point in following the InnoDB file naming conventions. Especially
because no one except Heikki knows the reason to name files like
xxx0yyy.c :)
Laurynas Biveinis (laurynas-biveinis) wrote : Posted in a previous version of this proposal | # |
Alexey -
I guess we want to minimize differences between the HailDB and XB versions of the utilities, and IMHO api0internal.h makes more sense in the former where there is no innodb_int.h. I agree we could name files better for XB, but for the HailDB modifications it makes sense to stick with foo0bar naming convention. But this is not a very strong opinion.
Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal | # |
Laurynas,
On 07/05/2012 09:26 AM, Laurynas Biveinis wrote:
> I guess we want to minimize differences between the HailDB and XB versions of the utilities, and IMHO api0internal.h makes more sense in the former where there is no innodb_int.h. I agree we could name files better for XB, but for the HailDB modifications it makes sense to stick with foo0bar naming convention. But this is not a very strong opinion.
>
I remember we were discussing this, but I'm not sure about our current
plans about the HailDB version of the utilities. Do we have anything
specific set?
Sergei Glushchenko (sergei.glushchenko) wrote : Posted in a previous version of this proposal | # |
Following been done:
Formatted to meet 80 chars limitation.
C++ parts rewritten in C.
Some code cleanup, removed commented and #if 0'ed parts.
innodb_init_param moved to innodb_int.c
api0* files were renamed to api_*
api0internal.h was merged with innodb_int.h
I consider that it is ready for the next iteration.
Laurynas Biveinis (laurynas-biveinis) wrote : Posted in a previous version of this proposal | # |
This is a partial review only, I will continue later.
Please create and link a blueprint for this work.
Is it possible to merge the tools InnoDB patch with some existing
patch? I guess for that some more effort would be required: to
uncomment but conditionally skip the commented
innobase_
know if this additional effort is justifiable or not.
Instead of open_or_
just open_log_file() that always sets the proposed log file from
the actual file size? In general I don't like the _ex naming
convention, because as time passes it is never apparent what is
meant by it.
What is the purpose of rec_get_
does not have a header comment, and the one next to its
declaration does not tell why "new" function is not good enough.
Why there are separate rules for the utility functions in XB? I
think we should just link them in the relevant xb configurations
by default. If they are needed then the Makefile diff at lines
591--599 contains $(CFLAGS), $(CXXFLAGS), $(CCFLAGS). I think
only the first is correct, and then the rules can be merged.
Makefile "utils" target should be marked as phony and IMHO it
should be included in the default build.
Can the INNODBOBJS definition for utils be reused from some other
target instead of copy-paste?
Line 677: please define MLOG_LSN conditionally with #ifndef
MLOG_LSN
The ib_log_rec_*, ib_log_sys_* structs and functions need
comments. This was my work, please ping me on IRC and we will
coordinate.
The #if 0 blocks in fill_parse_buffer should go away. Likewise in
ib_log_sys_g et_next_rec().
The untested log record types still need testing. That's a non
trivial task, need coordination with QA.
Stewart Smith (stewart) wrote : Posted in a previous version of this proposal | # |
Alexey Kopytov <email address hidden> writes:
> I remember we were discussing this, but I'm not sure about our current
> plans about the HailDB version of the utilities. Do we have anything
> specific set?
No, nothing solid. Although api0internal.h is more innodb-like naming.
--
Stewart Smith
Laurynas Biveinis (laurynas-biveinis) wrote : Posted in a previous version of this proposal | # |
Couple more comments:
The page printer utility starts & commits MTRs, for example i ib_page_
How do you plan automating testing this, both as standalone utility and GDB entry points in the XB binary?
Sergei Glushchenko (sergei.glushchenko) wrote : Posted in a previous version of this proposal | # |
Laurynas,
>
> Please create and link a blueprint for this work.
>
https:/
Please look at the BP above and tells whether it good or must be rewritten.
> Is it possible to merge the tools InnoDB patch with some existing
> patch? I guess for that some more effort would be required: to
> uncomment but conditionally skip the commented
> innobase_
> know if this additional effort is justifiable or not.
>
Yep, there is nothing hard in merging utils patch with innodb51.patch.
innobase_
for both xtrabackup and utils so there is no problem.
Patches been merged.
> Instead of open_or_
> just open_log_file() that always sets the proposed log file from
> the actual file size? In general I don't like the _ex naming
> convention, because as time passes it is never apparent what is
> meant by it.
>
Yep. I tend to agree with you.
> What is the purpose of rec_get_
> does not have a header comment, and the one next to its
> declaration does not tell why "new" function is not good enough.
>
In case when we deal with redundant page format we don't need to have
dict_index_t* for this page. However rec_get_offsets_new always require
this, so I made separate function rec_get_
to replace
ut_ad(index);
with something like
ut_ad(!
> Why there are separate rules for the utility functions in XB? I
> think we should just link them in the relevant xb configurations
> by default. If they are needed then the Makefile diff at lines
> 591--599 contains $(CFLAGS), $(CXXFLAGS), $(CCFLAGS). I think
> only the first is correct, and then the rules can be merged.
>
> Makefile "utils" target should be marked as phony and IMHO it
> should be included in the default build.
>
> Can the INNODBOBJS definition for utils be reused from some other
> target instead of copy-paste?
>
I've removed target 'utils'. Now utils are build with 'innodb51' target.
> Line 677: please define MLOG_LSN conditionally with #ifndef
> MLOG_LSN
>
done
> The #if 0 blocks in fill_parse_buffer should go away. Likewise in
> ib_log_sys_g et_next_rec().
>
done
> The ib_log_rec_*, ib_log_sys_* structs and functions need
> comments. This was my work, please ping me on IRC and we will
> coordinate.
>
I'll try to write comments by myself first (it's useful as I will get more familiar with code) and
will send you email my version. Then you will correct them and reply back to me. Will this work?
Sergei Glushchenko (sergei.glushchenko) wrote : Posted in a previous version of this proposal | # |
> Couple more comments:
>
> The page printer utility starts & commits MTRs, for example i
> ib_page_
> write to the log in the utility?
>
As long as page printer doesn't make changes to buffer pool pages, mtr_commit doesn't write to log.
> How do you plan automating testing this, both as standalone utility and GDB
> entry points in the XB binary?
We should think about it:)
Laurynas Biveinis (laurynas-biveinis) wrote : Posted in a previous version of this proposal | # |
> https:/
> printers-
> Please look at the BP above and tells whether it good or must be rewritten.
Thanks, I commented on its whiteboard.
> > The ib_log_rec_*, ib_log_sys_* structs and functions need
> > comments. This was my work, please ping me on IRC and we will
> > coordinate.
> >
>
> I'll try to write comments by myself first (it's useful as I will get more
> familiar with code) and
> will send you email my version. Then you will correct them and reply back to
> me. Will this work?
Yes.
Laurynas Biveinis (laurynas-biveinis) wrote : Posted in a previous version of this proposal | # |
> > Couple more comments:
> >
> > The page printer utility starts & commits MTRs, for example i
> > ib_page_
> > write to the log in the utility?
> >
>
> As long as page printer doesn't make changes to buffer pool pages, mtr_commit
> doesn't write to log.
No way to avoid creating those MTRs and passing NULL MTRs around? Or asserting that MTR did not write anything?
> > How do you plan automating testing this, both as standalone utility and GDB
> > entry points in the XB binary?
>
> We should think about it:)
I see two ways, with distinct advantages and disadvantages:
1) Provide entry to those functions through some new XB command-line options. Then test those options.
2) Script gdb to call these functions.
The latter is closer to the actual use case but the former might be enough perhaps?
Vlad Lesin (vlad-lesin) wrote : Posted in a previous version of this proposal | # |
1) Building:
AUTO_DOWNLOAD=yes utils/build.sh innodb51
...
Building XtraBackup
Makefile:190: target `innodb_int.o' given more than once in the same rule.
...
api_page.c: In function ‘ib_page_
api_page.c:2715:24: warning: variable ‘ifield’ set but not used [-Wunused-
api_page.c: In function ‘ib_page_
api_page.c:2880:9: warning: variable ‘n_recs’ set but not used [-Wunused-
api_log.c: In function ‘ib_log_
api_log.c:816:8: warning: variable ‘ret’ set but not used [-Wunused-
innodb_int.c: In function ‘innodb_
innodb_int.c:65:16: warning: assignment discards ‘const’ qualifier from pointer target type [enabled by default]
innodb_int.c:82:2: warning: passing argument 1 of ‘srv_parse_
/home/vlesin/
api_log.c: In function ‘ib_log_sys_print’:
api_log.c:1449:1: warning: control reaches end of non-void function [-Wreturn-type]
...
cc: error: percona-pprint.o: No such file or directory
2) Code style:
a) 16, 35, 93 - innodb code style requires comment which underlines function name the same length as underlined function name;
b) 100, 251 - unaligned comment;
c) 150, 151, 243- function description is absent;
d) 14-15, 33-34, 60-61, 67-68, 2427, 2444, 2468 and other functions in api_page.c containing page pointer as an argument, - function argument description is absent;
e) I don't think _old and _new function names postfixes is a good idea. What if there is one more new format? As I see there are two variants of code for calculating record offsets. One is for "compact" and another is for "external" formats. We could just use _cmp_fmt and _ext_fmt postfixes for that functions instead of _old and _new.
f) I think api_page.c should correspond to innodb code style as api_log.c does to have some uniformity in api_* files. If so there should be explaining comments for function declarations and definitions. And the same remark as 2a.
3) Possible errors:
a) 330-338 - if "create_new_db" is false then "ret" is not initialized but it is compared with "FALSE" in 338. This comparison is unneeded because "ret" is initialized only if "create_new_db" is true. Otherwise the first argument of "or" operator is true and there is not need to check the second one.
339-340 - the "if" block will never work because if we are at this line the "create_new_db" is false. I think this block should be under "if (create_new_db)" condition.
It would be great if you comment your changes in open_or_
b) 2567-2569 it would be good if we checked "create_new_db" for false.
Sergei Glushchenko (sergei.glushchenko) wrote : Posted in a previous version of this proposal | # |
Vlad,
> a) 330-338 - if "create_new_db" is false then "ret" is not initialized but it is compared with "FALSE" in 338. This comparison is unneeded because "ret" is initialized only if "create_new_db" is true. Otherwise the first argument of "or" operator is true and there is not need to check the second one.
Just a little comment. I put the code below to not move eyes up and down while writing this.
if (create_new_db) {
files[i]
= os_file_
OS_LOG_FILE, &ret);
}
if (!create_new_db || ret == FALSE) {
if (create_new_db
&& os_file_
...
) {
...
return(
}
files[i] = os_file_
OS_LOG_FILE, &ret);
I can't see any mistake in this lines.
Indeed, consider create_new_db is TRUE and we are trying to create new file. We have two options here. Creation succeeded and ret is set to TRUE, or creation failed and ret is set to FALSE.
Next we check whether we created file or not by using this condition (!create_new_db || ret == FALSE). Obviously if create_new_db is TRUE, the result depends only on the ret value. And we should report error (last error was not OS_FILE_
Now lets consider create_new_db is FALSE. In this case we go straight to opening file with OS_FILE_OPEN. Because all conditions in this case not depend on ret value, which is not set as you noticed before.
Sergei Glushchenko (sergei.glushchenko) wrote : Posted in a previous version of this proposal | # |
Vlad,
> e) I don't think _old and _new function names postfixes is a good idea. What if there is one more new format? As I see there are two variants of code for calculating record offsets. One is for "compact" and another is for "external" formats. We could just use _cmp_fmt and _ext_fmt postfixes for that functions instead of _old and _new.
Yes. There are two major physical row formats in InnoDB http://
Sergei Glushchenko (sergei.glushchenko) wrote : Posted in a previous version of this proposal | # |
I did some testing of entry points in xtrabackup and here are my findings:
In 'backup' mode:
Page printer fails. In order for it to work following initialization should be done first:
buf_pool_init();
dict_ind_init();
dict_boot(FALSE);
dict_check_
and IBUF should initialized in order to print IBUF pages
Log printer also fails.
recv_sys_create()
is needed.
In 'prepare' mode:
For page printer to work:
dict_ind_init();
dict_boot(FALSE);
dict_check_
Log printer work just fine
In 'stats' mode:
Both page and log printers work OK.
I don't think we should initialize all these systems every time when running xtrabackup. However it would be nice to make log and page printers more useable inside xtrabackup. Maybe we should make some initialization function for these tools which used could call from gdb before using log or page printer.
I also found that by making create_new_db flag meaningful breaks second '--prepare' run (in open_or_
Laurynas Biveinis (laurynas-biveinis) wrote : Posted in a previous version of this proposal | # |
I think all required subsystems must be initialized on startup then, unless something precludes this.
Sergei Glushchenko (sergei.glushchenko) wrote : Posted in a previous version of this proposal | # |
Couple more bugs been found in initialization of log printer.
1. When compiled with debug, several failures occurred on ut_a(&(
2. mem_init() call needed for debug builds
3. ib_log_sys_start opens only one log file from group.
Sergei Glushchenko (sergei.glushchenko) wrote : Posted in a previous version of this proposal | # |
Also it would be nice to have commandline argument --log-file-size
Sergei Glushchenko (sergei.glushchenko) wrote : Posted in a previous version of this proposal | # |
Comments for ib_page_* and ib_log_* fucntions, more InnoDB code conventions fixes.
Two testcases added for standalone tools.
Fixed number of initialization and locking errors.
Sergei Glushchenko (sergei.glushchenko) wrote : Posted in a previous version of this proposal | # |
Hey, guys!
Many of your comments were taken into account, many other things were spotted and fixed. Could you please review this once more.
Laurynas Biveinis (laurynas-biveinis) wrote : | # |
Diff has conflicts.
Unmerged revisions
- 417. By Sergei Glushchenko
-
made extra initialization for innodb51 only
- 416. By Sergei Glushchenko
-
Additional initialization in xtrabackup in order to be able to run printers entry points.
- 415. By Sergei Glushchenko
-
Buffer overrun. Fix bug in release build
- 414. By Sergei Glushchenko
-
Fix percona*.sh tests
- 413. By Sergei Glushchenko
-
Fix build with builtin innodb. Missing percona-*.o deps in Makefile. Added missing .sql for tests
- 412. By Sergei Glushchenko
-
2 basic tests
- 411. By Sergei Glushchenko
-
Merge trunk
- 410. By Sergei Glushchenko
-
Debug build tested. Some initialization errors fixed. Some locking errors fixed.
- 409. By Sergei Glushchenko
-
Fixes after entry points testing. Do not use create_new_db flag in open_or_
create_ log_file_ ex - 408. By Sergei Glushchenko
-
InnoDB coding conventions, comments for functions and arguments.
Fixed some warnings.
Preview Diff
1 | === modified file 'patches/innodb51.patch' | |||
2 | --- patches/innodb51.patch 2012-11-14 04:46:11 +0000 | |||
3 | +++ patches/innodb51.patch 2012-12-05 22:33:23 +0000 | |||
4 | @@ -50,7 +50,26 @@ | |||
5 | 50 | #endif | 50 | #endif |
6 | 51 | buf_pool->stat.n_page_gets++; | 51 | buf_pool->stat.n_page_gets++; |
7 | 52 | loop: | 52 | loop: |
9 | 53 | @@ -2894,7 +2896,7 @@ | 53 | @@ -2075,7 +2077,8 @@ |
10 | 54 | access_time = buf_page_is_accessed(&block->page); | ||
11 | 55 | buf_page_set_accessed_make_young(&block->page, access_time); | ||
12 | 56 | |||
13 | 57 | - ut_ad(!ibuf_inside() | ||
14 | 58 | + ut_ad(srv_fake_write | ||
15 | 59 | + || !ibuf_inside() | ||
16 | 60 | || ibuf_page(buf_block_get_space(block), | ||
17 | 61 | buf_block_get_zip_size(block), | ||
18 | 62 | buf_block_get_page_no(block), NULL)); | ||
19 | 63 | @@ -2203,7 +2206,7 @@ | ||
20 | 64 | buf_pool_mutex_exit(); | ||
21 | 65 | } | ||
22 | 66 | |||
23 | 67 | - ut_ad(!ibuf_inside() || (mode == BUF_KEEP_OLD)); | ||
24 | 68 | + ut_ad(srv_fake_write || !ibuf_inside() || (mode == BUF_KEEP_OLD)); | ||
25 | 69 | |||
26 | 70 | if (rw_latch == RW_S_LATCH) { | ||
27 | 71 | success = rw_lock_s_lock_nowait(&(block->lock), | ||
28 | 72 | @@ -2894,7 +2897,7 @@ | ||
29 | 54 | recv_recover_page(TRUE, (buf_block_t*) bpage); | 73 | recv_recover_page(TRUE, (buf_block_t*) bpage); |
30 | 55 | } | 74 | } |
31 | 56 | 75 | ||
32 | @@ -158,6 +177,49 @@ | |||
33 | 158 | return; | 177 | return; |
34 | 159 | } | 178 | } |
35 | 160 | 179 | ||
36 | 180 | --- a/storage/innodb_plugin/dict/dict0boot.c | ||
37 | 181 | +++ b/storage/innodb_plugin/dict/dict0boot.c | ||
38 | 182 | @@ -241,8 +241,8 @@ | ||
39 | 183 | started. This function is also called when the data dictionary is created. */ | ||
40 | 184 | UNIV_INTERN | ||
41 | 185 | void | ||
42 | 186 | -dict_boot(void) | ||
43 | 187 | -/*===========*/ | ||
44 | 188 | +dict_boot(ibool ibuf_init) | ||
45 | 189 | +/*======================*/ | ||
46 | 190 | { | ||
47 | 191 | dict_table_t* table; | ||
48 | 192 | dict_index_t* index; | ||
49 | 193 | @@ -442,7 +442,8 @@ | ||
50 | 194 | |||
51 | 195 | /* Initialize the insert buffer table and index for each tablespace */ | ||
52 | 196 | |||
53 | 197 | - ibuf_init_at_db_start(); | ||
54 | 198 | + if (ibuf_init) | ||
55 | 199 | + ibuf_init_at_db_start(); | ||
56 | 200 | |||
57 | 201 | /* Load definitions of other indexes on system tables */ | ||
58 | 202 | |||
59 | 203 | @@ -469,8 +470,8 @@ | ||
60 | 204 | Creates and initializes the data dictionary at the database creation. */ | ||
61 | 205 | UNIV_INTERN | ||
62 | 206 | void | ||
63 | 207 | -dict_create(void) | ||
64 | 208 | -/*=============*/ | ||
65 | 209 | +dict_create(ibool ibuf_init) | ||
66 | 210 | +/*========================*/ | ||
67 | 211 | { | ||
68 | 212 | mtr_t mtr; | ||
69 | 213 | |||
70 | 214 | @@ -480,7 +481,7 @@ | ||
71 | 215 | |||
72 | 216 | mtr_commit(&mtr); | ||
73 | 217 | |||
74 | 218 | - dict_boot(); | ||
75 | 219 | + dict_boot(ibuf_init); | ||
76 | 220 | |||
77 | 221 | dict_insert_initial_data(); | ||
78 | 222 | } | ||
79 | 161 | --- a/storage/innodb_plugin/fil/fil0fil.c | 223 | --- a/storage/innodb_plugin/fil/fil0fil.c |
80 | 162 | +++ b/storage/innodb_plugin/fil/fil0fil.c | 224 | +++ b/storage/innodb_plugin/fil/fil0fil.c |
81 | 163 | @@ -48,6 +48,8 @@ | 225 | @@ -48,6 +48,8 @@ |
82 | @@ -642,6 +704,27 @@ | |||
83 | 642 | while (sum_pages < n_pages) { | 704 | while (sum_pages < n_pages) { |
84 | 643 | n_bytes = ibuf_contract_ext(&n_pag2, sync); | 705 | n_bytes = ibuf_contract_ext(&n_pag2, sync); |
85 | 644 | 706 | ||
86 | 707 | --- a/storage/innodb_plugin/include/dict0boot.h | ||
87 | 708 | +++ b/storage/innodb_plugin/include/dict0boot.h | ||
88 | 709 | @@ -82,14 +82,14 @@ | ||
89 | 710 | started. This function is also called when the data dictionary is created. */ | ||
90 | 711 | UNIV_INTERN | ||
91 | 712 | void | ||
92 | 713 | -dict_boot(void); | ||
93 | 714 | -/*===========*/ | ||
94 | 715 | +dict_boot(ibool ibuf_init); | ||
95 | 716 | +/*=======================*/ | ||
96 | 717 | /*****************************************************************//** | ||
97 | 718 | Creates and initializes the data dictionary at the database creation. */ | ||
98 | 719 | UNIV_INTERN | ||
99 | 720 | void | ||
100 | 721 | -dict_create(void); | ||
101 | 722 | -/*=============*/ | ||
102 | 723 | +dict_create(ibool ibuf_init); | ||
103 | 724 | +/*=========================*/ | ||
104 | 725 | |||
105 | 726 | |||
106 | 727 | /* Space id and page no where the dictionary header resides */ | ||
107 | 645 | --- a/storage/innodb_plugin/include/mem0mem.ic | 728 | --- a/storage/innodb_plugin/include/mem0mem.ic |
108 | 646 | +++ b/storage/innodb_plugin/include/mem0mem.ic | 729 | +++ b/storage/innodb_plugin/include/mem0mem.ic |
109 | 647 | @@ -367,7 +367,7 @@ | 730 | @@ -367,7 +367,7 @@ |
110 | @@ -664,6 +747,41 @@ | |||
111 | 664 | 747 | ||
112 | 665 | if ((object == slot->object) && (type == slot->type)) { | 748 | if ((object == slot->object) && (type == slot->type)) { |
113 | 666 | 749 | ||
114 | 750 | --- a/storage/innodb_plugin/include/rem0rec.h | ||
115 | 751 | +++ b/storage/innodb_plugin/include/rem0rec.h | ||
116 | 752 | @@ -361,6 +361,32 @@ | ||
117 | 753 | #define rec_get_offsets(rec,index,offsets,n,heap) \ | ||
118 | 754 | rec_get_offsets_func(rec,index,offsets,n,heap,__FILE__,__LINE__) | ||
119 | 755 | |||
120 | 756 | + | ||
121 | 757 | +/******************************************************//** | ||
122 | 758 | +The following function determines the offsets to each field | ||
123 | 759 | +in the record. Function can only calculate offsets for | ||
124 | 760 | +redundant row format records. | ||
125 | 761 | +It can reuse a previously allocated array. | ||
126 | 762 | +@return the new offsets */ | ||
127 | 763 | +UNIV_INTERN | ||
128 | 764 | +ulint* | ||
129 | 765 | +rec_get_offsets_old_func( | ||
130 | 766 | +/*=====================*/ | ||
131 | 767 | + const rec_t* rec, /*!< in: physical record */ | ||
132 | 768 | + ulint* offsets,/*!< in/out: array consisting of | ||
133 | 769 | + offsets[0] allocated elements, | ||
134 | 770 | + or an array from rec_get_offsets(), | ||
135 | 771 | + or NULL */ | ||
136 | 772 | + ulint n_fields,/*!< in: maximum number of | ||
137 | 773 | + initialized fields | ||
138 | 774 | + (ULINT_UNDEFINED if all fields) */ | ||
139 | 775 | + mem_heap_t** heap, /*!< in/out: memory heap */ | ||
140 | 776 | + const char* file, /*!< in: file name where called */ | ||
141 | 777 | + ulint line); /*!< in: line number where called */ | ||
142 | 778 | + | ||
143 | 779 | +#define rec_get_offsets_old(rec,offsets,n,heap) \ | ||
144 | 780 | + rec_get_offsets_old_func(rec,offsets,n,heap,__FILE__,__LINE__) | ||
145 | 781 | + | ||
146 | 782 | /******************************************************//** | ||
147 | 783 | Determine the offset to each field in a leaf-page record | ||
148 | 784 | in ROW_FORMAT=COMPACT. This is a special case of | ||
149 | 667 | --- a/storage/innodb_plugin/include/srv0srv.h | 785 | --- a/storage/innodb_plugin/include/srv0srv.h |
150 | 668 | +++ b/storage/innodb_plugin/include/srv0srv.h | 786 | +++ b/storage/innodb_plugin/include/srv0srv.h |
151 | 669 | @@ -202,6 +202,10 @@ | 787 | @@ -202,6 +202,10 @@ |
152 | @@ -868,6 +986,24 @@ | |||
153 | 868 | || (recv_addr->state == RECV_BEING_PROCESSED) | 986 | || (recv_addr->state == RECV_BEING_PROCESSED) |
154 | 869 | || (recv_addr->state == RECV_PROCESSED)) { | 987 | || (recv_addr->state == RECV_PROCESSED)) { |
155 | 870 | 988 | ||
156 | 989 | @@ -2012,7 +2013,7 @@ | ||
157 | 990 | /*******************************************************************//** | ||
158 | 991 | Tries to parse a single log record and returns its length. | ||
159 | 992 | @return length of the record, or 0 if the record was not complete */ | ||
160 | 993 | -static | ||
161 | 994 | +UNIV_INTERN | ||
162 | 995 | ulint | ||
163 | 996 | recv_parse_log_rec( | ||
164 | 997 | /*===============*/ | ||
165 | 998 | @@ -2083,7 +2084,7 @@ | ||
166 | 999 | |||
167 | 1000 | /*******************************************************//** | ||
168 | 1001 | Calculates the new value for lsn when more data is added to the log. */ | ||
169 | 1002 | -static | ||
170 | 1003 | +UNIV_INTERN | ||
171 | 1004 | ib_uint64_t | ||
172 | 1005 | recv_calc_lsn_on_data_add( | ||
173 | 1006 | /*======================*/ | ||
174 | 871 | @@ -2297,7 +2298,7 @@ | 1007 | @@ -2297,7 +2298,7 @@ |
175 | 872 | || type == MLOG_FILE_RENAME | 1008 | || type == MLOG_FILE_RENAME |
176 | 873 | || type == MLOG_FILE_DELETE) { | 1009 | || type == MLOG_FILE_DELETE) { |
177 | @@ -1007,6 +1143,158 @@ | |||
178 | 1007 | #endif | 1143 | #endif |
179 | 1008 | } | 1144 | } |
180 | 1009 | 1145 | ||
181 | 1146 | --- a/storage/innodb_plugin/rem/rem0rec.c | ||
182 | 1147 | +++ b/storage/innodb_plugin/rem/rem0rec.c | ||
183 | 1148 | @@ -344,6 +344,50 @@ | ||
184 | 1149 | = (rec - (lens + 1)) | REC_OFFS_COMPACT | any_ext; | ||
185 | 1150 | } | ||
186 | 1151 | |||
187 | 1152 | +static void | ||
188 | 1153 | +rec_init_offsets_old( | ||
189 | 1154 | +/*=================*/ | ||
190 | 1155 | + const rec_t* rec, /*!< in: physical record */ | ||
191 | 1156 | + ulint* offsets)/*!< in/out: array of offsets; | ||
192 | 1157 | + in: n=rec_offs_n_fields(offsets) */ | ||
193 | 1158 | +{ | ||
194 | 1159 | + ulint i = 0; | ||
195 | 1160 | + ulint offs; | ||
196 | 1161 | + | ||
197 | 1162 | + /* Old-style record: determine extra size and end offsets */ | ||
198 | 1163 | + offs = REC_N_OLD_EXTRA_BYTES; | ||
199 | 1164 | + if (rec_get_1byte_offs_flag(rec)) { | ||
200 | 1165 | + offs += rec_offs_n_fields(offsets); | ||
201 | 1166 | + *rec_offs_base(offsets) = offs; | ||
202 | 1167 | + /* Determine offsets to fields */ | ||
203 | 1168 | + do { | ||
204 | 1169 | + offs = rec_1_get_field_end_info(rec, i); | ||
205 | 1170 | + if (offs & REC_1BYTE_SQL_NULL_MASK) { | ||
206 | 1171 | + offs &= ~REC_1BYTE_SQL_NULL_MASK; | ||
207 | 1172 | + offs |= REC_OFFS_SQL_NULL; | ||
208 | 1173 | + } | ||
209 | 1174 | + rec_offs_base(offsets)[1 + i] = offs; | ||
210 | 1175 | + } while (++i < rec_offs_n_fields(offsets)); | ||
211 | 1176 | + } else { | ||
212 | 1177 | + offs += 2 * rec_offs_n_fields(offsets); | ||
213 | 1178 | + *rec_offs_base(offsets) = offs; | ||
214 | 1179 | + /* Determine offsets to fields */ | ||
215 | 1180 | + do { | ||
216 | 1181 | + offs = rec_2_get_field_end_info(rec, i); | ||
217 | 1182 | + if (offs & REC_2BYTE_SQL_NULL_MASK) { | ||
218 | 1183 | + offs &= ~REC_2BYTE_SQL_NULL_MASK; | ||
219 | 1184 | + offs |= REC_OFFS_SQL_NULL; | ||
220 | 1185 | + } | ||
221 | 1186 | + if (offs & REC_2BYTE_EXTERN_MASK) { | ||
222 | 1187 | + offs &= ~REC_2BYTE_EXTERN_MASK; | ||
223 | 1188 | + offs |= REC_OFFS_EXTERNAL; | ||
224 | 1189 | + *rec_offs_base(offsets) |= REC_OFFS_EXTERNAL; | ||
225 | 1190 | + } | ||
226 | 1191 | + rec_offs_base(offsets)[1 + i] = offs; | ||
227 | 1192 | + } while (++i < rec_offs_n_fields(offsets)); | ||
228 | 1193 | + } | ||
229 | 1194 | +} | ||
230 | 1195 | + | ||
231 | 1196 | /******************************************************//** | ||
232 | 1197 | The following function determines the offsets to each field in the | ||
233 | 1198 | record. The offsets are written to a previously allocated array of | ||
234 | 1199 | @@ -480,38 +524,7 @@ | ||
235 | 1200 | *rec_offs_base(offsets) | ||
236 | 1201 | = (rec - (lens + 1)) | REC_OFFS_COMPACT; | ||
237 | 1202 | } else { | ||
238 | 1203 | - /* Old-style record: determine extra size and end offsets */ | ||
239 | 1204 | - offs = REC_N_OLD_EXTRA_BYTES; | ||
240 | 1205 | - if (rec_get_1byte_offs_flag(rec)) { | ||
241 | 1206 | - offs += rec_offs_n_fields(offsets); | ||
242 | 1207 | - *rec_offs_base(offsets) = offs; | ||
243 | 1208 | - /* Determine offsets to fields */ | ||
244 | 1209 | - do { | ||
245 | 1210 | - offs = rec_1_get_field_end_info(rec, i); | ||
246 | 1211 | - if (offs & REC_1BYTE_SQL_NULL_MASK) { | ||
247 | 1212 | - offs &= ~REC_1BYTE_SQL_NULL_MASK; | ||
248 | 1213 | - offs |= REC_OFFS_SQL_NULL; | ||
249 | 1214 | - } | ||
250 | 1215 | - rec_offs_base(offsets)[1 + i] = offs; | ||
251 | 1216 | - } while (++i < rec_offs_n_fields(offsets)); | ||
252 | 1217 | - } else { | ||
253 | 1218 | - offs += 2 * rec_offs_n_fields(offsets); | ||
254 | 1219 | - *rec_offs_base(offsets) = offs; | ||
255 | 1220 | - /* Determine offsets to fields */ | ||
256 | 1221 | - do { | ||
257 | 1222 | - offs = rec_2_get_field_end_info(rec, i); | ||
258 | 1223 | - if (offs & REC_2BYTE_SQL_NULL_MASK) { | ||
259 | 1224 | - offs &= ~REC_2BYTE_SQL_NULL_MASK; | ||
260 | 1225 | - offs |= REC_OFFS_SQL_NULL; | ||
261 | 1226 | - } | ||
262 | 1227 | - if (offs & REC_2BYTE_EXTERN_MASK) { | ||
263 | 1228 | - offs &= ~REC_2BYTE_EXTERN_MASK; | ||
264 | 1229 | - offs |= REC_OFFS_EXTERNAL; | ||
265 | 1230 | - *rec_offs_base(offsets) |= REC_OFFS_EXTERNAL; | ||
266 | 1231 | - } | ||
267 | 1232 | - rec_offs_base(offsets)[1 + i] = offs; | ||
268 | 1233 | - } while (++i < rec_offs_n_fields(offsets)); | ||
269 | 1234 | - } | ||
270 | 1235 | + rec_init_offsets_old(rec, offsets); | ||
271 | 1236 | } | ||
272 | 1237 | } | ||
273 | 1238 | |||
274 | 1239 | @@ -587,6 +600,58 @@ | ||
275 | 1240 | return(offsets); | ||
276 | 1241 | } | ||
277 | 1242 | |||
278 | 1243 | +/******************************************************//** | ||
279 | 1244 | +The following function determines the offsets to each field | ||
280 | 1245 | +in the record. Function can only calculate offsets for | ||
281 | 1246 | +redundant row format records. | ||
282 | 1247 | +It can reuse a previously allocated array. | ||
283 | 1248 | +@return the new offsets */ | ||
284 | 1249 | +UNIV_INTERN | ||
285 | 1250 | +ulint* | ||
286 | 1251 | +rec_get_offsets_old_func( | ||
287 | 1252 | +/*=====================*/ | ||
288 | 1253 | + const rec_t* rec, /*!< in: physical record */ | ||
289 | 1254 | + ulint* offsets,/*!< in/out: array consisting of | ||
290 | 1255 | + offsets[0] allocated elements, | ||
291 | 1256 | + or an array from rec_get_offsets(), | ||
292 | 1257 | + or NULL */ | ||
293 | 1258 | + ulint n_fields,/*!< in: maximum number of | ||
294 | 1259 | + initialized fields | ||
295 | 1260 | + (ULINT_UNDEFINED if all fields) */ | ||
296 | 1261 | + mem_heap_t** heap, /*!< in/out: memory heap */ | ||
297 | 1262 | + const char* file, /*!< in: file name where called */ | ||
298 | 1263 | + ulint line) /*!< in: line number where called */ | ||
299 | 1264 | +{ | ||
300 | 1265 | + ulint n; | ||
301 | 1266 | + ulint size; | ||
302 | 1267 | + | ||
303 | 1268 | + ut_ad(rec); | ||
304 | 1269 | + ut_ad(heap); | ||
305 | 1270 | + | ||
306 | 1271 | + n = rec_get_n_fields_old(rec); | ||
307 | 1272 | + | ||
308 | 1273 | + if (UNIV_UNLIKELY(n_fields < n)) { | ||
309 | 1274 | + n = n_fields; | ||
310 | 1275 | + } | ||
311 | 1276 | + | ||
312 | 1277 | + size = n + (1 + REC_OFFS_HEADER_SIZE); | ||
313 | 1278 | + | ||
314 | 1279 | + if (UNIV_UNLIKELY(!offsets) | ||
315 | 1280 | + || UNIV_UNLIKELY(rec_offs_get_n_alloc(offsets) < size)) { | ||
316 | 1281 | + if (UNIV_UNLIKELY(!*heap)) { | ||
317 | 1282 | + *heap = mem_heap_create_func(size * sizeof(ulint), | ||
318 | 1283 | + MEM_HEAP_DYNAMIC, | ||
319 | 1284 | + file, line); | ||
320 | 1285 | + } | ||
321 | 1286 | + offsets = mem_heap_alloc(*heap, size * sizeof(ulint)); | ||
322 | 1287 | + rec_offs_set_n_alloc(offsets, size); | ||
323 | 1288 | + } | ||
324 | 1289 | + | ||
325 | 1290 | + rec_offs_set_n_fields(offsets, n); | ||
326 | 1291 | + rec_init_offsets_old(rec, offsets); | ||
327 | 1292 | + return(offsets); | ||
328 | 1293 | +} | ||
329 | 1294 | + | ||
330 | 1295 | /******************************************************//** | ||
331 | 1296 | The following function determines the offsets to each field | ||
332 | 1297 | in the record. It can reuse a previously allocated array. */ | ||
333 | 1010 | --- a/storage/innodb_plugin/row/row0merge.c | 1298 | --- a/storage/innodb_plugin/row/row0merge.c |
334 | 1011 | +++ b/storage/innodb_plugin/row/row0merge.c | 1299 | +++ b/storage/innodb_plugin/row/row0merge.c |
335 | 1012 | @@ -453,7 +453,9 @@ | 1300 | @@ -453,7 +453,9 @@ |
336 | @@ -1084,6 +1372,15 @@ | |||
337 | 1084 | } | 1372 | } |
338 | 1085 | 1373 | ||
339 | 1086 | /*********************************************************************//** | 1374 | /*********************************************************************//** |
340 | 1375 | @@ -1321,7 +1326,7 @@ | ||
341 | 1376 | /*********************************************************************//** | ||
342 | 1377 | Normalizes init parameter values to use units we use inside InnoDB. | ||
343 | 1378 | @return DB_SUCCESS or error code */ | ||
344 | 1379 | -static | ||
345 | 1380 | +UNIV_INTERN | ||
346 | 1381 | ulint | ||
347 | 1382 | srv_normalize_init_values(void) | ||
348 | 1383 | /*===========================*/ | ||
349 | 1087 | --- a/storage/innodb_plugin/srv/srv0start.c | 1384 | --- a/storage/innodb_plugin/srv/srv0start.c |
350 | 1088 | +++ b/storage/innodb_plugin/srv/srv0start.c | 1385 | +++ b/storage/innodb_plugin/srv/srv0start.c |
351 | 1089 | @@ -94,6 +94,8 @@ | 1386 | @@ -94,6 +94,8 @@ |
352 | @@ -1104,7 +1401,18 @@ | |||
353 | 1104 | ulint | 1401 | ulint |
354 | 1105 | open_or_create_log_file( | 1402 | open_or_create_log_file( |
355 | 1106 | /*====================*/ | 1403 | /*====================*/ |
357 | 1107 | @@ -702,7 +704,7 @@ | 1404 | @@ -611,6 +619,10 @@ |
358 | 1405 | ret = os_file_get_size(files[i], &size, &size_high); | ||
359 | 1406 | ut_a(ret); | ||
360 | 1407 | |||
361 | 1408 | + srv_log_file_size = | ||
362 | 1409 | + ((ib_uint64_t)size_high << 32 | size) | ||
363 | 1410 | + >> UNIV_PAGE_SIZE_SHIFT; | ||
364 | 1411 | + | ||
365 | 1412 | if (size != srv_calc_low32(srv_log_file_size) | ||
366 | 1413 | || size_high != srv_calc_high32(srv_log_file_size)) { | ||
367 | 1414 | |||
368 | 1415 | @@ -702,7 +714,7 @@ | ||
369 | 1108 | /*********************************************************************//** | 1416 | /*********************************************************************//** |
370 | 1109 | Creates or opens database data files and closes them. | 1417 | Creates or opens database data files and closes them. |
371 | 1110 | @return DB_SUCCESS or error code */ | 1418 | @return DB_SUCCESS or error code */ |
372 | @@ -1113,7 +1421,7 @@ | |||
373 | 1113 | ulint | 1421 | ulint |
374 | 1114 | open_or_create_data_files( | 1422 | open_or_create_data_files( |
375 | 1115 | /*======================*/ | 1423 | /*======================*/ |
377 | 1116 | @@ -1359,7 +1361,7 @@ | 1424 | @@ -1359,7 +1371,7 @@ |
378 | 1117 | } | 1425 | } |
379 | 1118 | #endif /* UNIV_LOG_ARCHIVE */ | 1426 | #endif /* UNIV_LOG_ARCHIVE */ |
380 | 1119 | 1427 | ||
381 | @@ -1122,7 +1430,34 @@ | |||
382 | 1122 | fprintf(stderr, | 1430 | fprintf(stderr, |
383 | 1123 | "InnoDB: Error: combined size of log files" | 1431 | "InnoDB: Error: combined size of log files" |
384 | 1124 | " must be < 4 GB\n"); | 1432 | " must be < 4 GB\n"); |
386 | 1125 | @@ -1601,6 +1603,10 @@ | 1433 | @@ -1516,7 +1528,7 @@ |
387 | 1434 | mtr_commit(&mtr); | ||
388 | 1435 | |||
389 | 1436 | trx_sys_create(); | ||
390 | 1437 | - dict_create(); | ||
391 | 1438 | + dict_create(TRUE); | ||
392 | 1439 | srv_startup_is_before_trx_rollback_phase = FALSE; | ||
393 | 1440 | |||
394 | 1441 | #ifdef UNIV_LOG_ARCHIVE | ||
395 | 1442 | @@ -1534,7 +1546,7 @@ | ||
396 | 1443 | /* Since ibuf init is in dict_boot, and ibuf is needed | ||
397 | 1444 | in any disk i/o, first call dict_boot */ | ||
398 | 1445 | |||
399 | 1446 | - dict_boot(); | ||
400 | 1447 | + dict_boot(TRUE); | ||
401 | 1448 | trx_sys_init_at_db_start(); | ||
402 | 1449 | srv_startup_is_before_trx_rollback_phase = FALSE; | ||
403 | 1450 | |||
404 | 1451 | @@ -1590,7 +1602,7 @@ | ||
405 | 1452 | to access space 0, and the insert buffer at this stage already | ||
406 | 1453 | works for space 0. */ | ||
407 | 1454 | |||
408 | 1455 | - dict_boot(); | ||
409 | 1456 | + dict_boot(TRUE); | ||
410 | 1457 | trx_sys_init_at_db_start(); | ||
411 | 1458 | |||
412 | 1459 | /* Initialize the fsp free limit global variable in the log | ||
413 | 1460 | @@ -1601,6 +1613,10 @@ | ||
414 | 1126 | are initialized in trx_sys_init_at_db_start(). */ | 1461 | are initialized in trx_sys_init_at_db_start(). */ |
415 | 1127 | 1462 | ||
416 | 1128 | recv_recovery_from_checkpoint_finish(); | 1463 | recv_recovery_from_checkpoint_finish(); |
417 | @@ -1133,7 +1468,7 @@ | |||
418 | 1133 | if (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE) { | 1468 | if (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE) { |
419 | 1134 | /* The following call is necessary for the insert | 1469 | /* The following call is necessary for the insert |
420 | 1135 | buffer to work with multiple tablespaces. We must | 1470 | buffer to work with multiple tablespaces. We must |
422 | 1136 | @@ -1747,7 +1753,18 @@ | 1471 | @@ -1747,7 +1763,18 @@ |
423 | 1137 | 1472 | ||
424 | 1138 | if (srv_auto_extend_last_data_file | 1473 | if (srv_auto_extend_last_data_file |
425 | 1139 | && sum_of_data_file_sizes < tablespace_size_in_header) { | 1474 | && sum_of_data_file_sizes < tablespace_size_in_header) { |
426 | @@ -1152,7 +1487,7 @@ | |||
427 | 1152 | fprintf(stderr, | 1487 | fprintf(stderr, |
428 | 1153 | "InnoDB: Error: tablespace size stored in header" | 1488 | "InnoDB: Error: tablespace size stored in header" |
429 | 1154 | " is %lu pages, but\n" | 1489 | " is %lu pages, but\n" |
431 | 1155 | @@ -1772,6 +1789,7 @@ | 1490 | @@ -1772,6 +1799,7 @@ |
432 | 1156 | 1491 | ||
433 | 1157 | return(DB_ERROR); | 1492 | return(DB_ERROR); |
434 | 1158 | } | 1493 | } |
435 | @@ -1160,7 +1495,7 @@ | |||
436 | 1160 | } | 1495 | } |
437 | 1161 | 1496 | ||
438 | 1162 | /* Check that os_fast_mutexes work as expected */ | 1497 | /* Check that os_fast_mutexes work as expected */ |
440 | 1163 | @@ -1867,6 +1885,7 @@ | 1498 | @@ -1867,6 +1895,7 @@ |
441 | 1164 | ibuf_update_max_tablespace_id(); | 1499 | ibuf_update_max_tablespace_id(); |
442 | 1165 | } | 1500 | } |
443 | 1166 | 1501 | ||
444 | 1167 | 1502 | ||
445 | === modified file 'src/Makefile' | |||
446 | --- src/Makefile 2012-05-25 11:38:15 +0000 | |||
447 | +++ src/Makefile 2012-12-05 22:33:23 +0000 | |||
448 | @@ -35,6 +35,10 @@ | |||
449 | 35 | xbstream_write.o \ | 35 | xbstream_write.o \ |
450 | 36 | quicklz/quicklz.o | 36 | quicklz/quicklz.o |
451 | 37 | XBSTREAMOBJS = xbstream.o xbstream_write.o xbstream_read.o | 37 | XBSTREAMOBJS = xbstream.o xbstream_write.o xbstream_read.o |
452 | 38 | UTILSCOREOBJS = api_page.o api_log.o | ||
453 | 39 | UTILSCOBJS = innodb_int.o $(UTILSCOREOBJS) | ||
454 | 40 | REDOCOBJS = percona-redo.o | ||
455 | 41 | PAGECOBJS = percona-pprint.o | ||
456 | 38 | 42 | ||
457 | 39 | LIBARCHIVE_A = libarchive/libarchive/libarchive.a | 43 | LIBARCHIVE_A = libarchive/libarchive/libarchive.a |
458 | 40 | 44 | ||
459 | @@ -86,8 +90,9 @@ | |||
460 | 86 | 90 | ||
461 | 87 | plugin: MYSQLOBJS = $(addprefix $(MYSQL_ROOT_DIR)/, mysys/libmysys.a \ | 91 | plugin: MYSQLOBJS = $(addprefix $(MYSQL_ROOT_DIR)/, mysys/libmysys.a \ |
462 | 88 | strings/libmystrings.a zlib/.libs/libzlt.a dbug/libdbug.a) | 92 | strings/libmystrings.a zlib/.libs/libzlt.a dbug/libdbug.a) |
463 | 93 | plugin: EXTLINKOBJS := $(UTILSCOREOBJS) | ||
464 | 89 | plugin: TARGET := xtrabackup_plugin | 94 | plugin: TARGET := xtrabackup_plugin |
466 | 90 | plugin: $(TARGET) xbstream | 95 | plugin: utils $(TARGET) xbstream |
467 | 91 | 96 | ||
468 | 92 | # XtraBackup for MySQL 5.5 | 97 | # XtraBackup for MySQL 5.5 |
469 | 93 | 5.5: INC = $(COMMON_INC) $(addprefix -isystem$(MYSQL_ROOT_DIR)/, \ | 98 | 5.5: INC = $(COMMON_INC) $(addprefix -isystem$(MYSQL_ROOT_DIR)/, \ |
470 | @@ -179,7 +184,7 @@ | |||
471 | 179 | xtradb55: TARGET := xtrabackup_55 | 184 | xtradb55: TARGET := xtrabackup_55 |
472 | 180 | xtradb55: $(TARGET) xbstream | 185 | xtradb55: $(TARGET) xbstream |
473 | 181 | 186 | ||
475 | 182 | $(XTRABACKUPOBJS): %.o: %.c | 187 | $(XTRABACKUPOBJS) $(UTILSCOREOBJS) $(REDOCOBJS) $(PAGECOBJS): %.o: %.c |
476 | 183 | $(CC) $(CFLAGS) $(INC) $(DEFS) -c $< -o $@ | 188 | $(CC) $(CFLAGS) $(INC) $(DEFS) -c $< -o $@ |
477 | 184 | 189 | ||
478 | 185 | xbstream.o xbstream_read.o: %.o: %.c | 190 | xbstream.o xbstream_read.o: %.o: %.c |
479 | @@ -190,9 +195,13 @@ | |||
480 | 190 | 195 | ||
481 | 191 | xtrabackup.o: xtrabackup.c xb_regex.h write_filt.h fil_cur.h xtrabackup.h | 196 | xtrabackup.o: xtrabackup.c xb_regex.h write_filt.h fil_cur.h xtrabackup.h |
482 | 192 | 197 | ||
485 | 193 | $(TARGET): $(XTRABACKUPOBJS) $(INNODBOBJS) $(MYSQLOBJS) $(LIBARCHIVE_A) | 198 | $(TARGET): $(EXTLINKOBJS) $(XTRABACKUPOBJS) $(INNODBOBJS) $(MYSQLOBJS) $(LIBARCHIVE_A) |
486 | 194 | $(CC) $(CFLAGS) $(XTRABACKUPOBJS) $(INNODBOBJS) $(MYSQLOBJS) $(LIBS) \ | 199 | $(CC) $(CFLAGS) $(EXTLINKOBJS) $(XTRABACKUPOBJS) $(INNODBOBJS) $(MYSQLOBJS) $(LIBS) \ |
487 | 195 | $(LIBARCHIVE_A) -o $(TARGET) | 200 | $(LIBARCHIVE_A) -o $(TARGET) |
488 | 196 | 201 | ||
489 | 202 | utils: $(UTILSCOBJS) $(INNODBOBJS) $(MYSQLOBJS) $(REDOCOBJS) $(PAGECOBJS) | ||
490 | 203 | $(CC) $(UTILSCOBJS) $(REDOCOBJS) $(INNODBOBJS) $(MYSQLOBJS) $(LIBS) -o percona-redo | ||
491 | 204 | $(CC) $(UTILSCOBJS) $(PAGECOBJS) $(INNODBOBJS) $(MYSQLOBJS) $(LIBS) -o percona-pprint | ||
492 | 205 | |||
493 | 197 | clean: | 206 | clean: |
495 | 198 | rm -f $(XTRABACKUPOBJS) $(XBSTREAMOBJS) xtrabackup xtrabackup_* | 207 | rm -f $(UTILSCOBJS) $(XTRABACKUPOBJS) $(XBSTREAMOBJS) xtrabackup xtrabackup_* |
496 | 199 | 208 | ||
497 | === added file 'src/api_log.c' | |||
498 | --- src/api_log.c 1970-01-01 00:00:00 +0000 | |||
499 | +++ src/api_log.c 2012-12-05 22:33:23 +0000 | |||
500 | @@ -0,0 +1,1493 @@ | |||
501 | 1 | /* | ||
502 | 2 | * Copyright (C) 2012 Percona Inc. | ||
503 | 3 | * This program is free software: you can redistribute it and/or modify it | ||
504 | 4 | * under the terms of the GNU General Public License version 3, as published | ||
505 | 5 | * by the Free Software Foundation. | ||
506 | 6 | * | ||
507 | 7 | * This program is distributed in the hope that it will be useful, but | ||
508 | 8 | * WITHOUT ANY WARRANTY; without even the implied warranties of | ||
509 | 9 | * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
510 | 10 | * PURPOSE. See the GNU General Public License for more details. | ||
511 | 11 | * | ||
512 | 12 | * You should have received a copy of the GNU General Public License along | ||
513 | 13 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
514 | 14 | */ | ||
515 | 15 | |||
516 | 16 | #define DULINT_STANDARD | ||
517 | 17 | |||
518 | 18 | #include "api_log.h" | ||
519 | 19 | #include "fil0fil.h" | ||
520 | 20 | #include "log0log.h" | ||
521 | 21 | #include "log0recv.h" | ||
522 | 22 | #include "rem0rec.h" | ||
523 | 23 | #include "os0file.h" | ||
524 | 24 | #include "os0sync.h" | ||
525 | 25 | #include "sync0sync.h" | ||
526 | 26 | #include "srv0srv.h" | ||
527 | 27 | |||
528 | 28 | #include "innodb_int.h" | ||
529 | 29 | |||
530 | 30 | #define SRV_N_PENDING_IOS_PER_THREAD OS_AIO_N_PENDING_IOS_PER_THREAD | ||
531 | 31 | #define SRV_MAX_N_PENDING_SYNC_IOS 100 | ||
532 | 32 | |||
533 | 33 | #ifndef MLOG_LSN | ||
534 | 34 | #define MLOG_LSN ((byte)28) | ||
535 | 35 | #endif | ||
536 | 36 | |||
537 | 37 | static const char* mlog_type_names[] = { | ||
538 | 38 | "undefined (0)", | ||
539 | 39 | "MLOG_1BYTE", | ||
540 | 40 | "MLOG_2BYTES", | ||
541 | 41 | "undefined (3)", | ||
542 | 42 | "MLOG_4BYTES", | ||
543 | 43 | "undefined (5)", | ||
544 | 44 | "undefined (6)", | ||
545 | 45 | "undefined (7)", | ||
546 | 46 | "MLOG_8BYTES", | ||
547 | 47 | "MLOG_REC_INSERT", | ||
548 | 48 | "MLOG_REC_CLUST_DELETE_MARK", /* 10 */ | ||
549 | 49 | "MLOG_REC_SEC_DELETE_MARK", | ||
550 | 50 | "undefined (12)", | ||
551 | 51 | "MLOG_REC_UPDATE_IN_PLACE", | ||
552 | 52 | "MLOG_REC_DELETE", | ||
553 | 53 | "MLOG_LIST_END_DELETE", | ||
554 | 54 | "MLOG_LIST_START_DELETE", | ||
555 | 55 | "MLOG_LIST_END_COPY_CREATED", | ||
556 | 56 | "MLOG_PAGE_REORGANIZE", | ||
557 | 57 | "MLOG_PAGE_CREATE", | ||
558 | 58 | "MLOG_UNDO_INSERT", /* 20 */ | ||
559 | 59 | "MLOG_UNDO_ERASE_END", | ||
560 | 60 | "MLOG_UNDO_INIT", | ||
561 | 61 | "MLOG_UNDO_HDR_DISCARD", | ||
562 | 62 | "MLOG_UNDO_HDR_REUSE", | ||
563 | 63 | "MLOG_UNDO_HDR_CREATE", | ||
564 | 64 | "MLOG_REC_MIN_MARK", | ||
565 | 65 | "MLOG_IBUF_BITMAP_INIT", | ||
566 | 66 | "MLOG_LSN", | ||
567 | 67 | "MLOG_INIT_FILE_PAGE", | ||
568 | 68 | "MLOG_WRITE_STRING", /* 30 */ | ||
569 | 69 | "MLOG_MULTI_REC_END", | ||
570 | 70 | "MLOG_DUMMY_RECORD", | ||
571 | 71 | "MLOG_FILE_CREATE", | ||
572 | 72 | "MLOG_FILE_RENAME", | ||
573 | 73 | "MLOG_FILE_DELETE", | ||
574 | 74 | "MLOG_COMP_REC_MIN_MARK", | ||
575 | 75 | "MLOG_COMP_PAGE_CREATE", | ||
576 | 76 | "MLOG_COMP_REC_INSERT", | ||
577 | 77 | "MLOG_COMP_REC_CLUST_DELETE_MARK", | ||
578 | 78 | "MLOG_COMP_REC_SEC_DELETE_MARK", /* 40 */ | ||
579 | 79 | "MLOG_COMP_REC_UPDATE_IN_PLACE", | ||
580 | 80 | "MLOG_COMP_REC_DELETE", | ||
581 | 81 | "MLOG_COMP_LIST_END_DELETE", | ||
582 | 82 | "MLOG_COMP_LIST_START_DELETE", | ||
583 | 83 | "MLOG_COMP_LIST_END_COPY_CREATED", | ||
584 | 84 | "MLOG_COMP_PAGE_REORGANIZE", | ||
585 | 85 | "MLOG_FILE_CREATE2", | ||
586 | 86 | "MLOG_ZIP_WRITE_NODE_PTR", | ||
587 | 87 | "MLOG_ZIP_WRITE_BLOB_PTR", | ||
588 | 88 | "MLOG_ZIP_WRITE_HEADER", /* 50 */ | ||
589 | 89 | "MLOG_ZIP_PAGE_COMPRESS" | ||
590 | 90 | }; | ||
591 | 91 | |||
592 | 92 | /* Informaton about single log record */ | ||
593 | 93 | struct ib_log_rec_struct | ||
594 | 94 | { | ||
595 | 95 | ib_uint64_t lsn; /* record's LSN */ | ||
596 | 96 | ulint len; /* length */ | ||
597 | 97 | byte type; /* type MLOG_* */ | ||
598 | 98 | ulint space; /* space id or ULINT_UNDEFINED */ | ||
599 | 99 | ulint page_no; /* page number or ULINT_UNDEFINED */ | ||
600 | 100 | char* body_str; /* log record's body as string */ | ||
601 | 101 | unsigned single_rec:1; /* set if MLOG_SINGLE_REC_FLAG | ||
602 | 102 | is set for record */ | ||
603 | 103 | }; | ||
604 | 104 | |||
605 | 105 | /* log iterator */ | ||
606 | 106 | struct ib_log_rec_itr_struct | ||
607 | 107 | { | ||
608 | 108 | ib_uint64_t start_lsn; /* starting LSN */ | ||
609 | 109 | ib_uint64_t end_lsn; /* end LSN */ | ||
610 | 110 | ib_uint64_t block_start_lsn; /* OS_FILE_LOG_BLOCK_SIZE aligned LSN */ | ||
611 | 111 | byte* read_buf; /* read buffer */ | ||
612 | 112 | byte* read_buf_ptr; /* pointer to current record in read buffer */ | ||
613 | 113 | byte* parse_buf; /* parse buffer */ | ||
614 | 114 | byte* parse_buf_ptr; /* pointer to current record in parse buffer */ | ||
615 | 115 | byte* parse_buf_end; /* end of parse buffer */ | ||
616 | 116 | ulint scanned_checkpoint_no; /* last checkpoint stored in the log data */ | ||
617 | 117 | ibool eof; /* TRUE if end of scanned interval reached */ | ||
618 | 118 | ib_uint64_t next_parse_lsn; /* LSN of next record to be parsed */ | ||
619 | 119 | struct ib_log_rec_struct current_rec; /* current log record */ | ||
620 | 120 | }; | ||
621 | 121 | |||
622 | 122 | /*********************************************************************//** | ||
623 | 123 | Initialize InnoDB systems needed for the log printer | ||
624 | 124 | @return DB_SUCCESS if successfull */ | ||
625 | 125 | HAILDB_API | ||
626 | 126 | ib_err_t | ||
627 | 127 | ib_log_sys_start( | ||
628 | 128 | /*=============*/ | ||
629 | 129 | ib_ulint_t log_buf_size, /*!< in: the size of the buffer */ | ||
630 | 130 | const char* log_dir) /*!< in: path to InnoDB log files. */ | ||
631 | 131 | { | ||
632 | 132 | ibool log_file_created = TRUE; | ||
633 | 133 | ib_err_t err; | ||
634 | 134 | ulint i; | ||
635 | 135 | |||
636 | 136 | innodb_init_param_for_util("./", log_dir, 1024*1024, log_buf_size, TRUE); | ||
637 | 137 | |||
638 | 138 | srv_max_n_threads = 1; | ||
639 | 139 | srv_normalize_init_values(); | ||
640 | 140 | ut_mem_init(); | ||
641 | 141 | |||
642 | 142 | srv_n_read_io_threads = srv_n_write_io_threads = 1; | ||
643 | 143 | srv_n_file_io_threads = 2 + srv_n_read_io_threads + | ||
644 | 144 | srv_n_write_io_threads; | ||
645 | 145 | os_sync_init(); | ||
646 | 146 | sync_init(); | ||
647 | 147 | // os_io_init_simple(); | ||
648 | 148 | os_aio_init(8 * SRV_N_PENDING_IOS_PER_THREAD, | ||
649 | 149 | srv_n_read_io_threads, | ||
650 | 150 | srv_n_write_io_threads, | ||
651 | 151 | SRV_MAX_N_PENDING_SYNC_IOS); | ||
652 | 152 | |||
653 | 153 | mem_init(1); | ||
654 | 154 | fil_init(10, 10); | ||
655 | 155 | log_init(); | ||
656 | 156 | recv_sys_create(); | ||
657 | 157 | |||
658 | 158 | for (i = 0; i < srv_n_log_files; i++) { | ||
659 | 159 | err = open_or_create_log_file(FALSE, &log_file_created, TRUE, 0, 0); | ||
660 | 160 | if (err != DB_SUCCESS) { | ||
661 | 161 | ib_log_sys_stop(); | ||
662 | 162 | return err; | ||
663 | 163 | } | ||
664 | 164 | |||
665 | 165 | if (log_file_created) { | ||
666 | 166 | ib_logger(ib_stream, | ||
667 | 167 | "Something wrong with source files...\n"); | ||
668 | 168 | return DB_ERROR; | ||
669 | 169 | } | ||
670 | 170 | } | ||
671 | 171 | |||
672 | 172 | /* open_or_create_log_file will set srv_log_file_size. Normalize the | ||
673 | 173 | init values again to get srv_log_file_size/srv_log_file_curr_size in | ||
674 | 174 | sync. */ | ||
675 | 175 | srv_normalize_init_values(); | ||
676 | 176 | |||
677 | 177 | return DB_SUCCESS; | ||
678 | 178 | } | ||
679 | 179 | |||
680 | 180 | /*********************************************************************//** | ||
681 | 181 | Uninitialize InnoDB systems needed for the log printer */ | ||
682 | 182 | HAILDB_API | ||
683 | 183 | void | ||
684 | 184 | ib_log_sys_stop(void) | ||
685 | 185 | { | ||
686 | 186 | recv_sys_close(); | ||
687 | 187 | recv_sys_mem_free(); | ||
688 | 188 | fil_close_all_files(); | ||
689 | 189 | log_shutdown(); | ||
690 | 190 | log_mem_free(); | ||
691 | 191 | sync_close(); | ||
692 | 192 | os_sync_free(); | ||
693 | 193 | fil_close(); | ||
694 | 194 | mem_close(); | ||
695 | 195 | ut_free_all_mem(); | ||
696 | 196 | } | ||
697 | 197 | |||
698 | 198 | /*********************************************************************//** | ||
699 | 199 | Find last consistent checkpoint LSN in log groups */ | ||
700 | 200 | HAILDB_API | ||
701 | 201 | ib_err_t | ||
702 | 202 | ib_log_sys_find_last_checkpoint_lsn( | ||
703 | 203 | /*================================*/ | ||
704 | 204 | ib_u64_t* last_checkpoint_lsn) /*!< out: last checkpoint LSN */ | ||
705 | 205 | { | ||
706 | 206 | log_group_t* max_cp_group; | ||
707 | 207 | ulint max_cp_field; | ||
708 | 208 | |||
709 | 209 | mutex_enter(&log_sys->mutex); | ||
710 | 210 | |||
711 | 211 | uint err = recv_find_max_checkpoint(&max_cp_group, &max_cp_field); | ||
712 | 212 | if (err != DB_SUCCESS) | ||
713 | 213 | return err; | ||
714 | 214 | |||
715 | 215 | log_group_read_checkpoint_info(max_cp_group, max_cp_field); | ||
716 | 216 | *last_checkpoint_lsn | ||
717 | 217 | = mach_read_ull(log_sys->checkpoint_buf + LOG_CHECKPOINT_LSN); | ||
718 | 218 | |||
719 | 219 | mutex_exit(&log_sys->mutex); | ||
720 | 220 | |||
721 | 221 | return DB_SUCCESS; | ||
722 | 222 | } | ||
723 | 223 | |||
724 | 224 | /*********************************************************************//** | ||
725 | 225 | Create iterator through log records */ | ||
726 | 226 | HAILDB_API | ||
727 | 227 | ib_log_rec_itr_t | ||
728 | 228 | ib_log_sys_create_iterator( | ||
729 | 229 | /*=======================*/ | ||
730 | 230 | ib_u64_t start_lsn, /*!< in: starting LSN */ | ||
731 | 231 | ib_u64_t end_lsn) /*!< in: last LSN */ | ||
732 | 232 | { | ||
733 | 233 | ib_log_rec_itr_t result = mem_alloc(sizeof(*result)); | ||
734 | 234 | |||
735 | 235 | result->start_lsn = start_lsn; | ||
736 | 236 | result->end_lsn = end_lsn; | ||
737 | 237 | result->block_start_lsn = ut_uint64_align_down(start_lsn, | ||
738 | 238 | OS_FILE_LOG_BLOCK_SIZE); | ||
739 | 239 | result->read_buf = mem_alloc(RECV_SCAN_SIZE); | ||
740 | 240 | /* Pointing to the end of buffer will trigger the first read */ | ||
741 | 241 | result->read_buf_ptr = result->read_buf + RECV_SCAN_SIZE; | ||
742 | 242 | result->parse_buf = mem_alloc(RECV_PARSING_BUF_SIZE); | ||
743 | 243 | result->parse_buf_ptr = result->parse_buf; | ||
744 | 244 | result->parse_buf_end = result->parse_buf; | ||
745 | 245 | result->scanned_checkpoint_no = 0; | ||
746 | 246 | result->eof = FALSE; | ||
747 | 247 | result->next_parse_lsn = result->block_start_lsn; | ||
748 | 248 | |||
749 | 249 | result->current_rec.lsn = IB_ULONGLONG_MAX; | ||
750 | 250 | result->current_rec.len = ULINT_UNDEFINED; | ||
751 | 251 | result->current_rec.type = MLOG_BIGGEST_TYPE + 1; | ||
752 | 252 | result->current_rec.space = ULINT_UNDEFINED; | ||
753 | 253 | result->current_rec.page_no = ULINT_UNDEFINED; | ||
754 | 254 | result->current_rec.body_str = NULL; | ||
755 | 255 | return result; | ||
756 | 256 | } | ||
757 | 257 | |||
758 | 258 | /*********************************************************************//** | ||
759 | 259 | For the given minilog record type determines if the record has (space; page) | ||
760 | 260 | associated with it. | ||
761 | 261 | @return TRUE if the record has (space; page) in it */ | ||
762 | 262 | static | ||
763 | 263 | ibool | ||
764 | 264 | log_online_rec_has_page( | ||
765 | 265 | /*====================*/ | ||
766 | 266 | byte type) /*!<in: the minilog record type */ | ||
767 | 267 | { | ||
768 | 268 | return type != MLOG_MULTI_REC_END && type != MLOG_DUMMY_RECORD; | ||
769 | 269 | } | ||
770 | 270 | |||
771 | 271 | |||
772 | 272 | |||
773 | 273 | /*********************************************************************//** | ||
774 | 274 | Copies new log data to the parse buffer while skipping log block header, | ||
775 | 275 | and trailer. The decision how much to copy here is taken from | ||
776 | 276 | recv_sys_add_to_parsing_buf but simplified. */ | ||
777 | 277 | static | ||
778 | 278 | void | ||
779 | 279 | log_online_add_to_parse_buf( | ||
780 | 280 | /*========================*/ | ||
781 | 281 | const byte* log_block, /*!< in: read log data */ | ||
782 | 282 | ulint start_offset, /*!< in: data start offset */ | ||
783 | 283 | ulint data_len, /*!< in: length of read log data */ | ||
784 | 284 | byte* parse_buf, /*!< in: the parse buffer */ | ||
785 | 285 | byte** parse_buf_end) /*!< in/out: end of parse buffer */ | ||
786 | 286 | { | ||
787 | 287 | ulint end_offset | ||
788 | 288 | = (data_len == OS_FILE_LOG_BLOCK_SIZE) | ||
789 | 289 | ? data_len - LOG_BLOCK_TRL_SIZE | ||
790 | 290 | : data_len; | ||
791 | 291 | ulint actual_data_len = (end_offset >= start_offset) | ||
792 | 292 | ? end_offset - start_offset : 0; | ||
793 | 293 | |||
794 | 294 | ut_a (start_offset >= LOG_BLOCK_HDR_SIZE); | ||
795 | 295 | |||
796 | 296 | if ((*parse_buf_end + actual_data_len - parse_buf) | ||
797 | 297 | > RECV_PARSING_BUF_SIZE) { | ||
798 | 298 | |||
799 | 299 | ib_logger(ib_stream, "Parse buffer overflow! Most likely " | ||
800 | 300 | "caused by corrupt log data. In the case of " | ||
801 | 301 | "correct log increase RECV_PARSING_BUF_SIZE\n"); | ||
802 | 302 | ib_logger(ib_stream, "Discarding the overflowing data, some " | ||
803 | 303 | "records will be skipped\n"); | ||
804 | 304 | actual_data_len | ||
805 | 305 | = RECV_PARSING_BUF_SIZE - (*parse_buf_end - parse_buf); | ||
806 | 306 | } | ||
807 | 307 | |||
808 | 308 | ut_memcpy(*parse_buf_end, log_block + start_offset, actual_data_len); | ||
809 | 309 | *parse_buf_end += actual_data_len; | ||
810 | 310 | ut_ad (*parse_buf_end - parse_buf <= RECV_PARSING_BUF_SIZE); | ||
811 | 311 | } | ||
812 | 312 | |||
813 | 313 | /*********************************************************************//** | ||
814 | 314 | Checks if the log block checksum is OK. TODO: with comparisson to log0recv | ||
815 | 315 | checks, this one drops the scanned no vs. no in the log check. | ||
816 | 316 | TODO: copy-paste with innodb-changed-page-tracking log0online.c | ||
817 | 317 | @return TRUE if the log block checksum is OK, FALSE otherwise. */ | ||
818 | 318 | static | ||
819 | 319 | ibool | ||
820 | 320 | log_online_is_valid_log_seg( | ||
821 | 321 | /*========================*/ | ||
822 | 322 | const byte* log_block) /*!< in: read log data */ | ||
823 | 323 | { | ||
824 | 324 | ibool checksum_is_ok | ||
825 | 325 | = log_block_checksum_is_ok_or_old_format(log_block); | ||
826 | 326 | |||
827 | 327 | if (!checksum_is_ok) { | ||
828 | 328 | /* Garbage or an incompletely written log block */ | ||
829 | 329 | |||
830 | 330 | ib_logger(ib_stream, | ||
831 | 331 | "Log block checksum mismatch: " | ||
832 | 332 | "expected %lu, calculated checksum %lu\n", | ||
833 | 333 | (ulong) log_block_get_checksum(log_block), | ||
834 | 334 | (ulong) log_block_calc_checksum(log_block)); | ||
835 | 335 | } | ||
836 | 336 | |||
837 | 337 | return checksum_is_ok; | ||
838 | 338 | } | ||
839 | 339 | |||
840 | 340 | /*********************************************************************//** | ||
841 | 341 | Checks if the log block is in fact garbage from a log buffer flush which was | ||
842 | 342 | made before the most recent database recovery. | ||
843 | 343 | @return TRUE if log block is garbage from the flush */ | ||
844 | 344 | static | ||
845 | 345 | ibool | ||
846 | 346 | log_online_is_garbage_log_seg( | ||
847 | 347 | /*==========================*/ | ||
848 | 348 | const byte* log_block, /*!< in: read log data */ | ||
849 | 349 | ulint scanned_checkpoint_no) /*!< in: last checkpoint | ||
850 | 350 | stored in the log data */ | ||
851 | 351 | { | ||
852 | 352 | return (scanned_checkpoint_no > 0) | ||
853 | 353 | && (log_block_get_checkpoint_no(log_block) | ||
854 | 354 | < scanned_checkpoint_no) | ||
855 | 355 | && (scanned_checkpoint_no | ||
856 | 356 | - log_block_get_checkpoint_no(log_block) | ||
857 | 357 | > 0x80000000UL); | ||
858 | 358 | } | ||
859 | 359 | |||
860 | 360 | /*********************************************************************//** | ||
861 | 361 | Copy consistent piece of data from the read buffer to the parse buffer. | ||
862 | 362 | @return TRUE if data been copied */ | ||
863 | 363 | static | ||
864 | 364 | ibool | ||
865 | 365 | fill_parse_buffer( | ||
866 | 366 | /*==============*/ | ||
867 | 367 | ib_log_rec_itr_t itr) /*!< in: log records iterator */ | ||
868 | 368 | { | ||
869 | 369 | ulint block_data_len; | ||
870 | 370 | ulint data_start_offset = LOG_BLOCK_HDR_SIZE; | ||
871 | 371 | |||
872 | 372 | if (itr->eof) | ||
873 | 373 | return FALSE; | ||
874 | 374 | |||
875 | 375 | if (itr->read_buf_ptr == itr->read_buf + RECV_SCAN_SIZE) { | ||
876 | 376 | |||
877 | 377 | ib_uint64_t read_end_lsn; | ||
878 | 378 | log_group_t* group; | ||
879 | 379 | |||
880 | 380 | /* Read buf empty, read more recs if there are any */ | ||
881 | 381 | read_end_lsn = itr->block_start_lsn + RECV_SCAN_SIZE; | ||
882 | 382 | group = UT_LIST_GET_FIRST(log_sys->log_groups); | ||
883 | 383 | ut_a(group); | ||
884 | 384 | |||
885 | 385 | /* Single-threaded operation, no mutexes */ | ||
886 | 386 | mutex_enter(&log_sys->mutex); | ||
887 | 387 | log_group_read_log_seg(LOG_RECOVER, itr->read_buf, group, | ||
888 | 388 | itr->block_start_lsn, read_end_lsn); | ||
889 | 389 | mutex_exit(&log_sys->mutex); | ||
890 | 390 | itr->read_buf_ptr = itr->read_buf; | ||
891 | 391 | } | ||
892 | 392 | |||
893 | 393 | /* Read buffer has some data, process and move one block to the parse | ||
894 | 394 | * buffer. */ | ||
895 | 395 | if (!log_online_is_valid_log_seg(itr->read_buf_ptr)) { | ||
896 | 396 | return FALSE; | ||
897 | 397 | } | ||
898 | 398 | |||
899 | 399 | if (log_online_is_garbage_log_seg(itr->read_buf_ptr, | ||
900 | 400 | itr->scanned_checkpoint_no)) { | ||
901 | 401 | return FALSE; | ||
902 | 402 | } | ||
903 | 403 | |||
904 | 404 | block_data_len = log_block_get_data_len(itr->read_buf_ptr); | ||
905 | 405 | |||
906 | 406 | if (itr->next_parse_lsn == itr->block_start_lsn) { | ||
907 | 407 | |||
908 | 408 | /* First read, find the start of the first complete record | ||
909 | 409 | group in this block */ | ||
910 | 410 | ut_a (itr->start_lsn | ||
911 | 411 | < (itr->block_start_lsn + OS_FILE_LOG_BLOCK_SIZE)); | ||
912 | 412 | data_start_offset | ||
913 | 413 | = log_block_get_first_rec_group(itr->read_buf_ptr); | ||
914 | 414 | /* TODO: is this the correct way to handle 0 return value? */ | ||
915 | 415 | if (data_start_offset == 0) | ||
916 | 416 | data_start_offset = LOG_BLOCK_HDR_SIZE; | ||
917 | 417 | itr->next_parse_lsn += data_start_offset; | ||
918 | 418 | } | ||
919 | 419 | ut_ad (block_data_len % OS_FILE_LOG_BLOCK_SIZE == 0 | ||
920 | 420 | || block_data_len < OS_FILE_LOG_BLOCK_SIZE); | ||
921 | 421 | |||
922 | 422 | log_online_add_to_parse_buf(itr->read_buf_ptr, data_start_offset, | ||
923 | 423 | block_data_len, itr->parse_buf, | ||
924 | 424 | &itr->parse_buf_end); | ||
925 | 425 | |||
926 | 426 | /* TODO: check itr->scanned_checkpoint_no */ | ||
927 | 427 | itr->scanned_checkpoint_no | ||
928 | 428 | = log_block_get_checkpoint_no(itr->read_buf_ptr); | ||
929 | 429 | |||
930 | 430 | if (block_data_len < OS_FILE_LOG_BLOCK_SIZE) | ||
931 | 431 | itr->eof = TRUE; | ||
932 | 432 | |||
933 | 433 | if (!itr->eof) { | ||
934 | 434 | itr->block_start_lsn += OS_FILE_LOG_BLOCK_SIZE; | ||
935 | 435 | itr->read_buf_ptr += OS_FILE_LOG_BLOCK_SIZE; | ||
936 | 436 | } | ||
937 | 437 | |||
938 | 438 | return TRUE; | ||
939 | 439 | } | ||
940 | 440 | |||
941 | 441 | static char buf[RECV_SCAN_SIZE]; | ||
942 | 442 | |||
943 | 443 | /*********************************************************************//** | ||
944 | 444 | Parse index data and format it in human-readable form to static buffer. | ||
945 | 445 | @return end of data copied to buffer */ | ||
946 | 446 | static | ||
947 | 447 | char * | ||
948 | 448 | ib_log_sys_parse_index( | ||
949 | 449 | /*===================*/ | ||
950 | 450 | byte** ptr) /*!< in/out: pointer to log data */ | ||
951 | 451 | { | ||
952 | 452 | char* buf_end = buf; | ||
953 | 453 | ulint n_uniq; | ||
954 | 454 | ulint n = mach_read_from_2(*ptr); | ||
955 | 455 | unsigned i; | ||
956 | 456 | *ptr += 2; | ||
957 | 457 | n_uniq = mach_read_from_2(*ptr); | ||
958 | 458 | *ptr += 2; | ||
959 | 459 | buf_end += snprintf(buf, RECV_SCAN_SIZE, "n: %lu, n_unique: %lu", | ||
960 | 460 | n, n_uniq); | ||
961 | 461 | for (i = 0; i < n; i++) { | ||
962 | 462 | ulint len = mach_read_from_2(*ptr); | ||
963 | 463 | *ptr += 2; | ||
964 | 464 | buf_end += snprintf(buf_end, RECV_SCAN_SIZE - (buf_end - buf), | ||
965 | 465 | ", len%u: %lu", i, len); | ||
966 | 466 | } | ||
967 | 467 | return buf_end; | ||
968 | 468 | } | ||
969 | 469 | |||
970 | 470 | /*********************************************************************//** | ||
971 | 471 | Parse system fields of log record. */ | ||
972 | 472 | static | ||
973 | 473 | void | ||
974 | 474 | ib_log_sys_parse_sys_fields( | ||
975 | 475 | /*========================*/ | ||
976 | 476 | byte** ptr, /*!< in/out: pointer to log data */ | ||
977 | 477 | byte* body_end, /*!< in: pointer to end of | ||
978 | 478 | a log record body */ | ||
979 | 479 | ulint* pos, /*!< out: position */ | ||
980 | 480 | trx_id_t* trx_id, /*!< out: trx id */ | ||
981 | 481 | roll_ptr_t* roll_ptr) /*!< out: roll pointer */ | ||
982 | 482 | { | ||
983 | 483 | *ptr = mach_parse_compressed(*ptr, body_end, pos); | ||
984 | 484 | *roll_ptr = mach_read_from_7(*ptr); | ||
985 | 485 | *ptr += 7; | ||
986 | 486 | *ptr = mach_dulint_parse_compressed(*ptr, body_end, trx_id); | ||
987 | 487 | } | ||
988 | 488 | |||
989 | 489 | /*********************************************************************//** | ||
990 | 490 | Parse the redo log record for delete marking or unmarking of a clustered | ||
991 | 491 | index record. */ | ||
992 | 492 | static | ||
993 | 493 | void | ||
994 | 494 | ib_log_sys_parse_del_mark_set_clust_rec( | ||
995 | 495 | /*====================================*/ | ||
996 | 496 | ib_log_rec_itr_t itr, /*!< in/out: log iterator */ | ||
997 | 497 | byte** ptr, /*!< in/out: pointer to | ||
998 | 498 | log data */ | ||
999 | 499 | byte* body_end) /*!< in: pointer to end of a | ||
1000 | 500 | log record body */ | ||
1001 | 501 | { | ||
1002 | 502 | ulint val; | ||
1003 | 503 | ulint pos; | ||
1004 | 504 | roll_ptr_t roll_ptr; | ||
1005 | 505 | trx_id_t trx_id; | ||
1006 | 506 | ulint offset; | ||
1007 | 507 | int ret; | ||
1008 | 508 | ulint flags = mach_read_from_1(*ptr); | ||
1009 | 509 | (*ptr)++; | ||
1010 | 510 | val = mach_read_from_1(*ptr); | ||
1011 | 511 | (*ptr)++; | ||
1012 | 512 | ib_log_sys_parse_sys_fields(ptr, body_end, &pos, &trx_id, &roll_ptr); | ||
1013 | 513 | offset = mach_read_from_2(*ptr); | ||
1014 | 514 | *ptr += 2; | ||
1015 | 515 | ret = asprintf(&itr->current_rec.body_str, | ||
1016 | 516 | "%sflags: 0x%lX, value: 0x%lX, position: 0x%lX, " | ||
1017 | 517 | "roll_ptr: 0x%llX, trx_id: 0x%llX, offset: 0x%lX", | ||
1018 | 518 | buf, flags, val, pos, | ||
1019 | 519 | ut_conv_dulint_to_longlong(roll_ptr), | ||
1020 | 520 | ut_conv_dulint_to_longlong(trx_id), offset); | ||
1021 | 521 | ut_a (ret > 0); | ||
1022 | 522 | } | ||
1023 | 523 | |||
1024 | 524 | /*********************************************************************//** | ||
1025 | 525 | Dump a log record as a hex string */ | ||
1026 | 526 | static | ||
1027 | 527 | void | ||
1028 | 528 | ib_log_sys_output_raw( | ||
1029 | 529 | /*==================*/ | ||
1030 | 530 | byte** ptr, /*!< in/out: pointer to log data */ | ||
1031 | 531 | byte* body_end, /*!< in: pointer to end of a log record body */ | ||
1032 | 532 | char** buf_end) /*!< in/out: pointer to end of output buffer */ | ||
1033 | 533 | { | ||
1034 | 534 | while (*ptr != body_end) { | ||
1035 | 535 | *buf_end += snprintf(*buf_end, | ||
1036 | 536 | RECV_SCAN_SIZE - (*buf_end - buf), | ||
1037 | 537 | " %02X", **ptr); | ||
1038 | 538 | (*ptr)++; | ||
1039 | 539 | } | ||
1040 | 540 | } | ||
1041 | 541 | |||
1042 | 542 | /*********************************************************************//** | ||
1043 | 543 | Parse update of a compact record */ | ||
1044 | 544 | static | ||
1045 | 545 | void | ||
1046 | 546 | ib_log_sys_parse_update_in_place( | ||
1047 | 547 | /*=============================*/ | ||
1048 | 548 | ib_log_rec_itr_t itr, /*!< in/out: log iterator */ | ||
1049 | 549 | byte** ptr, /*!< in/out: pointer to | ||
1050 | 550 | log data */ | ||
1051 | 551 | byte* body_end) /*!< in: pointer to end of | ||
1052 | 552 | a log record body */ | ||
1053 | 553 | { | ||
1054 | 554 | char *buf_end = buf + strlen(buf); | ||
1055 | 555 | ulint pos; | ||
1056 | 556 | roll_ptr_t roll_ptr; | ||
1057 | 557 | trx_id_t trx_id; | ||
1058 | 558 | ulint offset; | ||
1059 | 559 | ulint info_bits; | ||
1060 | 560 | ulint n_fields; | ||
1061 | 561 | unsigned i; | ||
1062 | 562 | ulint flags = mach_read_from_1(*ptr); | ||
1063 | 563 | (*ptr)++; | ||
1064 | 564 | ib_log_sys_parse_sys_fields(ptr, body_end, &pos, &trx_id, &roll_ptr); | ||
1065 | 565 | offset = mach_read_from_2(*ptr); | ||
1066 | 566 | *ptr += 2; | ||
1067 | 567 | info_bits = mach_read_from_1(*ptr); | ||
1068 | 568 | (*ptr)++; | ||
1069 | 569 | *ptr = mach_parse_compressed(*ptr, body_end, &n_fields); | ||
1070 | 570 | buf_end += snprintf(buf_end, RECV_SCAN_SIZE - (buf_end - buf), | ||
1071 | 571 | "flags: 0x%lX, position: 0x%lX, roll_ptr: 0x%llX, " | ||
1072 | 572 | "trx_id: 0x%llX, offset: 0x%lX, info_bits: 0x%lX, " | ||
1073 | 573 | "n_fields: %lu", flags, pos, | ||
1074 | 574 | ut_conv_dulint_to_longlong(roll_ptr), | ||
1075 | 575 | ut_conv_dulint_to_longlong(trx_id), offset, | ||
1076 | 576 | info_bits, n_fields); | ||
1077 | 577 | for (i = 0; i < n_fields; i++) { | ||
1078 | 578 | ulint field_no; | ||
1079 | 579 | ulint len; | ||
1080 | 580 | *ptr = mach_parse_compressed(*ptr, body_end, &field_no); | ||
1081 | 581 | buf_end += snprintf(buf_end, RECV_SCAN_SIZE - (buf_end - buf), | ||
1082 | 582 | ", field_no_%d: %lu", i, field_no); | ||
1083 | 583 | *ptr = mach_parse_compressed(*ptr, body_end, &len); | ||
1084 | 584 | if (len != UNIV_SQL_NULL) { | ||
1085 | 585 | buf_end += snprintf(buf_end, | ||
1086 | 586 | RECV_SCAN_SIZE - (buf_end - buf), | ||
1087 | 587 | ", data_len_%d: %lu, data:", i, | ||
1088 | 588 | len); | ||
1089 | 589 | ib_log_sys_output_raw(ptr, *ptr + len, &buf_end); | ||
1090 | 590 | } | ||
1091 | 591 | else { | ||
1092 | 592 | buf_end += snprintf(buf_end, | ||
1093 | 593 | RECV_SCAN_SIZE - (buf_end - buf), | ||
1094 | 594 | ", data_len_%d: UNIV_SQL_NULL", i); | ||
1095 | 595 | } | ||
1096 | 596 | } | ||
1097 | 597 | itr->current_rec.body_str = strdup(buf); | ||
1098 | 598 | } | ||
1099 | 599 | |||
1100 | 600 | /*********************************************************************//** | ||
1101 | 601 | Parse delete record list */ | ||
1102 | 602 | static | ||
1103 | 603 | void | ||
1104 | 604 | ib_log_sys_parse_delete_rec_list( | ||
1105 | 605 | /*=============================*/ | ||
1106 | 606 | ib_log_rec_itr_t itr, /*!< in/out: log iterator */ | ||
1107 | 607 | byte** ptr) /*!< in/out: pointer to log data */ | ||
1108 | 608 | { | ||
1109 | 609 | ulint offset = mach_read_from_2(*ptr); | ||
1110 | 610 | char *buf_end = buf + strlen(buf); | ||
1111 | 611 | *ptr += 2; | ||
1112 | 612 | buf_end += snprintf(buf_end, RECV_SCAN_SIZE - (buf_end - buf), | ||
1113 | 613 | "offset: %lu", offset); | ||
1114 | 614 | itr->current_rec.body_str = strdup(buf); | ||
1115 | 615 | } | ||
1116 | 616 | |||
1117 | 617 | /*********************************************************************//** | ||
1118 | 618 | Read info bits of insert record */ | ||
1119 | 619 | static | ||
1120 | 620 | void | ||
1121 | 621 | ib_log_sys_parse_info_origin_mismatch( | ||
1122 | 622 | /*==================================*/ | ||
1123 | 623 | byte** ptr, /*!< in/out: pointer to log data */ | ||
1124 | 624 | byte* body_end, /*!< in: pointer to end of a log record body */ | ||
1125 | 625 | char** buf_end) /*!< in/out: pointer to end of output buffer */ | ||
1126 | 626 | { | ||
1127 | 627 | ulint origin_offset; | ||
1128 | 628 | ulint mismatch_index; | ||
1129 | 629 | ulint info_and_status_bits = mach_read_from_1(*ptr); | ||
1130 | 630 | (*ptr)++; | ||
1131 | 631 | *ptr = mach_parse_compressed(*ptr, body_end, &origin_offset); | ||
1132 | 632 | *ptr = mach_parse_compressed(*ptr, body_end, &mismatch_index); | ||
1133 | 633 | *buf_end += snprintf(*buf_end, RECV_SCAN_SIZE - (*buf_end - buf), | ||
1134 | 634 | ", info_status_bits: 0x%lX, origin_offset: %lu, " | ||
1135 | 635 | "mismatch_index: %lu", | ||
1136 | 636 | info_and_status_bits, origin_offset, | ||
1137 | 637 | mismatch_index); | ||
1138 | 638 | } | ||
1139 | 639 | |||
1140 | 640 | /*********************************************************************//** | ||
1141 | 641 | Parse compact record insert */ | ||
1142 | 642 | static | ||
1143 | 643 | void | ||
1144 | 644 | ib_log_sys_parse_rec_insert( | ||
1145 | 645 | /*========================*/ | ||
1146 | 646 | ib_log_rec_itr_t itr, /*!< in/out: log iterator */ | ||
1147 | 647 | byte** ptr, /*!< in/out: pointer to | ||
1148 | 648 | log data */ | ||
1149 | 649 | byte* body_end) /*!< in: pointer to end of a log | ||
1150 | 650 | record body */ | ||
1151 | 651 | { | ||
1152 | 652 | char* buf_end = buf; | ||
1153 | 653 | ulint end_seg_len; | ||
1154 | 654 | ulint offset = mach_read_from_2(*ptr); | ||
1155 | 655 | *ptr += 2; | ||
1156 | 656 | *ptr = mach_parse_compressed(*ptr, body_end, &end_seg_len); | ||
1157 | 657 | buf_end += snprintf(buf_end, RECV_SCAN_SIZE - (buf_end - buf), | ||
1158 | 658 | "offset: %lu, end_seg_len: %lu", offset, | ||
1159 | 659 | end_seg_len); | ||
1160 | 660 | if (end_seg_len & 0x1UL) { | ||
1161 | 661 | |||
1162 | 662 | ib_log_sys_parse_info_origin_mismatch(ptr, body_end, | ||
1163 | 663 | &buf_end); | ||
1164 | 664 | } | ||
1165 | 665 | strcpy(buf_end, ", data:"); | ||
1166 | 666 | buf_end += strlen(", data:"); | ||
1167 | 667 | ib_log_sys_output_raw(ptr, *ptr + (end_seg_len >> 1), &buf_end); | ||
1168 | 668 | itr->current_rec.body_str = strdup(buf); | ||
1169 | 669 | } | ||
1170 | 670 | |||
1171 | 671 | /*********************************************************************//** | ||
1172 | 672 | Parse copy record list end to a new created index page */ | ||
1173 | 673 | static | ||
1174 | 674 | void | ||
1175 | 675 | ib_log_sys_parse_end_list_copy( | ||
1176 | 676 | /*===========================*/ | ||
1177 | 677 | ib_log_rec_itr_t itr, /*!< in/out: log iterator */ | ||
1178 | 678 | byte** ptr, /*!< in/out: pointer to | ||
1179 | 679 | log data */ | ||
1180 | 680 | byte* body_end) /*!< in: pointer to end of a | ||
1181 | 681 | log record body */ | ||
1182 | 682 | { | ||
1183 | 683 | char *buf_end = buf + strlen(buf); | ||
1184 | 684 | ulint data_len = mach_read_from_4(*ptr); | ||
1185 | 685 | *ptr += 4; | ||
1186 | 686 | buf_end += snprintf(buf_end, RECV_SCAN_SIZE - (buf_end - buf), | ||
1187 | 687 | "len: %lu", data_len); | ||
1188 | 688 | while (*ptr < body_end) { | ||
1189 | 689 | ulint end_seg_len; | ||
1190 | 690 | *ptr = mach_parse_compressed(*ptr, body_end, &end_seg_len); | ||
1191 | 691 | buf_end += snprintf(buf_end, RECV_SCAN_SIZE - (buf_end - buf), | ||
1192 | 692 | ", end_seg_len: %lu", end_seg_len); | ||
1193 | 693 | if (end_seg_len & 0x1UL) { | ||
1194 | 694 | |||
1195 | 695 | ib_log_sys_parse_info_origin_mismatch(ptr, body_end, | ||
1196 | 696 | &buf_end); | ||
1197 | 697 | } | ||
1198 | 698 | strcpy(buf_end, ", data:"); | ||
1199 | 699 | buf_end += strlen(", data:"); | ||
1200 | 700 | ib_log_sys_output_raw(ptr, *ptr + (end_seg_len >> 1), | ||
1201 | 701 | &buf_end); | ||
1202 | 702 | } | ||
1203 | 703 | itr->current_rec.body_str = strdup(buf); | ||
1204 | 704 | } | ||
1205 | 705 | |||
1206 | 706 | /*********************************************************************//** | ||
1207 | 707 | Parse delete record from the page */ | ||
1208 | 708 | static | ||
1209 | 709 | void | ||
1210 | 710 | ib_log_sys_parse_delete_rec( | ||
1211 | 711 | /*========================*/ | ||
1212 | 712 | ib_log_rec_itr_t itr, /*!< in/out: log iterator */ | ||
1213 | 713 | byte** ptr) /*!< in/out: pointer to log data */ | ||
1214 | 714 | { | ||
1215 | 715 | char* buf_end = buf + strlen(buf); | ||
1216 | 716 | ulint offset = mach_read_from_2(*ptr); | ||
1217 | 717 | *ptr += 2; | ||
1218 | 718 | buf_end += snprintf(buf, RECV_SCAN_SIZE, "offset: %lu", offset); | ||
1219 | 719 | itr->current_rec.body_str = strdup(buf); | ||
1220 | 720 | } | ||
1221 | 721 | |||
1222 | 722 | /*********************************************************************//** | ||
1223 | 723 | Parse a file operation record */ | ||
1224 | 724 | static | ||
1225 | 725 | void | ||
1226 | 726 | ib_log_sys_parse_fil_op( | ||
1227 | 727 | /*====================*/ | ||
1228 | 728 | ib_log_rec_itr_t itr, /*!< in/out: log iterator */ | ||
1229 | 729 | byte** ptr, /*!< in/out: pointer to | ||
1230 | 730 | log data */ | ||
1231 | 731 | char** buf_end) /*!< in: pointer to end of a | ||
1232 | 732 | log record body */ | ||
1233 | 733 | { | ||
1234 | 734 | const char* name; | ||
1235 | 735 | ulint name_len = mach_read_from_2(*ptr); | ||
1236 | 736 | *ptr += 2; | ||
1237 | 737 | name = (const char *)(*ptr); | ||
1238 | 738 | *ptr += name_len; | ||
1239 | 739 | *buf_end += snprintf(*buf_end, RECV_SCAN_SIZE - (*buf_end - buf), | ||
1240 | 740 | "name_len: %lu, name: \"%s\"", name_len, name); | ||
1241 | 741 | if (itr->current_rec.type == MLOG_FILE_RENAME) { | ||
1242 | 742 | const char* new_name; | ||
1243 | 743 | ulint new_name_len = mach_read_from_2(*ptr); | ||
1244 | 744 | *ptr += 2; | ||
1245 | 745 | new_name = (const char *)(*ptr); | ||
1246 | 746 | *ptr += new_name_len; | ||
1247 | 747 | *buf_end += snprintf(*buf_end, | ||
1248 | 748 | RECV_SCAN_SIZE - (*buf_end - buf), | ||
1249 | 749 | ", new_name_len: %lu, new_name: \"%s\"", | ||
1250 | 750 | new_name_len, new_name); | ||
1251 | 751 | } | ||
1252 | 752 | itr->current_rec.body_str = strdup(buf); | ||
1253 | 753 | } | ||
1254 | 754 | |||
1255 | 755 | /*********************************************************************//** | ||
1256 | 756 | Get name of operation with compressed page */ | ||
1257 | 757 | static | ||
1258 | 758 | const char* | ||
1259 | 759 | ib_log_sys_get_zip_op_name( | ||
1260 | 760 | /*=======================*/ | ||
1261 | 761 | byte type) /*!< in: log record type */ | ||
1262 | 762 | { | ||
1263 | 763 | if (type == MLOG_ZIP_WRITE_NODE_PTR) | ||
1264 | 764 | return "node_ptr"; | ||
1265 | 765 | if (type == MLOG_ZIP_WRITE_BLOB_PTR) | ||
1266 | 766 | return "blob_ptr"; | ||
1267 | 767 | ut_a (0); | ||
1268 | 768 | return "WRONG TYPE"; | ||
1269 | 769 | } | ||
1270 | 770 | |||
1271 | 771 | /*********************************************************************//** | ||
1272 | 772 | Get pointer length for operation with compressed page */ | ||
1273 | 773 | static | ||
1274 | 774 | ulint | ||
1275 | 775 | ib_log_sys_get_zip_op_ptr_len( | ||
1276 | 776 | /*==========================*/ | ||
1277 | 777 | byte type) /*!< in: log record type */ | ||
1278 | 778 | { | ||
1279 | 779 | if (type == MLOG_ZIP_WRITE_NODE_PTR) | ||
1280 | 780 | return REC_NODE_PTR_SIZE; | ||
1281 | 781 | if (type == MLOG_ZIP_WRITE_BLOB_PTR) | ||
1282 | 782 | return BTR_EXTERN_FIELD_REF_SIZE; | ||
1283 | 783 | ut_a (0); | ||
1284 | 784 | return ULINT_UNDEFINED; | ||
1285 | 785 | } | ||
1286 | 786 | |||
1287 | 787 | /*********************************************************************//** | ||
1288 | 788 | Parse operation with compressed page */ | ||
1289 | 789 | static | ||
1290 | 790 | void | ||
1291 | 791 | ib_log_sys_parse_zip_op( | ||
1292 | 792 | /*====================*/ | ||
1293 | 793 | ib_log_rec_itr_t itr, /*!< in/out: log iterator */ | ||
1294 | 794 | byte** ptr) /*!< in/out: pointer to log data */ | ||
1295 | 795 | { | ||
1296 | 796 | char* buf_end = buf; | ||
1297 | 797 | ulint z_offset; | ||
1298 | 798 | ulint offset = mach_read_from_2(*ptr); | ||
1299 | 799 | *ptr += 2; | ||
1300 | 800 | z_offset = mach_read_from_2(*ptr); | ||
1301 | 801 | *ptr += 2; | ||
1302 | 802 | buf_end += snprintf(buf_end, | ||
1303 | 803 | RECV_SCAN_SIZE - (buf_end - buf), | ||
1304 | 804 | "offset: %lu, zip_offset: %lu, " | ||
1305 | 805 | "%s:", | ||
1306 | 806 | offset, z_offset, | ||
1307 | 807 | ib_log_sys_get_zip_op_name(itr->current_rec.type)); | ||
1308 | 808 | ib_log_sys_output_raw(ptr, *ptr + ib_log_sys_get_zip_op_ptr_len( | ||
1309 | 809 | itr->current_rec.type), &buf_end); | ||
1310 | 810 | itr->current_rec.body_str = strdup(buf); | ||
1311 | 811 | } | ||
1312 | 812 | |||
1313 | 813 | /*********************************************************************//** | ||
1314 | 814 | Parse log record body */ | ||
1315 | 815 | static | ||
1316 | 816 | void | ||
1317 | 817 | ib_log_sys_parse_rec_body( | ||
1318 | 818 | /*======================*/ | ||
1319 | 819 | ib_log_rec_itr_t itr, /*!< in/out: log iterator */ | ||
1320 | 820 | byte* body_start, /*!< in: pointer to start of | ||
1321 | 821 | a log record body */ | ||
1322 | 822 | byte* body_end) /*!< in: pointer to end of a log | ||
1323 | 823 | record body */ | ||
1324 | 824 | { | ||
1325 | 825 | byte* ptr = body_start; | ||
1326 | 826 | |||
1327 | 827 | ut_a (ib_log_sys_rec_has_body(&itr->current_rec) || ptr == NULL | ||
1328 | 828 | || body_start == body_end); | ||
1329 | 829 | if (ptr == NULL) | ||
1330 | 830 | ptr = body_end; | ||
1331 | 831 | |||
1332 | 832 | buf[0] = '\0'; | ||
1333 | 833 | |||
1334 | 834 | if (itr->current_rec.body_str) { | ||
1335 | 835 | |||
1336 | 836 | free (itr->current_rec.body_str); | ||
1337 | 837 | itr->current_rec.body_str = NULL; | ||
1338 | 838 | } | ||
1339 | 839 | |||
1340 | 840 | switch (itr->current_rec.type) { | ||
1341 | 841 | case MLOG_1BYTE: | ||
1342 | 842 | case MLOG_2BYTES: | ||
1343 | 843 | case MLOG_4BYTES: | ||
1344 | 844 | { | ||
1345 | 845 | ulint offset = mach_read_from_2(ptr); | ||
1346 | 846 | ulint val; | ||
1347 | 847 | int ret; | ||
1348 | 848 | ptr += 2; | ||
1349 | 849 | ptr = mach_parse_compressed(ptr, body_end, &val); | ||
1350 | 850 | ret = asprintf(&itr->current_rec.body_str, | ||
1351 | 851 | "offset: %lu, value: 0x%lX", offset, | ||
1352 | 852 | val); | ||
1353 | 853 | ut_a (ret > 0); | ||
1354 | 854 | break; | ||
1355 | 855 | } | ||
1356 | 856 | case MLOG_8BYTES: | ||
1357 | 857 | { | ||
1358 | 858 | ulint offset = mach_read_from_2(ptr); | ||
1359 | 859 | dulint val; | ||
1360 | 860 | int ret; | ||
1361 | 861 | ptr += 2; | ||
1362 | 862 | ptr = mach_dulint_parse_compressed(ptr, body_end, | ||
1363 | 863 | &val); | ||
1364 | 864 | ret = asprintf(&itr->current_rec.body_str, | ||
1365 | 865 | "offset: %lu, value: 0x%llX", offset, | ||
1366 | 866 | ut_conv_dulint_to_longlong(val)); | ||
1367 | 867 | ut_a (ret > 0); | ||
1368 | 868 | break; | ||
1369 | 869 | } | ||
1370 | 870 | case MLOG_REC_INSERT: | ||
1371 | 871 | ib_log_sys_parse_rec_insert(itr, &ptr, body_end); | ||
1372 | 872 | break; | ||
1373 | 873 | case MLOG_COMP_REC_INSERT: | ||
1374 | 874 | ib_log_sys_parse_index(&ptr); | ||
1375 | 875 | ib_log_sys_parse_rec_insert(itr, &ptr, body_end); | ||
1376 | 876 | break; | ||
1377 | 877 | case MLOG_COMP_PAGE_REORGANIZE: | ||
1378 | 878 | ib_log_sys_parse_index(&ptr); | ||
1379 | 879 | itr->current_rec.body_str = strdup(buf); | ||
1380 | 880 | break; | ||
1381 | 881 | case MLOG_COMP_REC_CLUST_DELETE_MARK: | ||
1382 | 882 | { | ||
1383 | 883 | char* buf_end = ib_log_sys_parse_index(&ptr); | ||
1384 | 884 | *buf_end++ = ','; | ||
1385 | 885 | *buf_end++ = ' '; | ||
1386 | 886 | ib_log_sys_parse_del_mark_set_clust_rec(itr, &ptr, | ||
1387 | 887 | body_end); | ||
1388 | 888 | break; | ||
1389 | 889 | } | ||
1390 | 890 | case MLOG_REC_SEC_DELETE_MARK: | ||
1391 | 891 | { | ||
1392 | 892 | int ret; | ||
1393 | 893 | ulint offset; | ||
1394 | 894 | ulint val = mach_read_from_1(ptr); | ||
1395 | 895 | ptr++; | ||
1396 | 896 | offset = mach_read_from_2(ptr); | ||
1397 | 897 | ptr += 2; | ||
1398 | 898 | ret = asprintf(&itr->current_rec.body_str, | ||
1399 | 899 | "value: %lu, offset: %lu", val, offset); | ||
1400 | 900 | ut_a(ret > 0); | ||
1401 | 901 | break; | ||
1402 | 902 | } | ||
1403 | 903 | case MLOG_REC_CLUST_DELETE_MARK: | ||
1404 | 904 | ib_log_sys_parse_del_mark_set_clust_rec(itr, &ptr, body_end); | ||
1405 | 905 | break; | ||
1406 | 906 | case MLOG_REC_UPDATE_IN_PLACE: | ||
1407 | 907 | ib_log_sys_parse_update_in_place(itr, &ptr, body_end); | ||
1408 | 908 | break; | ||
1409 | 909 | case MLOG_COMP_REC_UPDATE_IN_PLACE: | ||
1410 | 910 | { | ||
1411 | 911 | char* buf_end = ib_log_sys_parse_index(&ptr); | ||
1412 | 912 | *buf_end++ = ','; | ||
1413 | 913 | *buf_end++ = ' '; | ||
1414 | 914 | ib_log_sys_parse_update_in_place(itr, &ptr, body_end); | ||
1415 | 915 | break; | ||
1416 | 916 | } | ||
1417 | 917 | case MLOG_LIST_END_DELETE: | ||
1418 | 918 | case MLOG_LIST_START_DELETE: | ||
1419 | 919 | /* TODO: test */ | ||
1420 | 920 | ib_log_sys_parse_delete_rec_list(itr, &ptr); | ||
1421 | 921 | break; | ||
1422 | 922 | case MLOG_COMP_LIST_END_DELETE: | ||
1423 | 923 | case MLOG_COMP_LIST_START_DELETE: | ||
1424 | 924 | { | ||
1425 | 925 | char* buf_end = ib_log_sys_parse_index(&ptr); | ||
1426 | 926 | *buf_end++ = ','; *buf_end++ = ' '; *buf_end++ = '\0'; | ||
1427 | 927 | ib_log_sys_parse_delete_rec_list(itr, &ptr); | ||
1428 | 928 | break; | ||
1429 | 929 | } | ||
1430 | 930 | case MLOG_LIST_END_COPY_CREATED: | ||
1431 | 931 | /* TODO: test */ | ||
1432 | 932 | ib_log_sys_parse_end_list_copy(itr, &ptr, body_end); | ||
1433 | 933 | break; | ||
1434 | 934 | case MLOG_COMP_LIST_END_COPY_CREATED: | ||
1435 | 935 | { | ||
1436 | 936 | char* buf_end = ib_log_sys_parse_index(&ptr); | ||
1437 | 937 | *buf_end++ = ','; | ||
1438 | 938 | *buf_end++ = ' '; | ||
1439 | 939 | ib_log_sys_parse_end_list_copy(itr, &ptr, body_end); | ||
1440 | 940 | break; | ||
1441 | 941 | } | ||
1442 | 942 | case MLOG_UNDO_INSERT: | ||
1443 | 943 | { | ||
1444 | 944 | char* buf_end = buf; | ||
1445 | 945 | ulint data_len = mach_read_from_2(ptr); | ||
1446 | 946 | ptr += 2; | ||
1447 | 947 | buf_end += snprintf(buf_end, | ||
1448 | 948 | RECV_SCAN_SIZE - (buf_end - buf), | ||
1449 | 949 | "data_len: %lu, data:", data_len); | ||
1450 | 950 | ib_log_sys_output_raw(&ptr, ptr + data_len, &buf_end); | ||
1451 | 951 | itr->current_rec.body_str = strdup(buf); | ||
1452 | 952 | break; | ||
1453 | 953 | } | ||
1454 | 954 | case MLOG_UNDO_INIT: | ||
1455 | 955 | { | ||
1456 | 956 | int ret; | ||
1457 | 957 | ulint undo_log_seg_type; | ||
1458 | 958 | ptr = mach_parse_compressed(ptr, body_end, | ||
1459 | 959 | &undo_log_seg_type); | ||
1460 | 960 | ret = asprintf(&itr->current_rec.body_str, | ||
1461 | 961 | "undo_log_seg_type: %lu", | ||
1462 | 962 | undo_log_seg_type);; | ||
1463 | 963 | ut_a (ret > 0); | ||
1464 | 964 | break; | ||
1465 | 965 | } | ||
1466 | 966 | case MLOG_UNDO_HDR_CREATE: | ||
1467 | 967 | case MLOG_UNDO_HDR_REUSE: | ||
1468 | 968 | { | ||
1469 | 969 | int ret; | ||
1470 | 970 | trx_id_t trx_id; | ||
1471 | 971 | /* TODO: test _REUSE */ | ||
1472 | 972 | ptr = mach_dulint_parse_compressed(ptr, body_end, | ||
1473 | 973 | &trx_id); | ||
1474 | 974 | ret = asprintf(&itr->current_rec.body_str, | ||
1475 | 975 | "trx_id: 0x%llX", | ||
1476 | 976 | ut_conv_dulint_to_longlong(trx_id)); | ||
1477 | 977 | ut_a (ret > 0); | ||
1478 | 978 | break; | ||
1479 | 979 | } | ||
1480 | 980 | case MLOG_REC_MIN_MARK: | ||
1481 | 981 | case MLOG_COMP_REC_MIN_MARK: | ||
1482 | 982 | { | ||
1483 | 983 | /* TODO: test MLOG_REC_MIN_MARK */ | ||
1484 | 984 | int ret; | ||
1485 | 985 | ulint min_rec_mark_offset = mach_read_from_2(ptr); | ||
1486 | 986 | ptr += 2; | ||
1487 | 987 | ret = asprintf(&itr->current_rec.body_str, | ||
1488 | 988 | "min_rec_mark_offset: %lu", | ||
1489 | 989 | min_rec_mark_offset); | ||
1490 | 990 | ut_a (ret > 0); | ||
1491 | 991 | break; | ||
1492 | 992 | } | ||
1493 | 993 | case MLOG_REC_DELETE: | ||
1494 | 994 | ib_log_sys_parse_delete_rec(itr, &ptr); | ||
1495 | 995 | break; | ||
1496 | 996 | case MLOG_COMP_REC_DELETE: | ||
1497 | 997 | { | ||
1498 | 998 | char* buf_end = ib_log_sys_parse_index(&ptr); | ||
1499 | 999 | *buf_end++ = ','; | ||
1500 | 1000 | *buf_end++ = ' '; | ||
1501 | 1001 | ib_log_sys_parse_delete_rec(itr, &ptr); | ||
1502 | 1002 | break; | ||
1503 | 1003 | } | ||
1504 | 1004 | case MLOG_WRITE_STRING: | ||
1505 | 1005 | { | ||
1506 | 1006 | ulint data_len; | ||
1507 | 1007 | char* buf_end = buf; | ||
1508 | 1008 | ulint offset = mach_read_from_2(ptr); | ||
1509 | 1009 | ptr += 2; | ||
1510 | 1010 | data_len = mach_read_from_2(ptr); | ||
1511 | 1011 | ptr += 2; | ||
1512 | 1012 | buf_end += snprintf(buf_end, | ||
1513 | 1013 | RECV_SCAN_SIZE - (buf_end - buf), | ||
1514 | 1014 | "offset: %lu, data_len: %lu, " | ||
1515 | 1015 | "data:", offset, data_len); | ||
1516 | 1016 | ib_log_sys_output_raw(&ptr, ptr + data_len, &buf_end); | ||
1517 | 1017 | itr->current_rec.body_str = strdup(buf); | ||
1518 | 1018 | break; | ||
1519 | 1019 | } | ||
1520 | 1020 | case MLOG_FILE_CREATE2: | ||
1521 | 1021 | { | ||
1522 | 1022 | /* TODO: test */ | ||
1523 | 1023 | char* buf_end = buf; | ||
1524 | 1024 | ulint flags = mach_read_from_4(ptr); | ||
1525 | 1025 | ptr += 4; | ||
1526 | 1026 | buf_end += snprintf(buf_end, | ||
1527 | 1027 | RECV_SCAN_SIZE - (buf_end - buf), | ||
1528 | 1028 | "flags: 0x%lX:", flags); | ||
1529 | 1029 | *buf_end++ = ','; | ||
1530 | 1030 | *buf_end++ = ' '; | ||
1531 | 1031 | ib_log_sys_parse_fil_op(itr, &ptr, &buf_end); | ||
1532 | 1032 | break; | ||
1533 | 1033 | } | ||
1534 | 1034 | case MLOG_FILE_CREATE: | ||
1535 | 1035 | case MLOG_FILE_RENAME: | ||
1536 | 1036 | case MLOG_FILE_DELETE: | ||
1537 | 1037 | { | ||
1538 | 1038 | char* buf_end = buf; | ||
1539 | 1039 | ib_log_sys_parse_fil_op(itr, &ptr, &buf_end); | ||
1540 | 1040 | break; | ||
1541 | 1041 | } | ||
1542 | 1042 | case MLOG_ZIP_WRITE_NODE_PTR: | ||
1543 | 1043 | case MLOG_ZIP_WRITE_BLOB_PTR: | ||
1544 | 1044 | /* TODO: test */ | ||
1545 | 1045 | ib_log_sys_parse_zip_op(itr, &ptr); | ||
1546 | 1046 | break; | ||
1547 | 1047 | case MLOG_ZIP_WRITE_HEADER: | ||
1548 | 1048 | { | ||
1549 | 1049 | /* TODO: test */ | ||
1550 | 1050 | ulint offset = *ptr++; | ||
1551 | 1051 | ulint data_len = *ptr++; | ||
1552 | 1052 | char* buf_end = buf; | ||
1553 | 1053 | buf_end += snprintf(buf_end, | ||
1554 | 1054 | RECV_SCAN_SIZE - (buf_end - buf), | ||
1555 | 1055 | "offset: %lu, data_len: %lu, " | ||
1556 | 1056 | "data:", offset, data_len); | ||
1557 | 1057 | ib_log_sys_output_raw(&ptr, ptr + data_len, &buf_end); | ||
1558 | 1058 | itr->current_rec.body_str = strdup(buf); | ||
1559 | 1059 | break; | ||
1560 | 1060 | } | ||
1561 | 1061 | case MLOG_ZIP_PAGE_COMPRESS: | ||
1562 | 1062 | { | ||
1563 | 1063 | /* TODO: test */ | ||
1564 | 1064 | char* buf_end = buf; | ||
1565 | 1065 | ulint trailer_size; | ||
1566 | 1066 | ulint size = mach_read_from_2(ptr); | ||
1567 | 1067 | ptr += 2; | ||
1568 | 1068 | trailer_size = mach_read_from_2(ptr); | ||
1569 | 1069 | ptr += 2; | ||
1570 | 1070 | buf_end += snprintf(buf_end, | ||
1571 | 1071 | RECV_SCAN_SIZE - (buf_end - buf), | ||
1572 | 1072 | "data_size: %lu, " | ||
1573 | 1073 | "trailer_size: %lu, page_prev:", | ||
1574 | 1074 | size, trailer_size); | ||
1575 | 1075 | ib_log_sys_output_raw(&ptr, ptr + 4, &buf_end); | ||
1576 | 1076 | ptr += 4; | ||
1577 | 1077 | buf_end += snprintf(buf_end, | ||
1578 | 1078 | RECV_SCAN_SIZE - (buf_end - buf), | ||
1579 | 1079 | ", page_next:"); | ||
1580 | 1080 | ib_log_sys_output_raw(&ptr, ptr + 4, &buf_end); | ||
1581 | 1081 | ptr += 4; | ||
1582 | 1082 | buf_end += snprintf(buf_end, | ||
1583 | 1083 | RECV_SCAN_SIZE - (buf_end - buf), | ||
1584 | 1084 | ", data:"); | ||
1585 | 1085 | ib_log_sys_output_raw(&ptr, ptr + size, &buf_end); | ||
1586 | 1086 | ptr += size; | ||
1587 | 1087 | buf_end += snprintf(buf_end, | ||
1588 | 1088 | RECV_SCAN_SIZE - (buf_end - buf), | ||
1589 | 1089 | ", trailer_data:"); | ||
1590 | 1090 | ib_log_sys_output_raw(&ptr, ptr + trailer_size, | ||
1591 | 1091 | &buf_end); | ||
1592 | 1092 | ptr += trailer_size; | ||
1593 | 1093 | itr->current_rec.body_str = strdup(buf); | ||
1594 | 1094 | break; | ||
1595 | 1095 | } | ||
1596 | 1096 | case MLOG_INIT_FILE_PAGE: | ||
1597 | 1097 | case MLOG_IBUF_BITMAP_INIT: | ||
1598 | 1098 | case MLOG_UNDO_HDR_DISCARD: /* TODO: test */ | ||
1599 | 1099 | case MLOG_PAGE_REORGANIZE: /* TODO: test */ | ||
1600 | 1100 | case MLOG_PAGE_CREATE: | ||
1601 | 1101 | case MLOG_COMP_PAGE_CREATE: | ||
1602 | 1102 | case MLOG_UNDO_ERASE_END: | ||
1603 | 1103 | case MLOG_MULTI_REC_END: | ||
1604 | 1104 | case MLOG_DUMMY_RECORD: | ||
1605 | 1105 | case MLOG_LSN: | ||
1606 | 1106 | /* No body */ | ||
1607 | 1107 | break; | ||
1608 | 1108 | default: ; | ||
1609 | 1109 | ib_logger(ib_stream, "Corrupt log rec at LSN = %llu, ", | ||
1610 | 1110 | itr->current_rec.lsn); | ||
1611 | 1111 | ut_a(0); | ||
1612 | 1112 | } | ||
1613 | 1113 | ut_a (ptr == body_end); | ||
1614 | 1114 | } | ||
1615 | 1115 | |||
1616 | 1116 | /*********************************************************************//** | ||
1617 | 1117 | Get next log record */ | ||
1618 | 1118 | HAILDB_API | ||
1619 | 1119 | ib_log_rec_t | ||
1620 | 1120 | ib_log_sys_get_next_rec( | ||
1621 | 1121 | /*====================*/ | ||
1622 | 1122 | ib_log_rec_itr_t itr) /*!< in: log iterator */ | ||
1623 | 1123 | { | ||
1624 | 1124 | ulint len; | ||
1625 | 1125 | byte type; | ||
1626 | 1126 | ulint space; | ||
1627 | 1127 | ulint page_no; | ||
1628 | 1128 | byte* body; | ||
1629 | 1129 | |||
1630 | 1130 | /* Already reached the end of requested LSN range? */ | ||
1631 | 1131 | if (itr->next_parse_lsn >= itr->end_lsn) | ||
1632 | 1132 | return NULL; | ||
1633 | 1133 | |||
1634 | 1134 | if (itr->parse_buf_ptr == itr->parse_buf_end) { | ||
1635 | 1135 | |||
1636 | 1136 | /* Parse buf empty */ | ||
1637 | 1137 | if (!fill_parse_buffer(itr)) | ||
1638 | 1138 | return NULL; | ||
1639 | 1139 | } | ||
1640 | 1140 | |||
1641 | 1141 | /* Have some data in the parse buf, parse it */ | ||
1642 | 1142 | recv_sys->found_corrupt_log = FALSE; | ||
1643 | 1143 | len = recv_parse_log_rec(itr->parse_buf_ptr, itr->parse_buf_end, &type, | ||
1644 | 1144 | &space, &page_no, &body); | ||
1645 | 1145 | if (recv_sys->found_corrupt_log) { | ||
1646 | 1146 | |||
1647 | 1147 | /* Uh-oh, corrupt log. Now what? */ | ||
1648 | 1148 | ib_logger(ib_stream, "Corrupt log at LSN = %llu, " | ||
1649 | 1149 | "proceeding in 1 byte increments, " | ||
1650 | 1150 | "no correct parse guarantee and InnoDB may crash!\n", | ||
1651 | 1151 | itr->next_parse_lsn); | ||
1652 | 1152 | itr->parse_buf_ptr++; | ||
1653 | 1153 | itr->next_parse_lsn | ||
1654 | 1154 | = recv_calc_lsn_on_data_add(itr->next_parse_lsn, 1); | ||
1655 | 1155 | return ib_log_sys_get_next_rec(itr); | ||
1656 | 1156 | } | ||
1657 | 1157 | if (len > 0) { | ||
1658 | 1158 | |||
1659 | 1159 | /* Full rec, see if its LSN is inside the requested range */ | ||
1660 | 1160 | if (itr->next_parse_lsn >= itr->start_lsn) { | ||
1661 | 1161 | |||
1662 | 1162 | itr->current_rec.single_rec | ||
1663 | 1163 | = (*itr->parse_buf_ptr & MLOG_SINGLE_REC_FLAG) | ||
1664 | 1164 | != 0; | ||
1665 | 1165 | itr->current_rec.lsn = itr->next_parse_lsn; | ||
1666 | 1166 | itr->current_rec.len = len; | ||
1667 | 1167 | itr->current_rec.type = type; | ||
1668 | 1168 | |||
1669 | 1169 | if (log_online_rec_has_page(type)) { | ||
1670 | 1170 | |||
1671 | 1171 | itr->current_rec.space = space; | ||
1672 | 1172 | itr->current_rec.page_no = page_no; | ||
1673 | 1173 | } | ||
1674 | 1174 | else { | ||
1675 | 1175 | |||
1676 | 1176 | itr->current_rec.space = ULINT_UNDEFINED; | ||
1677 | 1177 | itr->current_rec.page_no = ULINT_UNDEFINED; | ||
1678 | 1178 | } | ||
1679 | 1179 | |||
1680 | 1180 | itr->parse_buf_ptr += len; | ||
1681 | 1181 | ib_log_sys_parse_rec_body(itr, body, | ||
1682 | 1182 | itr->parse_buf_ptr); | ||
1683 | 1183 | |||
1684 | 1184 | itr->next_parse_lsn | ||
1685 | 1185 | = recv_calc_lsn_on_data_add( | ||
1686 | 1186 | itr->next_parse_lsn, len); | ||
1687 | 1187 | |||
1688 | 1188 | return &itr->current_rec; | ||
1689 | 1189 | } | ||
1690 | 1190 | else if (itr->next_parse_lsn < itr->start_lsn) { | ||
1691 | 1191 | |||
1692 | 1192 | /* Full rec but below the requested LSN range. Eat it, | ||
1693 | 1193 | try the next one. */ | ||
1694 | 1194 | itr->parse_buf_ptr += len; | ||
1695 | 1195 | itr->next_parse_lsn | ||
1696 | 1196 | = recv_calc_lsn_on_data_add( | ||
1697 | 1197 | itr->next_parse_lsn, len); | ||
1698 | 1198 | return ib_log_sys_get_next_rec(itr); | ||
1699 | 1199 | } | ||
1700 | 1200 | else { | ||
1701 | 1201 | |||
1702 | 1202 | /* Rec past the requested LSN range, EOF */ | ||
1703 | 1203 | ut_a (itr->next_parse_lsn > itr->end_lsn); | ||
1704 | 1204 | return NULL; | ||
1705 | 1205 | } | ||
1706 | 1206 | } | ||
1707 | 1207 | |||
1708 | 1208 | /* Incomplete rec. Shift it to the beginning of the parse buffer, get | ||
1709 | 1209 | more data and parse it again. */ | ||
1710 | 1210 | ut_memmove(itr->parse_buf, itr->parse_buf_ptr, | ||
1711 | 1211 | itr->parse_buf_end - itr->parse_buf_ptr); | ||
1712 | 1212 | itr->parse_buf_end = itr->parse_buf | ||
1713 | 1213 | + (itr->parse_buf_end - itr->parse_buf_ptr); | ||
1714 | 1214 | itr->parse_buf_ptr = itr->parse_buf; | ||
1715 | 1215 | |||
1716 | 1216 | if (!fill_parse_buffer(itr)) { | ||
1717 | 1217 | |||
1718 | 1218 | ib_logger(ib_stream, "Incomplete record at LSN = %llu\n", | ||
1719 | 1219 | itr->next_parse_lsn); | ||
1720 | 1220 | return NULL; | ||
1721 | 1221 | } | ||
1722 | 1222 | return ib_log_sys_get_next_rec(itr); | ||
1723 | 1223 | } | ||
1724 | 1224 | |||
1725 | 1225 | /*********************************************************************//** | ||
1726 | 1226 | Get LSN of record */ | ||
1727 | 1227 | HAILDB_API | ||
1728 | 1228 | ib_u64_t | ||
1729 | 1229 | ib_log_sys_get_rec_lsn( | ||
1730 | 1230 | /*===================*/ | ||
1731 | 1231 | const ib_log_rec_t log_rec) /*!< in: log record */ | ||
1732 | 1232 | { | ||
1733 | 1233 | return log_rec->lsn; | ||
1734 | 1234 | } | ||
1735 | 1235 | |||
1736 | 1236 | /*********************************************************************//** | ||
1737 | 1237 | Get length of record */ | ||
1738 | 1238 | HAILDB_API | ||
1739 | 1239 | ib_ulint_t | ||
1740 | 1240 | ib_log_sys_get_rec_len( | ||
1741 | 1241 | /*===================*/ | ||
1742 | 1242 | const ib_log_rec_t log_rec) /*!< in: log record */ | ||
1743 | 1243 | { | ||
1744 | 1244 | return log_rec->len; | ||
1745 | 1245 | } | ||
1746 | 1246 | |||
1747 | 1247 | /*********************************************************************//** | ||
1748 | 1248 | Get log record type (MLOG_*) */ | ||
1749 | 1249 | HAILDB_API | ||
1750 | 1250 | ib_byte_t | ||
1751 | 1251 | ib_log_sys_get_rec_type( | ||
1752 | 1252 | /*====================*/ | ||
1753 | 1253 | const ib_log_rec_t log_rec) /*!< in: log record */ | ||
1754 | 1254 | { | ||
1755 | 1255 | return log_rec->type; | ||
1756 | 1256 | } | ||
1757 | 1257 | |||
1758 | 1258 | /*********************************************************************//** | ||
1759 | 1259 | @return TRUE if MLOG_SINGLE_REC_FLAG is set for log record */ | ||
1760 | 1260 | HAILDB_API | ||
1761 | 1261 | ib_bool_t | ||
1762 | 1262 | ib_log_sys_get_single_rec_flag( | ||
1763 | 1263 | /*===========================*/ | ||
1764 | 1264 | const ib_log_rec_t log_rec) /*!< in: log record */ | ||
1765 | 1265 | { | ||
1766 | 1266 | return log_rec->single_rec != 0; | ||
1767 | 1267 | } | ||
1768 | 1268 | |||
1769 | 1269 | /*********************************************************************//** | ||
1770 | 1270 | @return space id associated with log record or ULINT_UNDEFINED if | ||
1771 | 1271 | record doesn't have space id associated */ | ||
1772 | 1272 | HAILDB_API | ||
1773 | 1273 | ib_ulint_t | ||
1774 | 1274 | ib_log_sys_get_rec_space( | ||
1775 | 1275 | /*=====================*/ | ||
1776 | 1276 | const ib_log_rec_t log_rec) /*!< in: log record */ | ||
1777 | 1277 | { | ||
1778 | 1278 | if (!log_online_rec_has_page(log_rec->type)) | ||
1779 | 1279 | ut_a (log_rec->space == ULINT_UNDEFINED); | ||
1780 | 1280 | return log_rec->space; | ||
1781 | 1281 | } | ||
1782 | 1282 | |||
1783 | 1283 | /*********************************************************************//** | ||
1784 | 1284 | @return page id associated with log record or ULINT_UNDEFINED if | ||
1785 | 1285 | record doesn't have page id associated */ | ||
1786 | 1286 | HAILDB_API | ||
1787 | 1287 | ib_ulint_t | ||
1788 | 1288 | ib_log_sys_get_rec_page_no( | ||
1789 | 1289 | /*=======================*/ | ||
1790 | 1290 | const ib_log_rec_t log_rec) /*!< in: log record */ | ||
1791 | 1291 | { | ||
1792 | 1292 | if (!log_online_rec_has_page(log_rec->type)) | ||
1793 | 1293 | ut_a (log_rec->page_no == ULINT_UNDEFINED); | ||
1794 | 1294 | return log_rec->page_no; | ||
1795 | 1295 | } | ||
1796 | 1296 | |||
1797 | 1297 | /*********************************************************************//** | ||
1798 | 1298 | Release log iterator */ | ||
1799 | 1299 | HAILDB_API | ||
1800 | 1300 | void | ||
1801 | 1301 | ib_log_sys_free_iterator( | ||
1802 | 1302 | /*=====================*/ | ||
1803 | 1303 | ib_log_rec_itr_t itr) /*!< in: log iterator */ | ||
1804 | 1304 | { | ||
1805 | 1305 | mem_free(itr->read_buf); | ||
1806 | 1306 | mem_free(itr->parse_buf); | ||
1807 | 1307 | mem_free(itr); | ||
1808 | 1308 | } | ||
1809 | 1309 | |||
1810 | 1310 | /*********************************************************************//** | ||
1811 | 1311 | @return page id associated with log record or ULINT_UNDEFINED if | ||
1812 | 1312 | record doesn't have page id associated */ | ||
1813 | 1313 | HAILDB_API | ||
1814 | 1314 | const char * | ||
1815 | 1315 | ib_log_sys_get_rec_name( | ||
1816 | 1316 | /*====================*/ | ||
1817 | 1317 | const ib_log_rec_t log_rec) /*!< in: log record */ | ||
1818 | 1318 | { | ||
1819 | 1319 | byte type = ib_log_sys_get_rec_type(log_rec); | ||
1820 | 1320 | if (type < sizeof(mlog_type_names) / sizeof(char*)) | ||
1821 | 1321 | return mlog_type_names[type]; | ||
1822 | 1322 | return "undefined"; | ||
1823 | 1323 | } | ||
1824 | 1324 | |||
1825 | 1325 | /*********************************************************************//** | ||
1826 | 1326 | @return TRUE if is log record about an .ibd file operation */ | ||
1827 | 1327 | HAILDB_API | ||
1828 | 1328 | ib_bool_t | ||
1829 | 1329 | ib_log_sys_rec_has_mlog_file_flag( | ||
1830 | 1330 | /*==============================*/ | ||
1831 | 1331 | const ib_log_rec_t log_rec) /*!< in: log record */ | ||
1832 | 1332 | { | ||
1833 | 1333 | return log_rec->type == MLOG_FILE_CREATE | ||
1834 | 1334 | || log_rec->type == MLOG_FILE_RENAME | ||
1835 | 1335 | || log_rec->type == MLOG_FILE_DELETE | ||
1836 | 1336 | || log_rec->type == MLOG_FILE_CREATE2; | ||
1837 | 1337 | } | ||
1838 | 1338 | |||
1839 | 1339 | /*********************************************************************//** | ||
1840 | 1340 | @return TRUE if MLOG_FILE_FLAG_TEMP is set */ | ||
1841 | 1341 | HAILDB_API | ||
1842 | 1342 | ib_bool_t | ||
1843 | 1343 | ib_log_sys_get_mlog_file_flag_temp( | ||
1844 | 1344 | /*===============================*/ | ||
1845 | 1345 | const ib_log_rec_t log_rec) /*!< in: log record */ | ||
1846 | 1346 | { | ||
1847 | 1347 | ut_ad (ib_log_sys_rec_has_mlog_file_flag(log_rec)); | ||
1848 | 1348 | return ib_log_sys_get_rec_page_no(log_rec) & MLOG_FILE_FLAG_TEMP; | ||
1849 | 1349 | } | ||
1850 | 1350 | |||
1851 | 1351 | /*********************************************************************//** | ||
1852 | 1352 | @return TRUE if record of type MLOG_LSN (LSN pseudo-record) */ | ||
1853 | 1353 | HAILDB_API | ||
1854 | 1354 | ib_bool_t | ||
1855 | 1355 | ib_log_sys_is_mlog_lsn_rec( | ||
1856 | 1356 | /*=======================*/ | ||
1857 | 1357 | const ib_log_rec_t log_rec) /*!< in: log record */ | ||
1858 | 1358 | { | ||
1859 | 1359 | return log_rec->type == MLOG_LSN; | ||
1860 | 1360 | } | ||
1861 | 1361 | |||
1862 | 1362 | /*********************************************************************//** | ||
1863 | 1363 | @return LSN from lsn pseudo-record */ | ||
1864 | 1364 | HAILDB_API | ||
1865 | 1365 | ib_u64_t | ||
1866 | 1366 | ib_log_sys_get_mlog_lsn( | ||
1867 | 1367 | /*====================*/ | ||
1868 | 1368 | const ib_log_rec_t log_rec) /*!< in: log record */ | ||
1869 | 1369 | { | ||
1870 | 1370 | ut_a (ib_log_sys_is_mlog_lsn_rec(log_rec)); | ||
1871 | 1371 | return (ib_u64_t)log_rec->space << 32 | log_rec->page_no; | ||
1872 | 1372 | } | ||
1873 | 1373 | |||
1874 | 1374 | /*********************************************************************//** | ||
1875 | 1375 | @return TRUE if log record has body */ | ||
1876 | 1376 | HAILDB_API | ||
1877 | 1377 | ib_bool_t | ||
1878 | 1378 | ib_log_sys_rec_has_body( | ||
1879 | 1379 | /*====================*/ | ||
1880 | 1380 | const ib_log_rec_t log_rec) /*!< in: log record */ | ||
1881 | 1381 | { | ||
1882 | 1382 | return log_rec->type != MLOG_MULTI_REC_END | ||
1883 | 1383 | && log_rec->type != MLOG_DUMMY_RECORD | ||
1884 | 1384 | && log_rec->type != MLOG_LSN | ||
1885 | 1385 | && log_rec->type != MLOG_PAGE_REORGANIZE | ||
1886 | 1386 | && log_rec->type != MLOG_PAGE_CREATE | ||
1887 | 1387 | && log_rec->type != MLOG_COMP_PAGE_CREATE | ||
1888 | 1388 | && log_rec->type != MLOG_UNDO_ERASE_END | ||
1889 | 1389 | && log_rec->type != MLOG_UNDO_HDR_DISCARD | ||
1890 | 1390 | && log_rec->type != MLOG_IBUF_BITMAP_INIT | ||
1891 | 1391 | && log_rec->type != MLOG_INIT_FILE_PAGE; | ||
1892 | 1392 | } | ||
1893 | 1393 | |||
1894 | 1394 | /*********************************************************************//** | ||
1895 | 1395 | @return log record's body as string */ | ||
1896 | 1396 | HAILDB_API | ||
1897 | 1397 | const char* | ||
1898 | 1398 | ib_log_sys_get_rec_body_str( | ||
1899 | 1399 | /*========================*/ | ||
1900 | 1400 | const ib_log_rec_t log_rec) /*!< in: log record */ | ||
1901 | 1401 | { | ||
1902 | 1402 | ut_ad (ib_log_sys_rec_has_body(log_rec)); | ||
1903 | 1403 | return log_rec->body_str; | ||
1904 | 1404 | } | ||
1905 | 1405 | |||
1906 | 1406 | /*********************************************************************//** | ||
1907 | 1407 | Print log records in human-readable format */ | ||
1908 | 1408 | ibool | ||
1909 | 1409 | ib_log_sys_print( | ||
1910 | 1410 | /*=============*/ | ||
1911 | 1411 | ib_uint64_t start_lsn, /*!< in: parse start LSN. | ||
1912 | 1412 | 0 for START_LSN_LAST_CP */ | ||
1913 | 1413 | ib_uint64_t end_lsn, /*!< in: parse end LSN. | ||
1914 | 1414 | IB_ULONGLONG_MAX for log to be | ||
1915 | 1415 | parsed to the end */ | ||
1916 | 1416 | ulint filter_space, /*!< in: Space ID to filter | ||
1917 | 1417 | records on or ULINT_UNDEFINED */ | ||
1918 | 1418 | ulint filter_page, /*!< in: Page ID to filter | ||
1919 | 1419 | records on or ULINT_UNDEFINED */ | ||
1920 | 1420 | ibool numeric, /*!< in: TRUE for output log | ||
1921 | 1421 | item type byte values instead of | ||
1922 | 1422 | mnemonics */ | ||
1923 | 1423 | ibool print_rec_bodies) /*!< in: TRUE for print log | ||
1924 | 1424 | record body contents */ | ||
1925 | 1425 | { | ||
1926 | 1426 | ib_err_t ib_err; | ||
1927 | 1427 | |||
1928 | 1428 | if (start_lsn == 0) { | ||
1929 | 1429 | ib_logger(ib_stream, "Reading last checkpoint LSN\n"); | ||
1930 | 1430 | ib_err = ib_log_sys_find_last_checkpoint_lsn(&start_lsn); | ||
1931 | 1431 | if (ib_err != DB_SUCCESS) { | ||
1932 | 1432 | ib_logger(ib_stream, | ||
1933 | 1433 | "ib_log_sys_find_last_checkpoint_lsn: %d\n", | ||
1934 | 1434 | ib_err); | ||
1935 | 1435 | return FALSE; | ||
1936 | 1436 | } | ||
1937 | 1437 | } | ||
1938 | 1438 | |||
1939 | 1439 | ib_logger(ib_stream, "Reading InnoDB redo logs " | ||
1940 | 1440 | "from LSN %llu to %llu\n", | ||
1941 | 1441 | start_lsn, end_lsn); | ||
1942 | 1442 | |||
1943 | 1443 | ib_log_rec_itr_t log_rec_iterator = | ||
1944 | 1444 | ib_log_sys_create_iterator(start_lsn, end_lsn); | ||
1945 | 1445 | ib_log_rec_t log_rec; | ||
1946 | 1446 | |||
1947 | 1447 | while ((log_rec = ib_log_sys_get_next_rec(log_rec_iterator)) != NULL) { | ||
1948 | 1448 | |||
1949 | 1449 | ib_ulint_t space = ib_log_sys_get_rec_space(log_rec); | ||
1950 | 1450 | ib_ulint_t page = ib_log_sys_get_rec_page_no(log_rec); | ||
1951 | 1451 | |||
1952 | 1452 | if ((filter_space != ULINT_UNDEFINED && space != filter_space) | ||
1953 | 1453 | || (filter_page != ULINT_UNDEFINED | ||
1954 | 1454 | && page != filter_page)) | ||
1955 | 1455 | continue; | ||
1956 | 1456 | |||
1957 | 1457 | ib_logger(ib_stream, "{LSN: %llu, len: %lu, type: ", | ||
1958 | 1458 | ib_log_sys_get_rec_lsn(log_rec), | ||
1959 | 1459 | ib_log_sys_get_rec_len(log_rec)); | ||
1960 | 1460 | if (numeric) { | ||
1961 | 1461 | ib_logger(ib_stream, | ||
1962 | 1462 | "%d", ib_log_sys_get_rec_type(log_rec)); | ||
1963 | 1463 | } else { | ||
1964 | 1464 | ib_logger(ib_stream, | ||
1965 | 1465 | "%s", ib_log_sys_get_rec_name(log_rec)); | ||
1966 | 1466 | } | ||
1967 | 1467 | ib_logger(ib_stream, ", singlerec: %d", | ||
1968 | 1468 | (ib_log_sys_get_single_rec_flag(log_rec) ? 1 : 0)); | ||
1969 | 1469 | |||
1970 | 1470 | if (ib_log_sys_rec_has_mlog_file_flag(log_rec)) { | ||
1971 | 1471 | ib_logger(ib_stream, ", MLOG_FILE_FLAG_TEMP: %d", | ||
1972 | 1472 | (ib_log_sys_get_mlog_file_flag_temp(log_rec) ? | ||
1973 | 1473 | 1 : 0)); | ||
1974 | 1474 | } else if (ib_log_sys_is_mlog_lsn_rec(log_rec)) { | ||
1975 | 1475 | ib_logger(ib_stream, ", mloglsn: %llu", | ||
1976 | 1476 | ib_log_sys_get_mlog_lsn(log_rec)); | ||
1977 | 1477 | } else if (space != ULINT_UNDEFINED) { | ||
1978 | 1478 | ib_logger(ib_stream, ", space: %lu, page: %lu", | ||
1979 | 1479 | space, page); | ||
1980 | 1480 | } else { | ||
1981 | 1481 | assert(page == ULINT_UNDEFINED); | ||
1982 | 1482 | } | ||
1983 | 1483 | |||
1984 | 1484 | if (print_rec_bodies && ib_log_sys_rec_has_body(log_rec)) | ||
1985 | 1485 | { | ||
1986 | 1486 | ib_logger(ib_stream, ", %s", | ||
1987 | 1487 | ib_log_sys_get_rec_body_str(log_rec)); | ||
1988 | 1488 | } | ||
1989 | 1489 | ib_logger(ib_stream, "}\n"); | ||
1990 | 1490 | } | ||
1991 | 1491 | ib_log_sys_free_iterator(log_rec_iterator); | ||
1992 | 1492 | return TRUE; | ||
1993 | 1493 | } | ||
1994 | 0 | 1494 | ||
1995 | === added file 'src/api_log.h' | |||
1996 | --- src/api_log.h 1970-01-01 00:00:00 +0000 | |||
1997 | +++ src/api_log.h 2012-12-05 22:33:23 +0000 | |||
1998 | @@ -0,0 +1,213 @@ | |||
1999 | 1 | /* | ||
2000 | 2 | * Copyright (C) 2012 Percona Inc. | ||
2001 | 3 | * This program is free software: you can redistribute it and/or modify it | ||
2002 | 4 | * under the terms of the GNU General Public License version 3, as published | ||
2003 | 5 | * by the Free Software Foundation. | ||
2004 | 6 | * | ||
2005 | 7 | * This program is distributed in the hope that it will be useful, but | ||
2006 | 8 | * WITHOUT ANY WARRANTY; without even the implied warranties of | ||
2007 | 9 | * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
2008 | 10 | * PURPOSE. See the GNU General Public License for more details. | ||
2009 | 11 | * | ||
2010 | 12 | * You should have received a copy of the GNU General Public License along | ||
2011 | 13 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
2012 | 14 | */ | ||
2013 | 15 | |||
2014 | 16 | #ifndef api_log_h | ||
2015 | 17 | #define api_log_h | ||
2016 | 18 | |||
2017 | 19 | #include "univ.i" | ||
2018 | 20 | #include "innodb_int.h" | ||
2019 | 21 | |||
2020 | 22 | #ifdef __cplusplus | ||
2021 | 23 | extern "C" { | ||
2022 | 24 | #endif /* __cplusplus */ | ||
2023 | 25 | |||
2024 | 26 | #define HAILDB_API UNIV_INTERN | ||
2025 | 27 | |||
2026 | 28 | typedef struct ib_log_rec_itr_struct* ib_log_rec_itr_t; | ||
2027 | 29 | |||
2028 | 30 | typedef struct ib_log_rec_struct* ib_log_rec_t; | ||
2029 | 31 | |||
2030 | 32 | /*********************************************************************//** | ||
2031 | 33 | Initialize InnoDB systems needed for the log printer | ||
2032 | 34 | @return DB_SUCCESS if successfull */ | ||
2033 | 35 | HAILDB_API | ||
2034 | 36 | ib_err_t | ||
2035 | 37 | ib_log_sys_start( | ||
2036 | 38 | /*=============*/ | ||
2037 | 39 | ib_ulint_t log_buf_size, /*!< in: the size of the buffer */ | ||
2038 | 40 | const char* log_dir); /*!< in: path to InnoDB log files. */ | ||
2039 | 41 | |||
2040 | 42 | /*********************************************************************//** | ||
2041 | 43 | Uninitialize InnoDB systems needed for the log printer */ | ||
2042 | 44 | HAILDB_API | ||
2043 | 45 | void | ||
2044 | 46 | ib_log_sys_stop(void); | ||
2045 | 47 | |||
2046 | 48 | /*********************************************************************//** | ||
2047 | 49 | Find last consistent checkpoint LSN in log groups */ | ||
2048 | 50 | HAILDB_API | ||
2049 | 51 | ib_err_t | ||
2050 | 52 | ib_log_sys_find_last_checkpoint_lsn( | ||
2051 | 53 | /*================================*/ | ||
2052 | 54 | ib_u64_t* last_checkpoint_lsn); /*!< out: last checkpoint LSN */ | ||
2053 | 55 | |||
2054 | 56 | /*********************************************************************//** | ||
2055 | 57 | Create iterator through log records */ | ||
2056 | 58 | HAILDB_API | ||
2057 | 59 | ib_log_rec_itr_t | ||
2058 | 60 | ib_log_sys_create_iterator( | ||
2059 | 61 | /*=======================*/ | ||
2060 | 62 | ib_u64_t start_lsn, /*!< in: starting LSN */ | ||
2061 | 63 | ib_u64_t end_lsn); /*!< in: last LSN */ | ||
2062 | 64 | |||
2063 | 65 | /*********************************************************************//** | ||
2064 | 66 | Get next log record */ | ||
2065 | 67 | HAILDB_API | ||
2066 | 68 | ib_log_rec_t | ||
2067 | 69 | ib_log_sys_get_next_rec( | ||
2068 | 70 | /*====================*/ | ||
2069 | 71 | ib_log_rec_itr_t itr); /*!< in: log iterator */ | ||
2070 | 72 | |||
2071 | 73 | /*********************************************************************//** | ||
2072 | 74 | Release log iterator */ | ||
2073 | 75 | HAILDB_API | ||
2074 | 76 | void | ||
2075 | 77 | ib_log_sys_free_iterator( | ||
2076 | 78 | /*=====================*/ | ||
2077 | 79 | ib_log_rec_itr_t itr); /*!< in: log iterator */ | ||
2078 | 80 | |||
2079 | 81 | /*********************************************************************//** | ||
2080 | 82 | Get LSN of record */ | ||
2081 | 83 | HAILDB_API | ||
2082 | 84 | ib_u64_t | ||
2083 | 85 | ib_log_sys_get_rec_lsn( | ||
2084 | 86 | /*===================*/ | ||
2085 | 87 | const ib_log_rec_t log_rec); /*!< in: log record */ | ||
2086 | 88 | |||
2087 | 89 | /*********************************************************************//** | ||
2088 | 90 | Get length of record */ | ||
2089 | 91 | HAILDB_API | ||
2090 | 92 | ib_ulint_t | ||
2091 | 93 | ib_log_sys_get_rec_len( | ||
2092 | 94 | /*===================*/ | ||
2093 | 95 | const ib_log_rec_t log_rec); /*!< in: log record */ | ||
2094 | 96 | |||
2095 | 97 | /*********************************************************************//** | ||
2096 | 98 | Get log record type (MLOG_*) */ | ||
2097 | 99 | HAILDB_API | ||
2098 | 100 | ib_byte_t | ||
2099 | 101 | ib_log_sys_get_rec_type( | ||
2100 | 102 | /*====================*/ | ||
2101 | 103 | const ib_log_rec_t log_rec); /*!< in: log record */ | ||
2102 | 104 | |||
2103 | 105 | |||
2104 | 106 | /*********************************************************************//** | ||
2105 | 107 | @return TRUE if MLOG_SINGLE_REC_FLAG is set for log record */ | ||
2106 | 108 | HAILDB_API | ||
2107 | 109 | ib_bool_t | ||
2108 | 110 | ib_log_sys_get_single_rec_flag( | ||
2109 | 111 | /*===========================*/ | ||
2110 | 112 | const ib_log_rec_t log_rec); /*!< in: log record */ | ||
2111 | 113 | |||
2112 | 114 | /*********************************************************************//** | ||
2113 | 115 | @return space id associated with log record or ULINT_UNDEFINED if | ||
2114 | 116 | record doesn't have space id associated */ | ||
2115 | 117 | HAILDB_API | ||
2116 | 118 | ib_ulint_t | ||
2117 | 119 | ib_log_sys_get_rec_space( | ||
2118 | 120 | /*=====================*/ | ||
2119 | 121 | const ib_log_rec_t log_rec); /*!< in: log record */ | ||
2120 | 122 | |||
2121 | 123 | /*********************************************************************//** | ||
2122 | 124 | @return page id associated with log record or ULINT_UNDEFINED if | ||
2123 | 125 | record doesn't have page id associated */ | ||
2124 | 126 | HAILDB_API | ||
2125 | 127 | ib_ulint_t | ||
2126 | 128 | ib_log_sys_get_rec_page_no( | ||
2127 | 129 | /*=======================*/ | ||
2128 | 130 | const ib_log_rec_t log_rec); /*!< in: log record */ | ||
2129 | 131 | |||
2130 | 132 | /*********************************************************************//** | ||
2131 | 133 | @return page id associated with log record or ULINT_UNDEFINED if | ||
2132 | 134 | record doesn't have page id associated */ | ||
2133 | 135 | HAILDB_API | ||
2134 | 136 | const char * | ||
2135 | 137 | ib_log_sys_get_rec_name( | ||
2136 | 138 | /*====================*/ | ||
2137 | 139 | const ib_log_rec_t log_rec); /*!< in: log record */ | ||
2138 | 140 | |||
2139 | 141 | /*********************************************************************//** | ||
2140 | 142 | @return TRUE if is log record about an .ibd file operation */ | ||
2141 | 143 | HAILDB_API | ||
2142 | 144 | ib_bool_t | ||
2143 | 145 | ib_log_sys_rec_has_mlog_file_flag( | ||
2144 | 146 | /*==============================*/ | ||
2145 | 147 | const ib_log_rec_t log_rec); /*!< in: log record */ | ||
2146 | 148 | |||
2147 | 149 | /*********************************************************************//** | ||
2148 | 150 | @return TRUE if MLOG_FILE_FLAG_TEMP is set */ | ||
2149 | 151 | HAILDB_API | ||
2150 | 152 | ib_bool_t | ||
2151 | 153 | ib_log_sys_get_mlog_file_flag_temp( | ||
2152 | 154 | /*===============================*/ | ||
2153 | 155 | const ib_log_rec_t log_rec); /*!< in: log record */ | ||
2154 | 156 | |||
2155 | 157 | /*********************************************************************//** | ||
2156 | 158 | @return TRUE if record of type MLOG_LSN (LSN pseudo-record) */ | ||
2157 | 159 | HAILDB_API | ||
2158 | 160 | ib_bool_t | ||
2159 | 161 | ib_log_sys_is_mlog_lsn_rec( | ||
2160 | 162 | /*=======================*/ | ||
2161 | 163 | const ib_log_rec_t log_rec); /*!< in: log record */ | ||
2162 | 164 | |||
2163 | 165 | /*********************************************************************//** | ||
2164 | 166 | @return LSN from lsn pseudo-record */ | ||
2165 | 167 | HAILDB_API | ||
2166 | 168 | ib_u64_t | ||
2167 | 169 | ib_log_sys_get_mlog_lsn( | ||
2168 | 170 | /*====================*/ | ||
2169 | 171 | const ib_log_rec_t log_rec); /*!< in: log record */ | ||
2170 | 172 | |||
2171 | 173 | /*********************************************************************//** | ||
2172 | 174 | @return TRUE if log record has body */ | ||
2173 | 175 | HAILDB_API | ||
2174 | 176 | ib_bool_t | ||
2175 | 177 | ib_log_sys_rec_has_body( | ||
2176 | 178 | /*====================*/ | ||
2177 | 179 | const ib_log_rec_t log_rec); /*!< in: log record */ | ||
2178 | 180 | |||
2179 | 181 | /*********************************************************************//** | ||
2180 | 182 | @return log record's body as string */ | ||
2181 | 183 | HAILDB_API | ||
2182 | 184 | const char* | ||
2183 | 185 | ib_log_sys_get_rec_body_str( | ||
2184 | 186 | /*========================*/ | ||
2185 | 187 | const ib_log_rec_t log_rec); /*!< in: log record */ | ||
2186 | 188 | |||
2187 | 189 | /*********************************************************************//** | ||
2188 | 190 | Print log records in human-readable format */ | ||
2189 | 191 | ibool | ||
2190 | 192 | ib_log_sys_print( | ||
2191 | 193 | /*=============*/ | ||
2192 | 194 | ib_uint64_t start_lsn, /*!< in: parse start LSN. | ||
2193 | 195 | 0 for START_LSN_LAST_CP */ | ||
2194 | 196 | ib_uint64_t end_lsn, /*!< in: parse end LSN. | ||
2195 | 197 | IB_ULONGLONG_MAX for log to be | ||
2196 | 198 | parsed to the end */ | ||
2197 | 199 | ulint filter_space, /*!< in: Space ID to filter | ||
2198 | 200 | records on or ULINT_UNDEFINED */ | ||
2199 | 201 | ulint filter_page, /*!< in: Page ID to filter | ||
2200 | 202 | records on or ULINT_UNDEFINED */ | ||
2201 | 203 | ibool numeric, /*!< in: TRUE for output log | ||
2202 | 204 | item type byte values instead of | ||
2203 | 205 | mnemonics */ | ||
2204 | 206 | ibool print_rec_bodies); /*!< in: TRUE for print log | ||
2205 | 207 | record body contents */ | ||
2206 | 208 | |||
2207 | 209 | #ifdef __cplusplus | ||
2208 | 210 | } /* extern "C" */ | ||
2209 | 211 | #endif /* __cplusplus */ | ||
2210 | 212 | |||
2211 | 213 | #endif | ||
2212 | 0 | 214 | ||
2213 | === added file 'src/api_page.c' | |||
2214 | --- src/api_page.c 1970-01-01 00:00:00 +0000 | |||
2215 | +++ src/api_page.c 2012-12-05 22:33:23 +0000 | |||
2216 | @@ -0,0 +1,3522 @@ | |||
2217 | 1 | /* | ||
2218 | 2 | * Copyright (C) 2012 Percona Inc. | ||
2219 | 3 | * This program is free software: you can redistribute it and/or modify it | ||
2220 | 4 | * under the terms of the GNU General Public License version 3, as published | ||
2221 | 5 | * by the Free Software Foundation. | ||
2222 | 6 | * | ||
2223 | 7 | * This program is distributed in the hope that it will be useful, but | ||
2224 | 8 | * WITHOUT ANY WARRANTY; without even the implied warranties of | ||
2225 | 9 | * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
2226 | 10 | * PURPOSE. See the GNU General Public License for more details. | ||
2227 | 11 | * | ||
2228 | 12 | * You should have received a copy of the GNU General Public License along | ||
2229 | 13 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
2230 | 14 | */ | ||
2231 | 15 | |||
2232 | 16 | #define DULINT_STANDARD | ||
2233 | 17 | |||
2234 | 18 | #include <fil0fil.h> | ||
2235 | 19 | #include <log0log.h> | ||
2236 | 20 | #include <log0recv.h> | ||
2237 | 21 | #include <rem0rec.h> | ||
2238 | 22 | #include <os0file.h> | ||
2239 | 23 | #include <os0sync.h> | ||
2240 | 24 | #include <sync0sync.h> | ||
2241 | 25 | #include <srv0srv.h> | ||
2242 | 26 | #include <fsp0fsp.h> | ||
2243 | 27 | #include <buf0buf.h> | ||
2244 | 28 | #include <trx0undo.h> | ||
2245 | 29 | #include <btr0btr.h> | ||
2246 | 30 | #include <page0page.h> | ||
2247 | 31 | #include <page0zip.h> | ||
2248 | 32 | #include <lock0lock.h> | ||
2249 | 33 | #include <btr0pcur.h> | ||
2250 | 34 | #include <ibuf0ibuf.h> | ||
2251 | 35 | #include <dict0load.h> | ||
2252 | 36 | #include <dict0boot.h> | ||
2253 | 37 | #include <trx0rec.h> | ||
2254 | 38 | #include <row0upd.h> | ||
2255 | 39 | #include <row0row.h> | ||
2256 | 40 | #include <fsp0fsp.h> | ||
2257 | 41 | #include <data0type.h> | ||
2258 | 42 | #include <dict0boot.h> | ||
2259 | 43 | #include <srv0start.h> | ||
2260 | 44 | #include "api_page.h" | ||
2261 | 45 | #include "innodb_int.h" | ||
2262 | 46 | |||
2263 | 47 | #ifndef DATA_VARCLIENT | ||
2264 | 48 | #define DATA_VARCLIENT DATA_VARMYSQL | ||
2265 | 49 | #define DATA_CLIENT DATA_MYSQL | ||
2266 | 50 | #endif | ||
2267 | 51 | |||
2268 | 52 | #define SRV_N_PENDING_IOS_PER_THREAD OS_AIO_N_PENDING_IOS_PER_THREAD | ||
2269 | 53 | #define SRV_MAX_N_PENDING_SYNC_IOS 100 | ||
2270 | 54 | |||
2271 | 55 | #ifndef IBUF_PAGE_SIZE_PER_FREE_SPACE | ||
2272 | 56 | |||
2273 | 57 | /** An index page must contain at least UNIV_PAGE_SIZE / | ||
2274 | 58 | IBUF_PAGE_SIZE_PER_FREE_SPACE bytes of free space for ibuf to try to | ||
2275 | 59 | buffer inserts to this page. If there is this much of free space, the | ||
2276 | 60 | corresponding bits are set in the ibuf bitmap. */ | ||
2277 | 61 | #define IBUF_PAGE_SIZE_PER_FREE_SPACE 32 | ||
2278 | 62 | |||
2279 | 63 | /** Insert buffer struct */ | ||
2280 | 64 | struct ibuf_struct{ | ||
2281 | 65 | ulint size; /*!< current size of the ibuf index | ||
2282 | 66 | tree, in pages */ | ||
2283 | 67 | ulint max_size; /*!< recommended maximum size of the | ||
2284 | 68 | ibuf index tree, in pages */ | ||
2285 | 69 | ulint seg_size; /*!< allocated pages of the file | ||
2286 | 70 | segment containing ibuf header and | ||
2287 | 71 | tree */ | ||
2288 | 72 | ibool empty; /*!< after an insert to the ibuf tree | ||
2289 | 73 | is performed, this is set to FALSE, | ||
2290 | 74 | and if a contract operation finds | ||
2291 | 75 | the tree empty, this is set to | ||
2292 | 76 | TRUE */ | ||
2293 | 77 | ulint free_list_len; /*!< length of the free list */ | ||
2294 | 78 | ulint height; /*!< tree height */ | ||
2295 | 79 | dict_index_t* index; /*!< insert buffer index */ | ||
2296 | 80 | |||
2297 | 81 | ulint n_inserts; /*!< number of inserts made to | ||
2298 | 82 | the insert buffer */ | ||
2299 | 83 | ulint n_merges; /*!< number of pages merged */ | ||
2300 | 84 | ulint n_merged_recs; /*!< number of records merged */ | ||
2301 | 85 | }; | ||
2302 | 86 | |||
2303 | 87 | #endif | ||
2304 | 88 | |||
2305 | 89 | /***************************************************************//** | ||
2306 | 90 | Print undo log page. */ | ||
2307 | 91 | UNIV_INTERN | ||
2308 | 92 | void | ||
2309 | 93 | ib_page_print_undo( | ||
2310 | 94 | /*===============*/ | ||
2311 | 95 | const page_t* page); /*!< in: page */ | ||
2312 | 96 | |||
2313 | 97 | /***************************************************************//** | ||
2314 | 98 | Determine direction name. | ||
2315 | 99 | @return direction name. */ | ||
2316 | 100 | UNIV_INTERN | ||
2317 | 101 | const char* | ||
2318 | 102 | ib_page_page_cursor_direction( | ||
2319 | 103 | /*==========================*/ | ||
2320 | 104 | ulint direction); /*!< in: direction */ | ||
2321 | 105 | |||
2322 | 106 | /***************************************************************//** | ||
2323 | 107 | Dump raw field as hex and ascii. */ | ||
2324 | 108 | UNIV_INTERN | ||
2325 | 109 | void | ||
2326 | 110 | ib_page_print_field_hex_asc( | ||
2327 | 111 | /*========================*/ | ||
2328 | 112 | const rec_t* rec, /*!< in: physical record */ | ||
2329 | 113 | ulint i); /*!< in: field number */ | ||
2330 | 114 | |||
2331 | 115 | /***************************************************************//** | ||
2332 | 116 | Format externally stored field. */ | ||
2333 | 117 | UNIV_INTERN | ||
2334 | 118 | void | ||
2335 | 119 | ib_page_format_ext( | ||
2336 | 120 | /*===============*/ | ||
2337 | 121 | char* buf, /*!< out: buffer */ | ||
2338 | 122 | ulint buf_len, /*!< in: buffer length */ | ||
2339 | 123 | const rec_t* rec, /*!< in: physical record */ | ||
2340 | 124 | ulint no, /*!< in: field number */ | ||
2341 | 125 | const ulint* offsets); /*!< in: array returned by | ||
2342 | 126 | rec_get_offsets() */ | ||
2343 | 127 | |||
2344 | 128 | /***************************************************************//** | ||
2345 | 129 | Hex dump of page. */ | ||
2346 | 130 | UNIV_INTERN | ||
2347 | 131 | void | ||
2348 | 132 | ib_page_print_hex_dump( | ||
2349 | 133 | /*===================*/ | ||
2350 | 134 | const page_t* page, /*!< in: page */ | ||
2351 | 135 | ulint zip_size); /*!< in: compressed page size, or | ||
2352 | 136 | 0 for uncompressed pages */ | ||
2353 | 137 | |||
2354 | 138 | /***************************************************************//** | ||
2355 | 139 | Print page dictionary header. */ | ||
2356 | 140 | UNIV_INTERN | ||
2357 | 141 | void | ||
2358 | 142 | ib_page_print_dict_header( | ||
2359 | 143 | /*======================*/ | ||
2360 | 144 | const page_t* page); /*!< in: page */ | ||
2361 | 145 | |||
2362 | 146 | /***************************************************************//** | ||
2363 | 147 | @return XDES state as string. */ | ||
2364 | 148 | UNIV_INTERN | ||
2365 | 149 | const char* | ||
2366 | 150 | ib_page_xdes_state_str( | ||
2367 | 151 | /*===================*/ | ||
2368 | 152 | ulint state); /*!< in: XDES state */ | ||
2369 | 153 | |||
2370 | 154 | /***************************************************************//** | ||
2371 | 155 | Print XDES page. */ | ||
2372 | 156 | UNIV_INTERN | ||
2373 | 157 | void | ||
2374 | 158 | ib_page_print_xdes( | ||
2375 | 159 | /*===============*/ | ||
2376 | 160 | const page_t* page, /*!< in: page */ | ||
2377 | 161 | ulint zip_size); /*!< in: compressed page size, or | ||
2378 | 162 | 0 for uncompressed pages */ | ||
2379 | 163 | |||
2380 | 164 | /***************************************************************//** | ||
2381 | 165 | Create IBUF index in data dictionary. */ | ||
2382 | 166 | UNIV_INTERN | ||
2383 | 167 | void | ||
2384 | 168 | ib_page_ibuf_index_create(void); | ||
2385 | 169 | /*============================*/ | ||
2386 | 170 | |||
2387 | 171 | /***************************************************************//** | ||
2388 | 172 | Load a table object based on the index id. | ||
2389 | 173 | @return table; NULL if table does not exist */ | ||
2390 | 174 | UNIV_INTERN | ||
2391 | 175 | dict_table_t* | ||
2392 | 176 | ib_page_load_table_for_index( | ||
2393 | 177 | /*=========================*/ | ||
2394 | 178 | dulint index_id); /*!< in: index id */ | ||
2395 | 179 | |||
2396 | 180 | /***************************************************************//** | ||
2397 | 181 | Allocate signle aligned page. | ||
2398 | 182 | @return page */ | ||
2399 | 183 | UNIV_INTERN | ||
2400 | 184 | page_t* | ||
2401 | 185 | ib_page_page_alloc(); | ||
2402 | 186 | |||
2403 | 187 | /***************************************************************//** | ||
2404 | 188 | Allocate signle aligned page. | ||
2405 | 189 | @return page */ | ||
2406 | 190 | UNIV_INTERN | ||
2407 | 191 | page_t* | ||
2408 | 192 | ib_page_heap_page_alloc( | ||
2409 | 193 | /*====================*/ | ||
2410 | 194 | mem_heap_t* heap); /*!< in: memory heap where allocate in */ | ||
2411 | 195 | |||
2412 | 196 | /***************************************************************//** | ||
2413 | 197 | Get space id of given tablespace in file. | ||
2414 | 198 | @return space id if given tablespace file */ | ||
2415 | 199 | UNIV_INTERN | ||
2416 | 200 | ulint | ||
2417 | 201 | ib_page_file_space_id( | ||
2418 | 202 | /*==================*/ | ||
2419 | 203 | os_file_t file); /*!< in: file */ | ||
2420 | 204 | |||
2421 | 205 | /***************************************************************//** | ||
2422 | 206 | Calculate the low 32 bits and the high 32 bits | ||
2423 | 207 | of the file offset. */ | ||
2424 | 208 | UNIV_INTERN | ||
2425 | 209 | void | ||
2426 | 210 | ib_page_calc_offsets( | ||
2427 | 211 | /*=================*/ | ||
2428 | 212 | ulint zip_size, /*!< in: compressed page size, or | ||
2429 | 213 | 0 for uncompressed pages */ | ||
2430 | 214 | ulint page_no, /*!< in: page number */ | ||
2431 | 215 | ulint* offset_low, /*!< out: low 32 bits */ | ||
2432 | 216 | ulint* offset_high); /*!< out: high 32 bits */ | ||
2433 | 217 | |||
2434 | 218 | /***************************************************************//** | ||
2435 | 219 | Load compressed page into memory. | ||
2436 | 220 | Space for page allocated in heap. | ||
2437 | 221 | @return loaded page; NULL if page was not loaded */ | ||
2438 | 222 | UNIV_INTERN | ||
2439 | 223 | page_t* | ||
2440 | 224 | ib_page_load_compressed( | ||
2441 | 225 | /*====================*/ | ||
2442 | 226 | os_file_t file, /*!< in: file */ | ||
2443 | 227 | ulint page_no, /*!< in: page number */ | ||
2444 | 228 | ulint zip_size, /*!< in: compressed page size, or | ||
2445 | 229 | 0 for uncompressed pages */ | ||
2446 | 230 | mem_heap_t* heap); /*!< in: memory heap */ | ||
2447 | 231 | |||
2448 | 232 | /***************************************************************//** | ||
2449 | 233 | Decompress compressed page. | ||
2450 | 234 | Space for decompressed page allocated in heap. | ||
2451 | 235 | @return loaded page; NULL if page was not loaded */ | ||
2452 | 236 | UNIV_INTERN | ||
2453 | 237 | page_t* | ||
2454 | 238 | ib_page_decompress( | ||
2455 | 239 | /*===============*/ | ||
2456 | 240 | const page_t* compressed_page,/*!< in: compressed page */ | ||
2457 | 241 | ulint zip_size, /*!< in: compressed page size, or | ||
2458 | 242 | 0 for uncompressed pages */ | ||
2459 | 243 | mem_heap_t* heap); /*!< in: memory heap */ | ||
2460 | 244 | |||
2461 | 245 | /***************************************************************//** | ||
2462 | 246 | Test if page if IBUF page. | ||
2463 | 247 | @return TRUE if page is IBUF page; FALE otherwise */ | ||
2464 | 248 | UNIV_INTERN | ||
2465 | 249 | ibool | ||
2466 | 250 | ib_page_page_is_ibuf( | ||
2467 | 251 | /*=================*/ | ||
2468 | 252 | const page_t* page); /*!< in: page */ | ||
2469 | 253 | |||
2470 | 254 | /***************************************************************//** | ||
2471 | 255 | Test if page is UNDO INSERT page. | ||
2472 | 256 | @return TRUE if page is UNDO INSERT page; FALE otherwise */ | ||
2473 | 257 | UNIV_INTERN | ||
2474 | 258 | ibool | ||
2475 | 259 | ib_page_is_undo_insert( | ||
2476 | 260 | /*===================*/ | ||
2477 | 261 | const page_t* page); /*!< in: page */ | ||
2478 | 262 | |||
2479 | 263 | /***************************************************************//** | ||
2480 | 264 | Test if page is UNDO UPDATE page. | ||
2481 | 265 | @return TRUE if page is UNDO UPDATE page; FALE otherwise */ | ||
2482 | 266 | UNIV_INTERN | ||
2483 | 267 | ibool | ||
2484 | 268 | ib_page_is_undo_update( | ||
2485 | 269 | /*===================*/ | ||
2486 | 270 | const page_t* page); /*!< in: page */ | ||
2487 | 271 | |||
2488 | 272 | /***************************************************************//** | ||
2489 | 273 | Test if page is UNDO page. | ||
2490 | 274 | @return TRUE if page is UNDO page; FALE otherwise */ | ||
2491 | 275 | UNIV_INTERN | ||
2492 | 276 | ibool | ||
2493 | 277 | ib_page_is_undo( | ||
2494 | 278 | /*============*/ | ||
2495 | 279 | const page_t* page); /*!< in: page */ | ||
2496 | 280 | |||
2497 | 281 | /***************************************************************//** | ||
2498 | 282 | Print file-based list address. */ | ||
2499 | 283 | UNIV_INTERN | ||
2500 | 284 | void | ||
2501 | 285 | ib_page_print_flst_addr( | ||
2502 | 286 | /*====================*/ | ||
2503 | 287 | const byte* base); /*!< in: pointer to base node of list */ | ||
2504 | 288 | |||
2505 | 289 | /***************************************************************//** | ||
2506 | 290 | Print file-based list. */ | ||
2507 | 291 | UNIV_INTERN | ||
2508 | 292 | void | ||
2509 | 293 | ib_page_print_flst( | ||
2510 | 294 | /*===============*/ | ||
2511 | 295 | const byte* base); /*!< in: pointer to base node of list */ | ||
2512 | 296 | |||
2513 | 297 | /***************************************************************//** | ||
2514 | 298 | Print filespace header page. */ | ||
2515 | 299 | UNIV_INTERN | ||
2516 | 300 | void | ||
2517 | 301 | ib_page_print_fsp_header( | ||
2518 | 302 | /*=====================*/ | ||
2519 | 303 | const page_t* page); /*!< in: page */ | ||
2520 | 304 | |||
2521 | 305 | /***************************************************************//** | ||
2522 | 306 | Print ZBLOB page. */ | ||
2523 | 307 | UNIV_INTERN | ||
2524 | 308 | void | ||
2525 | 309 | ib_page_print_zblob( | ||
2526 | 310 | /*================*/ | ||
2527 | 311 | const page_t* page, /*!< in: page */ | ||
2528 | 312 | ulint zip_size); /*!< in: compressed page size, or | ||
2529 | 313 | 0 for uncompressed pages */ | ||
2530 | 314 | |||
2531 | 315 | /***************************************************************//** | ||
2532 | 316 | Print ZBLOB2 page. */ | ||
2533 | 317 | UNIV_INTERN | ||
2534 | 318 | void | ||
2535 | 319 | ib_page_print_zblob2( | ||
2536 | 320 | /*=================*/ | ||
2537 | 321 | const page_t* page, /*!< in: page */ | ||
2538 | 322 | ulint zip_size); /*!< in: compressed page size, or | ||
2539 | 323 | 0 for uncompressed pages */ | ||
2540 | 324 | |||
2541 | 325 | /***************************************************************//** | ||
2542 | 326 | Print BLOB page. */ | ||
2543 | 327 | UNIV_INTERN | ||
2544 | 328 | void | ||
2545 | 329 | ib_page_print_blob( | ||
2546 | 330 | /*===============*/ | ||
2547 | 331 | const page_t* page); /*!< in: page */ | ||
2548 | 332 | |||
2549 | 333 | /***************************************************************//** | ||
2550 | 334 | Print inode page. */ | ||
2551 | 335 | UNIV_INTERN | ||
2552 | 336 | void | ||
2553 | 337 | ib_page_print_inode( | ||
2554 | 338 | /*================*/ | ||
2555 | 339 | const page_t* page, /*!< in: page */ | ||
2556 | 340 | ulint zip_size); /*!< in: compressed page size, or | ||
2557 | 341 | 0 for uncompressed pages */ | ||
2558 | 342 | |||
2559 | 343 | /***************************************************************//** | ||
2560 | 344 | Print a physical record. */ | ||
2561 | 345 | UNIV_INTERN | ||
2562 | 346 | void | ||
2563 | 347 | ib_page_rec_print_new( | ||
2564 | 348 | /*==================*/ | ||
2565 | 349 | ib_stream_t ib_stream, /*!< in: stream where to print */ | ||
2566 | 350 | const page_t* page, /*!< in: page */ | ||
2567 | 351 | const rec_t* rec, /*!< in: physical record */ | ||
2568 | 352 | const ulint* offsets, /*!< in: array returned by | ||
2569 | 353 | rec_get_offsets() */ | ||
2570 | 354 | dict_index_t* index); /*!< in: index */ | ||
2571 | 355 | |||
2572 | 356 | |||
2573 | 357 | /***************************************************************//** | ||
2574 | 358 | Print an old-style physical record. */ | ||
2575 | 359 | UNIV_INTERN | ||
2576 | 360 | void | ||
2577 | 361 | ib_page_rec_print_old( | ||
2578 | 362 | /*==================*/ | ||
2579 | 363 | ib_stream_t ib_stream, /*!< in: stream where to print */ | ||
2580 | 364 | const page_t* page, | ||
2581 | 365 | const rec_t* rec, /*!< in: physical record */ | ||
2582 | 366 | const ulint* offsets, /*!< in: array returned by | ||
2583 | 367 | rec_get_offsets() */ | ||
2584 | 368 | dict_index_t* index); /*!< in: index */ | ||
2585 | 369 | |||
2586 | 370 | /***************************************************************//** | ||
2587 | 371 | Prints a physical record in ROW_FORMAT=COMPACT. Ignores the | ||
2588 | 372 | record header. */ | ||
2589 | 373 | UNIV_INTERN | ||
2590 | 374 | void | ||
2591 | 375 | ib_page_rec_print_comp( | ||
2592 | 376 | /*===================*/ | ||
2593 | 377 | ib_stream_t ib_stream, /*!< in: streamwhere to print */ | ||
2594 | 378 | const page_t* page, | ||
2595 | 379 | const rec_t* rec, /*!< in: physical record */ | ||
2596 | 380 | const ulint* offsets, /*!< in: array returned by | ||
2597 | 381 | rec_get_offsets() */ | ||
2598 | 382 | dict_index_t* index); /*!< in: index */ | ||
2599 | 383 | |||
2600 | 384 | /*******************************************************************//** | ||
2601 | 385 | Copy types of fields contained in index to tuple. */ | ||
2602 | 386 | UNIV_INTERN | ||
2603 | 387 | void | ||
2604 | 388 | ib_page_dict_index_copy_types( | ||
2605 | 389 | /*==========================*/ | ||
2606 | 390 | dtuple_t* tuple, /*!< in/out: data tuple */ | ||
2607 | 391 | const dict_index_t* index, /*!< in: index */ | ||
2608 | 392 | ulint n_fields, /*!< in: number of | ||
2609 | 393 | field types to copy */ | ||
2610 | 394 | ibool is_leaf_page); /*!< in: TRUE if leas page */ | ||
2611 | 395 | |||
2612 | 396 | /*******************************************************************//** | ||
2613 | 397 | Converts an index record to a typed data tuple. | ||
2614 | 398 | @return index entry built; does not set info_bits, and the data fields | ||
2615 | 399 | in the entry will point directly to rec */ | ||
2616 | 400 | UNIV_INTERN | ||
2617 | 401 | dtuple_t* | ||
2618 | 402 | ib_page_row_rec_to_index_entry_low( | ||
2619 | 403 | /*===============================*/ | ||
2620 | 404 | const page_t* page, | ||
2621 | 405 | const rec_t* rec, /*!< in: record in the index */ | ||
2622 | 406 | const dict_index_t* index, /*!< in: index */ | ||
2623 | 407 | const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */ | ||
2624 | 408 | ulint* n_ext, /*!< out: number of externally | ||
2625 | 409 | stored columns */ | ||
2626 | 410 | mem_heap_t* heap); /*!< in: memory heap from which | ||
2627 | 411 | the memory needed is allocated */ | ||
2628 | 412 | |||
2629 | 413 | /*******************************************************************//** | ||
2630 | 414 | Converts an index record to a typed data tuple. | ||
2631 | 415 | @return index entry built; does not set info_bits, and the data fields | ||
2632 | 416 | in the entry will point directly to rec */ | ||
2633 | 417 | UNIV_INTERN | ||
2634 | 418 | dtuple_t* | ||
2635 | 419 | ib_page_row_rec_to_index_entry_low( | ||
2636 | 420 | /*===============================*/ | ||
2637 | 421 | const page_t* page, | ||
2638 | 422 | const rec_t* rec, /*!< in: record in the index */ | ||
2639 | 423 | const dict_index_t* index, /*!< in: index */ | ||
2640 | 424 | const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */ | ||
2641 | 425 | ulint* n_ext, /*!< out: number of externally | ||
2642 | 426 | stored columns */ | ||
2643 | 427 | mem_heap_t* heap); /*!< in: memory heap from which | ||
2644 | 428 | the memory needed is allocated */ | ||
2645 | 429 | |||
2646 | 430 | |||
2647 | 431 | /*******************************************************************//** | ||
2648 | 432 | Converts an index record to a typed data tuple. NOTE that externally | ||
2649 | 433 | stored (often big) fields are NOT copied to heap. | ||
2650 | 434 | @return own: index entry built; see the NOTE below! */ | ||
2651 | 435 | UNIV_INTERN | ||
2652 | 436 | dtuple_t* | ||
2653 | 437 | ib_page_row_rec_to_index_entry( | ||
2654 | 438 | /*===========================*/ | ||
2655 | 439 | ulint type, /*!< in: ROW_COPY_DATA, or | ||
2656 | 440 | ROW_COPY_POINTERS: the former | ||
2657 | 441 | copies also the data fields to | ||
2658 | 442 | heap as the latter only places | ||
2659 | 443 | pointers to data fields on the | ||
2660 | 444 | index page */ | ||
2661 | 445 | const page_t* page, | ||
2662 | 446 | const rec_t* rec, /*!< in: record in the index; | ||
2663 | 447 | NOTE: in the case | ||
2664 | 448 | ROW_COPY_POINTERS the data | ||
2665 | 449 | fields in the row will point | ||
2666 | 450 | directly into this record, | ||
2667 | 451 | therefore, the buffer page of | ||
2668 | 452 | this record must be at least | ||
2669 | 453 | s-latched and the latch held | ||
2670 | 454 | as long as the dtuple is used! */ | ||
2671 | 455 | const dict_index_t* index, /*!< in: index */ | ||
2672 | 456 | ulint* offsets,/*!< in/out: rec_get_offsets(rec) */ | ||
2673 | 457 | ulint* n_ext, /*!< out: number of externally | ||
2674 | 458 | stored columns */ | ||
2675 | 459 | mem_heap_t* heap); /*!< in: memory heap from which | ||
2676 | 460 | the memory needed is allocated */ | ||
2677 | 461 | |||
2678 | 462 | /*******************************************************************//** | ||
2679 | 463 | Load page from file into memory and decompress it if needed. | ||
2680 | 464 | @return TRUE on success */ | ||
2681 | 465 | ibool | ||
2682 | 466 | ib_page_load( | ||
2683 | 467 | /*=========*/ | ||
2684 | 468 | const char* ibd_file_name, /*!< in: file name */ | ||
2685 | 469 | ulint page_no, /*!< in: page number */ | ||
2686 | 470 | ulint* zip_size, /*!< in: compressed page size, or | ||
2687 | 471 | 0 for uncompressed pages */ | ||
2688 | 472 | page_t** compressed_page, /*!< out: compressed page */ | ||
2689 | 473 | page_t** decompressed_page, /*!< out: decompressed page */ | ||
2690 | 474 | mem_heap_t* heap); /*!< out: memory heap */ | ||
2691 | 475 | |||
2692 | 476 | /*******************************************************************//** | ||
2693 | 477 | Print IBUF bitmap page. */ | ||
2694 | 478 | UNIV_INTERN | ||
2695 | 479 | void | ||
2696 | 480 | ib_page_ibuf_bitmap_print( | ||
2697 | 481 | /*======================*/ | ||
2698 | 482 | const page_t* page, /*!< in: page */ | ||
2699 | 483 | ulint zip_size); /*!< in: compressed page size, or | ||
2700 | 484 | 0 for uncompressed pages */ | ||
2701 | 485 | |||
2702 | 486 | /*******************************************************************//** | ||
2703 | 487 | Format SYS value. */ | ||
2704 | 488 | UNIV_INTERN | ||
2705 | 489 | void | ||
2706 | 490 | ib_page_format_sys( | ||
2707 | 491 | /*===============*/ | ||
2708 | 492 | ulint prtype, /*!< in: precise type */ | ||
2709 | 493 | char* buf, /*!< out: buffer */ | ||
2710 | 494 | ulint buf_len, /*!< in: buffer length */ | ||
2711 | 495 | const byte* data); /*!< in: field data */ | ||
2712 | 496 | |||
2713 | 497 | /*******************************************************************//** | ||
2714 | 498 | Format INT value. */ | ||
2715 | 499 | UNIV_INTERN | ||
2716 | 500 | void | ||
2717 | 501 | ib_page_format_int( | ||
2718 | 502 | /*===============*/ | ||
2719 | 503 | ulint prtype, /*!< in: precise type */ | ||
2720 | 504 | char* buf, /*!< out: buffer */ | ||
2721 | 505 | ulint buf_len, /*!< in: buffer length */ | ||
2722 | 506 | const byte* data, /*!< in: field data */ | ||
2723 | 507 | ulint data_len); /*!< in: length of data */ | ||
2724 | 508 | |||
2725 | 509 | /*******************************************************************//** | ||
2726 | 510 | Format string value. */ | ||
2727 | 511 | UNIV_INTERN | ||
2728 | 512 | void | ||
2729 | 513 | ib_page_format_str( | ||
2730 | 514 | /*===============*/ | ||
2731 | 515 | char* buf, /*!< out: buffer */ | ||
2732 | 516 | ulint buf_len, /*!< in: buffer length */ | ||
2733 | 517 | const byte* data, /*!< in: field data */ | ||
2734 | 518 | ulint data_len); /*!< in: length of data */ | ||
2735 | 519 | |||
2736 | 520 | /*******************************************************************//** | ||
2737 | 521 | Format binalry value. */ | ||
2738 | 522 | UNIV_INTERN | ||
2739 | 523 | void | ||
2740 | 524 | ib_page_format_bin( | ||
2741 | 525 | /*===============*/ | ||
2742 | 526 | char* buf, /*!< out: buffer */ | ||
2743 | 527 | ulint buf_len, /*!< in: buffer length */ | ||
2744 | 528 | const byte* data, /*!< in: field data */ | ||
2745 | 529 | ulint data_len); /*!< in: length of data */ | ||
2746 | 530 | |||
2747 | 531 | /*******************************************************************//** | ||
2748 | 532 | Print field. */ | ||
2749 | 533 | UNIV_INTERN | ||
2750 | 534 | void | ||
2751 | 535 | ib_page_rec_print_field( | ||
2752 | 536 | /*====================*/ | ||
2753 | 537 | const dfield_t* field, /*!< in: field */ | ||
2754 | 538 | const rec_t* rec, /*!< in: physical record */ | ||
2755 | 539 | ulint no, /*!< in: field number */ | ||
2756 | 540 | const ulint* offsets); /*!< in: array returned by | ||
2757 | 541 | rec_get_offsets() */ | ||
2758 | 542 | /********************************************************************//** | ||
2759 | 543 | Print first page header. */ | ||
2760 | 544 | UNIV_INTERN | ||
2761 | 545 | void | ||
2762 | 546 | ib_buf_page_print_header( | ||
2763 | 547 | /*=====================*/ | ||
2764 | 548 | const byte* read_buf, /*!< in: a database page */ | ||
2765 | 549 | ulint zip_size); /*!< in: compressed page size, or | ||
2766 | 550 | 0 for uncompressed pages */ | ||
2767 | 551 | |||
2768 | 552 | /***************************************************************//** | ||
2769 | 553 | Print second page header. */ | ||
2770 | 554 | UNIV_INTERN | ||
2771 | 555 | void | ||
2772 | 556 | ib_page_page_header_print( | ||
2773 | 557 | /*======================*/ | ||
2774 | 558 | const page_t* page); /*!< in: page */ | ||
2775 | 559 | |||
2776 | 560 | /***************************************************************//** | ||
2777 | 561 | Print the contents of the directory. */ | ||
2778 | 562 | UNIV_INTERN | ||
2779 | 563 | void | ||
2780 | 564 | ib_page_page_dir_print( | ||
2781 | 565 | /*===================*/ | ||
2782 | 566 | const page_t* page); /*!< in: index page */ | ||
2783 | 567 | |||
2784 | 568 | /************************************************************//** | ||
2785 | 569 | Print record contents including the data relevant only in | ||
2786 | 570 | the index page context. */ | ||
2787 | 571 | UNIV_INTERN | ||
2788 | 572 | void | ||
2789 | 573 | ib_page_page_rec_print( | ||
2790 | 574 | /*===================*/ | ||
2791 | 575 | const page_t* page, | ||
2792 | 576 | const rec_t* rec, /*!< in: physical record */ | ||
2793 | 577 | const ulint* offsets,/*!< in: record descriptor */ | ||
2794 | 578 | dict_index_t* index); /*!< in: dictionary index of the page */ | ||
2795 | 579 | |||
2796 | 580 | /***************************************************************//** | ||
2797 | 581 | This is used to print the contents of the page record list for | ||
2798 | 582 | debugging purposes. */ | ||
2799 | 583 | UNIV_INTERN | ||
2800 | 584 | void | ||
2801 | 585 | ib_page_page_print_list( | ||
2802 | 586 | /*====================*/ | ||
2803 | 587 | const page_t* page, /*!< in: index page */ | ||
2804 | 588 | dict_index_t* index); /*!< in: dictionary index of the page */ | ||
2805 | 589 | |||
2806 | 590 | |||
2807 | 591 | /** @name Offsets to the per-page bits in the insert buffer bitmap */ | ||
2808 | 592 | /* @{ */ | ||
2809 | 593 | #define IBUF_BITMAP_FREE 0 /*!< Bits indicating the | ||
2810 | 594 | amount of free space */ | ||
2811 | 595 | #define IBUF_BITMAP_BUFFERED 2 /*!< TRUE if there are buffered | ||
2812 | 596 | changes for the page */ | ||
2813 | 597 | #define IBUF_BITMAP_IBUF 3 /*!< TRUE if page is a part of | ||
2814 | 598 | the ibuf tree, excluding the | ||
2815 | 599 | root page, or is in the free | ||
2816 | 600 | list of the ibuf */ | ||
2817 | 601 | /* @} */ | ||
2818 | 602 | |||
2819 | 603 | /* Various constants for checking the type of an ibuf record and extracting | ||
2820 | 604 | data from it. For details, see the description of the record format at the | ||
2821 | 605 | top of this file. */ | ||
2822 | 606 | |||
2823 | 607 | /** @name Format of the fourth column of an insert buffer record | ||
2824 | 608 | The fourth column in the MySQL 5.5 format contains an operation | ||
2825 | 609 | type, counter, and some flags. */ | ||
2826 | 610 | /* @{ */ | ||
2827 | 611 | #define IBUF_REC_INFO_SIZE 4 /*!< Combined size of info fields at | ||
2828 | 612 | the beginning of the fourth field */ | ||
2829 | 613 | #if IBUF_REC_INFO_SIZE >= DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE | ||
2830 | 614 | # error "IBUF_REC_INFO_SIZE >= DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE" | ||
2831 | 615 | #endif | ||
2832 | 616 | |||
2833 | 617 | /* Offsets for the fields at the beginning of the fourth field */ | ||
2834 | 618 | #define IBUF_REC_OFFSET_COUNTER 0 /*!< Operation counter */ | ||
2835 | 619 | #define IBUF_REC_OFFSET_TYPE 2 /*!< Type of operation */ | ||
2836 | 620 | #define IBUF_REC_OFFSET_FLAGS 3 /*!< Additional flags */ | ||
2837 | 621 | |||
2838 | 622 | /* Record flag masks */ | ||
2839 | 623 | #define IBUF_REC_COMPACT 0x1 /*!< Set in | ||
2840 | 624 | IBUF_REC_OFFSET_FLAGS if the | ||
2841 | 625 | user index is in COMPACT | ||
2842 | 626 | format or later */ | ||
2843 | 627 | |||
2844 | 628 | |||
2845 | 629 | /** The area in pages from which contract looks for page numbers for merge */ | ||
2846 | 630 | #define IBUF_MERGE_AREA 8 | ||
2847 | 631 | |||
2848 | 632 | /** Inside the merge area, pages which have at most 1 per this number less | ||
2849 | 633 | buffered entries compared to maximum volume that can buffered for a single | ||
2850 | 634 | page are merged along with the page whose buffer became full */ | ||
2851 | 635 | #define IBUF_MERGE_THRESHOLD 4 | ||
2852 | 636 | |||
2853 | 637 | /** In ibuf_contract at most this number of pages is read to memory in one | ||
2854 | 638 | batch, in order to merge the entries for them in the insert buffer */ | ||
2855 | 639 | #define IBUF_MAX_N_PAGES_MERGED IBUF_MERGE_AREA | ||
2856 | 640 | |||
2857 | 641 | /** If the combined size of the ibuf trees exceeds ibuf->max_size by this | ||
2858 | 642 | many pages, we start to contract it in connection to inserts there, using | ||
2859 | 643 | non-synchronous contract */ | ||
2860 | 644 | #define IBUF_CONTRACT_ON_INSERT_NON_SYNC 0 | ||
2861 | 645 | |||
2862 | 646 | /** If the combined size of the ibuf trees exceeds ibuf->max_size by this | ||
2863 | 647 | many pages, we start to contract it in connection to inserts there, using | ||
2864 | 648 | synchronous contract */ | ||
2865 | 649 | #define IBUF_CONTRACT_ON_INSERT_SYNC 5 | ||
2866 | 650 | |||
2867 | 651 | /** If the combined size of the ibuf trees exceeds ibuf->max_size by | ||
2868 | 652 | this many pages, we start to contract it synchronous contract, but do | ||
2869 | 653 | not insert */ | ||
2870 | 654 | #define IBUF_CONTRACT_DO_NOT_INSERT 10 | ||
2871 | 655 | |||
2872 | 656 | |||
2873 | 657 | /* Possible operations buffered in the insert/whatever buffer. See | ||
2874 | 658 | ibuf_insert(). DO NOT CHANGE THE VALUES OF THESE, THEY ARE STORED ON DISK. */ | ||
2875 | 659 | typedef enum { | ||
2876 | 660 | IBUF_OP_INSERT = 0, | ||
2877 | 661 | IBUF_OP_DELETE_MARK = 1, | ||
2878 | 662 | IBUF_OP_DELETE = 2, | ||
2879 | 663 | |||
2880 | 664 | /* Number of different operation types. */ | ||
2881 | 665 | IBUF_OP_COUNT = 3 | ||
2882 | 666 | } ibuf_op_t; | ||
2883 | 667 | |||
2884 | 668 | /***************************************************************//** | ||
2885 | 669 | Load a index object based on the index id. | ||
2886 | 670 | @return index; NULL if table does not exist */ | ||
2887 | 671 | dict_index_t* | ||
2888 | 672 | ib_dict_index_get_on_id( | ||
2889 | 673 | /*====================*/ | ||
2890 | 674 | dulint index_id); /*!< in: index id */ | ||
2891 | 675 | |||
2892 | 676 | /****************************************************************//** | ||
2893 | 677 | Read the first two bytes from a record's fourth field (counter field in new | ||
2894 | 678 | records; something else in older records). | ||
2895 | 679 | @return "counter" field, or ULINT_UNDEFINED if for some reason it | ||
2896 | 680 | can't be read */ | ||
2897 | 681 | UNIV_INTERN | ||
2898 | 682 | ulint | ||
2899 | 683 | ib_page_ibuf_rec_get_counter( | ||
2900 | 684 | /*=========================*/ | ||
2901 | 685 | const rec_t* rec); /*!< in: ibuf record */ | ||
2902 | 686 | |||
2903 | 687 | |||
2904 | 688 | /*******************************************************************//** | ||
2905 | 689 | Initialize necessary InndoDB systems for page printer | ||
2906 | 690 | to work properly. */ | ||
2907 | 691 | ib_err_t | ||
2908 | 692 | ib_page_sys_start( | ||
2909 | 693 | /*==============*/ | ||
2910 | 694 | ulint buf_pool_size, /*!< in: size of buffer pool */ | ||
2911 | 695 | const char* datadir) /*!< in: InnoDB data directory */ | ||
2912 | 696 | { | ||
2913 | 697 | ulint err; | ||
2914 | 698 | |||
2915 | 699 | innodb_init_param_for_util(datadir, datadir, | ||
2916 | 700 | buf_pool_size, 16*1024*1024, TRUE); | ||
2917 | 701 | |||
2918 | 702 | srv_max_n_threads = 1; | ||
2919 | 703 | srv_normalize_init_values(); | ||
2920 | 704 | |||
2921 | 705 | ut_mem_init(); | ||
2922 | 706 | os_sync_init(); | ||
2923 | 707 | sync_init(); | ||
2924 | 708 | srv_n_read_io_threads = srv_n_write_io_threads = 1; | ||
2925 | 709 | srv_n_file_io_threads = 2 + srv_n_read_io_threads + | ||
2926 | 710 | srv_n_write_io_threads; | ||
2927 | 711 | // os_io_init_simple(); | ||
2928 | 712 | os_aio_init(8 * SRV_N_PENDING_IOS_PER_THREAD, | ||
2929 | 713 | srv_n_read_io_threads, | ||
2930 | 714 | srv_n_write_io_threads, | ||
2931 | 715 | SRV_MAX_N_PENDING_SYNC_IOS); | ||
2932 | 716 | mem_init(1); | ||
2933 | 717 | |||
2934 | 718 | kernel_mutex_temp = mem_alloc(sizeof(mutex_t)); | ||
2935 | 719 | mutex_create(&kernel_mutex, SYNC_KERNEL); | ||
2936 | 720 | |||
2937 | 721 | fil_init(10, 10); | ||
2938 | 722 | buf_pool_init(); | ||
2939 | 723 | fsp_init(); | ||
2940 | 724 | lock_sys_create(1000); | ||
2941 | 725 | recv_sys_create(); | ||
2942 | 726 | |||
2943 | 727 | ibool create_new_db; | ||
2944 | 728 | ib_uint64_t min_flushed_lsn, max_flushed_lsn; | ||
2945 | 729 | ulint sum_of_new_sizes; | ||
2946 | 730 | |||
2947 | 731 | err = open_or_create_data_files(&create_new_db, | ||
2948 | 732 | &min_flushed_lsn, &max_flushed_lsn, | ||
2949 | 733 | &sum_of_new_sizes); | ||
2950 | 734 | |||
2951 | 735 | if (err != DB_SUCCESS) { | ||
2952 | 736 | return err; | ||
2953 | 737 | } | ||
2954 | 738 | |||
2955 | 739 | /* open_or_create_log_file will set srv_log_file_size. Normalize the | ||
2956 | 740 | init values again to get srv_log_file_size/srv_log_file_curr_size in | ||
2957 | 741 | sync. */ | ||
2958 | 742 | srv_normalize_init_values(); | ||
2959 | 743 | |||
2960 | 744 | dict_ind_init(); | ||
2961 | 745 | dict_boot(FALSE); | ||
2962 | 746 | mutex_enter(&(dict_sys->mutex)); | ||
2963 | 747 | ib_page_ibuf_index_create(); | ||
2964 | 748 | mutex_exit(&(dict_sys->mutex)); | ||
2965 | 749 | dict_check_tablespaces_and_store_max_id(FALSE); | ||
2966 | 750 | |||
2967 | 751 | return DB_SUCCESS; | ||
2968 | 752 | } | ||
2969 | 753 | |||
2970 | 754 | /*******************************************************************//** | ||
2971 | 755 | Uninitialize InndoDB systems been initialized by ib_page_sys_start. */ | ||
2972 | 756 | void | ||
2973 | 757 | ib_page_sys_stop(void) | ||
2974 | 758 | /*==================*/ | ||
2975 | 759 | { | ||
2976 | 760 | /* This must be disabled before closing the buffer pool | ||
2977 | 761 | and closing the data dictionary. */ | ||
2978 | 762 | btr_search_disable(); | ||
2979 | 763 | |||
2980 | 764 | recv_sys_close(); | ||
2981 | 765 | recv_sys_mem_free(); | ||
2982 | 766 | fil_close_all_files(); | ||
2983 | 767 | dict_close(); | ||
2984 | 768 | // buf_close(); | ||
2985 | 769 | |||
2986 | 770 | mutex_free(&kernel_mutex); | ||
2987 | 771 | mem_free(kernel_mutex_temp); | ||
2988 | 772 | kernel_mutex_temp = NULL; | ||
2989 | 773 | |||
2990 | 774 | sync_close(); | ||
2991 | 775 | os_sync_free(); | ||
2992 | 776 | fil_close(); | ||
2993 | 777 | |||
2994 | 778 | buf_pool_free(); | ||
2995 | 779 | ut_free_all_mem(); | ||
2996 | 780 | } | ||
2997 | 781 | |||
2998 | 782 | #define ASSERT_MTR_READONLY(mtr) ut_a(!(mtr.modifications && mtr.n_log_recs)); | ||
2999 | 783 | |||
3000 | 784 | /***************************************************************//** | ||
3001 | 785 | Load a table object based on the index id. | ||
3002 | 786 | @return table; NULL if table does not exist */ | ||
3003 | 787 | UNIV_INTERN | ||
3004 | 788 | dict_table_t* | ||
3005 | 789 | ib_page_load_table_for_index( | ||
3006 | 790 | /*=========================*/ | ||
3007 | 791 | dulint index_id) /*!< in: index id */ | ||
3008 | 792 | { | ||
3009 | 793 | dict_table_t* sys_tables_table; | ||
3010 | 794 | dict_index_t* sys_tables_index; | ||
3011 | 795 | |||
3012 | 796 | mtr_t mtr; | ||
3013 | 797 | btr_pcur_t pcur; | ||
3014 | 798 | dict_table_t* result = NULL; | ||
3015 | 799 | |||
3016 | 800 | sys_tables_table = dict_table_get_low("SYS_INDEXES"); | ||
3017 | 801 | sys_tables_index = UT_LIST_GET_FIRST(sys_tables_table->indexes); | ||
3018 | 802 | |||
3019 | 803 | mtr_start(&mtr); | ||
3020 | 804 | |||
3021 | 805 | btr_pcur_open_at_index_side(TRUE, sys_tables_index, | ||
3022 | 806 | BTR_SEARCH_LEAF, &pcur, | ||
3023 | 807 | TRUE, &mtr); | ||
3024 | 808 | |||
3025 | 809 | for (;;) | ||
3026 | 810 | { | ||
3027 | 811 | rec_t* rec; | ||
3028 | 812 | ulint len; | ||
3029 | 813 | byte* field; | ||
3030 | 814 | dulint loc_index_id; | ||
3031 | 815 | dulint loc_table_id; | ||
3032 | 816 | |||
3033 | 817 | btr_pcur_move_to_next_user_rec(&pcur, &mtr); | ||
3034 | 818 | rec = btr_pcur_get_rec(&pcur); | ||
3035 | 819 | |||
3036 | 820 | if (!btr_pcur_is_on_user_rec(&pcur)) | ||
3037 | 821 | { | ||
3038 | 822 | /* end of index */ | ||
3039 | 823 | |||
3040 | 824 | break; | ||
3041 | 825 | } | ||
3042 | 826 | |||
3043 | 827 | if (rec_get_deleted_flag(rec, 0)) | ||
3044 | 828 | continue; | ||
3045 | 829 | |||
3046 | 830 | field = rec_get_nth_field_old(rec, 1, &len); | ||
3047 | 831 | loc_index_id = mach_read_from_8(field); | ||
3048 | 832 | |||
3049 | 833 | if (ut_dulint_cmp(loc_index_id, index_id) == 0) { | ||
3050 | 834 | field = rec_get_nth_field_old(rec, 0, &len); | ||
3051 | 835 | loc_table_id = mach_read_from_8(field); | ||
3052 | 836 | |||
3053 | 837 | btr_pcur_close(&pcur); | ||
3054 | 838 | |||
3055 | 839 | ASSERT_MTR_READONLY(mtr); | ||
3056 | 840 | mtr_commit(&mtr); | ||
3057 | 841 | |||
3058 | 842 | return dict_table_get_on_id_low(loc_table_id); | ||
3059 | 843 | } | ||
3060 | 844 | |||
3061 | 845 | } | ||
3062 | 846 | |||
3063 | 847 | btr_pcur_close(&pcur); | ||
3064 | 848 | |||
3065 | 849 | ASSERT_MTR_READONLY(mtr); | ||
3066 | 850 | mtr_commit(&mtr); | ||
3067 | 851 | |||
3068 | 852 | return(result); | ||
3069 | 853 | } | ||
3070 | 854 | |||
3071 | 855 | /** Table name for the insert buffer. */ | ||
3072 | 856 | #define IBUF_TABLE_NAME "SYS_IBUF_TABLE" | ||
3073 | 857 | |||
3074 | 858 | /***************************************************************//** | ||
3075 | 859 | Create IBUF index in data dictionary. */ | ||
3076 | 860 | UNIV_INTERN | ||
3077 | 861 | void | ||
3078 | 862 | ib_page_ibuf_index_create(void) | ||
3079 | 863 | /*===========================*/ | ||
3080 | 864 | { | ||
3081 | 865 | dict_table_t* table; | ||
3082 | 866 | mem_heap_t* heap; | ||
3083 | 867 | dict_index_t* index; | ||
3084 | 868 | ulint error; | ||
3085 | 869 | |||
3086 | 870 | ibuf = mem_alloc(sizeof(ibuf_t)); | ||
3087 | 871 | |||
3088 | 872 | memset(ibuf, 0, sizeof(*ibuf)); | ||
3089 | 873 | |||
3090 | 874 | heap = mem_heap_create(450); | ||
3091 | 875 | |||
3092 | 876 | /* Use old-style record format for the insert buffer. */ | ||
3093 | 877 | table = dict_mem_table_create(IBUF_TABLE_NAME, IBUF_SPACE_ID, 1, 0); | ||
3094 | 878 | |||
3095 | 879 | dict_mem_table_add_col(table, heap, "DUMMY_COLUMN", DATA_BINARY, 0, 0); | ||
3096 | 880 | |||
3097 | 881 | table->id = ut_dulint_add(DICT_IBUF_ID_MIN, IBUF_SPACE_ID); | ||
3098 | 882 | |||
3099 | 883 | dict_table_add_to_cache(table, heap); | ||
3100 | 884 | mem_heap_free(heap); | ||
3101 | 885 | |||
3102 | 886 | index = dict_mem_index_create( | ||
3103 | 887 | IBUF_TABLE_NAME, "CLUST_IND", | ||
3104 | 888 | IBUF_SPACE_ID, DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF, 1); | ||
3105 | 889 | |||
3106 | 890 | dict_mem_index_add_field(index, "DUMMY_COLUMN", 0); | ||
3107 | 891 | |||
3108 | 892 | index->id = ut_dulint_add(DICT_IBUF_ID_MIN, IBUF_SPACE_ID); | ||
3109 | 893 | |||
3110 | 894 | error = dict_index_add_to_cache(table, index, | ||
3111 | 895 | FSP_IBUF_TREE_ROOT_PAGE_NO, FALSE); | ||
3112 | 896 | ut_a(error == DB_SUCCESS); | ||
3113 | 897 | |||
3114 | 898 | ibuf->index = dict_table_get_first_index(table); | ||
3115 | 899 | |||
3116 | 900 | } | ||
3117 | 901 | |||
3118 | 902 | /***************************************************************//** | ||
3119 | 903 | Load a index object based on the index id. | ||
3120 | 904 | @return index; NULL if table does not exist */ | ||
3121 | 905 | dict_index_t* | ||
3122 | 906 | ib_dict_index_get_on_id( | ||
3123 | 907 | /*====================*/ | ||
3124 | 908 | dulint index_id) /*!< in: index id */ | ||
3125 | 909 | { | ||
3126 | 910 | dict_table_t* table; | ||
3127 | 911 | dict_index_t* index = NULL; | ||
3128 | 912 | |||
3129 | 913 | const char* SYS_TABLES[] = {"SYS_TABLES", "SYS_INDEXES", | ||
3130 | 914 | "SYS_COLUMNS", "SYS_FIELDS", | ||
3131 | 915 | IBUF_TABLE_NAME, NULL}; | ||
3132 | 916 | |||
3133 | 917 | mutex_enter(&(dict_sys->mutex)); | ||
3134 | 918 | for (const char** ptbl_name = SYS_TABLES; *ptbl_name; ptbl_name++) | ||
3135 | 919 | { | ||
3136 | 920 | table = dict_table_get_low(*ptbl_name); | ||
3137 | 921 | if (table != NULL) { | ||
3138 | 922 | index = dict_index_get_on_id_low(table, index_id); | ||
3139 | 923 | if (index != NULL) { | ||
3140 | 924 | mutex_exit(&(dict_sys->mutex)); | ||
3141 | 925 | return(index); | ||
3142 | 926 | } | ||
3143 | 927 | } | ||
3144 | 928 | } | ||
3145 | 929 | |||
3146 | 930 | table = ib_page_load_table_for_index(index_id); | ||
3147 | 931 | if (table != NULL) { | ||
3148 | 932 | index = dict_index_get_on_id_low(table, index_id); | ||
3149 | 933 | mutex_exit(&(dict_sys->mutex)); | ||
3150 | 934 | return index; | ||
3151 | 935 | } | ||
3152 | 936 | |||
3153 | 937 | mutex_exit(&(dict_sys->mutex)); | ||
3154 | 938 | |||
3155 | 939 | return(NULL); | ||
3156 | 940 | } | ||
3157 | 941 | |||
3158 | 942 | /********************************************************************//** | ||
3159 | 943 | Returns the page number field of an ibuf record. | ||
3160 | 944 | @return page number */ | ||
3161 | 945 | static | ||
3162 | 946 | ulint | ||
3163 | 947 | ib_page_ibuf_rec_get_page_no( | ||
3164 | 948 | /*=========================*/ | ||
3165 | 949 | const rec_t* rec) /*!< in: ibuf record */ | ||
3166 | 950 | { | ||
3167 | 951 | const byte* field; | ||
3168 | 952 | ulint len; | ||
3169 | 953 | |||
3170 | 954 | ut_ad(rec_get_n_fields_old(rec) > 2); | ||
3171 | 955 | |||
3172 | 956 | field = rec_get_nth_field_old(rec, 1, &len); | ||
3173 | 957 | |||
3174 | 958 | if (len == 1) { | ||
3175 | 959 | /* This is of the >= 4.1.x record format */ | ||
3176 | 960 | |||
3177 | 961 | field = rec_get_nth_field_old(rec, 2, &len); | ||
3178 | 962 | } else { | ||
3179 | 963 | |||
3180 | 964 | field = rec_get_nth_field_old(rec, 0, &len); | ||
3181 | 965 | } | ||
3182 | 966 | |||
3183 | 967 | ut_a(len == 4); | ||
3184 | 968 | |||
3185 | 969 | return(mach_read_from_4(field)); | ||
3186 | 970 | } | ||
3187 | 971 | |||
3188 | 972 | /********************************************************************//** | ||
3189 | 973 | Returns the space id field of an ibuf record. For < 4.1.x format records | ||
3190 | 974 | returns 0. | ||
3191 | 975 | @return space id */ | ||
3192 | 976 | static | ||
3193 | 977 | ulint | ||
3194 | 978 | ib_page_ibuf_rec_get_space( | ||
3195 | 979 | /*=======================*/ | ||
3196 | 980 | const rec_t* rec) /*!< in: ibuf record */ | ||
3197 | 981 | { | ||
3198 | 982 | const byte* field; | ||
3199 | 983 | ulint len; | ||
3200 | 984 | |||
3201 | 985 | field = rec_get_nth_field_old(rec, 1, &len); | ||
3202 | 986 | |||
3203 | 987 | if (len == 1) { | ||
3204 | 988 | /* This is of the >= 4.1.x record format */ | ||
3205 | 989 | |||
3206 | 990 | field = rec_get_nth_field_old(rec, 0, &len); | ||
3207 | 991 | ut_a(len == 4); | ||
3208 | 992 | |||
3209 | 993 | return(mach_read_from_4(field)); | ||
3210 | 994 | } | ||
3211 | 995 | |||
3212 | 996 | return(0); | ||
3213 | 997 | } | ||
3214 | 998 | |||
3215 | 999 | /****************************************************************//** | ||
3216 | 1000 | Get various information about an ibuf record in >= 4.1.x format. */ | ||
3217 | 1001 | static | ||
3218 | 1002 | void | ||
3219 | 1003 | ib_page_ibuf_rec_get_info( | ||
3220 | 1004 | /*======================*/ | ||
3221 | 1005 | const rec_t* rec, /*!< in: ibuf record */ | ||
3222 | 1006 | ibuf_op_t* op, /*!< out: operation type, or NULL */ | ||
3223 | 1007 | ibool* comp, /*!< out: compact flag, or NULL */ | ||
3224 | 1008 | ulint* info_len, /*!< out: length of info fields at the | ||
3225 | 1009 | start of the fourth field, or | ||
3226 | 1010 | NULL */ | ||
3227 | 1011 | ulint* counter) /*!< in: counter value, or NULL */ | ||
3228 | 1012 | { | ||
3229 | 1013 | const byte* types; | ||
3230 | 1014 | ulint fields; | ||
3231 | 1015 | ulint len; | ||
3232 | 1016 | |||
3233 | 1017 | /* Local variables to shadow arguments. */ | ||
3234 | 1018 | ibuf_op_t op_local; | ||
3235 | 1019 | ibool comp_local; | ||
3236 | 1020 | ulint info_len_local; | ||
3237 | 1021 | ulint counter_local; | ||
3238 | 1022 | |||
3239 | 1023 | fields = rec_get_n_fields_old(rec); | ||
3240 | 1024 | ut_a(fields > 4); | ||
3241 | 1025 | |||
3242 | 1026 | types = rec_get_nth_field_old(rec, 3, &len); | ||
3243 | 1027 | |||
3244 | 1028 | info_len_local = len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE; | ||
3245 | 1029 | |||
3246 | 1030 | switch (info_len_local) { | ||
3247 | 1031 | case 0: | ||
3248 | 1032 | case 1: | ||
3249 | 1033 | op_local = IBUF_OP_INSERT; | ||
3250 | 1034 | comp_local = info_len_local; | ||
3251 | 1035 | ut_ad(!counter); | ||
3252 | 1036 | counter_local = ULINT_UNDEFINED; | ||
3253 | 1037 | break; | ||
3254 | 1038 | |||
3255 | 1039 | case IBUF_REC_INFO_SIZE: | ||
3256 | 1040 | op_local = (ibuf_op_t)types[IBUF_REC_OFFSET_TYPE]; | ||
3257 | 1041 | comp_local = types[IBUF_REC_OFFSET_FLAGS] & IBUF_REC_COMPACT; | ||
3258 | 1042 | counter_local = mach_read_from_2( | ||
3259 | 1043 | types + IBUF_REC_OFFSET_COUNTER); | ||
3260 | 1044 | break; | ||
3261 | 1045 | |||
3262 | 1046 | default: | ||
3263 | 1047 | ut_error; | ||
3264 | 1048 | } | ||
3265 | 1049 | |||
3266 | 1050 | ut_a(op_local < IBUF_OP_COUNT); | ||
3267 | 1051 | ut_a((len - info_len_local) == | ||
3268 | 1052 | (fields - 4) * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE); | ||
3269 | 1053 | |||
3270 | 1054 | if (op) { | ||
3271 | 1055 | *op = op_local; | ||
3272 | 1056 | } | ||
3273 | 1057 | |||
3274 | 1058 | if (comp) { | ||
3275 | 1059 | *comp = comp_local; | ||
3276 | 1060 | } | ||
3277 | 1061 | |||
3278 | 1062 | if (info_len) { | ||
3279 | 1063 | *info_len = info_len_local; | ||
3280 | 1064 | } | ||
3281 | 1065 | |||
3282 | 1066 | if (counter) { | ||
3283 | 1067 | *counter = counter_local; | ||
3284 | 1068 | } | ||
3285 | 1069 | } | ||
3286 | 1070 | |||
3287 | 1071 | /****************************************************************//** | ||
3288 | 1072 | Returns the operation type field of an ibuf record. | ||
3289 | 1073 | @return operation type */ | ||
3290 | 1074 | static | ||
3291 | 1075 | ibuf_op_t | ||
3292 | 1076 | ib_page_ibuf_rec_get_op_type( | ||
3293 | 1077 | /*=========================*/ | ||
3294 | 1078 | const rec_t* rec) /*!< in: ibuf record */ | ||
3295 | 1079 | { | ||
3296 | 1080 | ulint len; | ||
3297 | 1081 | |||
3298 | 1082 | (void) rec_get_nth_field_old(rec, 1, &len); | ||
3299 | 1083 | |||
3300 | 1084 | if (len > 1) { | ||
3301 | 1085 | /* This is a < 4.1.x format record */ | ||
3302 | 1086 | |||
3303 | 1087 | return(IBUF_OP_INSERT); | ||
3304 | 1088 | } else { | ||
3305 | 1089 | ibuf_op_t op; | ||
3306 | 1090 | |||
3307 | 1091 | ib_page_ibuf_rec_get_info(rec, &op, NULL, NULL, NULL); | ||
3308 | 1092 | |||
3309 | 1093 | return(op); | ||
3310 | 1094 | } | ||
3311 | 1095 | } | ||
3312 | 1096 | |||
3313 | 1097 | /****************************************************************//** | ||
3314 | 1098 | Read the first two bytes from a record's fourth field (counter field in new | ||
3315 | 1099 | records; something else in older records). | ||
3316 | 1100 | @return "counter" field, or ULINT_UNDEFINED if for some reason it | ||
3317 | 1101 | can't be read */ | ||
3318 | 1102 | UNIV_INTERN | ||
3319 | 1103 | ulint | ||
3320 | 1104 | ib_page_ibuf_rec_get_counter( | ||
3321 | 1105 | /*=========================*/ | ||
3322 | 1106 | const rec_t* rec) /*!< in: ibuf record */ | ||
3323 | 1107 | { | ||
3324 | 1108 | const byte* ptr; | ||
3325 | 1109 | ulint len; | ||
3326 | 1110 | |||
3327 | 1111 | if (rec_get_n_fields_old(rec) < 4) { | ||
3328 | 1112 | |||
3329 | 1113 | return(ULINT_UNDEFINED); | ||
3330 | 1114 | } | ||
3331 | 1115 | |||
3332 | 1116 | ptr = rec_get_nth_field_old(rec, 3, &len); | ||
3333 | 1117 | |||
3334 | 1118 | if (len >= 2) { | ||
3335 | 1119 | |||
3336 | 1120 | return(mach_read_from_2(ptr)); | ||
3337 | 1121 | } else { | ||
3338 | 1122 | |||
3339 | 1123 | return(ULINT_UNDEFINED); | ||
3340 | 1124 | } | ||
3341 | 1125 | } | ||
3342 | 1126 | |||
3343 | 1127 | /********************************************************************//** | ||
3344 | 1128 | Creates a dummy index for inserting a record to a non-clustered index. | ||
3345 | 1129 | @return dummy index */ | ||
3346 | 1130 | static | ||
3347 | 1131 | dict_index_t* | ||
3348 | 1132 | ib_page_ibuf_dummy_index_create( | ||
3349 | 1133 | /*============================*/ | ||
3350 | 1134 | ulint n, /*!< in: number of fields */ | ||
3351 | 1135 | ibool comp) /*!< in: TRUE=use compact record format */ | ||
3352 | 1136 | { | ||
3353 | 1137 | dict_table_t* table; | ||
3354 | 1138 | dict_index_t* index; | ||
3355 | 1139 | |||
3356 | 1140 | table = dict_mem_table_create("IBUF_DUMMY", | ||
3357 | 1141 | DICT_HDR_SPACE, n, | ||
3358 | 1142 | comp ? DICT_TF_COMPACT : 0); | ||
3359 | 1143 | |||
3360 | 1144 | index = dict_mem_index_create("IBUF_DUMMY", "IBUF_DUMMY", | ||
3361 | 1145 | DICT_HDR_SPACE, 0, n); | ||
3362 | 1146 | |||
3363 | 1147 | index->table = table; | ||
3364 | 1148 | |||
3365 | 1149 | /* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */ | ||
3366 | 1150 | index->cached = TRUE; | ||
3367 | 1151 | |||
3368 | 1152 | return(index); | ||
3369 | 1153 | } | ||
3370 | 1154 | |||
3371 | 1155 | /********************************************************************//** | ||
3372 | 1156 | Add a column to the dummy index */ | ||
3373 | 1157 | static | ||
3374 | 1158 | void | ||
3375 | 1159 | ib_page_ibuf_dummy_index_add_col( | ||
3376 | 1160 | /*=============================*/ | ||
3377 | 1161 | dict_index_t* index, /*!< in: dummy index */ | ||
3378 | 1162 | const dtype_t* type, /*!< in: the data type of the column */ | ||
3379 | 1163 | ulint len) /*!< in: length of the column */ | ||
3380 | 1164 | { | ||
3381 | 1165 | ulint i = index->table->n_def; | ||
3382 | 1166 | dict_mem_table_add_col(index->table, NULL, NULL, | ||
3383 | 1167 | dtype_get_mtype(type), | ||
3384 | 1168 | dtype_get_prtype(type), | ||
3385 | 1169 | dtype_get_len(type)); | ||
3386 | 1170 | dict_index_add_col(index, index->table, | ||
3387 | 1171 | dict_table_get_nth_col(index->table, i), len); | ||
3388 | 1172 | } | ||
3389 | 1173 | /********************************************************************//** | ||
3390 | 1174 | Deallocates a dummy index for inserting a record to a non-clustered index. */ | ||
3391 | 1175 | static | ||
3392 | 1176 | void | ||
3393 | 1177 | ib_page_ibuf_dummy_index_free( | ||
3394 | 1178 | /*==========================*/ | ||
3395 | 1179 | dict_index_t* index) /*!< in, own: dummy index */ | ||
3396 | 1180 | { | ||
3397 | 1181 | dict_table_t* table = index->table; | ||
3398 | 1182 | |||
3399 | 1183 | dict_mem_index_free(index); | ||
3400 | 1184 | dict_mem_table_free(table); | ||
3401 | 1185 | } | ||
3402 | 1186 | |||
3403 | 1187 | /*********************************************************************//** | ||
3404 | 1188 | Builds the entry to insert into a non-clustered index when we have the | ||
3405 | 1189 | corresponding record in an ibuf index. | ||
3406 | 1190 | |||
3407 | 1191 | NOTE that as we copy pointers to fields in ibuf_rec, the caller must | ||
3408 | 1192 | hold a latch to the ibuf_rec page as long as the entry is used! | ||
3409 | 1193 | |||
3410 | 1194 | @return own: entry to insert to a non-clustered index */ | ||
3411 | 1195 | UNIV_INLINE | ||
3412 | 1196 | dtuple_t* | ||
3413 | 1197 | ib_page_ibuf_build_entry_pre_4_1_x( | ||
3414 | 1198 | /*===============================*/ | ||
3415 | 1199 | const rec_t* ibuf_rec, /*!< in: record in an insert buffer */ | ||
3416 | 1200 | mem_heap_t* heap, /*!< in: heap where built */ | ||
3417 | 1201 | dict_index_t** pindex) /*!< out, own: dummy index that | ||
3418 | 1202 | describes the entry */ | ||
3419 | 1203 | { | ||
3420 | 1204 | ulint i; | ||
3421 | 1205 | ulint len; | ||
3422 | 1206 | const byte* types; | ||
3423 | 1207 | dtuple_t* tuple; | ||
3424 | 1208 | ulint n_fields; | ||
3425 | 1209 | |||
3426 | 1210 | n_fields = rec_get_n_fields_old(ibuf_rec) - 2; | ||
3427 | 1211 | tuple = dtuple_create(heap, n_fields); | ||
3428 | 1212 | types = rec_get_nth_field_old(ibuf_rec, 1, &len); | ||
3429 | 1213 | |||
3430 | 1214 | ut_a(len == n_fields * DATA_ORDER_NULL_TYPE_BUF_SIZE); | ||
3431 | 1215 | |||
3432 | 1216 | for (i = 0; i < n_fields; i++) { | ||
3433 | 1217 | const byte* data; | ||
3434 | 1218 | dfield_t* field; | ||
3435 | 1219 | |||
3436 | 1220 | field = dtuple_get_nth_field(tuple, i); | ||
3437 | 1221 | |||
3438 | 1222 | data = rec_get_nth_field_old(ibuf_rec, i + 2, &len); | ||
3439 | 1223 | |||
3440 | 1224 | dfield_set_data(field, data, len); | ||
3441 | 1225 | |||
3442 | 1226 | dtype_read_for_order_and_null_size( | ||
3443 | 1227 | dfield_get_type(field), | ||
3444 | 1228 | types + i * DATA_ORDER_NULL_TYPE_BUF_SIZE); | ||
3445 | 1229 | } | ||
3446 | 1230 | |||
3447 | 1231 | *pindex = ib_page_ibuf_dummy_index_create(n_fields, FALSE); | ||
3448 | 1232 | |||
3449 | 1233 | return(tuple); | ||
3450 | 1234 | } | ||
3451 | 1235 | |||
3452 | 1236 | /*********************************************************************//** | ||
3453 | 1237 | Builds the entry used to | ||
3454 | 1238 | |||
3455 | 1239 | 1) IBUF_OP_INSERT: insert into a non-clustered index | ||
3456 | 1240 | |||
3457 | 1241 | 2) IBUF_OP_DELETE_MARK: find the record whose delete-mark flag we need to | ||
3458 | 1242 | activate | ||
3459 | 1243 | |||
3460 | 1244 | 3) IBUF_OP_DELETE: find the record we need to delete | ||
3461 | 1245 | |||
3462 | 1246 | when we have the corresponding record in an ibuf index. | ||
3463 | 1247 | |||
3464 | 1248 | NOTE that as we copy pointers to fields in ibuf_rec, the caller must | ||
3465 | 1249 | hold a latch to the ibuf_rec page as long as the entry is used! | ||
3466 | 1250 | |||
3467 | 1251 | @return own: entry to insert to a non-clustered index */ | ||
3468 | 1252 | static | ||
3469 | 1253 | dtuple_t* | ||
3470 | 1254 | ib_page_ibuf_build_entry_from_ibuf_rec( | ||
3471 | 1255 | /*===================================*/ | ||
3472 | 1256 | const rec_t* ibuf_rec, /*!< in: record in an insert buffer */ | ||
3473 | 1257 | mem_heap_t* heap, /*!< in: heap where built */ | ||
3474 | 1258 | dict_index_t** pindex) /*!< out, own: dummy index that | ||
3475 | 1259 | describes the entry */ | ||
3476 | 1260 | { | ||
3477 | 1261 | dtuple_t* tuple; | ||
3478 | 1262 | dfield_t* field; | ||
3479 | 1263 | ulint n_fields; | ||
3480 | 1264 | const byte* types; | ||
3481 | 1265 | const byte* data; | ||
3482 | 1266 | ulint len; | ||
3483 | 1267 | ulint info_len; | ||
3484 | 1268 | ulint i; | ||
3485 | 1269 | ulint comp; | ||
3486 | 1270 | dict_index_t* index; | ||
3487 | 1271 | |||
3488 | 1272 | data = rec_get_nth_field_old(ibuf_rec, 1, &len); | ||
3489 | 1273 | |||
3490 | 1274 | if (len > 1) { | ||
3491 | 1275 | /* This a < 4.1.x format record */ | ||
3492 | 1276 | |||
3493 | 1277 | return(ib_page_ibuf_build_entry_pre_4_1_x( | ||
3494 | 1278 | ibuf_rec, heap, pindex)); | ||
3495 | 1279 | } | ||
3496 | 1280 | |||
3497 | 1281 | /* This a >= 4.1.x format record */ | ||
3498 | 1282 | |||
3499 | 1283 | ut_a(*data == 0); | ||
3500 | 1284 | ut_a(rec_get_n_fields_old(ibuf_rec) > 4); | ||
3501 | 1285 | |||
3502 | 1286 | n_fields = rec_get_n_fields_old(ibuf_rec) - 4; | ||
3503 | 1287 | |||
3504 | 1288 | tuple = dtuple_create(heap, n_fields); | ||
3505 | 1289 | |||
3506 | 1290 | types = rec_get_nth_field_old(ibuf_rec, 3, &len); | ||
3507 | 1291 | |||
3508 | 1292 | ib_page_ibuf_rec_get_info(ibuf_rec, NULL, &comp, &info_len, NULL); | ||
3509 | 1293 | |||
3510 | 1294 | index = ib_page_ibuf_dummy_index_create(n_fields, comp); | ||
3511 | 1295 | |||
3512 | 1296 | len -= info_len; | ||
3513 | 1297 | types += info_len; | ||
3514 | 1298 | |||
3515 | 1299 | ut_a(len == n_fields * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE); | ||
3516 | 1300 | |||
3517 | 1301 | for (i = 0; i < n_fields; i++) { | ||
3518 | 1302 | field = dtuple_get_nth_field(tuple, i); | ||
3519 | 1303 | |||
3520 | 1304 | data = rec_get_nth_field_old(ibuf_rec, i + 4, &len); | ||
3521 | 1305 | |||
3522 | 1306 | dfield_set_data(field, data, len); | ||
3523 | 1307 | |||
3524 | 1308 | dtype_new_read_for_order_and_null_size( | ||
3525 | 1309 | dfield_get_type(field), | ||
3526 | 1310 | types + i * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE); | ||
3527 | 1311 | |||
3528 | 1312 | ib_page_ibuf_dummy_index_add_col( | ||
3529 | 1313 | index, dfield_get_type(field), len); | ||
3530 | 1314 | } | ||
3531 | 1315 | |||
3532 | 1316 | /* Prevent an ut_ad() failure in page_zip_write_rec() by | ||
3533 | 1317 | adding system columns to the dummy table pointed to by the | ||
3534 | 1318 | dummy secondary index. The insert buffer is only used for | ||
3535 | 1319 | secondary indexes, whose records never contain any system | ||
3536 | 1320 | columns, such as DB_TRX_ID. */ | ||
3537 | 1321 | ut_d(dict_table_add_system_columns(index->table, index->table->heap)); | ||
3538 | 1322 | |||
3539 | 1323 | *pindex = index; | ||
3540 | 1324 | |||
3541 | 1325 | return(tuple); | ||
3542 | 1326 | } | ||
3543 | 1327 | |||
3544 | 1328 | /******************************************************************//** | ||
3545 | 1329 | Get the data size. | ||
3546 | 1330 | @return size of fields */ | ||
3547 | 1331 | UNIV_INLINE | ||
3548 | 1332 | ulint | ||
3549 | 1333 | ib_page_ibuf_rec_get_size( | ||
3550 | 1334 | /*======================*/ | ||
3551 | 1335 | const rec_t* rec, /*!< in: ibuf record */ | ||
3552 | 1336 | const byte* types, /*!< in: fields */ | ||
3553 | 1337 | ulint n_fields, /*!< in: number of fields */ | ||
3554 | 1338 | ibool pre_4_1, /*!< in: TRUE=pre-4.1 format, | ||
3555 | 1339 | FALSE=newer */ | ||
3556 | 1340 | ulint comp) /*!< in: 0=ROW_FORMAT=REDUNDANT, | ||
3557 | 1341 | nonzero=ROW_FORMAT=COMPACT */ | ||
3558 | 1342 | { | ||
3559 | 1343 | ulint i; | ||
3560 | 1344 | ulint field_offset; | ||
3561 | 1345 | ulint types_offset; | ||
3562 | 1346 | ulint size = 0; | ||
3563 | 1347 | |||
3564 | 1348 | if (pre_4_1) { | ||
3565 | 1349 | field_offset = 2; | ||
3566 | 1350 | types_offset = DATA_ORDER_NULL_TYPE_BUF_SIZE; | ||
3567 | 1351 | } else { | ||
3568 | 1352 | field_offset = 4; | ||
3569 | 1353 | types_offset = DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE; | ||
3570 | 1354 | } | ||
3571 | 1355 | |||
3572 | 1356 | for (i = 0; i < n_fields; i++) { | ||
3573 | 1357 | ulint len; | ||
3574 | 1358 | dtype_t dtype; | ||
3575 | 1359 | |||
3576 | 1360 | rec_get_nth_field_offs_old(rec, i + field_offset, &len); | ||
3577 | 1361 | |||
3578 | 1362 | if (len != UNIV_SQL_NULL) { | ||
3579 | 1363 | size += len; | ||
3580 | 1364 | } else if (pre_4_1) { | ||
3581 | 1365 | dtype_read_for_order_and_null_size(&dtype, types); | ||
3582 | 1366 | |||
3583 | 1367 | size += dtype_get_sql_null_size(&dtype, comp); | ||
3584 | 1368 | } else { | ||
3585 | 1369 | dtype_new_read_for_order_and_null_size(&dtype, types); | ||
3586 | 1370 | |||
3587 | 1371 | size += dtype_get_sql_null_size(&dtype, comp); | ||
3588 | 1372 | } | ||
3589 | 1373 | |||
3590 | 1374 | types += types_offset; | ||
3591 | 1375 | } | ||
3592 | 1376 | |||
3593 | 1377 | return(size); | ||
3594 | 1378 | } | ||
3595 | 1379 | |||
3596 | 1380 | /*******************************************************************//** | ||
3597 | 1381 | Copy types of fields contained in index to tuple. */ | ||
3598 | 1382 | UNIV_INTERN | ||
3599 | 1383 | void | ||
3600 | 1384 | ib_page_dict_index_copy_types( | ||
3601 | 1385 | /*==========================*/ | ||
3602 | 1386 | dtuple_t* tuple, /*!< in/out: data tuple */ | ||
3603 | 1387 | const dict_index_t* index, /*!< in: index */ | ||
3604 | 1388 | ulint n_fields, /*!< in: number of | ||
3605 | 1389 | field types to copy */ | ||
3606 | 1390 | ibool is_leaf_page) /*!< in: TRUE if leas page */ | ||
3607 | 1391 | { | ||
3608 | 1392 | ulint i; | ||
3609 | 1393 | |||
3610 | 1394 | if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) { | ||
3611 | 1395 | dtuple_set_types_binary(tuple, n_fields); | ||
3612 | 1396 | |||
3613 | 1397 | return; | ||
3614 | 1398 | } | ||
3615 | 1399 | |||
3616 | 1400 | for (i = 0; i < n_fields; i++) { | ||
3617 | 1401 | const dict_field_t* ifield; | ||
3618 | 1402 | dtype_t* dfield_type; | ||
3619 | 1403 | |||
3620 | 1404 | ifield = dict_index_get_nth_field(index, i); | ||
3621 | 1405 | dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i)); | ||
3622 | 1406 | if (i >= dict_index_get_n_unique(index) && !is_leaf_page) { | ||
3623 | 1407 | dfield_type->mtype = DATA_INT; | ||
3624 | 1408 | dfield_type->prtype = 0; | ||
3625 | 1409 | dfield_type->len = 8; | ||
3626 | 1410 | dfield_type->mbminlen = 0; | ||
3627 | 1411 | dfield_type->mbmaxlen = 0; | ||
3628 | 1412 | } else { | ||
3629 | 1413 | dict_col_copy_type( | ||
3630 | 1414 | dict_field_get_col(ifield), dfield_type); | ||
3631 | 1415 | } | ||
3632 | 1416 | } | ||
3633 | 1417 | } | ||
3634 | 1418 | |||
3635 | 1419 | /*******************************************************************//** | ||
3636 | 1420 | Converts an index record to a typed data tuple. | ||
3637 | 1421 | @return index entry built; does not set info_bits, and the data fields | ||
3638 | 1422 | in the entry will point directly to rec */ | ||
3639 | 1423 | UNIV_INTERN | ||
3640 | 1424 | dtuple_t* | ||
3641 | 1425 | ib_page_row_rec_to_index_entry_low( | ||
3642 | 1426 | /*===============================*/ | ||
3643 | 1427 | const page_t* page, | ||
3644 | 1428 | const rec_t* rec, /*!< in: record in the index */ | ||
3645 | 1429 | const dict_index_t* index, /*!< in: index */ | ||
3646 | 1430 | const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */ | ||
3647 | 1431 | ulint* n_ext, /*!< out: number of externally | ||
3648 | 1432 | stored columns */ | ||
3649 | 1433 | mem_heap_t* heap) /*!< in: memory heap from which | ||
3650 | 1434 | the memory needed is allocated */ | ||
3651 | 1435 | { | ||
3652 | 1436 | dtuple_t* entry; | ||
3653 | 1437 | dfield_t* dfield; | ||
3654 | 1438 | ulint i; | ||
3655 | 1439 | const byte* field; | ||
3656 | 1440 | ulint len; | ||
3657 | 1441 | ulint rec_len; | ||
3658 | 1442 | |||
3659 | 1443 | ut_ad(rec && heap && index); | ||
3660 | 1444 | ut_ad(n_ext); | ||
3661 | 1445 | *n_ext = 0; | ||
3662 | 1446 | |||
3663 | 1447 | rec_len = rec_offs_n_fields(offsets); | ||
3664 | 1448 | |||
3665 | 1449 | entry = dtuple_create(heap, rec_len); | ||
3666 | 1450 | |||
3667 | 1451 | dtuple_set_n_fields_cmp(entry, | ||
3668 | 1452 | dict_index_get_n_unique_in_tree(index)); | ||
3669 | 1453 | ut_ad((!page_is_leaf(page) && rec_len == 2) | ||
3670 | 1454 | || (rec_len == dict_index_get_n_fields(index))); | ||
3671 | 1455 | |||
3672 | 1456 | ib_page_dict_index_copy_types( | ||
3673 | 1457 | entry, index, rec_len, page_is_leaf(page)); | ||
3674 | 1458 | |||
3675 | 1459 | for (i = 0; i < rec_len; i++) { | ||
3676 | 1460 | |||
3677 | 1461 | dfield = dtuple_get_nth_field(entry, i); | ||
3678 | 1462 | field = rec_get_nth_field(rec, offsets, i, &len); | ||
3679 | 1463 | |||
3680 | 1464 | dfield_set_data(dfield, field, len); | ||
3681 | 1465 | |||
3682 | 1466 | if (rec_offs_nth_extern(offsets, i)) { | ||
3683 | 1467 | dfield_set_ext(dfield); | ||
3684 | 1468 | (*n_ext)++; | ||
3685 | 1469 | } | ||
3686 | 1470 | } | ||
3687 | 1471 | |||
3688 | 1472 | ut_ad(dtuple_check_typed(entry)); | ||
3689 | 1473 | |||
3690 | 1474 | return(entry); | ||
3691 | 1475 | } | ||
3692 | 1476 | |||
3693 | 1477 | /*******************************************************************//** | ||
3694 | 1478 | Converts an index record to a typed data tuple. NOTE that externally | ||
3695 | 1479 | stored (often big) fields are NOT copied to heap. | ||
3696 | 1480 | @return own: index entry built; see the NOTE below! */ | ||
3697 | 1481 | UNIV_INTERN | ||
3698 | 1482 | dtuple_t* | ||
3699 | 1483 | ib_page_row_rec_to_index_entry( | ||
3700 | 1484 | /*===========================*/ | ||
3701 | 1485 | ulint type, /*!< in: ROW_COPY_DATA, or | ||
3702 | 1486 | ROW_COPY_POINTERS: the former | ||
3703 | 1487 | copies also the data fields to | ||
3704 | 1488 | heap as the latter only places | ||
3705 | 1489 | pointers to data fields on the | ||
3706 | 1490 | index page */ | ||
3707 | 1491 | const page_t* page, | ||
3708 | 1492 | const rec_t* rec, /*!< in: record in the index; | ||
3709 | 1493 | NOTE: in the case | ||
3710 | 1494 | ROW_COPY_POINTERS the data | ||
3711 | 1495 | fields in the row will point | ||
3712 | 1496 | directly into this record, | ||
3713 | 1497 | therefore, the buffer page of | ||
3714 | 1498 | this record must be at least | ||
3715 | 1499 | s-latched and the latch held | ||
3716 | 1500 | as long as the dtuple is used! */ | ||
3717 | 1501 | const dict_index_t* index, /*!< in: index */ | ||
3718 | 1502 | ulint* offsets,/*!< in/out: rec_get_offsets(rec) */ | ||
3719 | 1503 | ulint* n_ext, /*!< out: number of externally | ||
3720 | 1504 | stored columns */ | ||
3721 | 1505 | mem_heap_t* heap) /*!< in: memory heap from which | ||
3722 | 1506 | the memory needed is allocated */ | ||
3723 | 1507 | { | ||
3724 | 1508 | dtuple_t* entry; | ||
3725 | 1509 | byte* buf; | ||
3726 | 1510 | |||
3727 | 1511 | ut_ad(rec && heap && index); | ||
3728 | 1512 | ut_ad(rec_offs_validate(rec, index, offsets)); | ||
3729 | 1513 | |||
3730 | 1514 | if (type == ROW_COPY_DATA) { | ||
3731 | 1515 | /* Take a copy of rec to heap */ | ||
3732 | 1516 | buf = mem_heap_alloc(heap, rec_offs_size(offsets)); | ||
3733 | 1517 | rec = rec_copy(buf, rec, offsets); | ||
3734 | 1518 | /* Avoid a debug assertion in rec_offs_validate(). */ | ||
3735 | 1519 | rec_offs_make_valid(rec, index, offsets); | ||
3736 | 1520 | } | ||
3737 | 1521 | |||
3738 | 1522 | entry = ib_page_row_rec_to_index_entry_low( | ||
3739 | 1523 | page, rec, index, offsets, n_ext, heap); | ||
3740 | 1524 | |||
3741 | 1525 | dtuple_set_info_bits(entry, | ||
3742 | 1526 | rec_get_info_bits(rec, rec_offs_comp(offsets))); | ||
3743 | 1527 | |||
3744 | 1528 | return(entry); | ||
3745 | 1529 | } | ||
3746 | 1530 | |||
3747 | 1531 | /***************************************************************//** | ||
3748 | 1532 | Allocate signle aligned page. | ||
3749 | 1533 | @return page */ | ||
3750 | 1534 | UNIV_INTERN | ||
3751 | 1535 | page_t* | ||
3752 | 1536 | ib_page_heap_page_alloc( | ||
3753 | 1537 | /*====================*/ | ||
3754 | 1538 | mem_heap_t* heap) /*!< in: memory heap where allocate in */ | ||
3755 | 1539 | { | ||
3756 | 1540 | page_t* page = mem_heap_alloc(heap, UNIV_PAGE_SIZE * 2); | ||
3757 | 1541 | return page_align(page + UNIV_PAGE_SIZE); | ||
3758 | 1542 | } | ||
3759 | 1543 | |||
3760 | 1544 | /***************************************************************//** | ||
3761 | 1545 | Get space id of given tablespace in file. | ||
3762 | 1546 | @return space id if given tablespace file */ | ||
3763 | 1547 | UNIV_INTERN | ||
3764 | 1548 | ulint | ||
3765 | 1549 | ib_page_file_space_id( | ||
3766 | 1550 | /*==================*/ | ||
3767 | 1551 | os_file_t file) /*!< in: file */ | ||
3768 | 1552 | { | ||
3769 | 1553 | ulint space_id; | ||
3770 | 1554 | mem_heap_t* heap = mem_heap_create(100); | ||
3771 | 1555 | page_t* page = ib_page_heap_page_alloc(heap); | ||
3772 | 1556 | |||
3773 | 1557 | if (page == NULL) | ||
3774 | 1558 | { | ||
3775 | 1559 | mem_heap_free(heap); | ||
3776 | 1560 | ut_error; | ||
3777 | 1561 | } | ||
3778 | 1562 | |||
3779 | 1563 | if (!os_file_read(file, page, 0, 0, UNIV_PAGE_SIZE)) | ||
3780 | 1564 | { | ||
3781 | 1565 | mem_heap_free(heap); | ||
3782 | 1566 | ut_error; | ||
3783 | 1567 | } | ||
3784 | 1568 | |||
3785 | 1569 | space_id = page_get_space_id(page); | ||
3786 | 1570 | |||
3787 | 1571 | mem_heap_free(heap); | ||
3788 | 1572 | |||
3789 | 1573 | return space_id; | ||
3790 | 1574 | |||
3791 | 1575 | } | ||
3792 | 1576 | |||
3793 | 1577 | /***************************************************************//** | ||
3794 | 1578 | Calculate the low 32 bits and the high 32 bits | ||
3795 | 1579 | of the file offset. */ | ||
3796 | 1580 | UNIV_INTERN | ||
3797 | 1581 | void | ||
3798 | 1582 | ib_page_calc_offsets( | ||
3799 | 1583 | /*=================*/ | ||
3800 | 1584 | ulint zip_size, /*!< in: compressed page size, or | ||
3801 | 1585 | 0 for uncompressed pages */ | ||
3802 | 1586 | ulint page_no, /*!< in: page number */ | ||
3803 | 1587 | ulint* offset_low, /*!< out: low 32 bits */ | ||
3804 | 1588 | ulint* offset_high) /*!< out: high 32 bits */ | ||
3805 | 1589 | { | ||
3806 | 1590 | /* Calculate the low 32 bits and the high 32 bits of the file offset */ | ||
3807 | 1591 | |||
3808 | 1592 | if (!zip_size) { | ||
3809 | 1593 | *offset_high = (page_no >> (32 - UNIV_PAGE_SIZE_SHIFT)); | ||
3810 | 1594 | *offset_low = ((page_no << UNIV_PAGE_SIZE_SHIFT) | ||
3811 | 1595 | & 0xFFFFFFFFUL); | ||
3812 | 1596 | } else { | ||
3813 | 1597 | ulint zip_size_shift; | ||
3814 | 1598 | switch (zip_size) { | ||
3815 | 1599 | case 1024: zip_size_shift = 10; break; | ||
3816 | 1600 | case 2048: zip_size_shift = 11; break; | ||
3817 | 1601 | case 4096: zip_size_shift = 12; break; | ||
3818 | 1602 | case 8192: zip_size_shift = 13; break; | ||
3819 | 1603 | case 16384: zip_size_shift = 14; break; | ||
3820 | 1604 | default: ut_error; | ||
3821 | 1605 | } | ||
3822 | 1606 | *offset_high = page_no >> (32 - zip_size_shift); | ||
3823 | 1607 | *offset_low = (page_no << zip_size_shift & 0xFFFFFFFFUL); | ||
3824 | 1608 | } | ||
3825 | 1609 | } | ||
3826 | 1610 | |||
3827 | 1611 | /***************************************************************//** | ||
3828 | 1612 | Load compressed page into memory. | ||
3829 | 1613 | Space for page allocated in heap. | ||
3830 | 1614 | @return loaded page; NULL if page was not loaded */ | ||
3831 | 1615 | UNIV_INTERN | ||
3832 | 1616 | page_t* | ||
3833 | 1617 | ib_page_load_compressed( | ||
3834 | 1618 | /*====================*/ | ||
3835 | 1619 | os_file_t file, /*!< in: file */ | ||
3836 | 1620 | ulint page_no, /*!< in: page number */ | ||
3837 | 1621 | ulint zip_size, /*!< in: compressed page size, or | ||
3838 | 1622 | 0 for uncompressed pages */ | ||
3839 | 1623 | mem_heap_t* heap) /*!< in: memory heap */ | ||
3840 | 1624 | { | ||
3841 | 1625 | ulint offset_high; | ||
3842 | 1626 | ulint offset_low; | ||
3843 | 1627 | ulint page_size; | ||
3844 | 1628 | page_t* page; | ||
3845 | 1629 | |||
3846 | 1630 | page_size = zip_size ? zip_size : UNIV_PAGE_SIZE; | ||
3847 | 1631 | page = ib_page_heap_page_alloc(heap); | ||
3848 | 1632 | |||
3849 | 1633 | ib_page_calc_offsets(zip_size, page_no, &offset_low, &offset_high); | ||
3850 | 1634 | if (!os_file_read(file, page, offset_low, offset_high, page_size)) | ||
3851 | 1635 | { | ||
3852 | 1636 | ib_logger(ib_stream, | ||
3853 | 1637 | "Failed to read %lu bytes from offset {%lu %lu}\n", | ||
3854 | 1638 | page_size, offset_low, offset_high); | ||
3855 | 1639 | ut_error; | ||
3856 | 1640 | } | ||
3857 | 1641 | |||
3858 | 1642 | return page; | ||
3859 | 1643 | } | ||
3860 | 1644 | |||
3861 | 1645 | /***************************************************************//** | ||
3862 | 1646 | Decompress compressed page. | ||
3863 | 1647 | Space for decompressed page allocated in heap. | ||
3864 | 1648 | @return loaded page; NULL if page was not loaded */ | ||
3865 | 1649 | UNIV_INTERN | ||
3866 | 1650 | page_t* | ||
3867 | 1651 | ib_page_decompress( | ||
3868 | 1652 | /*===============*/ | ||
3869 | 1653 | const page_t* compressed_page,/*!< in: compressed page */ | ||
3870 | 1654 | ulint zip_size, /*!< in: compressed page size, or | ||
3871 | 1655 | 0 for uncompressed pages */ | ||
3872 | 1656 | mem_heap_t* heap) /*!< in: memory heap */ | ||
3873 | 1657 | { | ||
3874 | 1658 | page_t* decompressed_page = ib_page_heap_page_alloc(heap); | ||
3875 | 1659 | |||
3876 | 1660 | if (decompressed_page == NULL) | ||
3877 | 1661 | { | ||
3878 | 1662 | ut_error; | ||
3879 | 1663 | } | ||
3880 | 1664 | |||
3881 | 1665 | if (zip_size) | ||
3882 | 1666 | { | ||
3883 | 1667 | page_zip_des_t des; | ||
3884 | 1668 | des.data = (page_t*) compressed_page; | ||
3885 | 1669 | page_zip_set_size(&des, zip_size); | ||
3886 | 1670 | |||
3887 | 1671 | ulint stamp_checksum = mach_read_from_4( | ||
3888 | 1672 | compressed_page + FIL_PAGE_SPACE_OR_CHKSUM); | ||
3889 | 1673 | ulint calc_checksum = page_zip_calc_checksum( | ||
3890 | 1674 | compressed_page, zip_size); | ||
3891 | 1675 | |||
3892 | 1676 | if (UNIV_UNLIKELY(stamp_checksum != calc_checksum)) { | ||
3893 | 1677 | ut_print_timestamp(ib_stream); | ||
3894 | 1678 | ib_logger(ib_stream, | ||
3895 | 1679 | " compressed page checksum mismatch" | ||
3896 | 1680 | "%lu != %lu\n", | ||
3897 | 1681 | stamp_checksum, calc_checksum); | ||
3898 | 1682 | ut_error; | ||
3899 | 1683 | } | ||
3900 | 1684 | |||
3901 | 1685 | switch (fil_page_get_type(compressed_page)) { | ||
3902 | 1686 | case FIL_PAGE_INDEX: | ||
3903 | 1687 | if (page_zip_decompress(&des, | ||
3904 | 1688 | decompressed_page, TRUE)) { | ||
3905 | 1689 | return decompressed_page; | ||
3906 | 1690 | } | ||
3907 | 1691 | |||
3908 | 1692 | ib_logger(ib_stream, | ||
3909 | 1693 | " unable to decompress page\n"); | ||
3910 | 1694 | ut_error; | ||
3911 | 1695 | |||
3912 | 1696 | case FIL_PAGE_TYPE_ALLOCATED: | ||
3913 | 1697 | case FIL_PAGE_INODE: | ||
3914 | 1698 | case FIL_PAGE_IBUF_BITMAP: | ||
3915 | 1699 | case FIL_PAGE_TYPE_FSP_HDR: | ||
3916 | 1700 | case FIL_PAGE_TYPE_XDES: | ||
3917 | 1701 | case FIL_PAGE_TYPE_ZBLOB: | ||
3918 | 1702 | case FIL_PAGE_TYPE_ZBLOB2: | ||
3919 | 1703 | /* Copy to uncompressed storage. */ | ||
3920 | 1704 | memcpy(decompressed_page, compressed_page, zip_size); | ||
3921 | 1705 | return decompressed_page; | ||
3922 | 1706 | } | ||
3923 | 1707 | |||
3924 | 1708 | ut_print_timestamp(ib_stream); | ||
3925 | 1709 | ib_logger(ib_stream, | ||
3926 | 1710 | " unknown compressed page" | ||
3927 | 1711 | " type %lu\n", | ||
3928 | 1712 | fil_page_get_type(compressed_page)); | ||
3929 | 1713 | ut_error; | ||
3930 | 1714 | } | ||
3931 | 1715 | else | ||
3932 | 1716 | { | ||
3933 | 1717 | ut_memcpy(decompressed_page, compressed_page, UNIV_PAGE_SIZE); | ||
3934 | 1718 | } | ||
3935 | 1719 | |||
3936 | 1720 | return decompressed_page; | ||
3937 | 1721 | } | ||
3938 | 1722 | |||
3939 | 1723 | /*******************************************************************//** | ||
3940 | 1724 | Load page from file into memory and decompress it if needed. | ||
3941 | 1725 | @return TRUE on success */ | ||
3942 | 1726 | ibool | ||
3943 | 1727 | ib_page_load( | ||
3944 | 1728 | /*=========*/ | ||
3945 | 1729 | const char* ibd_file_name, /*!< in: file name */ | ||
3946 | 1730 | ulint page_no, /*!< in: page number */ | ||
3947 | 1731 | ulint* zip_size, /*!< in: compressed page size, or | ||
3948 | 1732 | 0 for uncompressed pages */ | ||
3949 | 1733 | page_t** compressed_page, /*!< out: compressed page */ | ||
3950 | 1734 | page_t** decompressed_page, /*!< out: decompressed page */ | ||
3951 | 1735 | mem_heap_t* heap) /*!< out: memory heap */ | ||
3952 | 1736 | { | ||
3953 | 1737 | ibool success; | ||
3954 | 1738 | os_file_t file; | ||
3955 | 1739 | |||
3956 | 1740 | file = os_file_create(ibd_file_name, | ||
3957 | 1741 | OS_FILE_OPEN, OS_FILE_NORMAL, | ||
3958 | 1742 | OS_DATA_FILE, &success); | ||
3959 | 1743 | |||
3960 | 1744 | if (!success) | ||
3961 | 1745 | { | ||
3962 | 1746 | ib_logger(ib_stream, "Failed to open file %s\n", ibd_file_name); | ||
3963 | 1747 | return(FALSE); | ||
3964 | 1748 | } | ||
3965 | 1749 | |||
3966 | 1750 | ulint space_id = ib_page_file_space_id(file); | ||
3967 | 1751 | *zip_size = fil_space_get_zip_size(space_id); | ||
3968 | 1752 | if (*zip_size == ULINT_UNDEFINED) { | ||
3969 | 1753 | *zip_size = 0; | ||
3970 | 1754 | } | ||
3971 | 1755 | |||
3972 | 1756 | *compressed_page = ib_page_load_compressed(file, page_no, | ||
3973 | 1757 | *zip_size, heap); | ||
3974 | 1758 | if (*compressed_page == NULL) | ||
3975 | 1759 | { | ||
3976 | 1760 | return(FALSE); | ||
3977 | 1761 | } | ||
3978 | 1762 | |||
3979 | 1763 | *decompressed_page = ib_page_decompress(*compressed_page, | ||
3980 | 1764 | *zip_size, heap); | ||
3981 | 1765 | if (*decompressed_page == NULL) | ||
3982 | 1766 | { | ||
3983 | 1767 | return(FALSE); | ||
3984 | 1768 | } | ||
3985 | 1769 | |||
3986 | 1770 | os_file_close(file); | ||
3987 | 1771 | |||
3988 | 1772 | return(TRUE); | ||
3989 | 1773 | |||
3990 | 1774 | } | ||
3991 | 1775 | |||
3992 | 1776 | |||
3993 | 1777 | /*******************************************************************//** | ||
3994 | 1778 | Print IBUF bitmap page. */ | ||
3995 | 1779 | UNIV_INTERN | ||
3996 | 1780 | void | ||
3997 | 1781 | ib_page_ibuf_bitmap_print( | ||
3998 | 1782 | /*======================*/ | ||
3999 | 1783 | const page_t* page, /*!< in: page */ | ||
4000 | 1784 | ulint zip_size) /*!< in: compressed page size, or | ||
4001 | 1785 | 0 for uncompressed pages */ | ||
4002 | 1786 | { | ||
4003 | 1787 | ulint byte_offset; | ||
4004 | 1788 | ulint i; | ||
4005 | 1789 | |||
4006 | 1790 | enum { IBUF_BITS_PER_PAGE = 4 }; | ||
4007 | 1791 | |||
4008 | 1792 | ulint page_no = page_get_page_no(page); | ||
4009 | 1793 | |||
4010 | 1794 | if (!zip_size) { | ||
4011 | 1795 | byte_offset = UT_BITS_IN_BYTES(UNIV_PAGE_SIZE | ||
4012 | 1796 | * IBUF_BITS_PER_PAGE); | ||
4013 | 1797 | } else { | ||
4014 | 1798 | byte_offset = UT_BITS_IN_BYTES(zip_size * IBUF_BITS_PER_PAGE); | ||
4015 | 1799 | } | ||
4016 | 1800 | |||
4017 | 1801 | for (i = 0; i < byte_offset; i++) { | ||
4018 | 1802 | uint bits; | ||
4019 | 1803 | |||
4020 | 1804 | bits = (uint)mach_read_from_1(page + PAGE_DATA + i / 2) & 0xF; | ||
4021 | 1805 | ib_logger(ib_stream, "%lu: %2x", page_no + 2*i - 1, bits); | ||
4022 | 1806 | ib_logger(ib_stream, " (%d free)", bits & 0x2); | ||
4023 | 1807 | if (bits & 2) { | ||
4024 | 1808 | ib_logger(ib_stream, ", buffered"); | ||
4025 | 1809 | } | ||
4026 | 1810 | if (bits & 4) { | ||
4027 | 1811 | ib_logger(ib_stream, ", ibuf"); | ||
4028 | 1812 | } | ||
4029 | 1813 | ib_logger(ib_stream, "\n"); | ||
4030 | 1814 | |||
4031 | 1815 | bits = (uint) | ||
4032 | 1816 | (mach_read_from_1(page + PAGE_DATA + i / 2) >> 4) & 0xF; | ||
4033 | 1817 | ib_logger(ib_stream, "%lu: %2x", page_no + 2*i, bits); | ||
4034 | 1818 | ib_logger(ib_stream, " (%d free)", bits & 0x2); | ||
4035 | 1819 | if (bits & 2) { | ||
4036 | 1820 | ib_logger(ib_stream, ", buffered"); | ||
4037 | 1821 | } | ||
4038 | 1822 | if (bits & 4) { | ||
4039 | 1823 | ib_logger(ib_stream, ", ibuf"); | ||
4040 | 1824 | } | ||
4041 | 1825 | ib_logger(ib_stream, "\n"); | ||
4042 | 1826 | |||
4043 | 1827 | } | ||
4044 | 1828 | |||
4045 | 1829 | } | ||
4046 | 1830 | |||
4047 | 1831 | /***************************************************************//** | ||
4048 | 1832 | Print undo log page. */ | ||
4049 | 1833 | UNIV_INTERN | ||
4050 | 1834 | void | ||
4051 | 1835 | ib_page_print_undo( | ||
4052 | 1836 | /*===============*/ | ||
4053 | 1837 | const page_t* page) /*!< in: page */ | ||
4054 | 1838 | { | ||
4055 | 1839 | const trx_undo_rec_t* rec; | ||
4056 | 1840 | ulint rec_offs; | ||
4057 | 1841 | ulint prev_offs; | ||
4058 | 1842 | ulint first_free; | ||
4059 | 1843 | ulint type; | ||
4060 | 1844 | ulint cmpl_info; | ||
4061 | 1845 | ibool updated_extern; | ||
4062 | 1846 | undo_no_t undo_no; | ||
4063 | 1847 | dulint table_id; | ||
4064 | 1848 | byte* ptr; | ||
4065 | 1849 | trx_id_t trx_id; | ||
4066 | 1850 | roll_ptr_t roll_ptr; | ||
4067 | 1851 | ulint info_bits; | ||
4068 | 1852 | dict_table_t* table; | ||
4069 | 1853 | dict_index_t* index; | ||
4070 | 1854 | upd_t* update; | ||
4071 | 1855 | |||
4072 | 1856 | first_free = mach_read_from_2(page + TRX_UNDO_PAGE_HDR | ||
4073 | 1857 | + TRX_UNDO_PAGE_FREE); | ||
4074 | 1858 | ib_logger(ib_stream, "first free: %lu\n", first_free); | ||
4075 | 1859 | rec_offs = mach_read_from_2(page + first_free - 2); | ||
4076 | 1860 | |||
4077 | 1861 | |||
4078 | 1862 | while (rec_offs != first_free | ||
4079 | 1863 | && rec_offs >= TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE) { | ||
4080 | 1864 | rec = page + rec_offs; | ||
4081 | 1865 | |||
4082 | 1866 | ib_logger(ib_stream, "===============================\n"); | ||
4083 | 1867 | |||
4084 | 1868 | ptr = trx_undo_rec_get_pars((trx_undo_rec_t*)rec, | ||
4085 | 1869 | &type, &cmpl_info, | ||
4086 | 1870 | &updated_extern, &undo_no, | ||
4087 | 1871 | &table_id); | ||
4088 | 1872 | ib_logger(ib_stream, | ||
4089 | 1873 | "Undo log record with offset: %lu," | ||
4090 | 1874 | " compiler info: %ld, updated extern: %s," | ||
4091 | 1875 | " undo log record number: {%lu %lu}," | ||
4092 | 1876 | " table id: {%lu %lu}\n", | ||
4093 | 1877 | rec_offs, cmpl_info, | ||
4094 | 1878 | updated_extern ? "YES" : "NO", | ||
4095 | 1879 | ut_dulint_get_high(undo_no), | ||
4096 | 1880 | ut_dulint_get_low(undo_no), | ||
4097 | 1881 | ut_dulint_get_high(table_id), | ||
4098 | 1882 | ut_dulint_get_low(table_id)); | ||
4099 | 1883 | |||
4100 | 1884 | mutex_enter(&(dict_sys->mutex)); | ||
4101 | 1885 | table = dict_table_get_on_id_low(table_id); | ||
4102 | 1886 | mutex_exit(&(dict_sys->mutex)); | ||
4103 | 1887 | if (table) | ||
4104 | 1888 | ib_logger(ib_stream, "table name: %s\n", table->name); | ||
4105 | 1889 | |||
4106 | 1890 | switch (type) { | ||
4107 | 1891 | case TRX_UNDO_INSERT_REC: | ||
4108 | 1892 | ib_logger(ib_stream, | ||
4109 | 1893 | "fresh insert into clustered index\n"); | ||
4110 | 1894 | break; | ||
4111 | 1895 | case TRX_UNDO_UPD_EXIST_REC: | ||
4112 | 1896 | ib_logger(ib_stream, | ||
4113 | 1897 | "update of a non-delete-marked record\n"); | ||
4114 | 1898 | break; | ||
4115 | 1899 | case TRX_UNDO_UPD_DEL_REC: | ||
4116 | 1900 | ib_logger(ib_stream, | ||
4117 | 1901 | "update of a delete marked record to " | ||
4118 | 1902 | "a not delete marked record; also the " | ||
4119 | 1903 | "fields of the record can change\n"); | ||
4120 | 1904 | break; | ||
4121 | 1905 | case TRX_UNDO_DEL_MARK_REC: | ||
4122 | 1906 | ib_logger(ib_stream, | ||
4123 | 1907 | "delete marking of a record; fields " | ||
4124 | 1908 | "do not change\n"); | ||
4125 | 1909 | break; | ||
4126 | 1910 | } | ||
4127 | 1911 | |||
4128 | 1912 | if (type == TRX_UNDO_UPD_EXIST_REC || | ||
4129 | 1913 | type == TRX_UNDO_UPD_DEL_REC || | ||
4130 | 1914 | type == TRX_UNDO_DEL_MARK_REC) { | ||
4131 | 1915 | ptr = trx_undo_update_rec_get_sys_cols(ptr, | ||
4132 | 1916 | &trx_id, | ||
4133 | 1917 | &roll_ptr, | ||
4134 | 1918 | &info_bits); | ||
4135 | 1919 | } | ||
4136 | 1920 | |||
4137 | 1921 | ib_logger(ib_stream, | ||
4138 | 1922 | "trx_id: {%lu %lu}, roll_ptr: {%lu %lu}, " | ||
4139 | 1923 | "info bits: %lu\n", | ||
4140 | 1924 | ut_dulint_get_high(trx_id), | ||
4141 | 1925 | ut_dulint_get_low(trx_id), | ||
4142 | 1926 | ut_dulint_get_high(roll_ptr), | ||
4143 | 1927 | ut_dulint_get_low(roll_ptr), | ||
4144 | 1928 | info_bits); | ||
4145 | 1929 | |||
4146 | 1930 | if (table) { | ||
4147 | 1931 | index = dict_table_get_first_index(table); | ||
4148 | 1932 | |||
4149 | 1933 | mem_heap_t* heap = mem_heap_create(100); | ||
4150 | 1934 | dtuple_t* ref; | ||
4151 | 1935 | |||
4152 | 1936 | ptr = trx_undo_rec_get_row_ref(ptr, index, &ref, heap); | ||
4153 | 1937 | |||
4154 | 1938 | if (ptr != NULL) { | ||
4155 | 1939 | |||
4156 | 1940 | for (ulint i = 0; | ||
4157 | 1941 | i < dtuple_get_n_fields(ref);i++) { | ||
4158 | 1942 | dfield_t* dfield = | ||
4159 | 1943 | dtuple_get_nth_field(ref, i); | ||
4160 | 1944 | |||
4161 | 1945 | ib_logger(ib_stream, | ||
4162 | 1946 | "(%s/%s/%lu) %s:", | ||
4163 | 1947 | table->name, index->name, | ||
4164 | 1948 | i, | ||
4165 | 1949 | dict_table_get_col_name(table, | ||
4166 | 1950 | i)); | ||
4167 | 1951 | ib_page_rec_print_field(dfield, | ||
4168 | 1952 | NULL, 0, NULL); | ||
4169 | 1953 | ib_logger(ib_stream, "\n"); | ||
4170 | 1954 | } | ||
4171 | 1955 | } | ||
4172 | 1956 | |||
4173 | 1957 | if (type == TRX_UNDO_UPD_EXIST_REC || | ||
4174 | 1958 | type == TRX_UNDO_UPD_DEL_REC || | ||
4175 | 1959 | type == TRX_UNDO_DEL_MARK_REC) { | ||
4176 | 1960 | |||
4177 | 1961 | ptr = trx_undo_update_rec_get_update(ptr, index, | ||
4178 | 1962 | type, trx_id, | ||
4179 | 1963 | roll_ptr, info_bits, | ||
4180 | 1964 | NULL, heap, &update); | ||
4181 | 1965 | |||
4182 | 1966 | if (ptr != NULL) { | ||
4183 | 1967 | |||
4184 | 1968 | for (ulint i = 0; | ||
4185 | 1969 | i < upd_get_n_fields(update); | ||
4186 | 1970 | i++) { | ||
4187 | 1971 | upd_field_t* upd_field; | ||
4188 | 1972 | dfield_t* field; | ||
4189 | 1973 | upd_field = upd_get_nth_field( | ||
4190 | 1974 | update, i); | ||
4191 | 1975 | field = &upd_field->new_val; | ||
4192 | 1976 | ib_logger(ib_stream, | ||
4193 | 1977 | "(%s/%s/%u) %s:", | ||
4194 | 1978 | table->name, | ||
4195 | 1979 | index->name, | ||
4196 | 1980 | upd_field->field_no, | ||
4197 | 1981 | dict_table_get_col_name( | ||
4198 | 1982 | table, | ||
4199 | 1983 | upd_field->field_no)); | ||
4200 | 1984 | ib_page_rec_print_field(field, | ||
4201 | 1985 | NULL, 0, NULL); | ||
4202 | 1986 | ib_logger(ib_stream, "\n"); | ||
4203 | 1987 | } | ||
4204 | 1988 | |||
4205 | 1989 | } | ||
4206 | 1990 | |||
4207 | 1991 | } | ||
4208 | 1992 | |||
4209 | 1993 | mem_heap_free(heap); | ||
4210 | 1994 | |||
4211 | 1995 | } | ||
4212 | 1996 | |||
4213 | 1997 | prev_offs = rec_offs; | ||
4214 | 1998 | rec_offs = mach_read_from_2(rec - 2); | ||
4215 | 1999 | |||
4216 | 2000 | ib_logger(ib_stream, "prev_offs: %lu, rec_offs: %lu\n", | ||
4217 | 2001 | prev_offs, rec_offs); | ||
4218 | 2002 | |||
4219 | 2003 | } | ||
4220 | 2004 | |||
4221 | 2005 | } | ||
4222 | 2006 | |||
4223 | 2007 | /***************************************************************//** | ||
4224 | 2008 | Test if page is UNDO INSERT page. | ||
4225 | 2009 | @return TRUE if page is UNDO INSERT page; FALE otherwise */ | ||
4226 | 2010 | UNIV_INTERN | ||
4227 | 2011 | ibool | ||
4228 | 2012 | ib_page_is_undo_insert( | ||
4229 | 2013 | /*===================*/ | ||
4230 | 2014 | const page_t* page) /*!< in: page */ | ||
4231 | 2015 | { | ||
4232 | 2016 | return (mach_read_from_2(page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE) | ||
4233 | 2017 | == TRX_UNDO_INSERT); | ||
4234 | 2018 | } | ||
4235 | 2019 | |||
4236 | 2020 | /***************************************************************//** | ||
4237 | 2021 | Test if page is UNDO UPDATE page. | ||
4238 | 2022 | @return TRUE if page is UNDO UPDATE page; FALE otherwise */ | ||
4239 | 2023 | UNIV_INTERN | ||
4240 | 2024 | ibool | ||
4241 | 2025 | ib_page_is_undo_update( | ||
4242 | 2026 | /*===================*/ | ||
4243 | 2027 | const page_t* page) /*!< in: page */ | ||
4244 | 2028 | { | ||
4245 | 2029 | return (mach_read_from_2(page + TRX_UNDO_PAGE_HDR | ||
4246 | 2030 | + TRX_UNDO_PAGE_TYPE) | ||
4247 | 2031 | == TRX_UNDO_UPDATE); | ||
4248 | 2032 | } | ||
4249 | 2033 | |||
4250 | 2034 | /***************************************************************//** | ||
4251 | 2035 | Test if page is UNDO page. | ||
4252 | 2036 | @return TRUE if page is UNDO page; FALE otherwise */ | ||
4253 | 2037 | UNIV_INTERN | ||
4254 | 2038 | ibool | ||
4255 | 2039 | ib_page_is_undo( | ||
4256 | 2040 | /*============*/ | ||
4257 | 2041 | const page_t* page) /*!< in: page */ | ||
4258 | 2042 | { | ||
4259 | 2043 | return ib_page_is_undo_insert(page) || ib_page_is_undo_update(page); | ||
4260 | 2044 | } | ||
4261 | 2045 | |||
4262 | 2046 | /***************************************************************//** | ||
4263 | 2047 | Print file-based list address. */ | ||
4264 | 2048 | UNIV_INTERN | ||
4265 | 2049 | void | ||
4266 | 2050 | ib_page_print_flst_addr( | ||
4267 | 2051 | /*====================*/ | ||
4268 | 2052 | const byte* base) /*!< in: pointer to base node of list */ | ||
4269 | 2053 | { | ||
4270 | 2054 | ulint page = mach_read_from_4(base + FIL_ADDR_PAGE); | ||
4271 | 2055 | ulint boffset = mach_read_from_2(base + FIL_ADDR_BYTE); | ||
4272 | 2056 | ib_logger(ib_stream, "page %lu, byte offset %lu\n", | ||
4273 | 2057 | page, boffset); | ||
4274 | 2058 | } | ||
4275 | 2059 | |||
4276 | 2060 | /***************************************************************//** | ||
4277 | 2061 | Print file-based list. */ | ||
4278 | 2062 | UNIV_INTERN | ||
4279 | 2063 | void | ||
4280 | 2064 | ib_page_print_flst( | ||
4281 | 2065 | /*===============*/ | ||
4282 | 2066 | const byte* base) /*!< in: pointer to base node of list */ | ||
4283 | 2067 | { | ||
4284 | 2068 | ulint len = mach_read_from_4(base + FLST_LEN); | ||
4285 | 2069 | ib_logger(ib_stream, "len: %lu\n", len); | ||
4286 | 2070 | ib_logger(ib_stream, "first: "); | ||
4287 | 2071 | ib_page_print_flst_addr(base + FLST_FIRST); | ||
4288 | 2072 | ib_logger(ib_stream, "last: "); | ||
4289 | 2073 | ib_page_print_flst_addr(base + FLST_LAST); | ||
4290 | 2074 | } | ||
4291 | 2075 | |||
4292 | 2076 | /***************************************************************//** | ||
4293 | 2077 | Print filespace header page. */ | ||
4294 | 2078 | UNIV_INTERN | ||
4295 | 2079 | void | ||
4296 | 2080 | ib_page_print_fsp_header( | ||
4297 | 2081 | /*=====================*/ | ||
4298 | 2082 | const page_t* page) /*!< in: page */ | ||
4299 | 2083 | { | ||
4300 | 2084 | const byte* header; | ||
4301 | 2085 | |||
4302 | 2086 | ut_a(mach_read_from_2(page + FIL_PAGE_TYPE) == FIL_PAGE_TYPE_FSP_HDR); | ||
4303 | 2087 | |||
4304 | 2088 | header = FSP_HEADER_OFFSET + page; | ||
4305 | 2089 | |||
4306 | 2090 | ib_logger(ib_stream, | ||
4307 | 2091 | "space id: %lu, not used: %lu, size: %lu\n" | ||
4308 | 2092 | "free limit: %lu, space flags: %lu, frag n used: %lu\n", | ||
4309 | 2093 | mach_read_from_4(header + FSP_SPACE_ID), | ||
4310 | 2094 | mach_read_from_4(header + FSP_NOT_USED), | ||
4311 | 2095 | mach_read_from_4(header + FSP_SIZE), | ||
4312 | 2096 | mach_read_from_4(header + FSP_FREE_LIMIT), | ||
4313 | 2097 | mach_read_from_4(header + FSP_SPACE_FLAGS), | ||
4314 | 2098 | mach_read_from_4(header + FSP_FRAG_N_USED)); | ||
4315 | 2099 | |||
4316 | 2100 | dulint seg_id = mach_read_from_8(header + FSP_SEG_ID); | ||
4317 | 2101 | ib_logger(ib_stream, "seg_id: {%lu %lu}\n\n", | ||
4318 | 2102 | ut_dulint_get_high(seg_id), | ||
4319 | 2103 | ut_dulint_get_low(seg_id)); | ||
4320 | 2104 | |||
4321 | 2105 | ib_logger(ib_stream, "FREE LIST:\n"); | ||
4322 | 2106 | ib_page_print_flst(header + FSP_FREE); | ||
4323 | 2107 | ib_logger(ib_stream, "\n"); | ||
4324 | 2108 | ib_logger(ib_stream, "FREE FRAG LIST:\n"); | ||
4325 | 2109 | ib_page_print_flst(header + FSP_FREE_FRAG); | ||
4326 | 2110 | ib_logger(ib_stream, "\n"); | ||
4327 | 2111 | ib_logger(ib_stream, "FREE FULL FRAG LIST:\n"); | ||
4328 | 2112 | ib_page_print_flst(header + FSP_FULL_FRAG); | ||
4329 | 2113 | ib_logger(ib_stream, "\n"); | ||
4330 | 2114 | ib_logger(ib_stream, "FREE FSP SEG INODES FULL LIST:\n"); | ||
4331 | 2115 | ib_page_print_flst(header + FSP_SEG_INODES_FULL); | ||
4332 | 2116 | ib_logger(ib_stream, "\n"); | ||
4333 | 2117 | ib_logger(ib_stream, "FREE FSP SEG INODES FREE LIST:\n"); | ||
4334 | 2118 | ib_page_print_flst(header + FSP_SEG_INODES_FREE); | ||
4335 | 2119 | ib_logger(ib_stream, "\n"); | ||
4336 | 2120 | |||
4337 | 2121 | } | ||
4338 | 2122 | |||
4339 | 2123 | /***************************************************************//** | ||
4340 | 2124 | Print ZBLOB page. */ | ||
4341 | 2125 | UNIV_INTERN | ||
4342 | 2126 | void | ||
4343 | 2127 | ib_page_print_zblob( | ||
4344 | 2128 | /*================*/ | ||
4345 | 2129 | const page_t* page, /*!< in: page */ | ||
4346 | 2130 | ulint zip_size) /*!< in: compressed page size, or | ||
4347 | 2131 | 0 for uncompressed pages */ | ||
4348 | 2132 | { | ||
4349 | 2133 | enum { buf_len = 80 }; | ||
4350 | 2134 | const ulint offset = FIL_PAGE_NEXT; | ||
4351 | 2135 | char buf[buf_len]; | ||
4352 | 2136 | |||
4353 | 2137 | ulint next_page_no = mach_read_from_4(page + offset); | ||
4354 | 2138 | |||
4355 | 2139 | ib_logger(ib_stream, | ||
4356 | 2140 | "compressed blob page, next page %lu\n", next_page_no); | ||
4357 | 2141 | ib_page_format_bin(buf, buf_len, page + FIL_PAGE_DATA, zip_size); | ||
4358 | 2142 | ib_logger(ib_stream, "data: %s\n", buf); | ||
4359 | 2143 | |||
4360 | 2144 | // TODO: we might uncompress page. do we need it? | ||
4361 | 2145 | } | ||
4362 | 2146 | |||
4363 | 2147 | /***************************************************************//** | ||
4364 | 2148 | Print ZBLOB2 page. */ | ||
4365 | 2149 | UNIV_INTERN | ||
4366 | 2150 | void | ||
4367 | 2151 | ib_page_print_zblob2( | ||
4368 | 2152 | /*=================*/ | ||
4369 | 2153 | const page_t* page, /*!< in: page */ | ||
4370 | 2154 | ulint zip_size) /*!< in: compressed page size, or | ||
4371 | 2155 | 0 for uncompressed pages */ | ||
4372 | 2156 | { | ||
4373 | 2157 | enum { buf_len = 80 }; | ||
4374 | 2158 | const ulint offset = FIL_PAGE_NEXT; | ||
4375 | 2159 | char buf[buf_len]; | ||
4376 | 2160 | |||
4377 | 2161 | ulint next_page_no = mach_read_from_4(page + offset); | ||
4378 | 2162 | |||
4379 | 2163 | ib_logger(ib_stream, | ||
4380 | 2164 | "compressed blob (continued) page, next page %lu\n", | ||
4381 | 2165 | next_page_no); | ||
4382 | 2166 | ib_page_format_bin(buf, buf_len, page + FIL_PAGE_DATA, zip_size); | ||
4383 | 2167 | ib_logger(ib_stream, "data: %s\n", buf); | ||
4384 | 2168 | } | ||
4385 | 2169 | |||
4386 | 2170 | /***************************************************************//** | ||
4387 | 2171 | Print BLOB page. */ | ||
4388 | 2172 | UNIV_INTERN | ||
4389 | 2173 | void | ||
4390 | 2174 | ib_page_print_blob( | ||
4391 | 2175 | /*===============*/ | ||
4392 | 2176 | const page_t* page) /*!< in: page */ | ||
4393 | 2177 | { | ||
4394 | 2178 | enum { buf_len = 80 }; | ||
4395 | 2179 | const ulint offset = FIL_PAGE_DATA; | ||
4396 | 2180 | char buf[buf_len]; | ||
4397 | 2181 | |||
4398 | 2182 | ulint next_page_no = mach_read_from_4( | ||
4399 | 2183 | page + offset + BTR_BLOB_HDR_NEXT_PAGE_NO); | ||
4400 | 2184 | ulint part_len = mach_read_from_4( | ||
4401 | 2185 | page + offset + BTR_BLOB_HDR_PART_LEN); | ||
4402 | 2186 | |||
4403 | 2187 | ib_logger(ib_stream, | ||
4404 | 2188 | "blob page, next page %lu, part len %lu\n", | ||
4405 | 2189 | next_page_no, part_len); | ||
4406 | 2190 | ib_page_format_bin(buf, buf_len, page + offset + BTR_BLOB_HDR_SIZE, | ||
4407 | 2191 | part_len); | ||
4408 | 2192 | ib_logger(ib_stream, "data: %s\n", buf); | ||
4409 | 2193 | } | ||
4410 | 2194 | |||
4411 | 2195 | /***************************************************************//** | ||
4412 | 2196 | Print inode page. */ | ||
4413 | 2197 | UNIV_INTERN | ||
4414 | 2198 | void | ||
4415 | 2199 | ib_page_print_inode( | ||
4416 | 2200 | /*================*/ | ||
4417 | 2201 | const page_t* page, /*!< in: page */ | ||
4418 | 2202 | ulint zip_size) /*!< in: compressed page size, or | ||
4419 | 2203 | 0 for uncompressed pages */ | ||
4420 | 2204 | { | ||
4421 | 2205 | for (ulint i = 0; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) | ||
4422 | 2206 | { | ||
4423 | 2207 | const byte* inode; | ||
4424 | 2208 | inode = page + FSEG_ARR_OFFSET + FSEG_INODE_SIZE * i; | ||
4425 | 2209 | |||
4426 | 2210 | ib_logger(ib_stream, "====================================\n"); | ||
4427 | 2211 | ib_logger(ib_stream, "Inode "); | ||
4428 | 2212 | |||
4429 | 2213 | dulint seg_id = mach_read_from_8(inode + FSEG_ID); | ||
4430 | 2214 | ib_logger(ib_stream, "segment id {%lu %lu}, ", | ||
4431 | 2215 | ut_dulint_get_high(seg_id), ut_dulint_get_low(seg_id)); | ||
4432 | 2216 | dulint seg_not_full_n_used = mach_read_from_8( | ||
4433 | 2217 | inode + FSEG_NOT_FULL_N_USED); | ||
4434 | 2218 | ib_logger(ib_stream, "number of used segment pages in " | ||
4435 | 2219 | "FSEG_NOT_FULL list {%lu %lu}\n\n", | ||
4436 | 2220 | ut_dulint_get_low(seg_not_full_n_used), | ||
4437 | 2221 | ut_dulint_get_low(seg_not_full_n_used)); | ||
4438 | 2222 | |||
4439 | 2223 | ib_logger(ib_stream, "List of free extents of this segment:\n"); | ||
4440 | 2224 | ib_page_print_flst(inode + FSEG_FREE); | ||
4441 | 2225 | |||
4442 | 2226 | ib_logger(ib_stream, "\nList of partially free extents:\n"); | ||
4443 | 2227 | ib_page_print_flst(inode + FSEG_NOT_FULL); | ||
4444 | 2228 | |||
4445 | 2229 | ib_logger(ib_stream, "\nList of full extents:\n"); | ||
4446 | 2230 | ib_page_print_flst(inode + FSEG_FULL); | ||
4447 | 2231 | |||
4448 | 2232 | ulint magic_n = mach_read_from_4(inode + FSEG_MAGIC_N); | ||
4449 | 2233 | ib_logger(ib_stream, "\nMagic number %lu (should be %lu)\n\n", | ||
4450 | 2234 | magic_n, (ulint) FSEG_MAGIC_N_VALUE); | ||
4451 | 2235 | |||
4452 | 2236 | for (ulint i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) | ||
4453 | 2237 | { | ||
4454 | 2238 | ulint frag_n = mach_read_from_4(inode + FSEG_FRAG_ARR | ||
4455 | 2239 | + i * FSEG_FRAG_SLOT_SIZE); | ||
4456 | 2240 | ib_logger(ib_stream, "%2lu frag slot: %lu", i, frag_n); | ||
4457 | 2241 | ib_logger(ib_stream, "%s\n", | ||
4458 | 2242 | frag_n == FIL_NULL ? " (null)" : ""); | ||
4459 | 2243 | } | ||
4460 | 2244 | ib_logger(ib_stream, "\n"); | ||
4461 | 2245 | } | ||
4462 | 2246 | } | ||
4463 | 2247 | |||
4464 | 2248 | /***************************************************************//** | ||
4465 | 2249 | @return XDES state as string. */ | ||
4466 | 2250 | UNIV_INTERN | ||
4467 | 2251 | const char* | ||
4468 | 2252 | ib_page_xdes_state_str( | ||
4469 | 2253 | /*===================*/ | ||
4470 | 2254 | ulint state) /*!< in: XDES state */ | ||
4471 | 2255 | { | ||
4472 | 2256 | switch (state) { | ||
4473 | 2257 | case XDES_FREE: | ||
4474 | 2258 | return "extent is in free list of space"; | ||
4475 | 2259 | case XDES_FREE_FRAG: | ||
4476 | 2260 | return "extent is in free fragment list of space"; | ||
4477 | 2261 | case XDES_FULL_FRAG: | ||
4478 | 2262 | return "extent is in full fragment list of space"; | ||
4479 | 2263 | case XDES_FSEG: | ||
4480 | 2264 | return "extent belongs to a segment"; | ||
4481 | 2265 | } | ||
4482 | 2266 | return "unknown"; | ||
4483 | 2267 | } | ||
4484 | 2268 | |||
4485 | 2269 | /***************************************************************//** | ||
4486 | 2270 | Print XDES page. */ | ||
4487 | 2271 | UNIV_INTERN | ||
4488 | 2272 | void | ||
4489 | 2273 | ib_page_print_xdes( | ||
4490 | 2274 | /*===============*/ | ||
4491 | 2275 | const page_t* page, /*!< in: page */ | ||
4492 | 2276 | ulint zip_size) /*!< in: compressed page size, or | ||
4493 | 2277 | 0 for uncompressed pages */ | ||
4494 | 2278 | { | ||
4495 | 2279 | |||
4496 | 2280 | for (ulint j = 0; | ||
4497 | 2281 | j < (zip_size ? zip_size : UNIV_PAGE_SIZE) / FSP_EXTENT_SIZE; | ||
4498 | 2282 | j++) | ||
4499 | 2283 | { | ||
4500 | 2284 | const byte* descr = page + XDES_ARR_OFFSET + XDES_SIZE * j; | ||
4501 | 2285 | |||
4502 | 2286 | dulint seg_id = mach_read_from_8(descr + XDES_ID); | ||
4503 | 2287 | ib_logger(ib_stream, "====================================\n"); | ||
4504 | 2288 | ib_logger(ib_stream, "Segment ID {%lu %lu}\n\n", | ||
4505 | 2289 | ut_dulint_get_high(seg_id), ut_dulint_get_low(seg_id)); | ||
4506 | 2290 | |||
4507 | 2291 | ib_logger(ib_stream, "List of descriptors:\n"); | ||
4508 | 2292 | ib_page_print_flst(descr + XDES_FLST_NODE); | ||
4509 | 2293 | |||
4510 | 2294 | ulint state = mach_read_from_4(descr + XDES_STATE); | ||
4511 | 2295 | ib_logger(ib_stream, "\nState of descriptor %lu (%s)\n", | ||
4512 | 2296 | state, ib_page_xdes_state_str(state)); | ||
4513 | 2297 | |||
4514 | 2298 | ib_logger(ib_stream, "\nXDES bitmap\n"); | ||
4515 | 2299 | for (ulint i = 0; i < FSP_EXTENT_SIZE; i++) | ||
4516 | 2300 | { | ||
4517 | 2301 | ulint index; | ||
4518 | 2302 | ulint byte_index; | ||
4519 | 2303 | ulint bit_index; | ||
4520 | 2304 | byte byte_contents; | ||
4521 | 2305 | |||
4522 | 2306 | index = XDES_FREE_BIT + XDES_BITS_PER_PAGE * i; | ||
4523 | 2307 | byte_index = index / 8; | ||
4524 | 2308 | bit_index = index % 8; | ||
4525 | 2309 | |||
4526 | 2310 | ib_logger(ib_stream, "%2lu", i); | ||
4527 | 2311 | |||
4528 | 2312 | byte_contents = mach_read_from_1(descr | ||
4529 | 2313 | + XDES_BITMAP + byte_index); | ||
4530 | 2314 | ib_logger(ib_stream, "%12s", ut_bit_get_nth( | ||
4531 | 2315 | byte_contents, | ||
4532 | 2316 | bit_index) ? "free" : "not free"); | ||
4533 | 2317 | |||
4534 | 2318 | index = XDES_CLEAN_BIT + XDES_BITS_PER_PAGE * i; | ||
4535 | 2319 | ib_logger(ib_stream, "%12s", ut_bit_get_nth( | ||
4536 | 2320 | byte_contents, | ||
4537 | 2321 | bit_index + 1) ? "clean" : "not clean"); | ||
4538 | 2322 | |||
4539 | 2323 | ib_logger(ib_stream, "\n"); | ||
4540 | 2324 | } | ||
4541 | 2325 | ib_logger(ib_stream, "\n"); | ||
4542 | 2326 | } | ||
4543 | 2327 | } | ||
4544 | 2328 | |||
4545 | 2329 | #define DICT_HDR_MIX_ID DICT_HDR_MAX_SPACE_ID | ||
4546 | 2330 | |||
4547 | 2331 | #define DICT_HDR_XTRADB_FLAG ut_dulint_create(0x58545241UL,0x44425F31UL) /* "XTRADB_1" */ | ||
4548 | 2332 | #define DICT_HDR_STATS 52 /* Root of the stats tree */ | ||
4549 | 2333 | #define DICT_HDR_XTRADB_MARK 256 /* Flag to distinguish expansion of XtraDB */ | ||
4550 | 2334 | |||
4551 | 2335 | /***************************************************************//** | ||
4552 | 2336 | Print page dictionary header. */ | ||
4553 | 2337 | UNIV_INTERN | ||
4554 | 2338 | void | ||
4555 | 2339 | ib_page_print_dict_header( | ||
4556 | 2340 | /*======================*/ | ||
4557 | 2341 | const page_t* page) /*!< in: page */ | ||
4558 | 2342 | { | ||
4559 | 2343 | const page_t* header; | ||
4560 | 2344 | dulint row_id; | ||
4561 | 2345 | dulint table_id; | ||
4562 | 2346 | dulint index_id; | ||
4563 | 2347 | dulint mix_id; | ||
4564 | 2348 | ulint tables_root; | ||
4565 | 2349 | ulint table_ids_root; | ||
4566 | 2350 | ulint columns_root; | ||
4567 | 2351 | ulint indexes_root; | ||
4568 | 2352 | ulint fields_root; | ||
4569 | 2353 | |||
4570 | 2354 | |||
4571 | 2355 | header = page + DICT_HDR; | ||
4572 | 2356 | row_id = mach_read_from_8(header + DICT_HDR_ROW_ID); | ||
4573 | 2357 | table_id = mach_read_from_8(header + DICT_HDR_TABLE_ID); | ||
4574 | 2358 | index_id = mach_read_from_8(header + DICT_HDR_INDEX_ID); | ||
4575 | 2359 | mix_id = mach_read_from_8(header + DICT_HDR_MIX_ID); | ||
4576 | 2360 | tables_root = mach_read_from_4(header + DICT_HDR_TABLES); | ||
4577 | 2361 | table_ids_root = mach_read_from_4(header + DICT_HDR_TABLE_IDS); | ||
4578 | 2362 | columns_root = mach_read_from_4(header + DICT_HDR_COLUMNS); | ||
4579 | 2363 | indexes_root = mach_read_from_4(header + DICT_HDR_INDEXES); | ||
4580 | 2364 | fields_root = mach_read_from_4(header + DICT_HDR_FIELDS); | ||
4581 | 2365 | |||
4582 | 2366 | ib_logger(ib_stream, "latest assigned IDS:\n" | ||
4583 | 2367 | "row {%lu, %lu}, table {%lu, %lu}, " | ||
4584 | 2368 | "index {%lu, %lu}, mix {%lu, %lu}\n" | ||
4585 | 2369 | "root pages:\n" | ||
4586 | 2370 | "tables %lu, tables secondary %lu, columns %lu, " | ||
4587 | 2371 | "indexes %lu, fields %lu\n", | ||
4588 | 2372 | ut_dulint_get_high(row_id), ut_dulint_get_low(row_id), | ||
4589 | 2373 | ut_dulint_get_high(table_id), ut_dulint_get_low(table_id), | ||
4590 | 2374 | ut_dulint_get_high(index_id), ut_dulint_get_low(index_id), | ||
4591 | 2375 | ut_dulint_get_high(mix_id), ut_dulint_get_low(mix_id), | ||
4592 | 2376 | tables_root, table_ids_root, columns_root, | ||
4593 | 2377 | indexes_root, fields_root); | ||
4594 | 2378 | |||
4595 | 2379 | |||
4596 | 2380 | if (ut_dulint_cmp(mach_read_from_8(header + DICT_HDR_XTRADB_MARK), | ||
4597 | 2381 | DICT_HDR_XTRADB_FLAG) == 0) | ||
4598 | 2382 | { | ||
4599 | 2383 | ib_logger(ib_stream, | ||
4600 | 2384 | "XtraDB detected, SYS_STATS root page %lu\n", | ||
4601 | 2385 | mach_read_from_4(header + DICT_HDR_STATS)); | ||
4602 | 2386 | } | ||
4603 | 2387 | } | ||
4604 | 2388 | |||
4605 | 2389 | /*******************************************************************//** | ||
4606 | 2390 | Print page stored in memory. */ | ||
4607 | 2391 | ib_err_t | ||
4608 | 2392 | ib_page_print_mem( | ||
4609 | 2393 | const page_t* page, /*!< in: page */ | ||
4610 | 2394 | ulint zip_size, /*!< in: compressed page size, or | ||
4611 | 2395 | 0 for uncompressed pages */ | ||
4612 | 2396 | ibool print_contents) /*!< in: TRUE if page print contents */ | ||
4613 | 2397 | { | ||
4614 | 2398 | ib_buf_page_print_header(page, zip_size); | ||
4615 | 2399 | ib_page_page_header_print(page); | ||
4616 | 2400 | if (print_contents) | ||
4617 | 2401 | { | ||
4618 | 2402 | switch (fil_page_get_type(page)) { | ||
4619 | 2403 | case FIL_PAGE_INDEX: | ||
4620 | 2404 | { | ||
4621 | 2405 | dict_index_t* index; | ||
4622 | 2406 | ib_page_page_dir_print(page); | ||
4623 | 2407 | ib_logger(ib_stream, "WILL PRINT RECORDS\n"); | ||
4624 | 2408 | index = ib_dict_index_get_on_id( | ||
4625 | 2409 | btr_page_get_index_id(page)); | ||
4626 | 2410 | ib_page_page_print_list(page, index); | ||
4627 | 2411 | break; | ||
4628 | 2412 | } | ||
4629 | 2413 | case FIL_PAGE_IBUF_BITMAP: | ||
4630 | 2414 | { | ||
4631 | 2415 | ib_logger(ib_stream, "PAGE BITS:\n"); | ||
4632 | 2416 | ib_page_ibuf_bitmap_print(page, zip_size); | ||
4633 | 2417 | break; | ||
4634 | 2418 | } | ||
4635 | 2419 | case FIL_PAGE_UNDO_LOG: | ||
4636 | 2420 | { | ||
4637 | 2421 | ib_page_print_undo(page); | ||
4638 | 2422 | break; | ||
4639 | 2423 | } | ||
4640 | 2424 | case FIL_PAGE_TYPE_BLOB: | ||
4641 | 2425 | { | ||
4642 | 2426 | ib_page_print_blob(page); | ||
4643 | 2427 | break; | ||
4644 | 2428 | } | ||
4645 | 2429 | case FIL_PAGE_TYPE_ZBLOB: | ||
4646 | 2430 | { | ||
4647 | 2431 | ib_page_print_zblob(page, zip_size); | ||
4648 | 2432 | break; | ||
4649 | 2433 | } | ||
4650 | 2434 | case FIL_PAGE_TYPE_ZBLOB2: | ||
4651 | 2435 | { | ||
4652 | 2436 | ib_page_print_zblob2(page, zip_size); | ||
4653 | 2437 | break; | ||
4654 | 2438 | } | ||
4655 | 2439 | case FIL_PAGE_TYPE_FSP_HDR: | ||
4656 | 2440 | { | ||
4657 | 2441 | ib_page_print_fsp_header(page); | ||
4658 | 2442 | break; | ||
4659 | 2443 | } | ||
4660 | 2444 | case FIL_PAGE_INODE: | ||
4661 | 2445 | { | ||
4662 | 2446 | ib_page_print_inode(page, zip_size); | ||
4663 | 2447 | break; | ||
4664 | 2448 | } | ||
4665 | 2449 | case FIL_PAGE_TYPE_XDES: | ||
4666 | 2450 | { | ||
4667 | 2451 | ib_page_print_xdes(page, zip_size); | ||
4668 | 2452 | break; | ||
4669 | 2453 | } | ||
4670 | 2454 | case FIL_PAGE_TYPE_SYS: | ||
4671 | 2455 | { | ||
4672 | 2456 | if (page_get_page_no(page) == DICT_HDR_PAGE_NO) | ||
4673 | 2457 | { | ||
4674 | 2458 | ib_page_print_dict_header(page); | ||
4675 | 2459 | } | ||
4676 | 2460 | } | ||
4677 | 2461 | } | ||
4678 | 2462 | } | ||
4679 | 2463 | ib_logger(ib_stream, "PAGE PRINT END\n"); | ||
4680 | 2464 | |||
4681 | 2465 | return DB_SUCCESS; | ||
4682 | 2466 | } | ||
4683 | 2467 | |||
4684 | 2468 | /*******************************************************************//** | ||
4685 | 2469 | Print page stored in file. */ | ||
4686 | 2470 | ib_err_t | ||
4687 | 2471 | ib_page_print_file( | ||
4688 | 2472 | const char* ibd_file_name, /*!< in: file name */ | ||
4689 | 2473 | ulint page_no, /*!< in: number of page to print */ | ||
4690 | 2474 | ibool print_contents) /*!< in: TRUE if page print contents */ | ||
4691 | 2475 | { | ||
4692 | 2476 | ib_err_t err; | ||
4693 | 2477 | mem_heap_t* heap = mem_heap_create(100); | ||
4694 | 2478 | ulint zip_size; | ||
4695 | 2479 | page_t* compressed_page; | ||
4696 | 2480 | page_t* decompressed_page; | ||
4697 | 2481 | |||
4698 | 2482 | if (!ib_page_load(ibd_file_name, page_no, &zip_size, | ||
4699 | 2483 | &compressed_page, &decompressed_page, heap)) | ||
4700 | 2484 | { | ||
4701 | 2485 | mem_heap_free(heap); | ||
4702 | 2486 | return DB_ERROR; | ||
4703 | 2487 | } | ||
4704 | 2488 | |||
4705 | 2489 | if (!print_contents) | ||
4706 | 2490 | { | ||
4707 | 2491 | ib_logger(ib_stream, "Print page header only\n"); | ||
4708 | 2492 | } | ||
4709 | 2493 | |||
4710 | 2494 | page_t* page = decompressed_page; | ||
4711 | 2495 | |||
4712 | 2496 | err = ib_page_print_mem(page, zip_size, print_contents); | ||
4713 | 2497 | |||
4714 | 2498 | mem_heap_free(heap); | ||
4715 | 2499 | |||
4716 | 2500 | return err; | ||
4717 | 2501 | } | ||
4718 | 2502 | |||
4719 | 2503 | /*******************************************************************//** | ||
4720 | 2504 | Format SYS value. */ | ||
4721 | 2505 | UNIV_INTERN | ||
4722 | 2506 | void | ||
4723 | 2507 | ib_page_format_sys( | ||
4724 | 2508 | /*===============*/ | ||
4725 | 2509 | ulint prtype, /*!< in: precise type */ | ||
4726 | 2510 | char* buf, /*!< out: buffer */ | ||
4727 | 2511 | ulint buf_len, /*!< in: buffer length */ | ||
4728 | 2512 | const byte* data) /*!< in: field data */ | ||
4729 | 2513 | { | ||
4730 | 2514 | dulint id; | ||
4731 | 2515 | switch (prtype & DATA_SYS_PRTYPE_MASK) { | ||
4732 | 2516 | case DATA_TRX_ID: | ||
4733 | 2517 | id = mach_read_from_6(data); | ||
4734 | 2518 | |||
4735 | 2519 | snprintf(buf, buf_len, "trx_id " TRX_ID_FMT, | ||
4736 | 2520 | TRX_ID_PREP_PRINTF(id)); | ||
4737 | 2521 | break; | ||
4738 | 2522 | |||
4739 | 2523 | case DATA_ROLL_PTR: | ||
4740 | 2524 | id = mach_read_from_7(data); | ||
4741 | 2525 | |||
4742 | 2526 | snprintf(buf, buf_len, "roll_ptr {%lu %lu}", | ||
4743 | 2527 | ut_dulint_get_high(id), ut_dulint_get_low(id)); | ||
4744 | 2528 | break; | ||
4745 | 2529 | |||
4746 | 2530 | case DATA_ROW_ID: | ||
4747 | 2531 | id = mach_read_from_6(data); | ||
4748 | 2532 | |||
4749 | 2533 | snprintf(buf, buf_len, "row_id {%lu %lu}", | ||
4750 | 2534 | ut_dulint_get_high(id), ut_dulint_get_low(id)); | ||
4751 | 2535 | break; | ||
4752 | 2536 | |||
4753 | 2537 | default: | ||
4754 | 2538 | id = mach_dulint_read_compressed(data); | ||
4755 | 2539 | |||
4756 | 2540 | snprintf(buf, buf_len, "mix_id {%lu %lu}", | ||
4757 | 2541 | ut_dulint_get_high(id), ut_dulint_get_low(id)); | ||
4758 | 2542 | } | ||
4759 | 2543 | } | ||
4760 | 2544 | |||
4761 | 2545 | /*******************************************************************//** | ||
4762 | 2546 | Format INT value. */ | ||
4763 | 2547 | UNIV_INTERN | ||
4764 | 2548 | void | ||
4765 | 2549 | ib_page_format_int( | ||
4766 | 2550 | /*===============*/ | ||
4767 | 2551 | ulint prtype, /*!< in: precise type */ | ||
4768 | 2552 | char* buf, /*!< out: buffer */ | ||
4769 | 2553 | ulint buf_len, /*!< in: buffer length */ | ||
4770 | 2554 | const byte* data, /*!< in: field data */ | ||
4771 | 2555 | ulint data_len) /*!< in: length of data */ | ||
4772 | 2556 | { | ||
4773 | 2557 | ulint val; | ||
4774 | 2558 | dulint id; | ||
4775 | 2559 | switch (data_len) { | ||
4776 | 2560 | case 1: | ||
4777 | 2561 | val = mach_read_from_1(data); | ||
4778 | 2562 | |||
4779 | 2563 | if (!(prtype & DATA_UNSIGNED)) { | ||
4780 | 2564 | val &= ~0x80; | ||
4781 | 2565 | snprintf(buf, buf_len, "%ld", (long) val); | ||
4782 | 2566 | } else { | ||
4783 | 2567 | snprintf(buf, buf_len, "%lu", (ulong) val); | ||
4784 | 2568 | } | ||
4785 | 2569 | break; | ||
4786 | 2570 | |||
4787 | 2571 | case 2: | ||
4788 | 2572 | val = mach_read_from_2(data); | ||
4789 | 2573 | |||
4790 | 2574 | if (!(prtype & DATA_UNSIGNED)) { | ||
4791 | 2575 | val &= ~0x8000; | ||
4792 | 2576 | snprintf(buf, buf_len, "%ld", (long) val); | ||
4793 | 2577 | } else { | ||
4794 | 2578 | snprintf(buf, buf_len, "%lu", (ulong) val); | ||
4795 | 2579 | } | ||
4796 | 2580 | break; | ||
4797 | 2581 | |||
4798 | 2582 | case 3: | ||
4799 | 2583 | val = mach_read_from_3(data); | ||
4800 | 2584 | |||
4801 | 2585 | if (!(prtype & DATA_UNSIGNED)) { | ||
4802 | 2586 | val &= ~0x800000; | ||
4803 | 2587 | snprintf(buf, buf_len, "%ld", (long) val); | ||
4804 | 2588 | } else { | ||
4805 | 2589 | snprintf(buf, buf_len, "%lu", (ulong) val); | ||
4806 | 2590 | } | ||
4807 | 2591 | break; | ||
4808 | 2592 | |||
4809 | 2593 | case 4: | ||
4810 | 2594 | val = mach_read_from_4(data); | ||
4811 | 2595 | |||
4812 | 2596 | if (!(prtype & DATA_UNSIGNED)) { | ||
4813 | 2597 | val &= ~0x80000000; | ||
4814 | 2598 | snprintf(buf, buf_len, "%ld", (long) val); | ||
4815 | 2599 | } else { | ||
4816 | 2600 | snprintf(buf, buf_len, "%lu", (ulong) val); | ||
4817 | 2601 | } | ||
4818 | 2602 | break; | ||
4819 | 2603 | |||
4820 | 2604 | case 6: | ||
4821 | 2605 | id = mach_read_from_6(data); | ||
4822 | 2606 | snprintf(buf, buf_len, "{%lu %lu}", | ||
4823 | 2607 | ut_dulint_get_high(id), | ||
4824 | 2608 | ut_dulint_get_low(id)); | ||
4825 | 2609 | break; | ||
4826 | 2610 | |||
4827 | 2611 | case 7: | ||
4828 | 2612 | id = mach_read_from_7(data); | ||
4829 | 2613 | snprintf(buf, buf_len, "{%lu %lu}", | ||
4830 | 2614 | ut_dulint_get_high(id), | ||
4831 | 2615 | ut_dulint_get_low(id)); | ||
4832 | 2616 | break; | ||
4833 | 2617 | case 8: | ||
4834 | 2618 | id = mach_read_from_8(data); | ||
4835 | 2619 | snprintf(buf, buf_len, "{%lu %lu}", | ||
4836 | 2620 | ut_dulint_get_high(id), | ||
4837 | 2621 | ut_dulint_get_low(id)); | ||
4838 | 2622 | break; | ||
4839 | 2623 | default: | ||
4840 | 2624 | break; | ||
4841 | 2625 | } | ||
4842 | 2626 | } | ||
4843 | 2627 | |||
4844 | 2628 | |||
4845 | 2629 | /*******************************************************************//** | ||
4846 | 2630 | Format string value. */ | ||
4847 | 2631 | UNIV_INTERN | ||
4848 | 2632 | void | ||
4849 | 2633 | ib_page_format_str( | ||
4850 | 2634 | /*===============*/ | ||
4851 | 2635 | char* buf, /*!< out: buffer */ | ||
4852 | 2636 | ulint buf_len, /*!< in: buffer length */ | ||
4853 | 2637 | const byte* data, /*!< in: field data */ | ||
4854 | 2638 | ulint data_len) /*!< in: length of data */ | ||
4855 | 2639 | { | ||
4856 | 2640 | if (data_len >= buf_len) { | ||
4857 | 2641 | strncpy(buf, (const char*)data, buf_len); | ||
4858 | 2642 | buf[buf_len - 4]= '.'; | ||
4859 | 2643 | buf[buf_len - 3]= '.'; | ||
4860 | 2644 | buf[buf_len - 2]= '.'; | ||
4861 | 2645 | buf[buf_len - 1]= 0; | ||
4862 | 2646 | } else if (data_len != UNIV_SQL_NULL) { | ||
4863 | 2647 | strncpy(buf, (const char*)data, data_len); | ||
4864 | 2648 | buf[data_len]= 0; | ||
4865 | 2649 | } | ||
4866 | 2650 | } | ||
4867 | 2651 | |||
4868 | 2652 | |||
4869 | 2653 | /*******************************************************************//** | ||
4870 | 2654 | Format binalry value. */ | ||
4871 | 2655 | UNIV_INTERN | ||
4872 | 2656 | void ib_page_format_bin( | ||
4873 | 2657 | /*====================*/ | ||
4874 | 2658 | char* buf, /*!< out: buffer */ | ||
4875 | 2659 | ulint buf_len, /*!< in: buffer length */ | ||
4876 | 2660 | const byte* data, /*!< in: field data */ | ||
4877 | 2661 | ulint data_len) /*!< in: length of data */ | ||
4878 | 2662 | { | ||
4879 | 2663 | ulint i; | ||
4880 | 2664 | for (i = 0; i < data_len * 2 && i + 2 < buf_len; i += 2) | ||
4881 | 2665 | sprintf(buf + i, "%02x", data[i / 2]); | ||
4882 | 2666 | if (data_len * 2 >= buf_len) { | ||
4883 | 2667 | buf[buf_len - 5]= '.'; | ||
4884 | 2668 | buf[buf_len - 4]= '.'; | ||
4885 | 2669 | buf[buf_len - 3]= '.'; | ||
4886 | 2670 | buf[buf_len - 2]= '.'; | ||
4887 | 2671 | } | ||
4888 | 2672 | buf[buf_len - 1]= 0; | ||
4889 | 2673 | } | ||
4890 | 2674 | |||
4891 | 2675 | |||
4892 | 2676 | /***************************************************************//** | ||
4893 | 2677 | Hex dump of page. */ | ||
4894 | 2678 | UNIV_INTERN | ||
4895 | 2679 | void | ||
4896 | 2680 | ib_page_print_hex_dump( | ||
4897 | 2681 | /*===================*/ | ||
4898 | 2682 | const page_t* page, /*!< in: page */ | ||
4899 | 2683 | ulint zip_size) /*!< in: compressed page size, or | ||
4900 | 2684 | 0 for uncompressed pages */ | ||
4901 | 2685 | { | ||
4902 | 2686 | const byte* s = page; | ||
4903 | 2687 | ulint addr; | ||
4904 | 2688 | const ulint width = 32; /* bytes per line */ | ||
4905 | 2689 | ulint size; | ||
4906 | 2690 | |||
4907 | 2691 | size = zip_size ? zip_size : UNIV_PAGE_SIZE; | ||
4908 | 2692 | |||
4909 | 2693 | for (addr = 0; addr < size; addr += width) { | ||
4910 | 2694 | ulint i; | ||
4911 | 2695 | |||
4912 | 2696 | ib_logger(ib_stream, "%04lx ", (ulong) addr); | ||
4913 | 2697 | |||
4914 | 2698 | i = ut_min(width, size - addr); | ||
4915 | 2699 | |||
4916 | 2700 | while (i--) { | ||
4917 | 2701 | ib_logger(ib_stream, "%02x", *s++); | ||
4918 | 2702 | } | ||
4919 | 2703 | |||
4920 | 2704 | ib_logger(ib_stream, "\n"); | ||
4921 | 2705 | } | ||
4922 | 2706 | } | ||
4923 | 2707 | |||
4924 | 2708 | |||
4925 | 2709 | /***************************************************************//** | ||
4926 | 2710 | Format externally stored field. */ | ||
4927 | 2711 | UNIV_INTERN | ||
4928 | 2712 | void | ||
4929 | 2713 | ib_page_format_ext( | ||
4930 | 2714 | /*===============*/ | ||
4931 | 2715 | char* buf, /*!< out: buffer */ | ||
4932 | 2716 | ulint buf_len, /*!< in: buffer length */ | ||
4933 | 2717 | const rec_t* rec, /*!< in: physical record */ | ||
4934 | 2718 | ulint no, /*!< in: field number */ | ||
4935 | 2719 | const ulint* offsets) /*!< in: array returned by | ||
4936 | 2720 | rec_get_offsets() */ | ||
4937 | 2721 | { | ||
4938 | 2722 | char local_data[30]; | ||
4939 | 2723 | ulint local_len; | ||
4940 | 2724 | ulint space_id; | ||
4941 | 2725 | ulint page_no; | ||
4942 | 2726 | ulint offset; | ||
4943 | 2727 | ulint extern_len; | ||
4944 | 2728 | const byte* data; | ||
4945 | 2729 | |||
4946 | 2730 | ut_a(rec_offs_nth_extern(offsets, no)); | ||
4947 | 2731 | |||
4948 | 2732 | /* An externally stored field can contain some initial | ||
4949 | 2733 | data from the field, and in the last 20 bytes it has the | ||
4950 | 2734 | space id, page number, and offset where the rest of the | ||
4951 | 2735 | field data is stored, and the data length in addition to | ||
4952 | 2736 | the data stored locally. We may need to store some data | ||
4953 | 2737 | locally to get the local record length above the 128 byte | ||
4954 | 2738 | limit so that field offsets are stored in two bytes, and | ||
4955 | 2739 | the extern bit is available in those two bytes. */ | ||
4956 | 2740 | |||
4957 | 2741 | data = rec_get_nth_field(rec, offsets, no, &local_len); | ||
4958 | 2742 | |||
4959 | 2743 | ib_page_format_bin(local_data, 30, data, local_len); | ||
4960 | 2744 | |||
4961 | 2745 | local_len -= BTR_EXTERN_FIELD_REF_SIZE; | ||
4962 | 2746 | |||
4963 | 2747 | space_id = mach_read_from_4(data + local_len + BTR_EXTERN_SPACE_ID); | ||
4964 | 2748 | |||
4965 | 2749 | page_no = mach_read_from_4(data + local_len + BTR_EXTERN_PAGE_NO); | ||
4966 | 2750 | |||
4967 | 2751 | offset = mach_read_from_4(data + local_len + BTR_EXTERN_OFFSET); | ||
4968 | 2752 | |||
4969 | 2753 | /* Currently a BLOB cannot be bigger than 4 GB; we | ||
4970 | 2754 | leave the 4 upper bytes in the length field unused */ | ||
4971 | 2755 | |||
4972 | 2756 | extern_len = mach_read_from_4(data + local_len + BTR_EXTERN_LEN + 4); | ||
4973 | 2757 | |||
4974 | 2758 | snprintf(buf, buf_len, | ||
4975 | 2759 | "(loc len %lu, space %lu, page %lu," | ||
4976 | 2760 | " offs %lu, ext len %lu) %s", | ||
4977 | 2761 | local_len, space_id, page_no, | ||
4978 | 2762 | offset, extern_len, local_data); | ||
4979 | 2763 | |||
4980 | 2764 | } | ||
4981 | 2765 | |||
4982 | 2766 | /*******************************************************************//** | ||
4983 | 2767 | Print field. */ | ||
4984 | 2768 | UNIV_INTERN | ||
4985 | 2769 | void | ||
4986 | 2770 | ib_page_rec_print_field( | ||
4987 | 2771 | /*====================*/ | ||
4988 | 2772 | const dfield_t* field, /*!< in: field */ | ||
4989 | 2773 | const rec_t* rec, /*!< in: physical record */ | ||
4990 | 2774 | ulint no, /*!< in: field number */ | ||
4991 | 2775 | const ulint* offsets) /*!< in: array returned by | ||
4992 | 2776 | rec_get_offsets() */ | ||
4993 | 2777 | { | ||
4994 | 2778 | enum { BUF_LEN = 80 }; | ||
4995 | 2779 | char buf[BUF_LEN]; | ||
4996 | 2780 | char type_buf[BUF_LEN]; | ||
4997 | 2781 | const dtype_t* type; | ||
4998 | 2782 | const byte* data; | ||
4999 | 2783 | ulint len; | ||
5000 | 2784 | ulint mtype; |
Sergei,
I didn't review the actual code, just want to comment on a number of basic things that caught my eye:
- large blocks of empty lines, i.e. after ib_page_ page_print_ list() ibuf_rec_ get_size( )
declaration (and what does that "SOME IBUF STUFF" comment mean?),
and after ib_page_
- lots of lines breaking the 80 chars limit
- I see absolutely no reasons to use C++ and Boost in percona-redo.cc
and percona-pprint.cc. Option parsing is available in my_getopt.c,
which is already used in xtrabackup.c and xbstream.c. And
pprint/reado are very small utilities.
- large block of "#if 0"ed code in percona-redo.cc. If it's a
debug-only code, create appropriately named #defines and some way
to compile a debug binary. If that code is not supposed to be used
by anyone, remove it.
- some commented out code in percona-pprint.c. Same comments as in
the previous item.
- what are those "BEGIN LICENSE" / "END LICENSE" for?
- can innodb_init_param() be moved to innodb_int.[ch] so we don't
create separate files for it, which are also confusingly similar to
innodb_int*?