Merge lp:~sergei.glushchenko/percona-xtrabackup/xb-tools into lp:percona-xtrabackup/2.1

Proposed by Stewart Smith
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
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.

Description of the change

Log and printers are build inside XtraBackup tree. Following are how it been done:
innodb51-utils.patch - patch needed for utils to work inside XtraBackup
innodb51-utils-init.patch - patch needed for utils to work standalone (in addition to innodb-utils.patch)
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

To post a comment you must log in.
Revision history for this message
Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal

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()
     declaration (and what does that "SOME IBUF STUFF" comment mean?),
     and after ib_page_ibuf_rec_get_size()
   - 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*?

review: Needs Fixing
Revision history for this message
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 :)

review: Needs Fixing
Revision history for this message
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.

Revision history for this message
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?

Revision history for this message
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.

Revision history for this message
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_rec_to_mysql(), trx_i_s_cache_init() etc. calls. I don't
    know if this additional effort is justifiable or not.

    Instead of open_or_create_log_file_ex() perhaps better to have
    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_offsets_old()? Its implementation
    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.

review: Needs Fixing
Revision history for this message
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

Revision history for this message
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_load_table_for_id(). How does that work since we are not allowed to write to the log in the utility?

How do you plan automating testing this, both as standalone utility and GDB entry points in the XB binary?

review: Needs Fixing
Revision history for this message
Sergei Glushchenko (sergei.glushchenko) wrote : Posted in a previous version of this proposal

Laurynas,

>
> Please create and link a blueprint for this work.
>

https://blueprints.launchpad.net/percona-xtrabackup/+spec/log-and-page-printers-for-xtrabackup
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_rec_to_mysql(), trx_i_s_cache_init() etc. calls. I don't
> know if this additional effort is justifiable or not.
>

Yep, there is nothing hard in merging utils patch with innodb51.patch.
innobase_rec_to_mysql(), trx_i_s_cache_init() etc. calls should be commented
for both xtrabackup and utils so there is no problem.
Patches been merged.

> Instead of open_or_create_log_file_ex() perhaps better to have
> 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_offsets_old()? Its implementation
> 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_offsets_old. Another way is
to replace
ut_ad(index);
with something like
ut_ad(!page_is_comp(page_align(rec))||index);

> 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?

Revision history for this message
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_load_table_for_id(). How does that work since we are not allowed to
> 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:)

Revision history for this message
Laurynas Biveinis (laurynas-biveinis) wrote : Posted in a previous version of this proposal

> https://blueprints.launchpad.net/percona-xtrabackup/+spec/log-and-page-
> printers-for-xtrabackup
> 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.

Revision history for this message
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_load_table_for_id(). How does that work since we are not allowed to
> > 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?

Revision history for this message
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_rec_print_old’:
api_page.c:2715:24: warning: variable ‘ifield’ set but not used [-Wunused-but-set-variable]
api_page.c: In function ‘ib_page_page_print_list’:
api_page.c:2880:9: warning: variable ‘n_recs’ set but not used [-Wunused-but-set-variable]
api_log.c: In function ‘ib_log_sys_parse_rec_body’:
api_log.c:816:8: warning: variable ‘ret’ set but not used [-Wunused-but-set-variable]
innodb_int.c: In function ‘innodb_init_param_for_util’:
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_log_group_home_dirs’ discards ‘const’ qualifier from pointer target type [enabled by default]
/home/vlesin/src/work/xb-tools-sergey_gl/mysql-5.1/storage/innodb_plugin/include/srv0start.h:54:1: note: expected ‘char *’ but argument is of type ‘const char *’
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_create_log_file() function.
b) 2567-2569 it would be good if we checked "create_new_db" for false.

Revision history for this message
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_create(name, OS_FILE_CREATE, OS_FILE_NORMAL,
      OS_LOG_FILE, &ret);
 }
 if (!create_new_db || ret == FALSE) {
  if (create_new_db
      && os_file_get_last_error(FALSE) != OS_FILE_ALREADY_EXISTS
...
      ) {
...
   return(DB_ERROR);
  }

  files[i] = os_file_create(name, OS_FILE_OPEN, OS_FILE_AIO,
       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_ALREADY_EXISTS) or try to open existing 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.

Revision history for this message
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://dev.mysql.com/doc/refman/5.0/en/innodb-physical-record.html. Redundant page keeps much more information inside the record itself, which allow us to print fields even if we have no information about the index which occupied this page. While compact page needs less space to store records. I don't like _old and _new suffixes as much as you do. But it is common practice to use these suffixes. Just look at rem0rec.h and you will see it. So I think we should use this convention too.

Revision history for this message
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_tablespaces_and_store_max_id(FALSE);
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_tablespaces_and_store_max_id(FALSE);
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_create_log_file). XtraBackup doesn't create new log files because of when datafiles been found, create_new_db=FALSE is passed. So I reverted a change with create_new_db.

Revision history for this message
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.

Revision history for this message
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(&(log_sys->mutex))
2. mem_init() call needed for debug builds
3. ib_log_sys_start opens only one log file from group.

Revision history for this message
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

Revision history for this message
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.

Revision history for this message
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.

Revision history for this message
Laurynas Biveinis (laurynas-biveinis) wrote :

Diff has conflicts.

review: Needs Fixing

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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'patches/innodb51.patch'
--- patches/innodb51.patch 2012-11-14 04:46:11 +0000
+++ patches/innodb51.patch 2012-12-05 22:33:23 +0000
@@ -50,7 +50,26 @@
50 #endif50 #endif
51 buf_pool->stat.n_page_gets++;51 buf_pool->stat.n_page_gets++;
52 loop:52 loop:
53@@ -2894,7 +2896,7 @@53@@ -2075,7 +2077,8 @@
54 access_time = buf_page_is_accessed(&block->page);
55 buf_page_set_accessed_make_young(&block->page, access_time);
56
57- ut_ad(!ibuf_inside()
58+ ut_ad(srv_fake_write
59+ || !ibuf_inside()
60 || ibuf_page(buf_block_get_space(block),
61 buf_block_get_zip_size(block),
62 buf_block_get_page_no(block), NULL));
63@@ -2203,7 +2206,7 @@
64 buf_pool_mutex_exit();
65 }
66
67- ut_ad(!ibuf_inside() || (mode == BUF_KEEP_OLD));
68+ ut_ad(srv_fake_write || !ibuf_inside() || (mode == BUF_KEEP_OLD));
69
70 if (rw_latch == RW_S_LATCH) {
71 success = rw_lock_s_lock_nowait(&(block->lock),
72@@ -2894,7 +2897,7 @@
54 recv_recover_page(TRUE, (buf_block_t*) bpage);73 recv_recover_page(TRUE, (buf_block_t*) bpage);
55 }74 }
56 75
@@ -158,6 +177,49 @@
158 return;177 return;
159 }178 }
160 179
180--- a/storage/innodb_plugin/dict/dict0boot.c
181+++ b/storage/innodb_plugin/dict/dict0boot.c
182@@ -241,8 +241,8 @@
183 started. This function is also called when the data dictionary is created. */
184 UNIV_INTERN
185 void
186-dict_boot(void)
187-/*===========*/
188+dict_boot(ibool ibuf_init)
189+/*======================*/
190 {
191 dict_table_t* table;
192 dict_index_t* index;
193@@ -442,7 +442,8 @@
194
195 /* Initialize the insert buffer table and index for each tablespace */
196
197- ibuf_init_at_db_start();
198+ if (ibuf_init)
199+ ibuf_init_at_db_start();
200
201 /* Load definitions of other indexes on system tables */
202
203@@ -469,8 +470,8 @@
204 Creates and initializes the data dictionary at the database creation. */
205 UNIV_INTERN
206 void
207-dict_create(void)
208-/*=============*/
209+dict_create(ibool ibuf_init)
210+/*========================*/
211 {
212 mtr_t mtr;
213
214@@ -480,7 +481,7 @@
215
216 mtr_commit(&mtr);
217
218- dict_boot();
219+ dict_boot(ibuf_init);
220
221 dict_insert_initial_data();
222 }
161--- a/storage/innodb_plugin/fil/fil0fil.c223--- a/storage/innodb_plugin/fil/fil0fil.c
162+++ b/storage/innodb_plugin/fil/fil0fil.c224+++ b/storage/innodb_plugin/fil/fil0fil.c
163@@ -48,6 +48,8 @@225@@ -48,6 +48,8 @@
@@ -642,6 +704,27 @@
642 while (sum_pages < n_pages) {704 while (sum_pages < n_pages) {
643 n_bytes = ibuf_contract_ext(&n_pag2, sync);705 n_bytes = ibuf_contract_ext(&n_pag2, sync);
644 706
707--- a/storage/innodb_plugin/include/dict0boot.h
708+++ b/storage/innodb_plugin/include/dict0boot.h
709@@ -82,14 +82,14 @@
710 started. This function is also called when the data dictionary is created. */
711 UNIV_INTERN
712 void
713-dict_boot(void);
714-/*===========*/
715+dict_boot(ibool ibuf_init);
716+/*=======================*/
717 /*****************************************************************//**
718 Creates and initializes the data dictionary at the database creation. */
719 UNIV_INTERN
720 void
721-dict_create(void);
722-/*=============*/
723+dict_create(ibool ibuf_init);
724+/*=========================*/
725
726
727 /* Space id and page no where the dictionary header resides */
645--- a/storage/innodb_plugin/include/mem0mem.ic728--- a/storage/innodb_plugin/include/mem0mem.ic
646+++ b/storage/innodb_plugin/include/mem0mem.ic729+++ b/storage/innodb_plugin/include/mem0mem.ic
647@@ -367,7 +367,7 @@730@@ -367,7 +367,7 @@
@@ -664,6 +747,41 @@
664 747
665 if ((object == slot->object) && (type == slot->type)) {748 if ((object == slot->object) && (type == slot->type)) {
666 749
750--- a/storage/innodb_plugin/include/rem0rec.h
751+++ b/storage/innodb_plugin/include/rem0rec.h
752@@ -361,6 +361,32 @@
753 #define rec_get_offsets(rec,index,offsets,n,heap) \
754 rec_get_offsets_func(rec,index,offsets,n,heap,__FILE__,__LINE__)
755
756+
757+/******************************************************//**
758+The following function determines the offsets to each field
759+in the record. Function can only calculate offsets for
760+redundant row format records.
761+It can reuse a previously allocated array.
762+@return the new offsets */
763+UNIV_INTERN
764+ulint*
765+rec_get_offsets_old_func(
766+/*=====================*/
767+ const rec_t* rec, /*!< in: physical record */
768+ ulint* offsets,/*!< in/out: array consisting of
769+ offsets[0] allocated elements,
770+ or an array from rec_get_offsets(),
771+ or NULL */
772+ ulint n_fields,/*!< in: maximum number of
773+ initialized fields
774+ (ULINT_UNDEFINED if all fields) */
775+ mem_heap_t** heap, /*!< in/out: memory heap */
776+ const char* file, /*!< in: file name where called */
777+ ulint line); /*!< in: line number where called */
778+
779+#define rec_get_offsets_old(rec,offsets,n,heap) \
780+ rec_get_offsets_old_func(rec,offsets,n,heap,__FILE__,__LINE__)
781+
782 /******************************************************//**
783 Determine the offset to each field in a leaf-page record
784 in ROW_FORMAT=COMPACT. This is a special case of
667--- a/storage/innodb_plugin/include/srv0srv.h785--- a/storage/innodb_plugin/include/srv0srv.h
668+++ b/storage/innodb_plugin/include/srv0srv.h786+++ b/storage/innodb_plugin/include/srv0srv.h
669@@ -202,6 +202,10 @@787@@ -202,6 +202,10 @@
@@ -868,6 +986,24 @@
868 || (recv_addr->state == RECV_BEING_PROCESSED)986 || (recv_addr->state == RECV_BEING_PROCESSED)
869 || (recv_addr->state == RECV_PROCESSED)) {987 || (recv_addr->state == RECV_PROCESSED)) {
870 988
989@@ -2012,7 +2013,7 @@
990 /*******************************************************************//**
991 Tries to parse a single log record and returns its length.
992 @return length of the record, or 0 if the record was not complete */
993-static
994+UNIV_INTERN
995 ulint
996 recv_parse_log_rec(
997 /*===============*/
998@@ -2083,7 +2084,7 @@
999
1000 /*******************************************************//**
1001 Calculates the new value for lsn when more data is added to the log. */
1002-static
1003+UNIV_INTERN
1004 ib_uint64_t
1005 recv_calc_lsn_on_data_add(
1006 /*======================*/
871@@ -2297,7 +2298,7 @@1007@@ -2297,7 +2298,7 @@
872 || type == MLOG_FILE_RENAME1008 || type == MLOG_FILE_RENAME
873 || type == MLOG_FILE_DELETE) {1009 || type == MLOG_FILE_DELETE) {
@@ -1007,6 +1143,158 @@
1007 #endif1143 #endif
1008 }1144 }
1009 1145
1146--- a/storage/innodb_plugin/rem/rem0rec.c
1147+++ b/storage/innodb_plugin/rem/rem0rec.c
1148@@ -344,6 +344,50 @@
1149 = (rec - (lens + 1)) | REC_OFFS_COMPACT | any_ext;
1150 }
1151
1152+static void
1153+rec_init_offsets_old(
1154+/*=================*/
1155+ const rec_t* rec, /*!< in: physical record */
1156+ ulint* offsets)/*!< in/out: array of offsets;
1157+ in: n=rec_offs_n_fields(offsets) */
1158+{
1159+ ulint i = 0;
1160+ ulint offs;
1161+
1162+ /* Old-style record: determine extra size and end offsets */
1163+ offs = REC_N_OLD_EXTRA_BYTES;
1164+ if (rec_get_1byte_offs_flag(rec)) {
1165+ offs += rec_offs_n_fields(offsets);
1166+ *rec_offs_base(offsets) = offs;
1167+ /* Determine offsets to fields */
1168+ do {
1169+ offs = rec_1_get_field_end_info(rec, i);
1170+ if (offs & REC_1BYTE_SQL_NULL_MASK) {
1171+ offs &= ~REC_1BYTE_SQL_NULL_MASK;
1172+ offs |= REC_OFFS_SQL_NULL;
1173+ }
1174+ rec_offs_base(offsets)[1 + i] = offs;
1175+ } while (++i < rec_offs_n_fields(offsets));
1176+ } else {
1177+ offs += 2 * rec_offs_n_fields(offsets);
1178+ *rec_offs_base(offsets) = offs;
1179+ /* Determine offsets to fields */
1180+ do {
1181+ offs = rec_2_get_field_end_info(rec, i);
1182+ if (offs & REC_2BYTE_SQL_NULL_MASK) {
1183+ offs &= ~REC_2BYTE_SQL_NULL_MASK;
1184+ offs |= REC_OFFS_SQL_NULL;
1185+ }
1186+ if (offs & REC_2BYTE_EXTERN_MASK) {
1187+ offs &= ~REC_2BYTE_EXTERN_MASK;
1188+ offs |= REC_OFFS_EXTERNAL;
1189+ *rec_offs_base(offsets) |= REC_OFFS_EXTERNAL;
1190+ }
1191+ rec_offs_base(offsets)[1 + i] = offs;
1192+ } while (++i < rec_offs_n_fields(offsets));
1193+ }
1194+}
1195+
1196 /******************************************************//**
1197 The following function determines the offsets to each field in the
1198 record. The offsets are written to a previously allocated array of
1199@@ -480,38 +524,7 @@
1200 *rec_offs_base(offsets)
1201 = (rec - (lens + 1)) | REC_OFFS_COMPACT;
1202 } else {
1203- /* Old-style record: determine extra size and end offsets */
1204- offs = REC_N_OLD_EXTRA_BYTES;
1205- if (rec_get_1byte_offs_flag(rec)) {
1206- offs += rec_offs_n_fields(offsets);
1207- *rec_offs_base(offsets) = offs;
1208- /* Determine offsets to fields */
1209- do {
1210- offs = rec_1_get_field_end_info(rec, i);
1211- if (offs & REC_1BYTE_SQL_NULL_MASK) {
1212- offs &= ~REC_1BYTE_SQL_NULL_MASK;
1213- offs |= REC_OFFS_SQL_NULL;
1214- }
1215- rec_offs_base(offsets)[1 + i] = offs;
1216- } while (++i < rec_offs_n_fields(offsets));
1217- } else {
1218- offs += 2 * rec_offs_n_fields(offsets);
1219- *rec_offs_base(offsets) = offs;
1220- /* Determine offsets to fields */
1221- do {
1222- offs = rec_2_get_field_end_info(rec, i);
1223- if (offs & REC_2BYTE_SQL_NULL_MASK) {
1224- offs &= ~REC_2BYTE_SQL_NULL_MASK;
1225- offs |= REC_OFFS_SQL_NULL;
1226- }
1227- if (offs & REC_2BYTE_EXTERN_MASK) {
1228- offs &= ~REC_2BYTE_EXTERN_MASK;
1229- offs |= REC_OFFS_EXTERNAL;
1230- *rec_offs_base(offsets) |= REC_OFFS_EXTERNAL;
1231- }
1232- rec_offs_base(offsets)[1 + i] = offs;
1233- } while (++i < rec_offs_n_fields(offsets));
1234- }
1235+ rec_init_offsets_old(rec, offsets);
1236 }
1237 }
1238
1239@@ -587,6 +600,58 @@
1240 return(offsets);
1241 }
1242
1243+/******************************************************//**
1244+The following function determines the offsets to each field
1245+in the record. Function can only calculate offsets for
1246+redundant row format records.
1247+It can reuse a previously allocated array.
1248+@return the new offsets */
1249+UNIV_INTERN
1250+ulint*
1251+rec_get_offsets_old_func(
1252+/*=====================*/
1253+ const rec_t* rec, /*!< in: physical record */
1254+ ulint* offsets,/*!< in/out: array consisting of
1255+ offsets[0] allocated elements,
1256+ or an array from rec_get_offsets(),
1257+ or NULL */
1258+ ulint n_fields,/*!< in: maximum number of
1259+ initialized fields
1260+ (ULINT_UNDEFINED if all fields) */
1261+ mem_heap_t** heap, /*!< in/out: memory heap */
1262+ const char* file, /*!< in: file name where called */
1263+ ulint line) /*!< in: line number where called */
1264+{
1265+ ulint n;
1266+ ulint size;
1267+
1268+ ut_ad(rec);
1269+ ut_ad(heap);
1270+
1271+ n = rec_get_n_fields_old(rec);
1272+
1273+ if (UNIV_UNLIKELY(n_fields < n)) {
1274+ n = n_fields;
1275+ }
1276+
1277+ size = n + (1 + REC_OFFS_HEADER_SIZE);
1278+
1279+ if (UNIV_UNLIKELY(!offsets)
1280+ || UNIV_UNLIKELY(rec_offs_get_n_alloc(offsets) < size)) {
1281+ if (UNIV_UNLIKELY(!*heap)) {
1282+ *heap = mem_heap_create_func(size * sizeof(ulint),
1283+ MEM_HEAP_DYNAMIC,
1284+ file, line);
1285+ }
1286+ offsets = mem_heap_alloc(*heap, size * sizeof(ulint));
1287+ rec_offs_set_n_alloc(offsets, size);
1288+ }
1289+
1290+ rec_offs_set_n_fields(offsets, n);
1291+ rec_init_offsets_old(rec, offsets);
1292+ return(offsets);
1293+}
1294+
1295 /******************************************************//**
1296 The following function determines the offsets to each field
1297 in the record. It can reuse a previously allocated array. */
1010--- a/storage/innodb_plugin/row/row0merge.c1298--- a/storage/innodb_plugin/row/row0merge.c
1011+++ b/storage/innodb_plugin/row/row0merge.c1299+++ b/storage/innodb_plugin/row/row0merge.c
1012@@ -453,7 +453,9 @@1300@@ -453,7 +453,9 @@
@@ -1084,6 +1372,15 @@
1084 }1372 }
1085 1373
1086 /*********************************************************************//**1374 /*********************************************************************//**
1375@@ -1321,7 +1326,7 @@
1376 /*********************************************************************//**
1377 Normalizes init parameter values to use units we use inside InnoDB.
1378 @return DB_SUCCESS or error code */
1379-static
1380+UNIV_INTERN
1381 ulint
1382 srv_normalize_init_values(void)
1383 /*===========================*/
1087--- a/storage/innodb_plugin/srv/srv0start.c1384--- a/storage/innodb_plugin/srv/srv0start.c
1088+++ b/storage/innodb_plugin/srv/srv0start.c1385+++ b/storage/innodb_plugin/srv/srv0start.c
1089@@ -94,6 +94,8 @@1386@@ -94,6 +94,8 @@
@@ -1104,7 +1401,18 @@
1104 ulint1401 ulint
1105 open_or_create_log_file(1402 open_or_create_log_file(
1106 /*====================*/1403 /*====================*/
1107@@ -702,7 +704,7 @@1404@@ -611,6 +619,10 @@
1405 ret = os_file_get_size(files[i], &size, &size_high);
1406 ut_a(ret);
1407
1408+ srv_log_file_size =
1409+ ((ib_uint64_t)size_high << 32 | size)
1410+ >> UNIV_PAGE_SIZE_SHIFT;
1411+
1412 if (size != srv_calc_low32(srv_log_file_size)
1413 || size_high != srv_calc_high32(srv_log_file_size)) {
1414
1415@@ -702,7 +714,7 @@
1108 /*********************************************************************//**1416 /*********************************************************************//**
1109 Creates or opens database data files and closes them.1417 Creates or opens database data files and closes them.
1110 @return DB_SUCCESS or error code */1418 @return DB_SUCCESS or error code */
@@ -1113,7 +1421,7 @@
1113 ulint1421 ulint
1114 open_or_create_data_files(1422 open_or_create_data_files(
1115 /*======================*/1423 /*======================*/
1116@@ -1359,7 +1361,7 @@1424@@ -1359,7 +1371,7 @@
1117 }1425 }
1118 #endif /* UNIV_LOG_ARCHIVE */1426 #endif /* UNIV_LOG_ARCHIVE */
1119 1427
@@ -1122,7 +1430,34 @@
1122 fprintf(stderr,1430 fprintf(stderr,
1123 "InnoDB: Error: combined size of log files"1431 "InnoDB: Error: combined size of log files"
1124 " must be < 4 GB\n");1432 " must be < 4 GB\n");
1125@@ -1601,6 +1603,10 @@1433@@ -1516,7 +1528,7 @@
1434 mtr_commit(&mtr);
1435
1436 trx_sys_create();
1437- dict_create();
1438+ dict_create(TRUE);
1439 srv_startup_is_before_trx_rollback_phase = FALSE;
1440
1441 #ifdef UNIV_LOG_ARCHIVE
1442@@ -1534,7 +1546,7 @@
1443 /* Since ibuf init is in dict_boot, and ibuf is needed
1444 in any disk i/o, first call dict_boot */
1445
1446- dict_boot();
1447+ dict_boot(TRUE);
1448 trx_sys_init_at_db_start();
1449 srv_startup_is_before_trx_rollback_phase = FALSE;
1450
1451@@ -1590,7 +1602,7 @@
1452 to access space 0, and the insert buffer at this stage already
1453 works for space 0. */
1454
1455- dict_boot();
1456+ dict_boot(TRUE);
1457 trx_sys_init_at_db_start();
1458
1459 /* Initialize the fsp free limit global variable in the log
1460@@ -1601,6 +1613,10 @@
1126 are initialized in trx_sys_init_at_db_start(). */1461 are initialized in trx_sys_init_at_db_start(). */
1127 1462
1128 recv_recovery_from_checkpoint_finish();1463 recv_recovery_from_checkpoint_finish();
@@ -1133,7 +1468,7 @@
1133 if (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE) {1468 if (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE) {
1134 /* The following call is necessary for the insert1469 /* The following call is necessary for the insert
1135 buffer to work with multiple tablespaces. We must1470 buffer to work with multiple tablespaces. We must
1136@@ -1747,7 +1753,18 @@1471@@ -1747,7 +1763,18 @@
1137 1472
1138 if (srv_auto_extend_last_data_file1473 if (srv_auto_extend_last_data_file
1139 && sum_of_data_file_sizes < tablespace_size_in_header) {1474 && sum_of_data_file_sizes < tablespace_size_in_header) {
@@ -1152,7 +1487,7 @@
1152 fprintf(stderr,1487 fprintf(stderr,
1153 "InnoDB: Error: tablespace size stored in header"1488 "InnoDB: Error: tablespace size stored in header"
1154 " is %lu pages, but\n"1489 " is %lu pages, but\n"
1155@@ -1772,6 +1789,7 @@1490@@ -1772,6 +1799,7 @@
1156 1491
1157 return(DB_ERROR);1492 return(DB_ERROR);
1158 }1493 }
@@ -1160,7 +1495,7 @@
1160 }1495 }
1161 1496
1162 /* Check that os_fast_mutexes work as expected */1497 /* Check that os_fast_mutexes work as expected */
1163@@ -1867,6 +1885,7 @@1498@@ -1867,6 +1895,7 @@
1164 ibuf_update_max_tablespace_id();1499 ibuf_update_max_tablespace_id();
1165 }1500 }
1166 1501
11671502
=== modified file 'src/Makefile'
--- src/Makefile 2012-05-25 11:38:15 +0000
+++ src/Makefile 2012-12-05 22:33:23 +0000
@@ -35,6 +35,10 @@
35 xbstream_write.o \35 xbstream_write.o \
36 quicklz/quicklz.o36 quicklz/quicklz.o
37XBSTREAMOBJS = xbstream.o xbstream_write.o xbstream_read.o37XBSTREAMOBJS = xbstream.o xbstream_write.o xbstream_read.o
38UTILSCOREOBJS = api_page.o api_log.o
39UTILSCOBJS = innodb_int.o $(UTILSCOREOBJS)
40REDOCOBJS = percona-redo.o
41PAGECOBJS = percona-pprint.o
3842
39LIBARCHIVE_A = libarchive/libarchive/libarchive.a43LIBARCHIVE_A = libarchive/libarchive/libarchive.a
4044
@@ -86,8 +90,9 @@
8690
87plugin: MYSQLOBJS = $(addprefix $(MYSQL_ROOT_DIR)/, mysys/libmysys.a \91plugin: MYSQLOBJS = $(addprefix $(MYSQL_ROOT_DIR)/, mysys/libmysys.a \
88 strings/libmystrings.a zlib/.libs/libzlt.a dbug/libdbug.a)92 strings/libmystrings.a zlib/.libs/libzlt.a dbug/libdbug.a)
93plugin: EXTLINKOBJS := $(UTILSCOREOBJS)
89plugin: TARGET := xtrabackup_plugin94plugin: TARGET := xtrabackup_plugin
90plugin: $(TARGET) xbstream95plugin: utils $(TARGET) xbstream
9196
92# XtraBackup for MySQL 5.597# XtraBackup for MySQL 5.5
935.5: INC = $(COMMON_INC) $(addprefix -isystem$(MYSQL_ROOT_DIR)/, \985.5: INC = $(COMMON_INC) $(addprefix -isystem$(MYSQL_ROOT_DIR)/, \
@@ -179,7 +184,7 @@
179xtradb55: TARGET := xtrabackup_55184xtradb55: TARGET := xtrabackup_55
180xtradb55: $(TARGET) xbstream185xtradb55: $(TARGET) xbstream
181186
182$(XTRABACKUPOBJS): %.o: %.c187$(XTRABACKUPOBJS) $(UTILSCOREOBJS) $(REDOCOBJS) $(PAGECOBJS): %.o: %.c
183 $(CC) $(CFLAGS) $(INC) $(DEFS) -c $< -o $@188 $(CC) $(CFLAGS) $(INC) $(DEFS) -c $< -o $@
184189
185xbstream.o xbstream_read.o: %.o: %.c190xbstream.o xbstream_read.o: %.o: %.c
@@ -190,9 +195,13 @@
190195
191xtrabackup.o: xtrabackup.c xb_regex.h write_filt.h fil_cur.h xtrabackup.h196xtrabackup.o: xtrabackup.c xb_regex.h write_filt.h fil_cur.h xtrabackup.h
192197
193$(TARGET): $(XTRABACKUPOBJS) $(INNODBOBJS) $(MYSQLOBJS) $(LIBARCHIVE_A)198$(TARGET): $(EXTLINKOBJS) $(XTRABACKUPOBJS) $(INNODBOBJS) $(MYSQLOBJS) $(LIBARCHIVE_A)
194 $(CC) $(CFLAGS) $(XTRABACKUPOBJS) $(INNODBOBJS) $(MYSQLOBJS) $(LIBS) \199 $(CC) $(CFLAGS) $(EXTLINKOBJS) $(XTRABACKUPOBJS) $(INNODBOBJS) $(MYSQLOBJS) $(LIBS) \
195 $(LIBARCHIVE_A) -o $(TARGET)200 $(LIBARCHIVE_A) -o $(TARGET)
196201
202utils: $(UTILSCOBJS) $(INNODBOBJS) $(MYSQLOBJS) $(REDOCOBJS) $(PAGECOBJS)
203 $(CC) $(UTILSCOBJS) $(REDOCOBJS) $(INNODBOBJS) $(MYSQLOBJS) $(LIBS) -o percona-redo
204 $(CC) $(UTILSCOBJS) $(PAGECOBJS) $(INNODBOBJS) $(MYSQLOBJS) $(LIBS) -o percona-pprint
205
197clean:206clean:
198 rm -f $(XTRABACKUPOBJS) $(XBSTREAMOBJS) xtrabackup xtrabackup_* 207 rm -f $(UTILSCOBJS) $(XTRABACKUPOBJS) $(XBSTREAMOBJS) xtrabackup xtrabackup_*
199208
=== added file 'src/api_log.c'
--- src/api_log.c 1970-01-01 00:00:00 +0000
+++ src/api_log.c 2012-12-05 22:33:23 +0000
@@ -0,0 +1,1493 @@
1/*
2 * Copyright (C) 2012 Percona Inc.
3 * This program is free software: you can redistribute it and/or modify it
4 * under the terms of the GNU General Public License version 3, as published
5 * by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful, but
8 * WITHOUT ANY WARRANTY; without even the implied warranties of
9 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
10 * PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along
13 * with this program. If not, see <http://www.gnu.org/licenses/>.
14 */
15
16#define DULINT_STANDARD
17
18#include "api_log.h"
19#include "fil0fil.h"
20#include "log0log.h"
21#include "log0recv.h"
22#include "rem0rec.h"
23#include "os0file.h"
24#include "os0sync.h"
25#include "sync0sync.h"
26#include "srv0srv.h"
27
28#include "innodb_int.h"
29
30#define SRV_N_PENDING_IOS_PER_THREAD OS_AIO_N_PENDING_IOS_PER_THREAD
31#define SRV_MAX_N_PENDING_SYNC_IOS 100
32
33#ifndef MLOG_LSN
34 #define MLOG_LSN ((byte)28)
35#endif
36
37static const char* mlog_type_names[] = {
38 "undefined (0)",
39 "MLOG_1BYTE",
40 "MLOG_2BYTES",
41 "undefined (3)",
42 "MLOG_4BYTES",
43 "undefined (5)",
44 "undefined (6)",
45 "undefined (7)",
46 "MLOG_8BYTES",
47 "MLOG_REC_INSERT",
48 "MLOG_REC_CLUST_DELETE_MARK", /* 10 */
49 "MLOG_REC_SEC_DELETE_MARK",
50 "undefined (12)",
51 "MLOG_REC_UPDATE_IN_PLACE",
52 "MLOG_REC_DELETE",
53 "MLOG_LIST_END_DELETE",
54 "MLOG_LIST_START_DELETE",
55 "MLOG_LIST_END_COPY_CREATED",
56 "MLOG_PAGE_REORGANIZE",
57 "MLOG_PAGE_CREATE",
58 "MLOG_UNDO_INSERT", /* 20 */
59 "MLOG_UNDO_ERASE_END",
60 "MLOG_UNDO_INIT",
61 "MLOG_UNDO_HDR_DISCARD",
62 "MLOG_UNDO_HDR_REUSE",
63 "MLOG_UNDO_HDR_CREATE",
64 "MLOG_REC_MIN_MARK",
65 "MLOG_IBUF_BITMAP_INIT",
66 "MLOG_LSN",
67 "MLOG_INIT_FILE_PAGE",
68 "MLOG_WRITE_STRING", /* 30 */
69 "MLOG_MULTI_REC_END",
70 "MLOG_DUMMY_RECORD",
71 "MLOG_FILE_CREATE",
72 "MLOG_FILE_RENAME",
73 "MLOG_FILE_DELETE",
74 "MLOG_COMP_REC_MIN_MARK",
75 "MLOG_COMP_PAGE_CREATE",
76 "MLOG_COMP_REC_INSERT",
77 "MLOG_COMP_REC_CLUST_DELETE_MARK",
78 "MLOG_COMP_REC_SEC_DELETE_MARK", /* 40 */
79 "MLOG_COMP_REC_UPDATE_IN_PLACE",
80 "MLOG_COMP_REC_DELETE",
81 "MLOG_COMP_LIST_END_DELETE",
82 "MLOG_COMP_LIST_START_DELETE",
83 "MLOG_COMP_LIST_END_COPY_CREATED",
84 "MLOG_COMP_PAGE_REORGANIZE",
85 "MLOG_FILE_CREATE2",
86 "MLOG_ZIP_WRITE_NODE_PTR",
87 "MLOG_ZIP_WRITE_BLOB_PTR",
88 "MLOG_ZIP_WRITE_HEADER", /* 50 */
89 "MLOG_ZIP_PAGE_COMPRESS"
90};
91
92/* Informaton about single log record */
93struct ib_log_rec_struct
94{
95 ib_uint64_t lsn; /* record's LSN */
96 ulint len; /* length */
97 byte type; /* type MLOG_* */
98 ulint space; /* space id or ULINT_UNDEFINED */
99 ulint page_no; /* page number or ULINT_UNDEFINED */
100 char* body_str; /* log record's body as string */
101 unsigned single_rec:1; /* set if MLOG_SINGLE_REC_FLAG
102 is set for record */
103};
104
105/* log iterator */
106struct ib_log_rec_itr_struct
107{
108 ib_uint64_t start_lsn; /* starting LSN */
109 ib_uint64_t end_lsn; /* end LSN */
110 ib_uint64_t block_start_lsn; /* OS_FILE_LOG_BLOCK_SIZE aligned LSN */
111 byte* read_buf; /* read buffer */
112 byte* read_buf_ptr; /* pointer to current record in read buffer */
113 byte* parse_buf; /* parse buffer */
114 byte* parse_buf_ptr; /* pointer to current record in parse buffer */
115 byte* parse_buf_end; /* end of parse buffer */
116 ulint scanned_checkpoint_no; /* last checkpoint stored in the log data */
117 ibool eof; /* TRUE if end of scanned interval reached */
118 ib_uint64_t next_parse_lsn; /* LSN of next record to be parsed */
119 struct ib_log_rec_struct current_rec; /* current log record */
120};
121
122/*********************************************************************//**
123Initialize InnoDB systems needed for the log printer
124@return DB_SUCCESS if successfull */
125HAILDB_API
126ib_err_t
127ib_log_sys_start(
128/*=============*/
129 ib_ulint_t log_buf_size, /*!< in: the size of the buffer */
130 const char* log_dir) /*!< in: path to InnoDB log files. */
131{
132 ibool log_file_created = TRUE;
133 ib_err_t err;
134 ulint i;
135
136 innodb_init_param_for_util("./", log_dir, 1024*1024, log_buf_size, TRUE);
137
138 srv_max_n_threads = 1;
139 srv_normalize_init_values();
140 ut_mem_init();
141
142 srv_n_read_io_threads = srv_n_write_io_threads = 1;
143 srv_n_file_io_threads = 2 + srv_n_read_io_threads +
144 srv_n_write_io_threads;
145 os_sync_init();
146 sync_init();
147 // os_io_init_simple();
148 os_aio_init(8 * SRV_N_PENDING_IOS_PER_THREAD,
149 srv_n_read_io_threads,
150 srv_n_write_io_threads,
151 SRV_MAX_N_PENDING_SYNC_IOS);
152
153 mem_init(1);
154 fil_init(10, 10);
155 log_init();
156 recv_sys_create();
157
158 for (i = 0; i < srv_n_log_files; i++) {
159 err = open_or_create_log_file(FALSE, &log_file_created, TRUE, 0, 0);
160 if (err != DB_SUCCESS) {
161 ib_log_sys_stop();
162 return err;
163 }
164
165 if (log_file_created) {
166 ib_logger(ib_stream,
167 "Something wrong with source files...\n");
168 return DB_ERROR;
169 }
170 }
171
172 /* open_or_create_log_file will set srv_log_file_size. Normalize the
173 init values again to get srv_log_file_size/srv_log_file_curr_size in
174 sync. */
175 srv_normalize_init_values();
176
177 return DB_SUCCESS;
178}
179
180/*********************************************************************//**
181Uninitialize InnoDB systems needed for the log printer */
182HAILDB_API
183void
184ib_log_sys_stop(void)
185{
186 recv_sys_close();
187 recv_sys_mem_free();
188 fil_close_all_files();
189 log_shutdown();
190 log_mem_free();
191 sync_close();
192 os_sync_free();
193 fil_close();
194 mem_close();
195 ut_free_all_mem();
196}
197
198/*********************************************************************//**
199Find last consistent checkpoint LSN in log groups */
200HAILDB_API
201ib_err_t
202ib_log_sys_find_last_checkpoint_lsn(
203/*================================*/
204 ib_u64_t* last_checkpoint_lsn) /*!< out: last checkpoint LSN */
205{
206 log_group_t* max_cp_group;
207 ulint max_cp_field;
208
209 mutex_enter(&log_sys->mutex);
210
211 uint err = recv_find_max_checkpoint(&max_cp_group, &max_cp_field);
212 if (err != DB_SUCCESS)
213 return err;
214
215 log_group_read_checkpoint_info(max_cp_group, max_cp_field);
216 *last_checkpoint_lsn
217 = mach_read_ull(log_sys->checkpoint_buf + LOG_CHECKPOINT_LSN);
218
219 mutex_exit(&log_sys->mutex);
220
221 return DB_SUCCESS;
222}
223
224/*********************************************************************//**
225Create iterator through log records */
226HAILDB_API
227ib_log_rec_itr_t
228ib_log_sys_create_iterator(
229/*=======================*/
230 ib_u64_t start_lsn, /*!< in: starting LSN */
231 ib_u64_t end_lsn) /*!< in: last LSN */
232{
233 ib_log_rec_itr_t result = mem_alloc(sizeof(*result));
234
235 result->start_lsn = start_lsn;
236 result->end_lsn = end_lsn;
237 result->block_start_lsn = ut_uint64_align_down(start_lsn,
238 OS_FILE_LOG_BLOCK_SIZE);
239 result->read_buf = mem_alloc(RECV_SCAN_SIZE);
240 /* Pointing to the end of buffer will trigger the first read */
241 result->read_buf_ptr = result->read_buf + RECV_SCAN_SIZE;
242 result->parse_buf = mem_alloc(RECV_PARSING_BUF_SIZE);
243 result->parse_buf_ptr = result->parse_buf;
244 result->parse_buf_end = result->parse_buf;
245 result->scanned_checkpoint_no = 0;
246 result->eof = FALSE;
247 result->next_parse_lsn = result->block_start_lsn;
248
249 result->current_rec.lsn = IB_ULONGLONG_MAX;
250 result->current_rec.len = ULINT_UNDEFINED;
251 result->current_rec.type = MLOG_BIGGEST_TYPE + 1;
252 result->current_rec.space = ULINT_UNDEFINED;
253 result->current_rec.page_no = ULINT_UNDEFINED;
254 result->current_rec.body_str = NULL;
255 return result;
256}
257
258/*********************************************************************//**
259For the given minilog record type determines if the record has (space; page)
260associated with it.
261@return TRUE if the record has (space; page) in it */
262static
263ibool
264log_online_rec_has_page(
265/*====================*/
266 byte type) /*!<in: the minilog record type */
267{
268 return type != MLOG_MULTI_REC_END && type != MLOG_DUMMY_RECORD;
269}
270
271
272
273/*********************************************************************//**
274Copies new log data to the parse buffer while skipping log block header,
275and trailer. The decision how much to copy here is taken from
276recv_sys_add_to_parsing_buf but simplified. */
277static
278void
279log_online_add_to_parse_buf(
280/*========================*/
281 const byte* log_block, /*!< in: read log data */
282 ulint start_offset, /*!< in: data start offset */
283 ulint data_len, /*!< in: length of read log data */
284 byte* parse_buf, /*!< in: the parse buffer */
285 byte** parse_buf_end) /*!< in/out: end of parse buffer */
286{
287 ulint end_offset
288 = (data_len == OS_FILE_LOG_BLOCK_SIZE)
289 ? data_len - LOG_BLOCK_TRL_SIZE
290 : data_len;
291 ulint actual_data_len = (end_offset >= start_offset)
292 ? end_offset - start_offset : 0;
293
294 ut_a (start_offset >= LOG_BLOCK_HDR_SIZE);
295
296 if ((*parse_buf_end + actual_data_len - parse_buf)
297 > RECV_PARSING_BUF_SIZE) {
298
299 ib_logger(ib_stream, "Parse buffer overflow! Most likely "
300 "caused by corrupt log data. In the case of "
301 "correct log increase RECV_PARSING_BUF_SIZE\n");
302 ib_logger(ib_stream, "Discarding the overflowing data, some "
303 "records will be skipped\n");
304 actual_data_len
305 = RECV_PARSING_BUF_SIZE - (*parse_buf_end - parse_buf);
306 }
307
308 ut_memcpy(*parse_buf_end, log_block + start_offset, actual_data_len);
309 *parse_buf_end += actual_data_len;
310 ut_ad (*parse_buf_end - parse_buf <= RECV_PARSING_BUF_SIZE);
311}
312
313/*********************************************************************//**
314Checks if the log block checksum is OK. TODO: with comparisson to log0recv
315checks, this one drops the scanned no vs. no in the log check.
316TODO: copy-paste with innodb-changed-page-tracking log0online.c
317@return TRUE if the log block checksum is OK, FALSE otherwise. */
318static
319ibool
320log_online_is_valid_log_seg(
321/*========================*/
322 const byte* log_block) /*!< in: read log data */
323{
324 ibool checksum_is_ok
325 = log_block_checksum_is_ok_or_old_format(log_block);
326
327 if (!checksum_is_ok) {
328 /* Garbage or an incompletely written log block */
329
330 ib_logger(ib_stream,
331 "Log block checksum mismatch: "
332 "expected %lu, calculated checksum %lu\n",
333 (ulong) log_block_get_checksum(log_block),
334 (ulong) log_block_calc_checksum(log_block));
335 }
336
337 return checksum_is_ok;
338}
339
340/*********************************************************************//**
341Checks if the log block is in fact garbage from a log buffer flush which was
342made before the most recent database recovery.
343@return TRUE if log block is garbage from the flush */
344static
345ibool
346log_online_is_garbage_log_seg(
347/*==========================*/
348 const byte* log_block, /*!< in: read log data */
349 ulint scanned_checkpoint_no) /*!< in: last checkpoint
350 stored in the log data */
351{
352 return (scanned_checkpoint_no > 0)
353 && (log_block_get_checkpoint_no(log_block)
354 < scanned_checkpoint_no)
355 && (scanned_checkpoint_no
356 - log_block_get_checkpoint_no(log_block)
357 > 0x80000000UL);
358}
359
360/*********************************************************************//**
361Copy consistent piece of data from the read buffer to the parse buffer.
362@return TRUE if data been copied */
363static
364ibool
365fill_parse_buffer(
366/*==============*/
367 ib_log_rec_itr_t itr) /*!< in: log records iterator */
368{
369 ulint block_data_len;
370 ulint data_start_offset = LOG_BLOCK_HDR_SIZE;
371
372 if (itr->eof)
373 return FALSE;
374
375 if (itr->read_buf_ptr == itr->read_buf + RECV_SCAN_SIZE) {
376
377 ib_uint64_t read_end_lsn;
378 log_group_t* group;
379
380 /* Read buf empty, read more recs if there are any */
381 read_end_lsn = itr->block_start_lsn + RECV_SCAN_SIZE;
382 group = UT_LIST_GET_FIRST(log_sys->log_groups);
383 ut_a(group);
384
385 /* Single-threaded operation, no mutexes */
386 mutex_enter(&log_sys->mutex);
387 log_group_read_log_seg(LOG_RECOVER, itr->read_buf, group,
388 itr->block_start_lsn, read_end_lsn);
389 mutex_exit(&log_sys->mutex);
390 itr->read_buf_ptr = itr->read_buf;
391 }
392
393 /* Read buffer has some data, process and move one block to the parse
394 * buffer. */
395 if (!log_online_is_valid_log_seg(itr->read_buf_ptr)) {
396 return FALSE;
397 }
398
399 if (log_online_is_garbage_log_seg(itr->read_buf_ptr,
400 itr->scanned_checkpoint_no)) {
401 return FALSE;
402 }
403
404 block_data_len = log_block_get_data_len(itr->read_buf_ptr);
405
406 if (itr->next_parse_lsn == itr->block_start_lsn) {
407
408 /* First read, find the start of the first complete record
409 group in this block */
410 ut_a (itr->start_lsn
411 < (itr->block_start_lsn + OS_FILE_LOG_BLOCK_SIZE));
412 data_start_offset
413 = log_block_get_first_rec_group(itr->read_buf_ptr);
414 /* TODO: is this the correct way to handle 0 return value? */
415 if (data_start_offset == 0)
416 data_start_offset = LOG_BLOCK_HDR_SIZE;
417 itr->next_parse_lsn += data_start_offset;
418 }
419 ut_ad (block_data_len % OS_FILE_LOG_BLOCK_SIZE == 0
420 || block_data_len < OS_FILE_LOG_BLOCK_SIZE);
421
422 log_online_add_to_parse_buf(itr->read_buf_ptr, data_start_offset,
423 block_data_len, itr->parse_buf,
424 &itr->parse_buf_end);
425
426 /* TODO: check itr->scanned_checkpoint_no */
427 itr->scanned_checkpoint_no
428 = log_block_get_checkpoint_no(itr->read_buf_ptr);
429
430 if (block_data_len < OS_FILE_LOG_BLOCK_SIZE)
431 itr->eof = TRUE;
432
433 if (!itr->eof) {
434 itr->block_start_lsn += OS_FILE_LOG_BLOCK_SIZE;
435 itr->read_buf_ptr += OS_FILE_LOG_BLOCK_SIZE;
436 }
437
438 return TRUE;
439}
440
441static char buf[RECV_SCAN_SIZE];
442
443/*********************************************************************//**
444Parse index data and format it in human-readable form to static buffer.
445@return end of data copied to buffer */
446static
447char *
448ib_log_sys_parse_index(
449/*===================*/
450 byte** ptr) /*!< in/out: pointer to log data */
451{
452 char* buf_end = buf;
453 ulint n_uniq;
454 ulint n = mach_read_from_2(*ptr);
455 unsigned i;
456 *ptr += 2;
457 n_uniq = mach_read_from_2(*ptr);
458 *ptr += 2;
459 buf_end += snprintf(buf, RECV_SCAN_SIZE, "n: %lu, n_unique: %lu",
460 n, n_uniq);
461 for (i = 0; i < n; i++) {
462 ulint len = mach_read_from_2(*ptr);
463 *ptr += 2;
464 buf_end += snprintf(buf_end, RECV_SCAN_SIZE - (buf_end - buf),
465 ", len%u: %lu", i, len);
466 }
467 return buf_end;
468}
469
470/*********************************************************************//**
471Parse system fields of log record. */
472static
473void
474ib_log_sys_parse_sys_fields(
475/*========================*/
476 byte** ptr, /*!< in/out: pointer to log data */
477 byte* body_end, /*!< in: pointer to end of
478 a log record body */
479 ulint* pos, /*!< out: position */
480 trx_id_t* trx_id, /*!< out: trx id */
481 roll_ptr_t* roll_ptr) /*!< out: roll pointer */
482{
483 *ptr = mach_parse_compressed(*ptr, body_end, pos);
484 *roll_ptr = mach_read_from_7(*ptr);
485 *ptr += 7;
486 *ptr = mach_dulint_parse_compressed(*ptr, body_end, trx_id);
487}
488
489/*********************************************************************//**
490Parse the redo log record for delete marking or unmarking of a clustered
491index record. */
492static
493void
494ib_log_sys_parse_del_mark_set_clust_rec(
495/*====================================*/
496 ib_log_rec_itr_t itr, /*!< in/out: log iterator */
497 byte** ptr, /*!< in/out: pointer to
498 log data */
499 byte* body_end) /*!< in: pointer to end of a
500 log record body */
501{
502 ulint val;
503 ulint pos;
504 roll_ptr_t roll_ptr;
505 trx_id_t trx_id;
506 ulint offset;
507 int ret;
508 ulint flags = mach_read_from_1(*ptr);
509 (*ptr)++;
510 val = mach_read_from_1(*ptr);
511 (*ptr)++;
512 ib_log_sys_parse_sys_fields(ptr, body_end, &pos, &trx_id, &roll_ptr);
513 offset = mach_read_from_2(*ptr);
514 *ptr += 2;
515 ret = asprintf(&itr->current_rec.body_str,
516 "%sflags: 0x%lX, value: 0x%lX, position: 0x%lX, "
517 "roll_ptr: 0x%llX, trx_id: 0x%llX, offset: 0x%lX",
518 buf, flags, val, pos,
519 ut_conv_dulint_to_longlong(roll_ptr),
520 ut_conv_dulint_to_longlong(trx_id), offset);
521 ut_a (ret > 0);
522}
523
524/*********************************************************************//**
525Dump a log record as a hex string */
526static
527void
528ib_log_sys_output_raw(
529/*==================*/
530 byte** ptr, /*!< in/out: pointer to log data */
531 byte* body_end, /*!< in: pointer to end of a log record body */
532 char** buf_end) /*!< in/out: pointer to end of output buffer */
533{
534 while (*ptr != body_end) {
535 *buf_end += snprintf(*buf_end,
536 RECV_SCAN_SIZE - (*buf_end - buf),
537 " %02X", **ptr);
538 (*ptr)++;
539 }
540}
541
542/*********************************************************************//**
543Parse update of a compact record */
544static
545void
546ib_log_sys_parse_update_in_place(
547/*=============================*/
548 ib_log_rec_itr_t itr, /*!< in/out: log iterator */
549 byte** ptr, /*!< in/out: pointer to
550 log data */
551 byte* body_end) /*!< in: pointer to end of
552 a log record body */
553{
554 char *buf_end = buf + strlen(buf);
555 ulint pos;
556 roll_ptr_t roll_ptr;
557 trx_id_t trx_id;
558 ulint offset;
559 ulint info_bits;
560 ulint n_fields;
561 unsigned i;
562 ulint flags = mach_read_from_1(*ptr);
563 (*ptr)++;
564 ib_log_sys_parse_sys_fields(ptr, body_end, &pos, &trx_id, &roll_ptr);
565 offset = mach_read_from_2(*ptr);
566 *ptr += 2;
567 info_bits = mach_read_from_1(*ptr);
568 (*ptr)++;
569 *ptr = mach_parse_compressed(*ptr, body_end, &n_fields);
570 buf_end += snprintf(buf_end, RECV_SCAN_SIZE - (buf_end - buf),
571 "flags: 0x%lX, position: 0x%lX, roll_ptr: 0x%llX, "
572 "trx_id: 0x%llX, offset: 0x%lX, info_bits: 0x%lX, "
573 "n_fields: %lu", flags, pos,
574 ut_conv_dulint_to_longlong(roll_ptr),
575 ut_conv_dulint_to_longlong(trx_id), offset,
576 info_bits, n_fields);
577 for (i = 0; i < n_fields; i++) {
578 ulint field_no;
579 ulint len;
580 *ptr = mach_parse_compressed(*ptr, body_end, &field_no);
581 buf_end += snprintf(buf_end, RECV_SCAN_SIZE - (buf_end - buf),
582 ", field_no_%d: %lu", i, field_no);
583 *ptr = mach_parse_compressed(*ptr, body_end, &len);
584 if (len != UNIV_SQL_NULL) {
585 buf_end += snprintf(buf_end,
586 RECV_SCAN_SIZE - (buf_end - buf),
587 ", data_len_%d: %lu, data:", i,
588 len);
589 ib_log_sys_output_raw(ptr, *ptr + len, &buf_end);
590 }
591 else {
592 buf_end += snprintf(buf_end,
593 RECV_SCAN_SIZE - (buf_end - buf),
594 ", data_len_%d: UNIV_SQL_NULL", i);
595 }
596 }
597 itr->current_rec.body_str = strdup(buf);
598}
599
600/*********************************************************************//**
601Parse delete record list */
602static
603void
604ib_log_sys_parse_delete_rec_list(
605/*=============================*/
606 ib_log_rec_itr_t itr, /*!< in/out: log iterator */
607 byte** ptr) /*!< in/out: pointer to log data */
608{
609 ulint offset = mach_read_from_2(*ptr);
610 char *buf_end = buf + strlen(buf);
611 *ptr += 2;
612 buf_end += snprintf(buf_end, RECV_SCAN_SIZE - (buf_end - buf),
613 "offset: %lu", offset);
614 itr->current_rec.body_str = strdup(buf);
615}
616
617/*********************************************************************//**
618Read info bits of insert record */
619static
620void
621ib_log_sys_parse_info_origin_mismatch(
622/*==================================*/
623 byte** ptr, /*!< in/out: pointer to log data */
624 byte* body_end, /*!< in: pointer to end of a log record body */
625 char** buf_end) /*!< in/out: pointer to end of output buffer */
626{
627 ulint origin_offset;
628 ulint mismatch_index;
629 ulint info_and_status_bits = mach_read_from_1(*ptr);
630 (*ptr)++;
631 *ptr = mach_parse_compressed(*ptr, body_end, &origin_offset);
632 *ptr = mach_parse_compressed(*ptr, body_end, &mismatch_index);
633 *buf_end += snprintf(*buf_end, RECV_SCAN_SIZE - (*buf_end - buf),
634 ", info_status_bits: 0x%lX, origin_offset: %lu, "
635 "mismatch_index: %lu",
636 info_and_status_bits, origin_offset,
637 mismatch_index);
638}
639
640/*********************************************************************//**
641Parse compact record insert */
642static
643void
644ib_log_sys_parse_rec_insert(
645/*========================*/
646 ib_log_rec_itr_t itr, /*!< in/out: log iterator */
647 byte** ptr, /*!< in/out: pointer to
648 log data */
649 byte* body_end) /*!< in: pointer to end of a log
650 record body */
651{
652 char* buf_end = buf;
653 ulint end_seg_len;
654 ulint offset = mach_read_from_2(*ptr);
655 *ptr += 2;
656 *ptr = mach_parse_compressed(*ptr, body_end, &end_seg_len);
657 buf_end += snprintf(buf_end, RECV_SCAN_SIZE - (buf_end - buf),
658 "offset: %lu, end_seg_len: %lu", offset,
659 end_seg_len);
660 if (end_seg_len & 0x1UL) {
661
662 ib_log_sys_parse_info_origin_mismatch(ptr, body_end,
663 &buf_end);
664 }
665 strcpy(buf_end, ", data:");
666 buf_end += strlen(", data:");
667 ib_log_sys_output_raw(ptr, *ptr + (end_seg_len >> 1), &buf_end);
668 itr->current_rec.body_str = strdup(buf);
669}
670
671/*********************************************************************//**
672Parse copy record list end to a new created index page */
673static
674void
675ib_log_sys_parse_end_list_copy(
676/*===========================*/
677 ib_log_rec_itr_t itr, /*!< in/out: log iterator */
678 byte** ptr, /*!< in/out: pointer to
679 log data */
680 byte* body_end) /*!< in: pointer to end of a
681 log record body */
682{
683 char *buf_end = buf + strlen(buf);
684 ulint data_len = mach_read_from_4(*ptr);
685 *ptr += 4;
686 buf_end += snprintf(buf_end, RECV_SCAN_SIZE - (buf_end - buf),
687 "len: %lu", data_len);
688 while (*ptr < body_end) {
689 ulint end_seg_len;
690 *ptr = mach_parse_compressed(*ptr, body_end, &end_seg_len);
691 buf_end += snprintf(buf_end, RECV_SCAN_SIZE - (buf_end - buf),
692 ", end_seg_len: %lu", end_seg_len);
693 if (end_seg_len & 0x1UL) {
694
695 ib_log_sys_parse_info_origin_mismatch(ptr, body_end,
696 &buf_end);
697 }
698 strcpy(buf_end, ", data:");
699 buf_end += strlen(", data:");
700 ib_log_sys_output_raw(ptr, *ptr + (end_seg_len >> 1),
701 &buf_end);
702 }
703 itr->current_rec.body_str = strdup(buf);
704}
705
706/*********************************************************************//**
707Parse delete record from the page */
708static
709void
710ib_log_sys_parse_delete_rec(
711/*========================*/
712 ib_log_rec_itr_t itr, /*!< in/out: log iterator */
713 byte** ptr) /*!< in/out: pointer to log data */
714{
715 char* buf_end = buf + strlen(buf);
716 ulint offset = mach_read_from_2(*ptr);
717 *ptr += 2;
718 buf_end += snprintf(buf, RECV_SCAN_SIZE, "offset: %lu", offset);
719 itr->current_rec.body_str = strdup(buf);
720}
721
722/*********************************************************************//**
723Parse a file operation record */
724static
725void
726ib_log_sys_parse_fil_op(
727/*====================*/
728 ib_log_rec_itr_t itr, /*!< in/out: log iterator */
729 byte** ptr, /*!< in/out: pointer to
730 log data */
731 char** buf_end) /*!< in: pointer to end of a
732 log record body */
733{
734 const char* name;
735 ulint name_len = mach_read_from_2(*ptr);
736 *ptr += 2;
737 name = (const char *)(*ptr);
738 *ptr += name_len;
739 *buf_end += snprintf(*buf_end, RECV_SCAN_SIZE - (*buf_end - buf),
740 "name_len: %lu, name: \"%s\"", name_len, name);
741 if (itr->current_rec.type == MLOG_FILE_RENAME) {
742 const char* new_name;
743 ulint new_name_len = mach_read_from_2(*ptr);
744 *ptr += 2;
745 new_name = (const char *)(*ptr);
746 *ptr += new_name_len;
747 *buf_end += snprintf(*buf_end,
748 RECV_SCAN_SIZE - (*buf_end - buf),
749 ", new_name_len: %lu, new_name: \"%s\"",
750 new_name_len, new_name);
751 }
752 itr->current_rec.body_str = strdup(buf);
753}
754
755/*********************************************************************//**
756Get name of operation with compressed page */
757static
758const char*
759ib_log_sys_get_zip_op_name(
760/*=======================*/
761 byte type) /*!< in: log record type */
762{
763 if (type == MLOG_ZIP_WRITE_NODE_PTR)
764 return "node_ptr";
765 if (type == MLOG_ZIP_WRITE_BLOB_PTR)
766 return "blob_ptr";
767 ut_a (0);
768 return "WRONG TYPE";
769}
770
771/*********************************************************************//**
772Get pointer length for operation with compressed page */
773static
774ulint
775ib_log_sys_get_zip_op_ptr_len(
776/*==========================*/
777 byte type) /*!< in: log record type */
778{
779 if (type == MLOG_ZIP_WRITE_NODE_PTR)
780 return REC_NODE_PTR_SIZE;
781 if (type == MLOG_ZIP_WRITE_BLOB_PTR)
782 return BTR_EXTERN_FIELD_REF_SIZE;
783 ut_a (0);
784 return ULINT_UNDEFINED;
785}
786
787/*********************************************************************//**
788Parse operation with compressed page */
789static
790void
791ib_log_sys_parse_zip_op(
792/*====================*/
793 ib_log_rec_itr_t itr, /*!< in/out: log iterator */
794 byte** ptr) /*!< in/out: pointer to log data */
795{
796 char* buf_end = buf;
797 ulint z_offset;
798 ulint offset = mach_read_from_2(*ptr);
799 *ptr += 2;
800 z_offset = mach_read_from_2(*ptr);
801 *ptr += 2;
802 buf_end += snprintf(buf_end,
803 RECV_SCAN_SIZE - (buf_end - buf),
804 "offset: %lu, zip_offset: %lu, "
805 "%s:",
806 offset, z_offset,
807 ib_log_sys_get_zip_op_name(itr->current_rec.type));
808 ib_log_sys_output_raw(ptr, *ptr + ib_log_sys_get_zip_op_ptr_len(
809 itr->current_rec.type), &buf_end);
810 itr->current_rec.body_str = strdup(buf);
811}
812
813/*********************************************************************//**
814Parse log record body */
815static
816void
817ib_log_sys_parse_rec_body(
818/*======================*/
819 ib_log_rec_itr_t itr, /*!< in/out: log iterator */
820 byte* body_start, /*!< in: pointer to start of
821 a log record body */
822 byte* body_end) /*!< in: pointer to end of a log
823 record body */
824{
825 byte* ptr = body_start;
826
827 ut_a (ib_log_sys_rec_has_body(&itr->current_rec) || ptr == NULL
828 || body_start == body_end);
829 if (ptr == NULL)
830 ptr = body_end;
831
832 buf[0] = '\0';
833
834 if (itr->current_rec.body_str) {
835
836 free (itr->current_rec.body_str);
837 itr->current_rec.body_str = NULL;
838 }
839
840 switch (itr->current_rec.type) {
841 case MLOG_1BYTE:
842 case MLOG_2BYTES:
843 case MLOG_4BYTES:
844 {
845 ulint offset = mach_read_from_2(ptr);
846 ulint val;
847 int ret;
848 ptr += 2;
849 ptr = mach_parse_compressed(ptr, body_end, &val);
850 ret = asprintf(&itr->current_rec.body_str,
851 "offset: %lu, value: 0x%lX", offset,
852 val);
853 ut_a (ret > 0);
854 break;
855 }
856 case MLOG_8BYTES:
857 {
858 ulint offset = mach_read_from_2(ptr);
859 dulint val;
860 int ret;
861 ptr += 2;
862 ptr = mach_dulint_parse_compressed(ptr, body_end,
863 &val);
864 ret = asprintf(&itr->current_rec.body_str,
865 "offset: %lu, value: 0x%llX", offset,
866 ut_conv_dulint_to_longlong(val));
867 ut_a (ret > 0);
868 break;
869 }
870 case MLOG_REC_INSERT:
871 ib_log_sys_parse_rec_insert(itr, &ptr, body_end);
872 break;
873 case MLOG_COMP_REC_INSERT:
874 ib_log_sys_parse_index(&ptr);
875 ib_log_sys_parse_rec_insert(itr, &ptr, body_end);
876 break;
877 case MLOG_COMP_PAGE_REORGANIZE:
878 ib_log_sys_parse_index(&ptr);
879 itr->current_rec.body_str = strdup(buf);
880 break;
881 case MLOG_COMP_REC_CLUST_DELETE_MARK:
882 {
883 char* buf_end = ib_log_sys_parse_index(&ptr);
884 *buf_end++ = ',';
885 *buf_end++ = ' ';
886 ib_log_sys_parse_del_mark_set_clust_rec(itr, &ptr,
887 body_end);
888 break;
889 }
890 case MLOG_REC_SEC_DELETE_MARK:
891 {
892 int ret;
893 ulint offset;
894 ulint val = mach_read_from_1(ptr);
895 ptr++;
896 offset = mach_read_from_2(ptr);
897 ptr += 2;
898 ret = asprintf(&itr->current_rec.body_str,
899 "value: %lu, offset: %lu", val, offset);
900 ut_a(ret > 0);
901 break;
902 }
903 case MLOG_REC_CLUST_DELETE_MARK:
904 ib_log_sys_parse_del_mark_set_clust_rec(itr, &ptr, body_end);
905 break;
906 case MLOG_REC_UPDATE_IN_PLACE:
907 ib_log_sys_parse_update_in_place(itr, &ptr, body_end);
908 break;
909 case MLOG_COMP_REC_UPDATE_IN_PLACE:
910 {
911 char* buf_end = ib_log_sys_parse_index(&ptr);
912 *buf_end++ = ',';
913 *buf_end++ = ' ';
914 ib_log_sys_parse_update_in_place(itr, &ptr, body_end);
915 break;
916 }
917 case MLOG_LIST_END_DELETE:
918 case MLOG_LIST_START_DELETE:
919 /* TODO: test */
920 ib_log_sys_parse_delete_rec_list(itr, &ptr);
921 break;
922 case MLOG_COMP_LIST_END_DELETE:
923 case MLOG_COMP_LIST_START_DELETE:
924 {
925 char* buf_end = ib_log_sys_parse_index(&ptr);
926 *buf_end++ = ','; *buf_end++ = ' '; *buf_end++ = '\0';
927 ib_log_sys_parse_delete_rec_list(itr, &ptr);
928 break;
929 }
930 case MLOG_LIST_END_COPY_CREATED:
931 /* TODO: test */
932 ib_log_sys_parse_end_list_copy(itr, &ptr, body_end);
933 break;
934 case MLOG_COMP_LIST_END_COPY_CREATED:
935 {
936 char* buf_end = ib_log_sys_parse_index(&ptr);
937 *buf_end++ = ',';
938 *buf_end++ = ' ';
939 ib_log_sys_parse_end_list_copy(itr, &ptr, body_end);
940 break;
941 }
942 case MLOG_UNDO_INSERT:
943 {
944 char* buf_end = buf;
945 ulint data_len = mach_read_from_2(ptr);
946 ptr += 2;
947 buf_end += snprintf(buf_end,
948 RECV_SCAN_SIZE - (buf_end - buf),
949 "data_len: %lu, data:", data_len);
950 ib_log_sys_output_raw(&ptr, ptr + data_len, &buf_end);
951 itr->current_rec.body_str = strdup(buf);
952 break;
953 }
954 case MLOG_UNDO_INIT:
955 {
956 int ret;
957 ulint undo_log_seg_type;
958 ptr = mach_parse_compressed(ptr, body_end,
959 &undo_log_seg_type);
960 ret = asprintf(&itr->current_rec.body_str,
961 "undo_log_seg_type: %lu",
962 undo_log_seg_type);;
963 ut_a (ret > 0);
964 break;
965 }
966 case MLOG_UNDO_HDR_CREATE:
967 case MLOG_UNDO_HDR_REUSE:
968 {
969 int ret;
970 trx_id_t trx_id;
971 /* TODO: test _REUSE */
972 ptr = mach_dulint_parse_compressed(ptr, body_end,
973 &trx_id);
974 ret = asprintf(&itr->current_rec.body_str,
975 "trx_id: 0x%llX",
976 ut_conv_dulint_to_longlong(trx_id));
977 ut_a (ret > 0);
978 break;
979 }
980 case MLOG_REC_MIN_MARK:
981 case MLOG_COMP_REC_MIN_MARK:
982 {
983 /* TODO: test MLOG_REC_MIN_MARK */
984 int ret;
985 ulint min_rec_mark_offset = mach_read_from_2(ptr);
986 ptr += 2;
987 ret = asprintf(&itr->current_rec.body_str,
988 "min_rec_mark_offset: %lu",
989 min_rec_mark_offset);
990 ut_a (ret > 0);
991 break;
992 }
993 case MLOG_REC_DELETE:
994 ib_log_sys_parse_delete_rec(itr, &ptr);
995 break;
996 case MLOG_COMP_REC_DELETE:
997 {
998 char* buf_end = ib_log_sys_parse_index(&ptr);
999 *buf_end++ = ',';
1000 *buf_end++ = ' ';
1001 ib_log_sys_parse_delete_rec(itr, &ptr);
1002 break;
1003 }
1004 case MLOG_WRITE_STRING:
1005 {
1006 ulint data_len;
1007 char* buf_end = buf;
1008 ulint offset = mach_read_from_2(ptr);
1009 ptr += 2;
1010 data_len = mach_read_from_2(ptr);
1011 ptr += 2;
1012 buf_end += snprintf(buf_end,
1013 RECV_SCAN_SIZE - (buf_end - buf),
1014 "offset: %lu, data_len: %lu, "
1015 "data:", offset, data_len);
1016 ib_log_sys_output_raw(&ptr, ptr + data_len, &buf_end);
1017 itr->current_rec.body_str = strdup(buf);
1018 break;
1019 }
1020 case MLOG_FILE_CREATE2:
1021 {
1022 /* TODO: test */
1023 char* buf_end = buf;
1024 ulint flags = mach_read_from_4(ptr);
1025 ptr += 4;
1026 buf_end += snprintf(buf_end,
1027 RECV_SCAN_SIZE - (buf_end - buf),
1028 "flags: 0x%lX:", flags);
1029 *buf_end++ = ',';
1030 *buf_end++ = ' ';
1031 ib_log_sys_parse_fil_op(itr, &ptr, &buf_end);
1032 break;
1033 }
1034 case MLOG_FILE_CREATE:
1035 case MLOG_FILE_RENAME:
1036 case MLOG_FILE_DELETE:
1037 {
1038 char* buf_end = buf;
1039 ib_log_sys_parse_fil_op(itr, &ptr, &buf_end);
1040 break;
1041 }
1042 case MLOG_ZIP_WRITE_NODE_PTR:
1043 case MLOG_ZIP_WRITE_BLOB_PTR:
1044 /* TODO: test */
1045 ib_log_sys_parse_zip_op(itr, &ptr);
1046 break;
1047 case MLOG_ZIP_WRITE_HEADER:
1048 {
1049 /* TODO: test */
1050 ulint offset = *ptr++;
1051 ulint data_len = *ptr++;
1052 char* buf_end = buf;
1053 buf_end += snprintf(buf_end,
1054 RECV_SCAN_SIZE - (buf_end - buf),
1055 "offset: %lu, data_len: %lu, "
1056 "data:", offset, data_len);
1057 ib_log_sys_output_raw(&ptr, ptr + data_len, &buf_end);
1058 itr->current_rec.body_str = strdup(buf);
1059 break;
1060 }
1061 case MLOG_ZIP_PAGE_COMPRESS:
1062 {
1063 /* TODO: test */
1064 char* buf_end = buf;
1065 ulint trailer_size;
1066 ulint size = mach_read_from_2(ptr);
1067 ptr += 2;
1068 trailer_size = mach_read_from_2(ptr);
1069 ptr += 2;
1070 buf_end += snprintf(buf_end,
1071 RECV_SCAN_SIZE - (buf_end - buf),
1072 "data_size: %lu, "
1073 "trailer_size: %lu, page_prev:",
1074 size, trailer_size);
1075 ib_log_sys_output_raw(&ptr, ptr + 4, &buf_end);
1076 ptr += 4;
1077 buf_end += snprintf(buf_end,
1078 RECV_SCAN_SIZE - (buf_end - buf),
1079 ", page_next:");
1080 ib_log_sys_output_raw(&ptr, ptr + 4, &buf_end);
1081 ptr += 4;
1082 buf_end += snprintf(buf_end,
1083 RECV_SCAN_SIZE - (buf_end - buf),
1084 ", data:");
1085 ib_log_sys_output_raw(&ptr, ptr + size, &buf_end);
1086 ptr += size;
1087 buf_end += snprintf(buf_end,
1088 RECV_SCAN_SIZE - (buf_end - buf),
1089 ", trailer_data:");
1090 ib_log_sys_output_raw(&ptr, ptr + trailer_size,
1091 &buf_end);
1092 ptr += trailer_size;
1093 itr->current_rec.body_str = strdup(buf);
1094 break;
1095 }
1096 case MLOG_INIT_FILE_PAGE:
1097 case MLOG_IBUF_BITMAP_INIT:
1098 case MLOG_UNDO_HDR_DISCARD: /* TODO: test */
1099 case MLOG_PAGE_REORGANIZE: /* TODO: test */
1100 case MLOG_PAGE_CREATE:
1101 case MLOG_COMP_PAGE_CREATE:
1102 case MLOG_UNDO_ERASE_END:
1103 case MLOG_MULTI_REC_END:
1104 case MLOG_DUMMY_RECORD:
1105 case MLOG_LSN:
1106 /* No body */
1107 break;
1108 default: ;
1109 ib_logger(ib_stream, "Corrupt log rec at LSN = %llu, ",
1110 itr->current_rec.lsn);
1111 ut_a(0);
1112 }
1113 ut_a (ptr == body_end);
1114}
1115
1116/*********************************************************************//**
1117Get next log record */
1118HAILDB_API
1119ib_log_rec_t
1120ib_log_sys_get_next_rec(
1121/*====================*/
1122 ib_log_rec_itr_t itr) /*!< in: log iterator */
1123{
1124 ulint len;
1125 byte type;
1126 ulint space;
1127 ulint page_no;
1128 byte* body;
1129
1130 /* Already reached the end of requested LSN range? */
1131 if (itr->next_parse_lsn >= itr->end_lsn)
1132 return NULL;
1133
1134 if (itr->parse_buf_ptr == itr->parse_buf_end) {
1135
1136 /* Parse buf empty */
1137 if (!fill_parse_buffer(itr))
1138 return NULL;
1139 }
1140
1141 /* Have some data in the parse buf, parse it */
1142 recv_sys->found_corrupt_log = FALSE;
1143 len = recv_parse_log_rec(itr->parse_buf_ptr, itr->parse_buf_end, &type,
1144 &space, &page_no, &body);
1145 if (recv_sys->found_corrupt_log) {
1146
1147 /* Uh-oh, corrupt log. Now what? */
1148 ib_logger(ib_stream, "Corrupt log at LSN = %llu, "
1149 "proceeding in 1 byte increments, "
1150 "no correct parse guarantee and InnoDB may crash!\n",
1151 itr->next_parse_lsn);
1152 itr->parse_buf_ptr++;
1153 itr->next_parse_lsn
1154 = recv_calc_lsn_on_data_add(itr->next_parse_lsn, 1);
1155 return ib_log_sys_get_next_rec(itr);
1156 }
1157 if (len > 0) {
1158
1159 /* Full rec, see if its LSN is inside the requested range */
1160 if (itr->next_parse_lsn >= itr->start_lsn) {
1161
1162 itr->current_rec.single_rec
1163 = (*itr->parse_buf_ptr & MLOG_SINGLE_REC_FLAG)
1164 != 0;
1165 itr->current_rec.lsn = itr->next_parse_lsn;
1166 itr->current_rec.len = len;
1167 itr->current_rec.type = type;
1168
1169 if (log_online_rec_has_page(type)) {
1170
1171 itr->current_rec.space = space;
1172 itr->current_rec.page_no = page_no;
1173 }
1174 else {
1175
1176 itr->current_rec.space = ULINT_UNDEFINED;
1177 itr->current_rec.page_no = ULINT_UNDEFINED;
1178 }
1179
1180 itr->parse_buf_ptr += len;
1181 ib_log_sys_parse_rec_body(itr, body,
1182 itr->parse_buf_ptr);
1183
1184 itr->next_parse_lsn
1185 = recv_calc_lsn_on_data_add(
1186 itr->next_parse_lsn, len);
1187
1188 return &itr->current_rec;
1189 }
1190 else if (itr->next_parse_lsn < itr->start_lsn) {
1191
1192 /* Full rec but below the requested LSN range. Eat it,
1193 try the next one. */
1194 itr->parse_buf_ptr += len;
1195 itr->next_parse_lsn
1196 = recv_calc_lsn_on_data_add(
1197 itr->next_parse_lsn, len);
1198 return ib_log_sys_get_next_rec(itr);
1199 }
1200 else {
1201
1202 /* Rec past the requested LSN range, EOF */
1203 ut_a (itr->next_parse_lsn > itr->end_lsn);
1204 return NULL;
1205 }
1206 }
1207
1208 /* Incomplete rec. Shift it to the beginning of the parse buffer, get
1209 more data and parse it again. */
1210 ut_memmove(itr->parse_buf, itr->parse_buf_ptr,
1211 itr->parse_buf_end - itr->parse_buf_ptr);
1212 itr->parse_buf_end = itr->parse_buf
1213 + (itr->parse_buf_end - itr->parse_buf_ptr);
1214 itr->parse_buf_ptr = itr->parse_buf;
1215
1216 if (!fill_parse_buffer(itr)) {
1217
1218 ib_logger(ib_stream, "Incomplete record at LSN = %llu\n",
1219 itr->next_parse_lsn);
1220 return NULL;
1221 }
1222 return ib_log_sys_get_next_rec(itr);
1223}
1224
1225/*********************************************************************//**
1226Get LSN of record */
1227HAILDB_API
1228ib_u64_t
1229ib_log_sys_get_rec_lsn(
1230/*===================*/
1231 const ib_log_rec_t log_rec) /*!< in: log record */
1232{
1233 return log_rec->lsn;
1234}
1235
1236/*********************************************************************//**
1237Get length of record */
1238HAILDB_API
1239ib_ulint_t
1240ib_log_sys_get_rec_len(
1241/*===================*/
1242 const ib_log_rec_t log_rec) /*!< in: log record */
1243{
1244 return log_rec->len;
1245}
1246
1247/*********************************************************************//**
1248Get log record type (MLOG_*) */
1249HAILDB_API
1250ib_byte_t
1251ib_log_sys_get_rec_type(
1252/*====================*/
1253 const ib_log_rec_t log_rec) /*!< in: log record */
1254{
1255 return log_rec->type;
1256}
1257
1258/*********************************************************************//**
1259@return TRUE if MLOG_SINGLE_REC_FLAG is set for log record */
1260HAILDB_API
1261ib_bool_t
1262ib_log_sys_get_single_rec_flag(
1263/*===========================*/
1264 const ib_log_rec_t log_rec) /*!< in: log record */
1265{
1266 return log_rec->single_rec != 0;
1267}
1268
1269/*********************************************************************//**
1270@return space id associated with log record or ULINT_UNDEFINED if
1271record doesn't have space id associated */
1272HAILDB_API
1273ib_ulint_t
1274ib_log_sys_get_rec_space(
1275/*=====================*/
1276 const ib_log_rec_t log_rec) /*!< in: log record */
1277{
1278 if (!log_online_rec_has_page(log_rec->type))
1279 ut_a (log_rec->space == ULINT_UNDEFINED);
1280 return log_rec->space;
1281}
1282
1283/*********************************************************************//**
1284@return page id associated with log record or ULINT_UNDEFINED if
1285record doesn't have page id associated */
1286HAILDB_API
1287ib_ulint_t
1288ib_log_sys_get_rec_page_no(
1289/*=======================*/
1290 const ib_log_rec_t log_rec) /*!< in: log record */
1291{
1292 if (!log_online_rec_has_page(log_rec->type))
1293 ut_a (log_rec->page_no == ULINT_UNDEFINED);
1294 return log_rec->page_no;
1295}
1296
1297/*********************************************************************//**
1298Release log iterator */
1299HAILDB_API
1300void
1301ib_log_sys_free_iterator(
1302/*=====================*/
1303 ib_log_rec_itr_t itr) /*!< in: log iterator */
1304{
1305 mem_free(itr->read_buf);
1306 mem_free(itr->parse_buf);
1307 mem_free(itr);
1308}
1309
1310/*********************************************************************//**
1311@return page id associated with log record or ULINT_UNDEFINED if
1312record doesn't have page id associated */
1313HAILDB_API
1314const char *
1315ib_log_sys_get_rec_name(
1316/*====================*/
1317 const ib_log_rec_t log_rec) /*!< in: log record */
1318{
1319 byte type = ib_log_sys_get_rec_type(log_rec);
1320 if (type < sizeof(mlog_type_names) / sizeof(char*))
1321 return mlog_type_names[type];
1322 return "undefined";
1323}
1324
1325/*********************************************************************//**
1326@return TRUE if is log record about an .ibd file operation */
1327HAILDB_API
1328ib_bool_t
1329ib_log_sys_rec_has_mlog_file_flag(
1330/*==============================*/
1331 const ib_log_rec_t log_rec) /*!< in: log record */
1332{
1333 return log_rec->type == MLOG_FILE_CREATE
1334 || log_rec->type == MLOG_FILE_RENAME
1335 || log_rec->type == MLOG_FILE_DELETE
1336 || log_rec->type == MLOG_FILE_CREATE2;
1337}
1338
1339/*********************************************************************//**
1340@return TRUE if MLOG_FILE_FLAG_TEMP is set */
1341HAILDB_API
1342ib_bool_t
1343ib_log_sys_get_mlog_file_flag_temp(
1344/*===============================*/
1345 const ib_log_rec_t log_rec) /*!< in: log record */
1346{
1347 ut_ad (ib_log_sys_rec_has_mlog_file_flag(log_rec));
1348 return ib_log_sys_get_rec_page_no(log_rec) & MLOG_FILE_FLAG_TEMP;
1349}
1350
1351/*********************************************************************//**
1352@return TRUE if record of type MLOG_LSN (LSN pseudo-record) */
1353HAILDB_API
1354ib_bool_t
1355ib_log_sys_is_mlog_lsn_rec(
1356/*=======================*/
1357 const ib_log_rec_t log_rec) /*!< in: log record */
1358{
1359 return log_rec->type == MLOG_LSN;
1360}
1361
1362/*********************************************************************//**
1363@return LSN from lsn pseudo-record */
1364HAILDB_API
1365ib_u64_t
1366ib_log_sys_get_mlog_lsn(
1367/*====================*/
1368 const ib_log_rec_t log_rec) /*!< in: log record */
1369{
1370 ut_a (ib_log_sys_is_mlog_lsn_rec(log_rec));
1371 return (ib_u64_t)log_rec->space << 32 | log_rec->page_no;
1372}
1373
1374/*********************************************************************//**
1375@return TRUE if log record has body */
1376HAILDB_API
1377ib_bool_t
1378ib_log_sys_rec_has_body(
1379/*====================*/
1380 const ib_log_rec_t log_rec) /*!< in: log record */
1381{
1382 return log_rec->type != MLOG_MULTI_REC_END
1383 && log_rec->type != MLOG_DUMMY_RECORD
1384 && log_rec->type != MLOG_LSN
1385 && log_rec->type != MLOG_PAGE_REORGANIZE
1386 && log_rec->type != MLOG_PAGE_CREATE
1387 && log_rec->type != MLOG_COMP_PAGE_CREATE
1388 && log_rec->type != MLOG_UNDO_ERASE_END
1389 && log_rec->type != MLOG_UNDO_HDR_DISCARD
1390 && log_rec->type != MLOG_IBUF_BITMAP_INIT
1391 && log_rec->type != MLOG_INIT_FILE_PAGE;
1392}
1393
1394/*********************************************************************//**
1395@return log record's body as string */
1396HAILDB_API
1397const char*
1398ib_log_sys_get_rec_body_str(
1399/*========================*/
1400 const ib_log_rec_t log_rec) /*!< in: log record */
1401{
1402 ut_ad (ib_log_sys_rec_has_body(log_rec));
1403 return log_rec->body_str;
1404}
1405
1406/*********************************************************************//**
1407Print log records in human-readable format */
1408ibool
1409ib_log_sys_print(
1410/*=============*/
1411 ib_uint64_t start_lsn, /*!< in: parse start LSN.
1412 0 for START_LSN_LAST_CP */
1413 ib_uint64_t end_lsn, /*!< in: parse end LSN.
1414 IB_ULONGLONG_MAX for log to be
1415 parsed to the end */
1416 ulint filter_space, /*!< in: Space ID to filter
1417 records on or ULINT_UNDEFINED */
1418 ulint filter_page, /*!< in: Page ID to filter
1419 records on or ULINT_UNDEFINED */
1420 ibool numeric, /*!< in: TRUE for output log
1421 item type byte values instead of
1422 mnemonics */
1423 ibool print_rec_bodies) /*!< in: TRUE for print log
1424 record body contents */
1425{
1426 ib_err_t ib_err;
1427
1428 if (start_lsn == 0) {
1429 ib_logger(ib_stream, "Reading last checkpoint LSN\n");
1430 ib_err = ib_log_sys_find_last_checkpoint_lsn(&start_lsn);
1431 if (ib_err != DB_SUCCESS) {
1432 ib_logger(ib_stream,
1433 "ib_log_sys_find_last_checkpoint_lsn: %d\n",
1434 ib_err);
1435 return FALSE;
1436 }
1437 }
1438
1439 ib_logger(ib_stream, "Reading InnoDB redo logs "
1440 "from LSN %llu to %llu\n",
1441 start_lsn, end_lsn);
1442
1443 ib_log_rec_itr_t log_rec_iterator =
1444 ib_log_sys_create_iterator(start_lsn, end_lsn);
1445 ib_log_rec_t log_rec;
1446
1447 while ((log_rec = ib_log_sys_get_next_rec(log_rec_iterator)) != NULL) {
1448
1449 ib_ulint_t space = ib_log_sys_get_rec_space(log_rec);
1450 ib_ulint_t page = ib_log_sys_get_rec_page_no(log_rec);
1451
1452 if ((filter_space != ULINT_UNDEFINED && space != filter_space)
1453 || (filter_page != ULINT_UNDEFINED
1454 && page != filter_page))
1455 continue;
1456
1457 ib_logger(ib_stream, "{LSN: %llu, len: %lu, type: ",
1458 ib_log_sys_get_rec_lsn(log_rec),
1459 ib_log_sys_get_rec_len(log_rec));
1460 if (numeric) {
1461 ib_logger(ib_stream,
1462 "%d", ib_log_sys_get_rec_type(log_rec));
1463 } else {
1464 ib_logger(ib_stream,
1465 "%s", ib_log_sys_get_rec_name(log_rec));
1466 }
1467 ib_logger(ib_stream, ", singlerec: %d",
1468 (ib_log_sys_get_single_rec_flag(log_rec) ? 1 : 0));
1469
1470 if (ib_log_sys_rec_has_mlog_file_flag(log_rec)) {
1471 ib_logger(ib_stream, ", MLOG_FILE_FLAG_TEMP: %d",
1472 (ib_log_sys_get_mlog_file_flag_temp(log_rec) ?
1473 1 : 0));
1474 } else if (ib_log_sys_is_mlog_lsn_rec(log_rec)) {
1475 ib_logger(ib_stream, ", mloglsn: %llu",
1476 ib_log_sys_get_mlog_lsn(log_rec));
1477 } else if (space != ULINT_UNDEFINED) {
1478 ib_logger(ib_stream, ", space: %lu, page: %lu",
1479 space, page);
1480 } else {
1481 assert(page == ULINT_UNDEFINED);
1482 }
1483
1484 if (print_rec_bodies && ib_log_sys_rec_has_body(log_rec))
1485 {
1486 ib_logger(ib_stream, ", %s",
1487 ib_log_sys_get_rec_body_str(log_rec));
1488 }
1489 ib_logger(ib_stream, "}\n");
1490 }
1491 ib_log_sys_free_iterator(log_rec_iterator);
1492 return TRUE;
1493}
01494
=== added file 'src/api_log.h'
--- src/api_log.h 1970-01-01 00:00:00 +0000
+++ src/api_log.h 2012-12-05 22:33:23 +0000
@@ -0,0 +1,213 @@
1/*
2 * Copyright (C) 2012 Percona Inc.
3 * This program is free software: you can redistribute it and/or modify it
4 * under the terms of the GNU General Public License version 3, as published
5 * by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful, but
8 * WITHOUT ANY WARRANTY; without even the implied warranties of
9 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
10 * PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along
13 * with this program. If not, see <http://www.gnu.org/licenses/>.
14 */
15
16#ifndef api_log_h
17#define api_log_h
18
19#include "univ.i"
20#include "innodb_int.h"
21
22#ifdef __cplusplus
23extern "C" {
24#endif /* __cplusplus */
25
26#define HAILDB_API UNIV_INTERN
27
28typedef struct ib_log_rec_itr_struct* ib_log_rec_itr_t;
29
30typedef struct ib_log_rec_struct* ib_log_rec_t;
31
32/*********************************************************************//**
33Initialize InnoDB systems needed for the log printer
34@return DB_SUCCESS if successfull */
35HAILDB_API
36ib_err_t
37ib_log_sys_start(
38/*=============*/
39 ib_ulint_t log_buf_size, /*!< in: the size of the buffer */
40 const char* log_dir); /*!< in: path to InnoDB log files. */
41
42/*********************************************************************//**
43Uninitialize InnoDB systems needed for the log printer */
44HAILDB_API
45void
46ib_log_sys_stop(void);
47
48/*********************************************************************//**
49Find last consistent checkpoint LSN in log groups */
50HAILDB_API
51ib_err_t
52ib_log_sys_find_last_checkpoint_lsn(
53/*================================*/
54 ib_u64_t* last_checkpoint_lsn); /*!< out: last checkpoint LSN */
55
56/*********************************************************************//**
57Create iterator through log records */
58HAILDB_API
59ib_log_rec_itr_t
60ib_log_sys_create_iterator(
61/*=======================*/
62 ib_u64_t start_lsn, /*!< in: starting LSN */
63 ib_u64_t end_lsn); /*!< in: last LSN */
64
65/*********************************************************************//**
66Get next log record */
67HAILDB_API
68ib_log_rec_t
69ib_log_sys_get_next_rec(
70/*====================*/
71 ib_log_rec_itr_t itr); /*!< in: log iterator */
72
73/*********************************************************************//**
74Release log iterator */
75HAILDB_API
76void
77ib_log_sys_free_iterator(
78/*=====================*/
79 ib_log_rec_itr_t itr); /*!< in: log iterator */
80
81/*********************************************************************//**
82Get LSN of record */
83HAILDB_API
84ib_u64_t
85ib_log_sys_get_rec_lsn(
86/*===================*/
87 const ib_log_rec_t log_rec); /*!< in: log record */
88
89/*********************************************************************//**
90Get length of record */
91HAILDB_API
92ib_ulint_t
93ib_log_sys_get_rec_len(
94/*===================*/
95 const ib_log_rec_t log_rec); /*!< in: log record */
96
97/*********************************************************************//**
98Get log record type (MLOG_*) */
99HAILDB_API
100ib_byte_t
101ib_log_sys_get_rec_type(
102/*====================*/
103 const ib_log_rec_t log_rec); /*!< in: log record */
104
105
106/*********************************************************************//**
107@return TRUE if MLOG_SINGLE_REC_FLAG is set for log record */
108HAILDB_API
109ib_bool_t
110ib_log_sys_get_single_rec_flag(
111/*===========================*/
112 const ib_log_rec_t log_rec); /*!< in: log record */
113
114/*********************************************************************//**
115@return space id associated with log record or ULINT_UNDEFINED if
116record doesn't have space id associated */
117HAILDB_API
118ib_ulint_t
119ib_log_sys_get_rec_space(
120/*=====================*/
121 const ib_log_rec_t log_rec); /*!< in: log record */
122
123/*********************************************************************//**
124@return page id associated with log record or ULINT_UNDEFINED if
125record doesn't have page id associated */
126HAILDB_API
127ib_ulint_t
128ib_log_sys_get_rec_page_no(
129/*=======================*/
130 const ib_log_rec_t log_rec); /*!< in: log record */
131
132/*********************************************************************//**
133@return page id associated with log record or ULINT_UNDEFINED if
134record doesn't have page id associated */
135HAILDB_API
136const char *
137ib_log_sys_get_rec_name(
138/*====================*/
139 const ib_log_rec_t log_rec); /*!< in: log record */
140
141/*********************************************************************//**
142@return TRUE if is log record about an .ibd file operation */
143HAILDB_API
144ib_bool_t
145ib_log_sys_rec_has_mlog_file_flag(
146/*==============================*/
147 const ib_log_rec_t log_rec); /*!< in: log record */
148
149/*********************************************************************//**
150@return TRUE if MLOG_FILE_FLAG_TEMP is set */
151HAILDB_API
152ib_bool_t
153ib_log_sys_get_mlog_file_flag_temp(
154/*===============================*/
155 const ib_log_rec_t log_rec); /*!< in: log record */
156
157/*********************************************************************//**
158@return TRUE if record of type MLOG_LSN (LSN pseudo-record) */
159HAILDB_API
160ib_bool_t
161ib_log_sys_is_mlog_lsn_rec(
162/*=======================*/
163 const ib_log_rec_t log_rec); /*!< in: log record */
164
165/*********************************************************************//**
166@return LSN from lsn pseudo-record */
167HAILDB_API
168ib_u64_t
169ib_log_sys_get_mlog_lsn(
170/*====================*/
171 const ib_log_rec_t log_rec); /*!< in: log record */
172
173/*********************************************************************//**
174@return TRUE if log record has body */
175HAILDB_API
176ib_bool_t
177ib_log_sys_rec_has_body(
178/*====================*/
179 const ib_log_rec_t log_rec); /*!< in: log record */
180
181/*********************************************************************//**
182@return log record's body as string */
183HAILDB_API
184const char*
185ib_log_sys_get_rec_body_str(
186/*========================*/
187 const ib_log_rec_t log_rec); /*!< in: log record */
188
189/*********************************************************************//**
190Print log records in human-readable format */
191ibool
192ib_log_sys_print(
193/*=============*/
194 ib_uint64_t start_lsn, /*!< in: parse start LSN.
195 0 for START_LSN_LAST_CP */
196 ib_uint64_t end_lsn, /*!< in: parse end LSN.
197 IB_ULONGLONG_MAX for log to be
198 parsed to the end */
199 ulint filter_space, /*!< in: Space ID to filter
200 records on or ULINT_UNDEFINED */
201 ulint filter_page, /*!< in: Page ID to filter
202 records on or ULINT_UNDEFINED */
203 ibool numeric, /*!< in: TRUE for output log
204 item type byte values instead of
205 mnemonics */
206 ibool print_rec_bodies); /*!< in: TRUE for print log
207 record body contents */
208
209#ifdef __cplusplus
210} /* extern "C" */
211#endif /* __cplusplus */
212
213#endif
0214
=== added file 'src/api_page.c'
--- src/api_page.c 1970-01-01 00:00:00 +0000
+++ src/api_page.c 2012-12-05 22:33:23 +0000
@@ -0,0 +1,3522 @@
1/*
2 * Copyright (C) 2012 Percona Inc.
3 * This program is free software: you can redistribute it and/or modify it
4 * under the terms of the GNU General Public License version 3, as published
5 * by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful, but
8 * WITHOUT ANY WARRANTY; without even the implied warranties of
9 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
10 * PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along
13 * with this program. If not, see <http://www.gnu.org/licenses/>.
14 */
15
16#define DULINT_STANDARD
17
18#include <fil0fil.h>
19#include <log0log.h>
20#include <log0recv.h>
21#include <rem0rec.h>
22#include <os0file.h>
23#include <os0sync.h>
24#include <sync0sync.h>
25#include <srv0srv.h>
26#include <fsp0fsp.h>
27#include <buf0buf.h>
28#include <trx0undo.h>
29#include <btr0btr.h>
30#include <page0page.h>
31#include <page0zip.h>
32#include <lock0lock.h>
33#include <btr0pcur.h>
34#include <ibuf0ibuf.h>
35#include <dict0load.h>
36#include <dict0boot.h>
37#include <trx0rec.h>
38#include <row0upd.h>
39#include <row0row.h>
40#include <fsp0fsp.h>
41#include <data0type.h>
42#include <dict0boot.h>
43#include <srv0start.h>
44#include "api_page.h"
45#include "innodb_int.h"
46
47#ifndef DATA_VARCLIENT
48#define DATA_VARCLIENT DATA_VARMYSQL
49#define DATA_CLIENT DATA_MYSQL
50#endif
51
52#define SRV_N_PENDING_IOS_PER_THREAD OS_AIO_N_PENDING_IOS_PER_THREAD
53#define SRV_MAX_N_PENDING_SYNC_IOS 100
54
55#ifndef IBUF_PAGE_SIZE_PER_FREE_SPACE
56
57/** An index page must contain at least UNIV_PAGE_SIZE /
58IBUF_PAGE_SIZE_PER_FREE_SPACE bytes of free space for ibuf to try to
59buffer inserts to this page. If there is this much of free space, the
60corresponding bits are set in the ibuf bitmap. */
61#define IBUF_PAGE_SIZE_PER_FREE_SPACE 32
62
63/** Insert buffer struct */
64struct ibuf_struct{
65 ulint size; /*!< current size of the ibuf index
66 tree, in pages */
67 ulint max_size; /*!< recommended maximum size of the
68 ibuf index tree, in pages */
69 ulint seg_size; /*!< allocated pages of the file
70 segment containing ibuf header and
71 tree */
72 ibool empty; /*!< after an insert to the ibuf tree
73 is performed, this is set to FALSE,
74 and if a contract operation finds
75 the tree empty, this is set to
76 TRUE */
77 ulint free_list_len; /*!< length of the free list */
78 ulint height; /*!< tree height */
79 dict_index_t* index; /*!< insert buffer index */
80
81 ulint n_inserts; /*!< number of inserts made to
82 the insert buffer */
83 ulint n_merges; /*!< number of pages merged */
84 ulint n_merged_recs; /*!< number of records merged */
85};
86
87#endif
88
89/***************************************************************//**
90Print undo log page. */
91UNIV_INTERN
92void
93ib_page_print_undo(
94/*===============*/
95 const page_t* page); /*!< in: page */
96
97/***************************************************************//**
98Determine direction name.
99@return direction name. */
100UNIV_INTERN
101const char*
102ib_page_page_cursor_direction(
103/*==========================*/
104 ulint direction); /*!< in: direction */
105
106/***************************************************************//**
107Dump raw field as hex and ascii. */
108UNIV_INTERN
109void
110ib_page_print_field_hex_asc(
111/*========================*/
112 const rec_t* rec, /*!< in: physical record */
113 ulint i); /*!< in: field number */
114
115/***************************************************************//**
116Format externally stored field. */
117UNIV_INTERN
118void
119ib_page_format_ext(
120/*===============*/
121 char* buf, /*!< out: buffer */
122 ulint buf_len, /*!< in: buffer length */
123 const rec_t* rec, /*!< in: physical record */
124 ulint no, /*!< in: field number */
125 const ulint* offsets); /*!< in: array returned by
126 rec_get_offsets() */
127
128/***************************************************************//**
129Hex dump of page. */
130UNIV_INTERN
131void
132ib_page_print_hex_dump(
133/*===================*/
134 const page_t* page, /*!< in: page */
135 ulint zip_size); /*!< in: compressed page size, or
136 0 for uncompressed pages */
137
138/***************************************************************//**
139Print page dictionary header. */
140UNIV_INTERN
141void
142ib_page_print_dict_header(
143/*======================*/
144 const page_t* page); /*!< in: page */
145
146/***************************************************************//**
147@return XDES state as string. */
148UNIV_INTERN
149const char*
150ib_page_xdes_state_str(
151/*===================*/
152 ulint state); /*!< in: XDES state */
153
154/***************************************************************//**
155Print XDES page. */
156UNIV_INTERN
157void
158ib_page_print_xdes(
159/*===============*/
160 const page_t* page, /*!< in: page */
161 ulint zip_size); /*!< in: compressed page size, or
162 0 for uncompressed pages */
163
164/***************************************************************//**
165Create IBUF index in data dictionary. */
166UNIV_INTERN
167void
168ib_page_ibuf_index_create(void);
169/*============================*/
170
171/***************************************************************//**
172Load a table object based on the index id.
173@return table; NULL if table does not exist */
174UNIV_INTERN
175dict_table_t*
176ib_page_load_table_for_index(
177/*=========================*/
178 dulint index_id); /*!< in: index id */
179
180/***************************************************************//**
181Allocate signle aligned page.
182@return page */
183UNIV_INTERN
184page_t*
185ib_page_page_alloc();
186
187/***************************************************************//**
188Allocate signle aligned page.
189@return page */
190UNIV_INTERN
191page_t*
192ib_page_heap_page_alloc(
193/*====================*/
194 mem_heap_t* heap); /*!< in: memory heap where allocate in */
195
196/***************************************************************//**
197Get space id of given tablespace in file.
198@return space id if given tablespace file */
199UNIV_INTERN
200ulint
201ib_page_file_space_id(
202/*==================*/
203 os_file_t file); /*!< in: file */
204
205/***************************************************************//**
206Calculate the low 32 bits and the high 32 bits
207of the file offset. */
208UNIV_INTERN
209void
210ib_page_calc_offsets(
211/*=================*/
212 ulint zip_size, /*!< in: compressed page size, or
213 0 for uncompressed pages */
214 ulint page_no, /*!< in: page number */
215 ulint* offset_low, /*!< out: low 32 bits */
216 ulint* offset_high); /*!< out: high 32 bits */
217
218/***************************************************************//**
219Load compressed page into memory.
220Space for page allocated in heap.
221@return loaded page; NULL if page was not loaded */
222UNIV_INTERN
223page_t*
224ib_page_load_compressed(
225/*====================*/
226 os_file_t file, /*!< in: file */
227 ulint page_no, /*!< in: page number */
228 ulint zip_size, /*!< in: compressed page size, or
229 0 for uncompressed pages */
230 mem_heap_t* heap); /*!< in: memory heap */
231
232/***************************************************************//**
233Decompress compressed page.
234Space for decompressed page allocated in heap.
235@return loaded page; NULL if page was not loaded */
236UNIV_INTERN
237page_t*
238ib_page_decompress(
239/*===============*/
240 const page_t* compressed_page,/*!< in: compressed page */
241 ulint zip_size, /*!< in: compressed page size, or
242 0 for uncompressed pages */
243 mem_heap_t* heap); /*!< in: memory heap */
244
245/***************************************************************//**
246Test if page if IBUF page.
247@return TRUE if page is IBUF page; FALE otherwise */
248UNIV_INTERN
249ibool
250ib_page_page_is_ibuf(
251/*=================*/
252 const page_t* page); /*!< in: page */
253
254/***************************************************************//**
255Test if page is UNDO INSERT page.
256@return TRUE if page is UNDO INSERT page; FALE otherwise */
257UNIV_INTERN
258ibool
259ib_page_is_undo_insert(
260/*===================*/
261 const page_t* page); /*!< in: page */
262
263/***************************************************************//**
264Test if page is UNDO UPDATE page.
265@return TRUE if page is UNDO UPDATE page; FALE otherwise */
266UNIV_INTERN
267ibool
268ib_page_is_undo_update(
269/*===================*/
270 const page_t* page); /*!< in: page */
271
272/***************************************************************//**
273Test if page is UNDO page.
274@return TRUE if page is UNDO page; FALE otherwise */
275UNIV_INTERN
276ibool
277ib_page_is_undo(
278/*============*/
279 const page_t* page); /*!< in: page */
280
281/***************************************************************//**
282Print file-based list address. */
283UNIV_INTERN
284void
285ib_page_print_flst_addr(
286/*====================*/
287 const byte* base); /*!< in: pointer to base node of list */
288
289/***************************************************************//**
290Print file-based list. */
291UNIV_INTERN
292void
293ib_page_print_flst(
294/*===============*/
295 const byte* base); /*!< in: pointer to base node of list */
296
297/***************************************************************//**
298Print filespace header page. */
299UNIV_INTERN
300void
301ib_page_print_fsp_header(
302/*=====================*/
303 const page_t* page); /*!< in: page */
304
305/***************************************************************//**
306Print ZBLOB page. */
307UNIV_INTERN
308void
309ib_page_print_zblob(
310/*================*/
311 const page_t* page, /*!< in: page */
312 ulint zip_size); /*!< in: compressed page size, or
313 0 for uncompressed pages */
314
315/***************************************************************//**
316Print ZBLOB2 page. */
317UNIV_INTERN
318void
319ib_page_print_zblob2(
320/*=================*/
321 const page_t* page, /*!< in: page */
322 ulint zip_size); /*!< in: compressed page size, or
323 0 for uncompressed pages */
324
325/***************************************************************//**
326Print BLOB page. */
327UNIV_INTERN
328void
329ib_page_print_blob(
330/*===============*/
331 const page_t* page); /*!< in: page */
332
333/***************************************************************//**
334Print inode page. */
335UNIV_INTERN
336void
337ib_page_print_inode(
338/*================*/
339 const page_t* page, /*!< in: page */
340 ulint zip_size); /*!< in: compressed page size, or
341 0 for uncompressed pages */
342
343/***************************************************************//**
344Print a physical record. */
345UNIV_INTERN
346void
347ib_page_rec_print_new(
348/*==================*/
349 ib_stream_t ib_stream, /*!< in: stream where to print */
350 const page_t* page, /*!< in: page */
351 const rec_t* rec, /*!< in: physical record */
352 const ulint* offsets, /*!< in: array returned by
353 rec_get_offsets() */
354 dict_index_t* index); /*!< in: index */
355
356
357/***************************************************************//**
358Print an old-style physical record. */
359UNIV_INTERN
360void
361ib_page_rec_print_old(
362/*==================*/
363 ib_stream_t ib_stream, /*!< in: stream where to print */
364 const page_t* page,
365 const rec_t* rec, /*!< in: physical record */
366 const ulint* offsets, /*!< in: array returned by
367 rec_get_offsets() */
368 dict_index_t* index); /*!< in: index */
369
370/***************************************************************//**
371Prints a physical record in ROW_FORMAT=COMPACT. Ignores the
372record header. */
373UNIV_INTERN
374void
375ib_page_rec_print_comp(
376/*===================*/
377 ib_stream_t ib_stream, /*!< in: streamwhere to print */
378 const page_t* page,
379 const rec_t* rec, /*!< in: physical record */
380 const ulint* offsets, /*!< in: array returned by
381 rec_get_offsets() */
382 dict_index_t* index); /*!< in: index */
383
384/*******************************************************************//**
385Copy types of fields contained in index to tuple. */
386UNIV_INTERN
387void
388ib_page_dict_index_copy_types(
389/*==========================*/
390 dtuple_t* tuple, /*!< in/out: data tuple */
391 const dict_index_t* index, /*!< in: index */
392 ulint n_fields, /*!< in: number of
393 field types to copy */
394 ibool is_leaf_page); /*!< in: TRUE if leas page */
395
396/*******************************************************************//**
397Converts an index record to a typed data tuple.
398@return index entry built; does not set info_bits, and the data fields
399in the entry will point directly to rec */
400UNIV_INTERN
401dtuple_t*
402ib_page_row_rec_to_index_entry_low(
403/*===============================*/
404 const page_t* page,
405 const rec_t* rec, /*!< in: record in the index */
406 const dict_index_t* index, /*!< in: index */
407 const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */
408 ulint* n_ext, /*!< out: number of externally
409 stored columns */
410 mem_heap_t* heap); /*!< in: memory heap from which
411 the memory needed is allocated */
412
413/*******************************************************************//**
414Converts an index record to a typed data tuple.
415@return index entry built; does not set info_bits, and the data fields
416in the entry will point directly to rec */
417UNIV_INTERN
418dtuple_t*
419ib_page_row_rec_to_index_entry_low(
420/*===============================*/
421 const page_t* page,
422 const rec_t* rec, /*!< in: record in the index */
423 const dict_index_t* index, /*!< in: index */
424 const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */
425 ulint* n_ext, /*!< out: number of externally
426 stored columns */
427 mem_heap_t* heap); /*!< in: memory heap from which
428 the memory needed is allocated */
429
430
431/*******************************************************************//**
432Converts an index record to a typed data tuple. NOTE that externally
433stored (often big) fields are NOT copied to heap.
434@return own: index entry built; see the NOTE below! */
435UNIV_INTERN
436dtuple_t*
437ib_page_row_rec_to_index_entry(
438/*===========================*/
439 ulint type, /*!< in: ROW_COPY_DATA, or
440 ROW_COPY_POINTERS: the former
441 copies also the data fields to
442 heap as the latter only places
443 pointers to data fields on the
444 index page */
445 const page_t* page,
446 const rec_t* rec, /*!< in: record in the index;
447 NOTE: in the case
448 ROW_COPY_POINTERS the data
449 fields in the row will point
450 directly into this record,
451 therefore, the buffer page of
452 this record must be at least
453 s-latched and the latch held
454 as long as the dtuple is used! */
455 const dict_index_t* index, /*!< in: index */
456 ulint* offsets,/*!< in/out: rec_get_offsets(rec) */
457 ulint* n_ext, /*!< out: number of externally
458 stored columns */
459 mem_heap_t* heap); /*!< in: memory heap from which
460 the memory needed is allocated */
461
462/*******************************************************************//**
463Load page from file into memory and decompress it if needed.
464@return TRUE on success */
465ibool
466ib_page_load(
467/*=========*/
468 const char* ibd_file_name, /*!< in: file name */
469 ulint page_no, /*!< in: page number */
470 ulint* zip_size, /*!< in: compressed page size, or
471 0 for uncompressed pages */
472 page_t** compressed_page, /*!< out: compressed page */
473 page_t** decompressed_page, /*!< out: decompressed page */
474 mem_heap_t* heap); /*!< out: memory heap */
475
476/*******************************************************************//**
477Print IBUF bitmap page. */
478UNIV_INTERN
479void
480ib_page_ibuf_bitmap_print(
481/*======================*/
482 const page_t* page, /*!< in: page */
483 ulint zip_size); /*!< in: compressed page size, or
484 0 for uncompressed pages */
485
486/*******************************************************************//**
487Format SYS value. */
488UNIV_INTERN
489void
490ib_page_format_sys(
491/*===============*/
492 ulint prtype, /*!< in: precise type */
493 char* buf, /*!< out: buffer */
494 ulint buf_len, /*!< in: buffer length */
495 const byte* data); /*!< in: field data */
496
497/*******************************************************************//**
498Format INT value. */
499UNIV_INTERN
500void
501ib_page_format_int(
502/*===============*/
503 ulint prtype, /*!< in: precise type */
504 char* buf, /*!< out: buffer */
505 ulint buf_len, /*!< in: buffer length */
506 const byte* data, /*!< in: field data */
507 ulint data_len); /*!< in: length of data */
508
509/*******************************************************************//**
510Format string value. */
511UNIV_INTERN
512void
513ib_page_format_str(
514/*===============*/
515 char* buf, /*!< out: buffer */
516 ulint buf_len, /*!< in: buffer length */
517 const byte* data, /*!< in: field data */
518 ulint data_len); /*!< in: length of data */
519
520/*******************************************************************//**
521Format binalry value. */
522UNIV_INTERN
523void
524ib_page_format_bin(
525/*===============*/
526 char* buf, /*!< out: buffer */
527 ulint buf_len, /*!< in: buffer length */
528 const byte* data, /*!< in: field data */
529 ulint data_len); /*!< in: length of data */
530
531/*******************************************************************//**
532Print field. */
533UNIV_INTERN
534void
535ib_page_rec_print_field(
536/*====================*/
537 const dfield_t* field, /*!< in: field */
538 const rec_t* rec, /*!< in: physical record */
539 ulint no, /*!< in: field number */
540 const ulint* offsets); /*!< in: array returned by
541 rec_get_offsets() */
542/********************************************************************//**
543Print first page header. */
544UNIV_INTERN
545void
546ib_buf_page_print_header(
547/*=====================*/
548 const byte* read_buf, /*!< in: a database page */
549 ulint zip_size); /*!< in: compressed page size, or
550 0 for uncompressed pages */
551
552/***************************************************************//**
553Print second page header. */
554UNIV_INTERN
555void
556ib_page_page_header_print(
557/*======================*/
558 const page_t* page); /*!< in: page */
559
560/***************************************************************//**
561Print the contents of the directory. */
562UNIV_INTERN
563void
564ib_page_page_dir_print(
565/*===================*/
566 const page_t* page); /*!< in: index page */
567
568/************************************************************//**
569Print record contents including the data relevant only in
570the index page context. */
571UNIV_INTERN
572void
573ib_page_page_rec_print(
574/*===================*/
575 const page_t* page,
576 const rec_t* rec, /*!< in: physical record */
577 const ulint* offsets,/*!< in: record descriptor */
578 dict_index_t* index); /*!< in: dictionary index of the page */
579
580/***************************************************************//**
581This is used to print the contents of the page record list for
582debugging purposes. */
583UNIV_INTERN
584void
585ib_page_page_print_list(
586/*====================*/
587 const page_t* page, /*!< in: index page */
588 dict_index_t* index); /*!< in: dictionary index of the page */
589
590
591/** @name Offsets to the per-page bits in the insert buffer bitmap */
592/* @{ */
593#define IBUF_BITMAP_FREE 0 /*!< Bits indicating the
594 amount of free space */
595#define IBUF_BITMAP_BUFFERED 2 /*!< TRUE if there are buffered
596 changes for the page */
597#define IBUF_BITMAP_IBUF 3 /*!< TRUE if page is a part of
598 the ibuf tree, excluding the
599 root page, or is in the free
600 list of the ibuf */
601/* @} */
602
603/* Various constants for checking the type of an ibuf record and extracting
604data from it. For details, see the description of the record format at the
605top of this file. */
606
607/** @name Format of the fourth column of an insert buffer record
608The fourth column in the MySQL 5.5 format contains an operation
609type, counter, and some flags. */
610/* @{ */
611#define IBUF_REC_INFO_SIZE 4 /*!< Combined size of info fields at
612 the beginning of the fourth field */
613#if IBUF_REC_INFO_SIZE >= DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE
614# error "IBUF_REC_INFO_SIZE >= DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE"
615#endif
616
617/* Offsets for the fields at the beginning of the fourth field */
618#define IBUF_REC_OFFSET_COUNTER 0 /*!< Operation counter */
619#define IBUF_REC_OFFSET_TYPE 2 /*!< Type of operation */
620#define IBUF_REC_OFFSET_FLAGS 3 /*!< Additional flags */
621
622/* Record flag masks */
623#define IBUF_REC_COMPACT 0x1 /*!< Set in
624 IBUF_REC_OFFSET_FLAGS if the
625 user index is in COMPACT
626 format or later */
627
628
629/** The area in pages from which contract looks for page numbers for merge */
630#define IBUF_MERGE_AREA 8
631
632/** Inside the merge area, pages which have at most 1 per this number less
633buffered entries compared to maximum volume that can buffered for a single
634page are merged along with the page whose buffer became full */
635#define IBUF_MERGE_THRESHOLD 4
636
637/** In ibuf_contract at most this number of pages is read to memory in one
638batch, in order to merge the entries for them in the insert buffer */
639#define IBUF_MAX_N_PAGES_MERGED IBUF_MERGE_AREA
640
641/** If the combined size of the ibuf trees exceeds ibuf->max_size by this
642many pages, we start to contract it in connection to inserts there, using
643non-synchronous contract */
644#define IBUF_CONTRACT_ON_INSERT_NON_SYNC 0
645
646/** If the combined size of the ibuf trees exceeds ibuf->max_size by this
647many pages, we start to contract it in connection to inserts there, using
648synchronous contract */
649#define IBUF_CONTRACT_ON_INSERT_SYNC 5
650
651/** If the combined size of the ibuf trees exceeds ibuf->max_size by
652this many pages, we start to contract it synchronous contract, but do
653not insert */
654#define IBUF_CONTRACT_DO_NOT_INSERT 10
655
656
657/* Possible operations buffered in the insert/whatever buffer. See
658ibuf_insert(). DO NOT CHANGE THE VALUES OF THESE, THEY ARE STORED ON DISK. */
659typedef enum {
660 IBUF_OP_INSERT = 0,
661 IBUF_OP_DELETE_MARK = 1,
662 IBUF_OP_DELETE = 2,
663
664 /* Number of different operation types. */
665 IBUF_OP_COUNT = 3
666} ibuf_op_t;
667
668/***************************************************************//**
669Load a index object based on the index id.
670@return index; NULL if table does not exist */
671dict_index_t*
672ib_dict_index_get_on_id(
673/*====================*/
674 dulint index_id); /*!< in: index id */
675
676/****************************************************************//**
677Read the first two bytes from a record's fourth field (counter field in new
678records; something else in older records).
679@return "counter" field, or ULINT_UNDEFINED if for some reason it
680can't be read */
681UNIV_INTERN
682ulint
683ib_page_ibuf_rec_get_counter(
684/*=========================*/
685 const rec_t* rec); /*!< in: ibuf record */
686
687
688/*******************************************************************//**
689Initialize necessary InndoDB systems for page printer
690to work properly. */
691ib_err_t
692ib_page_sys_start(
693/*==============*/
694 ulint buf_pool_size, /*!< in: size of buffer pool */
695 const char* datadir) /*!< in: InnoDB data directory */
696{
697 ulint err;
698
699 innodb_init_param_for_util(datadir, datadir,
700 buf_pool_size, 16*1024*1024, TRUE);
701
702 srv_max_n_threads = 1;
703 srv_normalize_init_values();
704
705 ut_mem_init();
706 os_sync_init();
707 sync_init();
708 srv_n_read_io_threads = srv_n_write_io_threads = 1;
709 srv_n_file_io_threads = 2 + srv_n_read_io_threads +
710 srv_n_write_io_threads;
711 // os_io_init_simple();
712 os_aio_init(8 * SRV_N_PENDING_IOS_PER_THREAD,
713 srv_n_read_io_threads,
714 srv_n_write_io_threads,
715 SRV_MAX_N_PENDING_SYNC_IOS);
716 mem_init(1);
717
718 kernel_mutex_temp = mem_alloc(sizeof(mutex_t));
719 mutex_create(&kernel_mutex, SYNC_KERNEL);
720
721 fil_init(10, 10);
722 buf_pool_init();
723 fsp_init();
724 lock_sys_create(1000);
725 recv_sys_create();
726
727 ibool create_new_db;
728 ib_uint64_t min_flushed_lsn, max_flushed_lsn;
729 ulint sum_of_new_sizes;
730
731 err = open_or_create_data_files(&create_new_db,
732 &min_flushed_lsn, &max_flushed_lsn,
733 &sum_of_new_sizes);
734
735 if (err != DB_SUCCESS) {
736 return err;
737 }
738
739 /* open_or_create_log_file will set srv_log_file_size. Normalize the
740 init values again to get srv_log_file_size/srv_log_file_curr_size in
741 sync. */
742 srv_normalize_init_values();
743
744 dict_ind_init();
745 dict_boot(FALSE);
746 mutex_enter(&(dict_sys->mutex));
747 ib_page_ibuf_index_create();
748 mutex_exit(&(dict_sys->mutex));
749 dict_check_tablespaces_and_store_max_id(FALSE);
750
751 return DB_SUCCESS;
752}
753
754/*******************************************************************//**
755Uninitialize InndoDB systems been initialized by ib_page_sys_start. */
756void
757ib_page_sys_stop(void)
758/*==================*/
759{
760 /* This must be disabled before closing the buffer pool
761 and closing the data dictionary. */
762 btr_search_disable();
763
764 recv_sys_close();
765 recv_sys_mem_free();
766 fil_close_all_files();
767 dict_close();
768 // buf_close();
769
770 mutex_free(&kernel_mutex);
771 mem_free(kernel_mutex_temp);
772 kernel_mutex_temp = NULL;
773
774 sync_close();
775 os_sync_free();
776 fil_close();
777
778 buf_pool_free();
779 ut_free_all_mem();
780}
781
782#define ASSERT_MTR_READONLY(mtr) ut_a(!(mtr.modifications && mtr.n_log_recs));
783
784/***************************************************************//**
785Load a table object based on the index id.
786@return table; NULL if table does not exist */
787UNIV_INTERN
788dict_table_t*
789ib_page_load_table_for_index(
790/*=========================*/
791 dulint index_id) /*!< in: index id */
792{
793 dict_table_t* sys_tables_table;
794 dict_index_t* sys_tables_index;
795
796 mtr_t mtr;
797 btr_pcur_t pcur;
798 dict_table_t* result = NULL;
799
800 sys_tables_table = dict_table_get_low("SYS_INDEXES");
801 sys_tables_index = UT_LIST_GET_FIRST(sys_tables_table->indexes);
802
803 mtr_start(&mtr);
804
805 btr_pcur_open_at_index_side(TRUE, sys_tables_index,
806 BTR_SEARCH_LEAF, &pcur,
807 TRUE, &mtr);
808
809 for (;;)
810 {
811 rec_t* rec;
812 ulint len;
813 byte* field;
814 dulint loc_index_id;
815 dulint loc_table_id;
816
817 btr_pcur_move_to_next_user_rec(&pcur, &mtr);
818 rec = btr_pcur_get_rec(&pcur);
819
820 if (!btr_pcur_is_on_user_rec(&pcur))
821 {
822 /* end of index */
823
824 break;
825 }
826
827 if (rec_get_deleted_flag(rec, 0))
828 continue;
829
830 field = rec_get_nth_field_old(rec, 1, &len);
831 loc_index_id = mach_read_from_8(field);
832
833 if (ut_dulint_cmp(loc_index_id, index_id) == 0) {
834 field = rec_get_nth_field_old(rec, 0, &len);
835 loc_table_id = mach_read_from_8(field);
836
837 btr_pcur_close(&pcur);
838
839 ASSERT_MTR_READONLY(mtr);
840 mtr_commit(&mtr);
841
842 return dict_table_get_on_id_low(loc_table_id);
843 }
844
845 }
846
847 btr_pcur_close(&pcur);
848
849 ASSERT_MTR_READONLY(mtr);
850 mtr_commit(&mtr);
851
852 return(result);
853}
854
855/** Table name for the insert buffer. */
856#define IBUF_TABLE_NAME "SYS_IBUF_TABLE"
857
858/***************************************************************//**
859Create IBUF index in data dictionary. */
860UNIV_INTERN
861void
862ib_page_ibuf_index_create(void)
863/*===========================*/
864{
865 dict_table_t* table;
866 mem_heap_t* heap;
867 dict_index_t* index;
868 ulint error;
869
870 ibuf = mem_alloc(sizeof(ibuf_t));
871
872 memset(ibuf, 0, sizeof(*ibuf));
873
874 heap = mem_heap_create(450);
875
876 /* Use old-style record format for the insert buffer. */
877 table = dict_mem_table_create(IBUF_TABLE_NAME, IBUF_SPACE_ID, 1, 0);
878
879 dict_mem_table_add_col(table, heap, "DUMMY_COLUMN", DATA_BINARY, 0, 0);
880
881 table->id = ut_dulint_add(DICT_IBUF_ID_MIN, IBUF_SPACE_ID);
882
883 dict_table_add_to_cache(table, heap);
884 mem_heap_free(heap);
885
886 index = dict_mem_index_create(
887 IBUF_TABLE_NAME, "CLUST_IND",
888 IBUF_SPACE_ID, DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF, 1);
889
890 dict_mem_index_add_field(index, "DUMMY_COLUMN", 0);
891
892 index->id = ut_dulint_add(DICT_IBUF_ID_MIN, IBUF_SPACE_ID);
893
894 error = dict_index_add_to_cache(table, index,
895 FSP_IBUF_TREE_ROOT_PAGE_NO, FALSE);
896 ut_a(error == DB_SUCCESS);
897
898 ibuf->index = dict_table_get_first_index(table);
899
900}
901
902/***************************************************************//**
903Load a index object based on the index id.
904@return index; NULL if table does not exist */
905dict_index_t*
906ib_dict_index_get_on_id(
907/*====================*/
908 dulint index_id) /*!< in: index id */
909{
910 dict_table_t* table;
911 dict_index_t* index = NULL;
912
913 const char* SYS_TABLES[] = {"SYS_TABLES", "SYS_INDEXES",
914 "SYS_COLUMNS", "SYS_FIELDS",
915 IBUF_TABLE_NAME, NULL};
916
917 mutex_enter(&(dict_sys->mutex));
918 for (const char** ptbl_name = SYS_TABLES; *ptbl_name; ptbl_name++)
919 {
920 table = dict_table_get_low(*ptbl_name);
921 if (table != NULL) {
922 index = dict_index_get_on_id_low(table, index_id);
923 if (index != NULL) {
924 mutex_exit(&(dict_sys->mutex));
925 return(index);
926 }
927 }
928 }
929
930 table = ib_page_load_table_for_index(index_id);
931 if (table != NULL) {
932 index = dict_index_get_on_id_low(table, index_id);
933 mutex_exit(&(dict_sys->mutex));
934 return index;
935 }
936
937 mutex_exit(&(dict_sys->mutex));
938
939 return(NULL);
940}
941
942/********************************************************************//**
943Returns the page number field of an ibuf record.
944@return page number */
945static
946ulint
947ib_page_ibuf_rec_get_page_no(
948/*=========================*/
949 const rec_t* rec) /*!< in: ibuf record */
950{
951 const byte* field;
952 ulint len;
953
954 ut_ad(rec_get_n_fields_old(rec) > 2);
955
956 field = rec_get_nth_field_old(rec, 1, &len);
957
958 if (len == 1) {
959 /* This is of the >= 4.1.x record format */
960
961 field = rec_get_nth_field_old(rec, 2, &len);
962 } else {
963
964 field = rec_get_nth_field_old(rec, 0, &len);
965 }
966
967 ut_a(len == 4);
968
969 return(mach_read_from_4(field));
970}
971
972/********************************************************************//**
973Returns the space id field of an ibuf record. For < 4.1.x format records
974returns 0.
975@return space id */
976static
977ulint
978ib_page_ibuf_rec_get_space(
979/*=======================*/
980 const rec_t* rec) /*!< in: ibuf record */
981{
982 const byte* field;
983 ulint len;
984
985 field = rec_get_nth_field_old(rec, 1, &len);
986
987 if (len == 1) {
988 /* This is of the >= 4.1.x record format */
989
990 field = rec_get_nth_field_old(rec, 0, &len);
991 ut_a(len == 4);
992
993 return(mach_read_from_4(field));
994 }
995
996 return(0);
997}
998
999/****************************************************************//**
1000Get various information about an ibuf record in >= 4.1.x format. */
1001static
1002void
1003ib_page_ibuf_rec_get_info(
1004/*======================*/
1005 const rec_t* rec, /*!< in: ibuf record */
1006 ibuf_op_t* op, /*!< out: operation type, or NULL */
1007 ibool* comp, /*!< out: compact flag, or NULL */
1008 ulint* info_len, /*!< out: length of info fields at the
1009 start of the fourth field, or
1010 NULL */
1011 ulint* counter) /*!< in: counter value, or NULL */
1012{
1013 const byte* types;
1014 ulint fields;
1015 ulint len;
1016
1017 /* Local variables to shadow arguments. */
1018 ibuf_op_t op_local;
1019 ibool comp_local;
1020 ulint info_len_local;
1021 ulint counter_local;
1022
1023 fields = rec_get_n_fields_old(rec);
1024 ut_a(fields > 4);
1025
1026 types = rec_get_nth_field_old(rec, 3, &len);
1027
1028 info_len_local = len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE;
1029
1030 switch (info_len_local) {
1031 case 0:
1032 case 1:
1033 op_local = IBUF_OP_INSERT;
1034 comp_local = info_len_local;
1035 ut_ad(!counter);
1036 counter_local = ULINT_UNDEFINED;
1037 break;
1038
1039 case IBUF_REC_INFO_SIZE:
1040 op_local = (ibuf_op_t)types[IBUF_REC_OFFSET_TYPE];
1041 comp_local = types[IBUF_REC_OFFSET_FLAGS] & IBUF_REC_COMPACT;
1042 counter_local = mach_read_from_2(
1043 types + IBUF_REC_OFFSET_COUNTER);
1044 break;
1045
1046 default:
1047 ut_error;
1048 }
1049
1050 ut_a(op_local < IBUF_OP_COUNT);
1051 ut_a((len - info_len_local) ==
1052 (fields - 4) * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
1053
1054 if (op) {
1055 *op = op_local;
1056 }
1057
1058 if (comp) {
1059 *comp = comp_local;
1060 }
1061
1062 if (info_len) {
1063 *info_len = info_len_local;
1064 }
1065
1066 if (counter) {
1067 *counter = counter_local;
1068 }
1069}
1070
1071/****************************************************************//**
1072Returns the operation type field of an ibuf record.
1073@return operation type */
1074static
1075ibuf_op_t
1076ib_page_ibuf_rec_get_op_type(
1077/*=========================*/
1078 const rec_t* rec) /*!< in: ibuf record */
1079{
1080 ulint len;
1081
1082 (void) rec_get_nth_field_old(rec, 1, &len);
1083
1084 if (len > 1) {
1085 /* This is a < 4.1.x format record */
1086
1087 return(IBUF_OP_INSERT);
1088 } else {
1089 ibuf_op_t op;
1090
1091 ib_page_ibuf_rec_get_info(rec, &op, NULL, NULL, NULL);
1092
1093 return(op);
1094 }
1095}
1096
1097/****************************************************************//**
1098Read the first two bytes from a record's fourth field (counter field in new
1099records; something else in older records).
1100@return "counter" field, or ULINT_UNDEFINED if for some reason it
1101can't be read */
1102UNIV_INTERN
1103ulint
1104ib_page_ibuf_rec_get_counter(
1105/*=========================*/
1106 const rec_t* rec) /*!< in: ibuf record */
1107{
1108 const byte* ptr;
1109 ulint len;
1110
1111 if (rec_get_n_fields_old(rec) < 4) {
1112
1113 return(ULINT_UNDEFINED);
1114 }
1115
1116 ptr = rec_get_nth_field_old(rec, 3, &len);
1117
1118 if (len >= 2) {
1119
1120 return(mach_read_from_2(ptr));
1121 } else {
1122
1123 return(ULINT_UNDEFINED);
1124 }
1125}
1126
1127/********************************************************************//**
1128Creates a dummy index for inserting a record to a non-clustered index.
1129@return dummy index */
1130static
1131dict_index_t*
1132ib_page_ibuf_dummy_index_create(
1133/*============================*/
1134 ulint n, /*!< in: number of fields */
1135 ibool comp) /*!< in: TRUE=use compact record format */
1136{
1137 dict_table_t* table;
1138 dict_index_t* index;
1139
1140 table = dict_mem_table_create("IBUF_DUMMY",
1141 DICT_HDR_SPACE, n,
1142 comp ? DICT_TF_COMPACT : 0);
1143
1144 index = dict_mem_index_create("IBUF_DUMMY", "IBUF_DUMMY",
1145 DICT_HDR_SPACE, 0, n);
1146
1147 index->table = table;
1148
1149 /* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */
1150 index->cached = TRUE;
1151
1152 return(index);
1153}
1154
1155/********************************************************************//**
1156Add a column to the dummy index */
1157static
1158void
1159ib_page_ibuf_dummy_index_add_col(
1160/*=============================*/
1161 dict_index_t* index, /*!< in: dummy index */
1162 const dtype_t* type, /*!< in: the data type of the column */
1163 ulint len) /*!< in: length of the column */
1164{
1165 ulint i = index->table->n_def;
1166 dict_mem_table_add_col(index->table, NULL, NULL,
1167 dtype_get_mtype(type),
1168 dtype_get_prtype(type),
1169 dtype_get_len(type));
1170 dict_index_add_col(index, index->table,
1171 dict_table_get_nth_col(index->table, i), len);
1172}
1173/********************************************************************//**
1174Deallocates a dummy index for inserting a record to a non-clustered index. */
1175static
1176void
1177ib_page_ibuf_dummy_index_free(
1178/*==========================*/
1179 dict_index_t* index) /*!< in, own: dummy index */
1180{
1181 dict_table_t* table = index->table;
1182
1183 dict_mem_index_free(index);
1184 dict_mem_table_free(table);
1185}
1186
1187/*********************************************************************//**
1188Builds the entry to insert into a non-clustered index when we have the
1189corresponding record in an ibuf index.
1190
1191NOTE that as we copy pointers to fields in ibuf_rec, the caller must
1192hold a latch to the ibuf_rec page as long as the entry is used!
1193
1194@return own: entry to insert to a non-clustered index */
1195UNIV_INLINE
1196dtuple_t*
1197ib_page_ibuf_build_entry_pre_4_1_x(
1198/*===============================*/
1199 const rec_t* ibuf_rec, /*!< in: record in an insert buffer */
1200 mem_heap_t* heap, /*!< in: heap where built */
1201 dict_index_t** pindex) /*!< out, own: dummy index that
1202 describes the entry */
1203{
1204 ulint i;
1205 ulint len;
1206 const byte* types;
1207 dtuple_t* tuple;
1208 ulint n_fields;
1209
1210 n_fields = rec_get_n_fields_old(ibuf_rec) - 2;
1211 tuple = dtuple_create(heap, n_fields);
1212 types = rec_get_nth_field_old(ibuf_rec, 1, &len);
1213
1214 ut_a(len == n_fields * DATA_ORDER_NULL_TYPE_BUF_SIZE);
1215
1216 for (i = 0; i < n_fields; i++) {
1217 const byte* data;
1218 dfield_t* field;
1219
1220 field = dtuple_get_nth_field(tuple, i);
1221
1222 data = rec_get_nth_field_old(ibuf_rec, i + 2, &len);
1223
1224 dfield_set_data(field, data, len);
1225
1226 dtype_read_for_order_and_null_size(
1227 dfield_get_type(field),
1228 types + i * DATA_ORDER_NULL_TYPE_BUF_SIZE);
1229 }
1230
1231 *pindex = ib_page_ibuf_dummy_index_create(n_fields, FALSE);
1232
1233 return(tuple);
1234}
1235
1236/*********************************************************************//**
1237Builds the entry used to
1238
12391) IBUF_OP_INSERT: insert into a non-clustered index
1240
12412) IBUF_OP_DELETE_MARK: find the record whose delete-mark flag we need to
1242 activate
1243
12443) IBUF_OP_DELETE: find the record we need to delete
1245
1246when we have the corresponding record in an ibuf index.
1247
1248NOTE that as we copy pointers to fields in ibuf_rec, the caller must
1249hold a latch to the ibuf_rec page as long as the entry is used!
1250
1251@return own: entry to insert to a non-clustered index */
1252static
1253dtuple_t*
1254ib_page_ibuf_build_entry_from_ibuf_rec(
1255/*===================================*/
1256 const rec_t* ibuf_rec, /*!< in: record in an insert buffer */
1257 mem_heap_t* heap, /*!< in: heap where built */
1258 dict_index_t** pindex) /*!< out, own: dummy index that
1259 describes the entry */
1260{
1261 dtuple_t* tuple;
1262 dfield_t* field;
1263 ulint n_fields;
1264 const byte* types;
1265 const byte* data;
1266 ulint len;
1267 ulint info_len;
1268 ulint i;
1269 ulint comp;
1270 dict_index_t* index;
1271
1272 data = rec_get_nth_field_old(ibuf_rec, 1, &len);
1273
1274 if (len > 1) {
1275 /* This a < 4.1.x format record */
1276
1277 return(ib_page_ibuf_build_entry_pre_4_1_x(
1278 ibuf_rec, heap, pindex));
1279 }
1280
1281 /* This a >= 4.1.x format record */
1282
1283 ut_a(*data == 0);
1284 ut_a(rec_get_n_fields_old(ibuf_rec) > 4);
1285
1286 n_fields = rec_get_n_fields_old(ibuf_rec) - 4;
1287
1288 tuple = dtuple_create(heap, n_fields);
1289
1290 types = rec_get_nth_field_old(ibuf_rec, 3, &len);
1291
1292 ib_page_ibuf_rec_get_info(ibuf_rec, NULL, &comp, &info_len, NULL);
1293
1294 index = ib_page_ibuf_dummy_index_create(n_fields, comp);
1295
1296 len -= info_len;
1297 types += info_len;
1298
1299 ut_a(len == n_fields * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
1300
1301 for (i = 0; i < n_fields; i++) {
1302 field = dtuple_get_nth_field(tuple, i);
1303
1304 data = rec_get_nth_field_old(ibuf_rec, i + 4, &len);
1305
1306 dfield_set_data(field, data, len);
1307
1308 dtype_new_read_for_order_and_null_size(
1309 dfield_get_type(field),
1310 types + i * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
1311
1312 ib_page_ibuf_dummy_index_add_col(
1313 index, dfield_get_type(field), len);
1314 }
1315
1316 /* Prevent an ut_ad() failure in page_zip_write_rec() by
1317 adding system columns to the dummy table pointed to by the
1318 dummy secondary index. The insert buffer is only used for
1319 secondary indexes, whose records never contain any system
1320 columns, such as DB_TRX_ID. */
1321 ut_d(dict_table_add_system_columns(index->table, index->table->heap));
1322
1323 *pindex = index;
1324
1325 return(tuple);
1326}
1327
1328/******************************************************************//**
1329Get the data size.
1330@return size of fields */
1331UNIV_INLINE
1332ulint
1333ib_page_ibuf_rec_get_size(
1334/*======================*/
1335 const rec_t* rec, /*!< in: ibuf record */
1336 const byte* types, /*!< in: fields */
1337 ulint n_fields, /*!< in: number of fields */
1338 ibool pre_4_1, /*!< in: TRUE=pre-4.1 format,
1339 FALSE=newer */
1340 ulint comp) /*!< in: 0=ROW_FORMAT=REDUNDANT,
1341 nonzero=ROW_FORMAT=COMPACT */
1342{
1343 ulint i;
1344 ulint field_offset;
1345 ulint types_offset;
1346 ulint size = 0;
1347
1348 if (pre_4_1) {
1349 field_offset = 2;
1350 types_offset = DATA_ORDER_NULL_TYPE_BUF_SIZE;
1351 } else {
1352 field_offset = 4;
1353 types_offset = DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE;
1354 }
1355
1356 for (i = 0; i < n_fields; i++) {
1357 ulint len;
1358 dtype_t dtype;
1359
1360 rec_get_nth_field_offs_old(rec, i + field_offset, &len);
1361
1362 if (len != UNIV_SQL_NULL) {
1363 size += len;
1364 } else if (pre_4_1) {
1365 dtype_read_for_order_and_null_size(&dtype, types);
1366
1367 size += dtype_get_sql_null_size(&dtype, comp);
1368 } else {
1369 dtype_new_read_for_order_and_null_size(&dtype, types);
1370
1371 size += dtype_get_sql_null_size(&dtype, comp);
1372 }
1373
1374 types += types_offset;
1375 }
1376
1377 return(size);
1378}
1379
1380/*******************************************************************//**
1381Copy types of fields contained in index to tuple. */
1382UNIV_INTERN
1383void
1384ib_page_dict_index_copy_types(
1385/*==========================*/
1386 dtuple_t* tuple, /*!< in/out: data tuple */
1387 const dict_index_t* index, /*!< in: index */
1388 ulint n_fields, /*!< in: number of
1389 field types to copy */
1390 ibool is_leaf_page) /*!< in: TRUE if leas page */
1391{
1392 ulint i;
1393
1394 if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1395 dtuple_set_types_binary(tuple, n_fields);
1396
1397 return;
1398 }
1399
1400 for (i = 0; i < n_fields; i++) {
1401 const dict_field_t* ifield;
1402 dtype_t* dfield_type;
1403
1404 ifield = dict_index_get_nth_field(index, i);
1405 dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
1406 if (i >= dict_index_get_n_unique(index) && !is_leaf_page) {
1407 dfield_type->mtype = DATA_INT;
1408 dfield_type->prtype = 0;
1409 dfield_type->len = 8;
1410 dfield_type->mbminlen = 0;
1411 dfield_type->mbmaxlen = 0;
1412 } else {
1413 dict_col_copy_type(
1414 dict_field_get_col(ifield), dfield_type);
1415 }
1416 }
1417}
1418
1419/*******************************************************************//**
1420Converts an index record to a typed data tuple.
1421@return index entry built; does not set info_bits, and the data fields
1422in the entry will point directly to rec */
1423UNIV_INTERN
1424dtuple_t*
1425ib_page_row_rec_to_index_entry_low(
1426/*===============================*/
1427 const page_t* page,
1428 const rec_t* rec, /*!< in: record in the index */
1429 const dict_index_t* index, /*!< in: index */
1430 const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */
1431 ulint* n_ext, /*!< out: number of externally
1432 stored columns */
1433 mem_heap_t* heap) /*!< in: memory heap from which
1434 the memory needed is allocated */
1435{
1436 dtuple_t* entry;
1437 dfield_t* dfield;
1438 ulint i;
1439 const byte* field;
1440 ulint len;
1441 ulint rec_len;
1442
1443 ut_ad(rec && heap && index);
1444 ut_ad(n_ext);
1445 *n_ext = 0;
1446
1447 rec_len = rec_offs_n_fields(offsets);
1448
1449 entry = dtuple_create(heap, rec_len);
1450
1451 dtuple_set_n_fields_cmp(entry,
1452 dict_index_get_n_unique_in_tree(index));
1453 ut_ad((!page_is_leaf(page) && rec_len == 2)
1454 || (rec_len == dict_index_get_n_fields(index)));
1455
1456 ib_page_dict_index_copy_types(
1457 entry, index, rec_len, page_is_leaf(page));
1458
1459 for (i = 0; i < rec_len; i++) {
1460
1461 dfield = dtuple_get_nth_field(entry, i);
1462 field = rec_get_nth_field(rec, offsets, i, &len);
1463
1464 dfield_set_data(dfield, field, len);
1465
1466 if (rec_offs_nth_extern(offsets, i)) {
1467 dfield_set_ext(dfield);
1468 (*n_ext)++;
1469 }
1470 }
1471
1472 ut_ad(dtuple_check_typed(entry));
1473
1474 return(entry);
1475}
1476
1477/*******************************************************************//**
1478Converts an index record to a typed data tuple. NOTE that externally
1479stored (often big) fields are NOT copied to heap.
1480@return own: index entry built; see the NOTE below! */
1481UNIV_INTERN
1482dtuple_t*
1483ib_page_row_rec_to_index_entry(
1484/*===========================*/
1485 ulint type, /*!< in: ROW_COPY_DATA, or
1486 ROW_COPY_POINTERS: the former
1487 copies also the data fields to
1488 heap as the latter only places
1489 pointers to data fields on the
1490 index page */
1491 const page_t* page,
1492 const rec_t* rec, /*!< in: record in the index;
1493 NOTE: in the case
1494 ROW_COPY_POINTERS the data
1495 fields in the row will point
1496 directly into this record,
1497 therefore, the buffer page of
1498 this record must be at least
1499 s-latched and the latch held
1500 as long as the dtuple is used! */
1501 const dict_index_t* index, /*!< in: index */
1502 ulint* offsets,/*!< in/out: rec_get_offsets(rec) */
1503 ulint* n_ext, /*!< out: number of externally
1504 stored columns */
1505 mem_heap_t* heap) /*!< in: memory heap from which
1506 the memory needed is allocated */
1507{
1508 dtuple_t* entry;
1509 byte* buf;
1510
1511 ut_ad(rec && heap && index);
1512 ut_ad(rec_offs_validate(rec, index, offsets));
1513
1514 if (type == ROW_COPY_DATA) {
1515 /* Take a copy of rec to heap */
1516 buf = mem_heap_alloc(heap, rec_offs_size(offsets));
1517 rec = rec_copy(buf, rec, offsets);
1518 /* Avoid a debug assertion in rec_offs_validate(). */
1519 rec_offs_make_valid(rec, index, offsets);
1520 }
1521
1522 entry = ib_page_row_rec_to_index_entry_low(
1523 page, rec, index, offsets, n_ext, heap);
1524
1525 dtuple_set_info_bits(entry,
1526 rec_get_info_bits(rec, rec_offs_comp(offsets)));
1527
1528 return(entry);
1529}
1530
1531/***************************************************************//**
1532Allocate signle aligned page.
1533@return page */
1534UNIV_INTERN
1535page_t*
1536ib_page_heap_page_alloc(
1537/*====================*/
1538 mem_heap_t* heap) /*!< in: memory heap where allocate in */
1539{
1540 page_t* page = mem_heap_alloc(heap, UNIV_PAGE_SIZE * 2);
1541 return page_align(page + UNIV_PAGE_SIZE);
1542}
1543
1544/***************************************************************//**
1545Get space id of given tablespace in file.
1546@return space id if given tablespace file */
1547UNIV_INTERN
1548ulint
1549ib_page_file_space_id(
1550/*==================*/
1551 os_file_t file) /*!< in: file */
1552{
1553 ulint space_id;
1554 mem_heap_t* heap = mem_heap_create(100);
1555 page_t* page = ib_page_heap_page_alloc(heap);
1556
1557 if (page == NULL)
1558 {
1559 mem_heap_free(heap);
1560 ut_error;
1561 }
1562
1563 if (!os_file_read(file, page, 0, 0, UNIV_PAGE_SIZE))
1564 {
1565 mem_heap_free(heap);
1566 ut_error;
1567 }
1568
1569 space_id = page_get_space_id(page);
1570
1571 mem_heap_free(heap);
1572
1573 return space_id;
1574
1575}
1576
1577/***************************************************************//**
1578Calculate the low 32 bits and the high 32 bits
1579of the file offset. */
1580UNIV_INTERN
1581void
1582ib_page_calc_offsets(
1583/*=================*/
1584 ulint zip_size, /*!< in: compressed page size, or
1585 0 for uncompressed pages */
1586 ulint page_no, /*!< in: page number */
1587 ulint* offset_low, /*!< out: low 32 bits */
1588 ulint* offset_high) /*!< out: high 32 bits */
1589{
1590 /* Calculate the low 32 bits and the high 32 bits of the file offset */
1591
1592 if (!zip_size) {
1593 *offset_high = (page_no >> (32 - UNIV_PAGE_SIZE_SHIFT));
1594 *offset_low = ((page_no << UNIV_PAGE_SIZE_SHIFT)
1595 & 0xFFFFFFFFUL);
1596 } else {
1597 ulint zip_size_shift;
1598 switch (zip_size) {
1599 case 1024: zip_size_shift = 10; break;
1600 case 2048: zip_size_shift = 11; break;
1601 case 4096: zip_size_shift = 12; break;
1602 case 8192: zip_size_shift = 13; break;
1603 case 16384: zip_size_shift = 14; break;
1604 default: ut_error;
1605 }
1606 *offset_high = page_no >> (32 - zip_size_shift);
1607 *offset_low = (page_no << zip_size_shift & 0xFFFFFFFFUL);
1608 }
1609}
1610
1611/***************************************************************//**
1612Load compressed page into memory.
1613Space for page allocated in heap.
1614@return loaded page; NULL if page was not loaded */
1615UNIV_INTERN
1616page_t*
1617ib_page_load_compressed(
1618/*====================*/
1619 os_file_t file, /*!< in: file */
1620 ulint page_no, /*!< in: page number */
1621 ulint zip_size, /*!< in: compressed page size, or
1622 0 for uncompressed pages */
1623 mem_heap_t* heap) /*!< in: memory heap */
1624{
1625 ulint offset_high;
1626 ulint offset_low;
1627 ulint page_size;
1628 page_t* page;
1629
1630 page_size = zip_size ? zip_size : UNIV_PAGE_SIZE;
1631 page = ib_page_heap_page_alloc(heap);
1632
1633 ib_page_calc_offsets(zip_size, page_no, &offset_low, &offset_high);
1634 if (!os_file_read(file, page, offset_low, offset_high, page_size))
1635 {
1636 ib_logger(ib_stream,
1637 "Failed to read %lu bytes from offset {%lu %lu}\n",
1638 page_size, offset_low, offset_high);
1639 ut_error;
1640 }
1641
1642 return page;
1643}
1644
1645/***************************************************************//**
1646Decompress compressed page.
1647Space for decompressed page allocated in heap.
1648@return loaded page; NULL if page was not loaded */
1649UNIV_INTERN
1650page_t*
1651ib_page_decompress(
1652/*===============*/
1653 const page_t* compressed_page,/*!< in: compressed page */
1654 ulint zip_size, /*!< in: compressed page size, or
1655 0 for uncompressed pages */
1656 mem_heap_t* heap) /*!< in: memory heap */
1657{
1658 page_t* decompressed_page = ib_page_heap_page_alloc(heap);
1659
1660 if (decompressed_page == NULL)
1661 {
1662 ut_error;
1663 }
1664
1665 if (zip_size)
1666 {
1667 page_zip_des_t des;
1668 des.data = (page_t*) compressed_page;
1669 page_zip_set_size(&des, zip_size);
1670
1671 ulint stamp_checksum = mach_read_from_4(
1672 compressed_page + FIL_PAGE_SPACE_OR_CHKSUM);
1673 ulint calc_checksum = page_zip_calc_checksum(
1674 compressed_page, zip_size);
1675
1676 if (UNIV_UNLIKELY(stamp_checksum != calc_checksum)) {
1677 ut_print_timestamp(ib_stream);
1678 ib_logger(ib_stream,
1679 " compressed page checksum mismatch"
1680 "%lu != %lu\n",
1681 stamp_checksum, calc_checksum);
1682 ut_error;
1683 }
1684
1685 switch (fil_page_get_type(compressed_page)) {
1686 case FIL_PAGE_INDEX:
1687 if (page_zip_decompress(&des,
1688 decompressed_page, TRUE)) {
1689 return decompressed_page;
1690 }
1691
1692 ib_logger(ib_stream,
1693 " unable to decompress page\n");
1694 ut_error;
1695
1696 case FIL_PAGE_TYPE_ALLOCATED:
1697 case FIL_PAGE_INODE:
1698 case FIL_PAGE_IBUF_BITMAP:
1699 case FIL_PAGE_TYPE_FSP_HDR:
1700 case FIL_PAGE_TYPE_XDES:
1701 case FIL_PAGE_TYPE_ZBLOB:
1702 case FIL_PAGE_TYPE_ZBLOB2:
1703 /* Copy to uncompressed storage. */
1704 memcpy(decompressed_page, compressed_page, zip_size);
1705 return decompressed_page;
1706 }
1707
1708 ut_print_timestamp(ib_stream);
1709 ib_logger(ib_stream,
1710 " unknown compressed page"
1711 " type %lu\n",
1712 fil_page_get_type(compressed_page));
1713 ut_error;
1714 }
1715 else
1716 {
1717 ut_memcpy(decompressed_page, compressed_page, UNIV_PAGE_SIZE);
1718 }
1719
1720 return decompressed_page;
1721}
1722
1723/*******************************************************************//**
1724Load page from file into memory and decompress it if needed.
1725@return TRUE on success */
1726ibool
1727ib_page_load(
1728/*=========*/
1729 const char* ibd_file_name, /*!< in: file name */
1730 ulint page_no, /*!< in: page number */
1731 ulint* zip_size, /*!< in: compressed page size, or
1732 0 for uncompressed pages */
1733 page_t** compressed_page, /*!< out: compressed page */
1734 page_t** decompressed_page, /*!< out: decompressed page */
1735 mem_heap_t* heap) /*!< out: memory heap */
1736{
1737 ibool success;
1738 os_file_t file;
1739
1740 file = os_file_create(ibd_file_name,
1741 OS_FILE_OPEN, OS_FILE_NORMAL,
1742 OS_DATA_FILE, &success);
1743
1744 if (!success)
1745 {
1746 ib_logger(ib_stream, "Failed to open file %s\n", ibd_file_name);
1747 return(FALSE);
1748 }
1749
1750 ulint space_id = ib_page_file_space_id(file);
1751 *zip_size = fil_space_get_zip_size(space_id);
1752 if (*zip_size == ULINT_UNDEFINED) {
1753 *zip_size = 0;
1754 }
1755
1756 *compressed_page = ib_page_load_compressed(file, page_no,
1757 *zip_size, heap);
1758 if (*compressed_page == NULL)
1759 {
1760 return(FALSE);
1761 }
1762
1763 *decompressed_page = ib_page_decompress(*compressed_page,
1764 *zip_size, heap);
1765 if (*decompressed_page == NULL)
1766 {
1767 return(FALSE);
1768 }
1769
1770 os_file_close(file);
1771
1772 return(TRUE);
1773
1774}
1775
1776
1777/*******************************************************************//**
1778Print IBUF bitmap page. */
1779UNIV_INTERN
1780void
1781ib_page_ibuf_bitmap_print(
1782/*======================*/
1783 const page_t* page, /*!< in: page */
1784 ulint zip_size) /*!< in: compressed page size, or
1785 0 for uncompressed pages */
1786{
1787 ulint byte_offset;
1788 ulint i;
1789
1790 enum { IBUF_BITS_PER_PAGE = 4 };
1791
1792 ulint page_no = page_get_page_no(page);
1793
1794 if (!zip_size) {
1795 byte_offset = UT_BITS_IN_BYTES(UNIV_PAGE_SIZE
1796 * IBUF_BITS_PER_PAGE);
1797 } else {
1798 byte_offset = UT_BITS_IN_BYTES(zip_size * IBUF_BITS_PER_PAGE);
1799 }
1800
1801 for (i = 0; i < byte_offset; i++) {
1802 uint bits;
1803
1804 bits = (uint)mach_read_from_1(page + PAGE_DATA + i / 2) & 0xF;
1805 ib_logger(ib_stream, "%lu: %2x", page_no + 2*i - 1, bits);
1806 ib_logger(ib_stream, " (%d free)", bits & 0x2);
1807 if (bits & 2) {
1808 ib_logger(ib_stream, ", buffered");
1809 }
1810 if (bits & 4) {
1811 ib_logger(ib_stream, ", ibuf");
1812 }
1813 ib_logger(ib_stream, "\n");
1814
1815 bits = (uint)
1816 (mach_read_from_1(page + PAGE_DATA + i / 2) >> 4) & 0xF;
1817 ib_logger(ib_stream, "%lu: %2x", page_no + 2*i, bits);
1818 ib_logger(ib_stream, " (%d free)", bits & 0x2);
1819 if (bits & 2) {
1820 ib_logger(ib_stream, ", buffered");
1821 }
1822 if (bits & 4) {
1823 ib_logger(ib_stream, ", ibuf");
1824 }
1825 ib_logger(ib_stream, "\n");
1826
1827 }
1828
1829}
1830
1831/***************************************************************//**
1832Print undo log page. */
1833UNIV_INTERN
1834void
1835ib_page_print_undo(
1836/*===============*/
1837 const page_t* page) /*!< in: page */
1838{
1839 const trx_undo_rec_t* rec;
1840 ulint rec_offs;
1841 ulint prev_offs;
1842 ulint first_free;
1843 ulint type;
1844 ulint cmpl_info;
1845 ibool updated_extern;
1846 undo_no_t undo_no;
1847 dulint table_id;
1848 byte* ptr;
1849 trx_id_t trx_id;
1850 roll_ptr_t roll_ptr;
1851 ulint info_bits;
1852 dict_table_t* table;
1853 dict_index_t* index;
1854 upd_t* update;
1855
1856 first_free = mach_read_from_2(page + TRX_UNDO_PAGE_HDR
1857 + TRX_UNDO_PAGE_FREE);
1858 ib_logger(ib_stream, "first free: %lu\n", first_free);
1859 rec_offs = mach_read_from_2(page + first_free - 2);
1860
1861
1862 while (rec_offs != first_free
1863 && rec_offs >= TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE) {
1864 rec = page + rec_offs;
1865
1866 ib_logger(ib_stream, "===============================\n");
1867
1868 ptr = trx_undo_rec_get_pars((trx_undo_rec_t*)rec,
1869 &type, &cmpl_info,
1870 &updated_extern, &undo_no,
1871 &table_id);
1872 ib_logger(ib_stream,
1873 "Undo log record with offset: %lu,"
1874 " compiler info: %ld, updated extern: %s,"
1875 " undo log record number: {%lu %lu},"
1876 " table id: {%lu %lu}\n",
1877 rec_offs, cmpl_info,
1878 updated_extern ? "YES" : "NO",
1879 ut_dulint_get_high(undo_no),
1880 ut_dulint_get_low(undo_no),
1881 ut_dulint_get_high(table_id),
1882 ut_dulint_get_low(table_id));
1883
1884 mutex_enter(&(dict_sys->mutex));
1885 table = dict_table_get_on_id_low(table_id);
1886 mutex_exit(&(dict_sys->mutex));
1887 if (table)
1888 ib_logger(ib_stream, "table name: %s\n", table->name);
1889
1890 switch (type) {
1891 case TRX_UNDO_INSERT_REC:
1892 ib_logger(ib_stream,
1893 "fresh insert into clustered index\n");
1894 break;
1895 case TRX_UNDO_UPD_EXIST_REC:
1896 ib_logger(ib_stream,
1897 "update of a non-delete-marked record\n");
1898 break;
1899 case TRX_UNDO_UPD_DEL_REC:
1900 ib_logger(ib_stream,
1901 "update of a delete marked record to "
1902 "a not delete marked record; also the "
1903 "fields of the record can change\n");
1904 break;
1905 case TRX_UNDO_DEL_MARK_REC:
1906 ib_logger(ib_stream,
1907 "delete marking of a record; fields "
1908 "do not change\n");
1909 break;
1910 }
1911
1912 if (type == TRX_UNDO_UPD_EXIST_REC ||
1913 type == TRX_UNDO_UPD_DEL_REC ||
1914 type == TRX_UNDO_DEL_MARK_REC) {
1915 ptr = trx_undo_update_rec_get_sys_cols(ptr,
1916 &trx_id,
1917 &roll_ptr,
1918 &info_bits);
1919 }
1920
1921 ib_logger(ib_stream,
1922 "trx_id: {%lu %lu}, roll_ptr: {%lu %lu}, "
1923 "info bits: %lu\n",
1924 ut_dulint_get_high(trx_id),
1925 ut_dulint_get_low(trx_id),
1926 ut_dulint_get_high(roll_ptr),
1927 ut_dulint_get_low(roll_ptr),
1928 info_bits);
1929
1930 if (table) {
1931 index = dict_table_get_first_index(table);
1932
1933 mem_heap_t* heap = mem_heap_create(100);
1934 dtuple_t* ref;
1935
1936 ptr = trx_undo_rec_get_row_ref(ptr, index, &ref, heap);
1937
1938 if (ptr != NULL) {
1939
1940 for (ulint i = 0;
1941 i < dtuple_get_n_fields(ref);i++) {
1942 dfield_t* dfield =
1943 dtuple_get_nth_field(ref, i);
1944
1945 ib_logger(ib_stream,
1946 "(%s/%s/%lu) %s:",
1947 table->name, index->name,
1948 i,
1949 dict_table_get_col_name(table,
1950 i));
1951 ib_page_rec_print_field(dfield,
1952 NULL, 0, NULL);
1953 ib_logger(ib_stream, "\n");
1954 }
1955 }
1956
1957 if (type == TRX_UNDO_UPD_EXIST_REC ||
1958 type == TRX_UNDO_UPD_DEL_REC ||
1959 type == TRX_UNDO_DEL_MARK_REC) {
1960
1961 ptr = trx_undo_update_rec_get_update(ptr, index,
1962 type, trx_id,
1963 roll_ptr, info_bits,
1964 NULL, heap, &update);
1965
1966 if (ptr != NULL) {
1967
1968 for (ulint i = 0;
1969 i < upd_get_n_fields(update);
1970 i++) {
1971 upd_field_t* upd_field;
1972 dfield_t* field;
1973 upd_field = upd_get_nth_field(
1974 update, i);
1975 field = &upd_field->new_val;
1976 ib_logger(ib_stream,
1977 "(%s/%s/%u) %s:",
1978 table->name,
1979 index->name,
1980 upd_field->field_no,
1981 dict_table_get_col_name(
1982 table,
1983 upd_field->field_no));
1984 ib_page_rec_print_field(field,
1985 NULL, 0, NULL);
1986 ib_logger(ib_stream, "\n");
1987 }
1988
1989 }
1990
1991 }
1992
1993 mem_heap_free(heap);
1994
1995 }
1996
1997 prev_offs = rec_offs;
1998 rec_offs = mach_read_from_2(rec - 2);
1999
2000 ib_logger(ib_stream, "prev_offs: %lu, rec_offs: %lu\n",
2001 prev_offs, rec_offs);
2002
2003 }
2004
2005}
2006
2007/***************************************************************//**
2008Test if page is UNDO INSERT page.
2009@return TRUE if page is UNDO INSERT page; FALE otherwise */
2010UNIV_INTERN
2011ibool
2012ib_page_is_undo_insert(
2013/*===================*/
2014 const page_t* page) /*!< in: page */
2015{
2016 return (mach_read_from_2(page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE)
2017 == TRX_UNDO_INSERT);
2018}
2019
2020/***************************************************************//**
2021Test if page is UNDO UPDATE page.
2022@return TRUE if page is UNDO UPDATE page; FALE otherwise */
2023UNIV_INTERN
2024ibool
2025ib_page_is_undo_update(
2026/*===================*/
2027 const page_t* page) /*!< in: page */
2028{
2029 return (mach_read_from_2(page + TRX_UNDO_PAGE_HDR
2030 + TRX_UNDO_PAGE_TYPE)
2031 == TRX_UNDO_UPDATE);
2032}
2033
2034/***************************************************************//**
2035Test if page is UNDO page.
2036@return TRUE if page is UNDO page; FALE otherwise */
2037UNIV_INTERN
2038ibool
2039ib_page_is_undo(
2040/*============*/
2041 const page_t* page) /*!< in: page */
2042{
2043 return ib_page_is_undo_insert(page) || ib_page_is_undo_update(page);
2044}
2045
2046/***************************************************************//**
2047Print file-based list address. */
2048UNIV_INTERN
2049void
2050ib_page_print_flst_addr(
2051/*====================*/
2052 const byte* base) /*!< in: pointer to base node of list */
2053{
2054 ulint page = mach_read_from_4(base + FIL_ADDR_PAGE);
2055 ulint boffset = mach_read_from_2(base + FIL_ADDR_BYTE);
2056 ib_logger(ib_stream, "page %lu, byte offset %lu\n",
2057 page, boffset);
2058}
2059
2060/***************************************************************//**
2061Print file-based list. */
2062UNIV_INTERN
2063void
2064ib_page_print_flst(
2065/*===============*/
2066 const byte* base) /*!< in: pointer to base node of list */
2067{
2068 ulint len = mach_read_from_4(base + FLST_LEN);
2069 ib_logger(ib_stream, "len: %lu\n", len);
2070 ib_logger(ib_stream, "first: ");
2071 ib_page_print_flst_addr(base + FLST_FIRST);
2072 ib_logger(ib_stream, "last: ");
2073 ib_page_print_flst_addr(base + FLST_LAST);
2074}
2075
2076/***************************************************************//**
2077Print filespace header page. */
2078UNIV_INTERN
2079void
2080ib_page_print_fsp_header(
2081/*=====================*/
2082 const page_t* page) /*!< in: page */
2083{
2084 const byte* header;
2085
2086 ut_a(mach_read_from_2(page + FIL_PAGE_TYPE) == FIL_PAGE_TYPE_FSP_HDR);
2087
2088 header = FSP_HEADER_OFFSET + page;
2089
2090 ib_logger(ib_stream,
2091 "space id: %lu, not used: %lu, size: %lu\n"
2092 "free limit: %lu, space flags: %lu, frag n used: %lu\n",
2093 mach_read_from_4(header + FSP_SPACE_ID),
2094 mach_read_from_4(header + FSP_NOT_USED),
2095 mach_read_from_4(header + FSP_SIZE),
2096 mach_read_from_4(header + FSP_FREE_LIMIT),
2097 mach_read_from_4(header + FSP_SPACE_FLAGS),
2098 mach_read_from_4(header + FSP_FRAG_N_USED));
2099
2100 dulint seg_id = mach_read_from_8(header + FSP_SEG_ID);
2101 ib_logger(ib_stream, "seg_id: {%lu %lu}\n\n",
2102 ut_dulint_get_high(seg_id),
2103 ut_dulint_get_low(seg_id));
2104
2105 ib_logger(ib_stream, "FREE LIST:\n");
2106 ib_page_print_flst(header + FSP_FREE);
2107 ib_logger(ib_stream, "\n");
2108 ib_logger(ib_stream, "FREE FRAG LIST:\n");
2109 ib_page_print_flst(header + FSP_FREE_FRAG);
2110 ib_logger(ib_stream, "\n");
2111 ib_logger(ib_stream, "FREE FULL FRAG LIST:\n");
2112 ib_page_print_flst(header + FSP_FULL_FRAG);
2113 ib_logger(ib_stream, "\n");
2114 ib_logger(ib_stream, "FREE FSP SEG INODES FULL LIST:\n");
2115 ib_page_print_flst(header + FSP_SEG_INODES_FULL);
2116 ib_logger(ib_stream, "\n");
2117 ib_logger(ib_stream, "FREE FSP SEG INODES FREE LIST:\n");
2118 ib_page_print_flst(header + FSP_SEG_INODES_FREE);
2119 ib_logger(ib_stream, "\n");
2120
2121}
2122
2123/***************************************************************//**
2124Print ZBLOB page. */
2125UNIV_INTERN
2126void
2127ib_page_print_zblob(
2128/*================*/
2129 const page_t* page, /*!< in: page */
2130 ulint zip_size) /*!< in: compressed page size, or
2131 0 for uncompressed pages */
2132{
2133 enum { buf_len = 80 };
2134 const ulint offset = FIL_PAGE_NEXT;
2135 char buf[buf_len];
2136
2137 ulint next_page_no = mach_read_from_4(page + offset);
2138
2139 ib_logger(ib_stream,
2140 "compressed blob page, next page %lu\n", next_page_no);
2141 ib_page_format_bin(buf, buf_len, page + FIL_PAGE_DATA, zip_size);
2142 ib_logger(ib_stream, "data: %s\n", buf);
2143
2144 // TODO: we might uncompress page. do we need it?
2145}
2146
2147/***************************************************************//**
2148Print ZBLOB2 page. */
2149UNIV_INTERN
2150void
2151ib_page_print_zblob2(
2152/*=================*/
2153 const page_t* page, /*!< in: page */
2154 ulint zip_size) /*!< in: compressed page size, or
2155 0 for uncompressed pages */
2156{
2157 enum { buf_len = 80 };
2158 const ulint offset = FIL_PAGE_NEXT;
2159 char buf[buf_len];
2160
2161 ulint next_page_no = mach_read_from_4(page + offset);
2162
2163 ib_logger(ib_stream,
2164 "compressed blob (continued) page, next page %lu\n",
2165 next_page_no);
2166 ib_page_format_bin(buf, buf_len, page + FIL_PAGE_DATA, zip_size);
2167 ib_logger(ib_stream, "data: %s\n", buf);
2168}
2169
2170/***************************************************************//**
2171Print BLOB page. */
2172UNIV_INTERN
2173void
2174ib_page_print_blob(
2175/*===============*/
2176 const page_t* page) /*!< in: page */
2177{
2178 enum { buf_len = 80 };
2179 const ulint offset = FIL_PAGE_DATA;
2180 char buf[buf_len];
2181
2182 ulint next_page_no = mach_read_from_4(
2183 page + offset + BTR_BLOB_HDR_NEXT_PAGE_NO);
2184 ulint part_len = mach_read_from_4(
2185 page + offset + BTR_BLOB_HDR_PART_LEN);
2186
2187 ib_logger(ib_stream,
2188 "blob page, next page %lu, part len %lu\n",
2189 next_page_no, part_len);
2190 ib_page_format_bin(buf, buf_len, page + offset + BTR_BLOB_HDR_SIZE,
2191 part_len);
2192 ib_logger(ib_stream, "data: %s\n", buf);
2193}
2194
2195/***************************************************************//**
2196Print inode page. */
2197UNIV_INTERN
2198void
2199ib_page_print_inode(
2200/*================*/
2201 const page_t* page, /*!< in: page */
2202 ulint zip_size) /*!< in: compressed page size, or
2203 0 for uncompressed pages */
2204{
2205 for (ulint i = 0; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++)
2206 {
2207 const byte* inode;
2208 inode = page + FSEG_ARR_OFFSET + FSEG_INODE_SIZE * i;
2209
2210 ib_logger(ib_stream, "====================================\n");
2211 ib_logger(ib_stream, "Inode ");
2212
2213 dulint seg_id = mach_read_from_8(inode + FSEG_ID);
2214 ib_logger(ib_stream, "segment id {%lu %lu}, ",
2215 ut_dulint_get_high(seg_id), ut_dulint_get_low(seg_id));
2216 dulint seg_not_full_n_used = mach_read_from_8(
2217 inode + FSEG_NOT_FULL_N_USED);
2218 ib_logger(ib_stream, "number of used segment pages in "
2219 "FSEG_NOT_FULL list {%lu %lu}\n\n",
2220 ut_dulint_get_low(seg_not_full_n_used),
2221 ut_dulint_get_low(seg_not_full_n_used));
2222
2223 ib_logger(ib_stream, "List of free extents of this segment:\n");
2224 ib_page_print_flst(inode + FSEG_FREE);
2225
2226 ib_logger(ib_stream, "\nList of partially free extents:\n");
2227 ib_page_print_flst(inode + FSEG_NOT_FULL);
2228
2229 ib_logger(ib_stream, "\nList of full extents:\n");
2230 ib_page_print_flst(inode + FSEG_FULL);
2231
2232 ulint magic_n = mach_read_from_4(inode + FSEG_MAGIC_N);
2233 ib_logger(ib_stream, "\nMagic number %lu (should be %lu)\n\n",
2234 magic_n, (ulint) FSEG_MAGIC_N_VALUE);
2235
2236 for (ulint i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++)
2237 {
2238 ulint frag_n = mach_read_from_4(inode + FSEG_FRAG_ARR
2239 + i * FSEG_FRAG_SLOT_SIZE);
2240 ib_logger(ib_stream, "%2lu frag slot: %lu", i, frag_n);
2241 ib_logger(ib_stream, "%s\n",
2242 frag_n == FIL_NULL ? " (null)" : "");
2243 }
2244 ib_logger(ib_stream, "\n");
2245 }
2246}
2247
2248/***************************************************************//**
2249@return XDES state as string. */
2250UNIV_INTERN
2251const char*
2252ib_page_xdes_state_str(
2253/*===================*/
2254 ulint state) /*!< in: XDES state */
2255{
2256 switch (state) {
2257 case XDES_FREE:
2258 return "extent is in free list of space";
2259 case XDES_FREE_FRAG:
2260 return "extent is in free fragment list of space";
2261 case XDES_FULL_FRAG:
2262 return "extent is in full fragment list of space";
2263 case XDES_FSEG:
2264 return "extent belongs to a segment";
2265 }
2266 return "unknown";
2267}
2268
2269/***************************************************************//**
2270Print XDES page. */
2271UNIV_INTERN
2272void
2273ib_page_print_xdes(
2274/*===============*/
2275 const page_t* page, /*!< in: page */
2276 ulint zip_size) /*!< in: compressed page size, or
2277 0 for uncompressed pages */
2278{
2279
2280 for (ulint j = 0;
2281 j < (zip_size ? zip_size : UNIV_PAGE_SIZE) / FSP_EXTENT_SIZE;
2282 j++)
2283 {
2284 const byte* descr = page + XDES_ARR_OFFSET + XDES_SIZE * j;
2285
2286 dulint seg_id = mach_read_from_8(descr + XDES_ID);
2287 ib_logger(ib_stream, "====================================\n");
2288 ib_logger(ib_stream, "Segment ID {%lu %lu}\n\n",
2289 ut_dulint_get_high(seg_id), ut_dulint_get_low(seg_id));
2290
2291 ib_logger(ib_stream, "List of descriptors:\n");
2292 ib_page_print_flst(descr + XDES_FLST_NODE);
2293
2294 ulint state = mach_read_from_4(descr + XDES_STATE);
2295 ib_logger(ib_stream, "\nState of descriptor %lu (%s)\n",
2296 state, ib_page_xdes_state_str(state));
2297
2298 ib_logger(ib_stream, "\nXDES bitmap\n");
2299 for (ulint i = 0; i < FSP_EXTENT_SIZE; i++)
2300 {
2301 ulint index;
2302 ulint byte_index;
2303 ulint bit_index;
2304 byte byte_contents;
2305
2306 index = XDES_FREE_BIT + XDES_BITS_PER_PAGE * i;
2307 byte_index = index / 8;
2308 bit_index = index % 8;
2309
2310 ib_logger(ib_stream, "%2lu", i);
2311
2312 byte_contents = mach_read_from_1(descr
2313 + XDES_BITMAP + byte_index);
2314 ib_logger(ib_stream, "%12s", ut_bit_get_nth(
2315 byte_contents,
2316 bit_index) ? "free" : "not free");
2317
2318 index = XDES_CLEAN_BIT + XDES_BITS_PER_PAGE * i;
2319 ib_logger(ib_stream, "%12s", ut_bit_get_nth(
2320 byte_contents,
2321 bit_index + 1) ? "clean" : "not clean");
2322
2323 ib_logger(ib_stream, "\n");
2324 }
2325 ib_logger(ib_stream, "\n");
2326 }
2327}
2328
2329#define DICT_HDR_MIX_ID DICT_HDR_MAX_SPACE_ID
2330
2331#define DICT_HDR_XTRADB_FLAG ut_dulint_create(0x58545241UL,0x44425F31UL) /* "XTRADB_1" */
2332#define DICT_HDR_STATS 52 /* Root of the stats tree */
2333#define DICT_HDR_XTRADB_MARK 256 /* Flag to distinguish expansion of XtraDB */
2334
2335/***************************************************************//**
2336Print page dictionary header. */
2337UNIV_INTERN
2338void
2339ib_page_print_dict_header(
2340/*======================*/
2341 const page_t* page) /*!< in: page */
2342{
2343 const page_t* header;
2344 dulint row_id;
2345 dulint table_id;
2346 dulint index_id;
2347 dulint mix_id;
2348 ulint tables_root;
2349 ulint table_ids_root;
2350 ulint columns_root;
2351 ulint indexes_root;
2352 ulint fields_root;
2353
2354
2355 header = page + DICT_HDR;
2356 row_id = mach_read_from_8(header + DICT_HDR_ROW_ID);
2357 table_id = mach_read_from_8(header + DICT_HDR_TABLE_ID);
2358 index_id = mach_read_from_8(header + DICT_HDR_INDEX_ID);
2359 mix_id = mach_read_from_8(header + DICT_HDR_MIX_ID);
2360 tables_root = mach_read_from_4(header + DICT_HDR_TABLES);
2361 table_ids_root = mach_read_from_4(header + DICT_HDR_TABLE_IDS);
2362 columns_root = mach_read_from_4(header + DICT_HDR_COLUMNS);
2363 indexes_root = mach_read_from_4(header + DICT_HDR_INDEXES);
2364 fields_root = mach_read_from_4(header + DICT_HDR_FIELDS);
2365
2366 ib_logger(ib_stream, "latest assigned IDS:\n"
2367 "row {%lu, %lu}, table {%lu, %lu}, "
2368 "index {%lu, %lu}, mix {%lu, %lu}\n"
2369 "root pages:\n"
2370 "tables %lu, tables secondary %lu, columns %lu, "
2371 "indexes %lu, fields %lu\n",
2372 ut_dulint_get_high(row_id), ut_dulint_get_low(row_id),
2373 ut_dulint_get_high(table_id), ut_dulint_get_low(table_id),
2374 ut_dulint_get_high(index_id), ut_dulint_get_low(index_id),
2375 ut_dulint_get_high(mix_id), ut_dulint_get_low(mix_id),
2376 tables_root, table_ids_root, columns_root,
2377 indexes_root, fields_root);
2378
2379
2380 if (ut_dulint_cmp(mach_read_from_8(header + DICT_HDR_XTRADB_MARK),
2381 DICT_HDR_XTRADB_FLAG) == 0)
2382 {
2383 ib_logger(ib_stream,
2384 "XtraDB detected, SYS_STATS root page %lu\n",
2385 mach_read_from_4(header + DICT_HDR_STATS));
2386 }
2387}
2388
2389/*******************************************************************//**
2390Print page stored in memory. */
2391ib_err_t
2392ib_page_print_mem(
2393 const page_t* page, /*!< in: page */
2394 ulint zip_size, /*!< in: compressed page size, or
2395 0 for uncompressed pages */
2396 ibool print_contents) /*!< in: TRUE if page print contents */
2397{
2398 ib_buf_page_print_header(page, zip_size);
2399 ib_page_page_header_print(page);
2400 if (print_contents)
2401 {
2402 switch (fil_page_get_type(page)) {
2403 case FIL_PAGE_INDEX:
2404 {
2405 dict_index_t* index;
2406 ib_page_page_dir_print(page);
2407 ib_logger(ib_stream, "WILL PRINT RECORDS\n");
2408 index = ib_dict_index_get_on_id(
2409 btr_page_get_index_id(page));
2410 ib_page_page_print_list(page, index);
2411 break;
2412 }
2413 case FIL_PAGE_IBUF_BITMAP:
2414 {
2415 ib_logger(ib_stream, "PAGE BITS:\n");
2416 ib_page_ibuf_bitmap_print(page, zip_size);
2417 break;
2418 }
2419 case FIL_PAGE_UNDO_LOG:
2420 {
2421 ib_page_print_undo(page);
2422 break;
2423 }
2424 case FIL_PAGE_TYPE_BLOB:
2425 {
2426 ib_page_print_blob(page);
2427 break;
2428 }
2429 case FIL_PAGE_TYPE_ZBLOB:
2430 {
2431 ib_page_print_zblob(page, zip_size);
2432 break;
2433 }
2434 case FIL_PAGE_TYPE_ZBLOB2:
2435 {
2436 ib_page_print_zblob2(page, zip_size);
2437 break;
2438 }
2439 case FIL_PAGE_TYPE_FSP_HDR:
2440 {
2441 ib_page_print_fsp_header(page);
2442 break;
2443 }
2444 case FIL_PAGE_INODE:
2445 {
2446 ib_page_print_inode(page, zip_size);
2447 break;
2448 }
2449 case FIL_PAGE_TYPE_XDES:
2450 {
2451 ib_page_print_xdes(page, zip_size);
2452 break;
2453 }
2454 case FIL_PAGE_TYPE_SYS:
2455 {
2456 if (page_get_page_no(page) == DICT_HDR_PAGE_NO)
2457 {
2458 ib_page_print_dict_header(page);
2459 }
2460 }
2461 }
2462 }
2463 ib_logger(ib_stream, "PAGE PRINT END\n");
2464
2465 return DB_SUCCESS;
2466}
2467
2468/*******************************************************************//**
2469Print page stored in file. */
2470ib_err_t
2471ib_page_print_file(
2472 const char* ibd_file_name, /*!< in: file name */
2473 ulint page_no, /*!< in: number of page to print */
2474 ibool print_contents) /*!< in: TRUE if page print contents */
2475{
2476 ib_err_t err;
2477 mem_heap_t* heap = mem_heap_create(100);
2478 ulint zip_size;
2479 page_t* compressed_page;
2480 page_t* decompressed_page;
2481
2482 if (!ib_page_load(ibd_file_name, page_no, &zip_size,
2483 &compressed_page, &decompressed_page, heap))
2484 {
2485 mem_heap_free(heap);
2486 return DB_ERROR;
2487 }
2488
2489 if (!print_contents)
2490 {
2491 ib_logger(ib_stream, "Print page header only\n");
2492 }
2493
2494 page_t* page = decompressed_page;
2495
2496 err = ib_page_print_mem(page, zip_size, print_contents);
2497
2498 mem_heap_free(heap);
2499
2500 return err;
2501}
2502
2503/*******************************************************************//**
2504Format SYS value. */
2505UNIV_INTERN
2506void
2507ib_page_format_sys(
2508/*===============*/
2509 ulint prtype, /*!< in: precise type */
2510 char* buf, /*!< out: buffer */
2511 ulint buf_len, /*!< in: buffer length */
2512 const byte* data) /*!< in: field data */
2513{
2514 dulint id;
2515 switch (prtype & DATA_SYS_PRTYPE_MASK) {
2516 case DATA_TRX_ID:
2517 id = mach_read_from_6(data);
2518
2519 snprintf(buf, buf_len, "trx_id " TRX_ID_FMT,
2520 TRX_ID_PREP_PRINTF(id));
2521 break;
2522
2523 case DATA_ROLL_PTR:
2524 id = mach_read_from_7(data);
2525
2526 snprintf(buf, buf_len, "roll_ptr {%lu %lu}",
2527 ut_dulint_get_high(id), ut_dulint_get_low(id));
2528 break;
2529
2530 case DATA_ROW_ID:
2531 id = mach_read_from_6(data);
2532
2533 snprintf(buf, buf_len, "row_id {%lu %lu}",
2534 ut_dulint_get_high(id), ut_dulint_get_low(id));
2535 break;
2536
2537 default:
2538 id = mach_dulint_read_compressed(data);
2539
2540 snprintf(buf, buf_len, "mix_id {%lu %lu}",
2541 ut_dulint_get_high(id), ut_dulint_get_low(id));
2542 }
2543}
2544
2545/*******************************************************************//**
2546Format INT value. */
2547UNIV_INTERN
2548void
2549ib_page_format_int(
2550/*===============*/
2551 ulint prtype, /*!< in: precise type */
2552 char* buf, /*!< out: buffer */
2553 ulint buf_len, /*!< in: buffer length */
2554 const byte* data, /*!< in: field data */
2555 ulint data_len) /*!< in: length of data */
2556{
2557 ulint val;
2558 dulint id;
2559 switch (data_len) {
2560 case 1:
2561 val = mach_read_from_1(data);
2562
2563 if (!(prtype & DATA_UNSIGNED)) {
2564 val &= ~0x80;
2565 snprintf(buf, buf_len, "%ld", (long) val);
2566 } else {
2567 snprintf(buf, buf_len, "%lu", (ulong) val);
2568 }
2569 break;
2570
2571 case 2:
2572 val = mach_read_from_2(data);
2573
2574 if (!(prtype & DATA_UNSIGNED)) {
2575 val &= ~0x8000;
2576 snprintf(buf, buf_len, "%ld", (long) val);
2577 } else {
2578 snprintf(buf, buf_len, "%lu", (ulong) val);
2579 }
2580 break;
2581
2582 case 3:
2583 val = mach_read_from_3(data);
2584
2585 if (!(prtype & DATA_UNSIGNED)) {
2586 val &= ~0x800000;
2587 snprintf(buf, buf_len, "%ld", (long) val);
2588 } else {
2589 snprintf(buf, buf_len, "%lu", (ulong) val);
2590 }
2591 break;
2592
2593 case 4:
2594 val = mach_read_from_4(data);
2595
2596 if (!(prtype & DATA_UNSIGNED)) {
2597 val &= ~0x80000000;
2598 snprintf(buf, buf_len, "%ld", (long) val);
2599 } else {
2600 snprintf(buf, buf_len, "%lu", (ulong) val);
2601 }
2602 break;
2603
2604 case 6:
2605 id = mach_read_from_6(data);
2606 snprintf(buf, buf_len, "{%lu %lu}",
2607 ut_dulint_get_high(id),
2608 ut_dulint_get_low(id));
2609 break;
2610
2611 case 7:
2612 id = mach_read_from_7(data);
2613 snprintf(buf, buf_len, "{%lu %lu}",
2614 ut_dulint_get_high(id),
2615 ut_dulint_get_low(id));
2616 break;
2617 case 8:
2618 id = mach_read_from_8(data);
2619 snprintf(buf, buf_len, "{%lu %lu}",
2620 ut_dulint_get_high(id),
2621 ut_dulint_get_low(id));
2622 break;
2623 default:
2624 break;
2625 }
2626}
2627
2628
2629/*******************************************************************//**
2630Format string value. */
2631UNIV_INTERN
2632void
2633ib_page_format_str(
2634/*===============*/
2635 char* buf, /*!< out: buffer */
2636 ulint buf_len, /*!< in: buffer length */
2637 const byte* data, /*!< in: field data */
2638 ulint data_len) /*!< in: length of data */
2639{
2640 if (data_len >= buf_len) {
2641 strncpy(buf, (const char*)data, buf_len);
2642 buf[buf_len - 4]= '.';
2643 buf[buf_len - 3]= '.';
2644 buf[buf_len - 2]= '.';
2645 buf[buf_len - 1]= 0;
2646 } else if (data_len != UNIV_SQL_NULL) {
2647 strncpy(buf, (const char*)data, data_len);
2648 buf[data_len]= 0;
2649 }
2650}
2651
2652
2653/*******************************************************************//**
2654Format binalry value. */
2655UNIV_INTERN
2656void ib_page_format_bin(
2657/*====================*/
2658 char* buf, /*!< out: buffer */
2659 ulint buf_len, /*!< in: buffer length */
2660 const byte* data, /*!< in: field data */
2661 ulint data_len) /*!< in: length of data */
2662{
2663 ulint i;
2664 for (i = 0; i < data_len * 2 && i + 2 < buf_len; i += 2)
2665 sprintf(buf + i, "%02x", data[i / 2]);
2666 if (data_len * 2 >= buf_len) {
2667 buf[buf_len - 5]= '.';
2668 buf[buf_len - 4]= '.';
2669 buf[buf_len - 3]= '.';
2670 buf[buf_len - 2]= '.';
2671 }
2672 buf[buf_len - 1]= 0;
2673}
2674
2675
2676/***************************************************************//**
2677Hex dump of page. */
2678UNIV_INTERN
2679void
2680ib_page_print_hex_dump(
2681/*===================*/
2682 const page_t* page, /*!< in: page */
2683 ulint zip_size) /*!< in: compressed page size, or
2684 0 for uncompressed pages */
2685{
2686 const byte* s = page;
2687 ulint addr;
2688 const ulint width = 32; /* bytes per line */
2689 ulint size;
2690
2691 size = zip_size ? zip_size : UNIV_PAGE_SIZE;
2692
2693 for (addr = 0; addr < size; addr += width) {
2694 ulint i;
2695
2696 ib_logger(ib_stream, "%04lx ", (ulong) addr);
2697
2698 i = ut_min(width, size - addr);
2699
2700 while (i--) {
2701 ib_logger(ib_stream, "%02x", *s++);
2702 }
2703
2704 ib_logger(ib_stream, "\n");
2705 }
2706}
2707
2708
2709/***************************************************************//**
2710Format externally stored field. */
2711UNIV_INTERN
2712void
2713ib_page_format_ext(
2714/*===============*/
2715 char* buf, /*!< out: buffer */
2716 ulint buf_len, /*!< in: buffer length */
2717 const rec_t* rec, /*!< in: physical record */
2718 ulint no, /*!< in: field number */
2719 const ulint* offsets) /*!< in: array returned by
2720 rec_get_offsets() */
2721{
2722 char local_data[30];
2723 ulint local_len;
2724 ulint space_id;
2725 ulint page_no;
2726 ulint offset;
2727 ulint extern_len;
2728 const byte* data;
2729
2730 ut_a(rec_offs_nth_extern(offsets, no));
2731
2732 /* An externally stored field can contain some initial
2733 data from the field, and in the last 20 bytes it has the
2734 space id, page number, and offset where the rest of the
2735 field data is stored, and the data length in addition to
2736 the data stored locally. We may need to store some data
2737 locally to get the local record length above the 128 byte
2738 limit so that field offsets are stored in two bytes, and
2739 the extern bit is available in those two bytes. */
2740
2741 data = rec_get_nth_field(rec, offsets, no, &local_len);
2742
2743 ib_page_format_bin(local_data, 30, data, local_len);
2744
2745 local_len -= BTR_EXTERN_FIELD_REF_SIZE;
2746
2747 space_id = mach_read_from_4(data + local_len + BTR_EXTERN_SPACE_ID);
2748
2749 page_no = mach_read_from_4(data + local_len + BTR_EXTERN_PAGE_NO);
2750
2751 offset = mach_read_from_4(data + local_len + BTR_EXTERN_OFFSET);
2752
2753 /* Currently a BLOB cannot be bigger than 4 GB; we
2754 leave the 4 upper bytes in the length field unused */
2755
2756 extern_len = mach_read_from_4(data + local_len + BTR_EXTERN_LEN + 4);
2757
2758 snprintf(buf, buf_len,
2759 "(loc len %lu, space %lu, page %lu,"
2760 " offs %lu, ext len %lu) %s",
2761 local_len, space_id, page_no,
2762 offset, extern_len, local_data);
2763
2764}
2765
2766/*******************************************************************//**
2767Print field. */
2768UNIV_INTERN
2769void
2770ib_page_rec_print_field(
2771/*====================*/
2772 const dfield_t* field, /*!< in: field */
2773 const rec_t* rec, /*!< in: physical record */
2774 ulint no, /*!< in: field number */
2775 const ulint* offsets) /*!< in: array returned by
2776 rec_get_offsets() */
2777{
2778 enum { BUF_LEN = 80 };
2779 char buf[BUF_LEN];
2780 char type_buf[BUF_LEN];
2781 const dtype_t* type;
2782 const byte* data;
2783 ulint len;
2784 ulint mtype;
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches