MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
row0import.cc
Go to the documentation of this file.
1 /*****************************************************************************
2 
3 Copyright (c) 2012, 2013, Oracle and/or its affiliates. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free Software
7 Foundation; version 2 of the License.
8 
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 
13 You should have received a copy of the GNU General Public License along with
14 this program; if not, write to the Free Software Foundation, Inc.,
15 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
16 
17 *****************************************************************************/
18 
19 /**************************************************/
26 #include "row0import.h"
27 
28 #ifdef UNIV_NONINL
29 #include "row0import.ic"
30 #endif
31 
32 #include "btr0pcur.h"
33 #include "que0que.h"
34 #include "dict0boot.h"
35 #include "ibuf0ibuf.h"
36 #include "pars0pars.h"
37 #include "row0upd.h"
38 #include "row0sel.h"
39 #include "row0mysql.h"
40 #include "srv0start.h"
41 #include "row0quiesce.h"
42 
43 #include <vector>
44 
50 #define IO_BUFFER_SIZE(n) ((1024 * 1024) / n)
51 
53 struct row_stats_t {
54  ulint m_n_deleted;
57  ulint m_n_purged;
60  ulint m_n_rows;
64 };
65 
67 struct row_index_t {
68  index_id_t m_id;
70  byte* m_name;
72  ulint m_space;
74  ulint m_page_no;
76  ulint m_type;
84  ulint m_n_uniq;
87  ulint m_n_nullable;
90  ulint m_n_fields;
94  const dict_index_t*
101 };
102 
104 struct row_import {
105  row_import() UNIV_NOTHROW
106  :
107  m_table(),
108  m_version(),
109  m_hostname(),
110  m_table_name(),
111  m_autoinc(),
112  m_page_size(),
113  m_flags(),
114  m_n_cols(),
115  m_cols(),
116  m_col_names(),
117  m_n_indexes(),
118  m_indexes(),
119  m_missing(true) { }
120 
121  ~row_import() UNIV_NOTHROW;
122 
127  row_index_t* get_index(const char* name) const UNIV_NOTHROW;
128 
133  ulint get_n_rows(const char* name) const UNIV_NOTHROW;
134 
139  ulint find_col(const char* name) const UNIV_NOTHROW;
140 
145  const dict_field_t* find_field(
146  const row_index_t* cfg_index,
147  const char* name) const UNIV_NOTHROW;
148 
153  ulint get_n_purge_failed(const char* name) const UNIV_NOTHROW;
154 
159  bool requires_purge(const char* name) const UNIV_NOTHROW
160  {
161  return(get_n_purge_failed(name) > 0);
162  }
163 
166  void set_root_by_name() UNIV_NOTHROW;
167 
171  dberr_t set_root_by_heuristic() UNIV_NOTHROW;
172 
179  THD* thd,
180  const dict_index_t* index) UNIV_NOTHROW;
181 
188  THD* thd) UNIV_NOTHROW;
189 
196  THD* thd) UNIV_NOTHROW;
197 
200  ulint m_version;
202  byte* m_hostname;
204  byte* m_table_name;
207  ib_uint64_t m_autoinc;
209  ulint m_page_size;
211  ulint m_flags;
213  ulint m_n_cols;
218  byte** m_col_names;
223  ulint m_n_indexes;
228  bool m_missing;
230 };
231 
233 class RecIterator {
234 public:
237  RecIterator() UNIV_NOTHROW
238  {
239  memset(&m_cur, 0x0, sizeof(m_cur));
240  }
241 
244  void open(buf_block_t* block) UNIV_NOTHROW
245  {
247 
248  if (!end()) {
249  next();
250  }
251  }
252 
255  void next() UNIV_NOTHROW
256  {
257  page_cur_move_to_next(&m_cur);
258  }
259 
262  rec_t* current() UNIV_NOTHROW
263  {
264  ut_ad(!end());
265  return(page_cur_get_rec(&m_cur));
266  }
267 
270  bool end() UNIV_NOTHROW
271  {
272  return(page_cur_is_after_last(&m_cur) == TRUE);
273  }
274 
277  bool remove(
278  const dict_index_t* index,
279  page_zip_des_t* page_zip,
280  ulint* offsets) UNIV_NOTHROW
281  {
282  /* We can't end up with an empty page unless it is root. */
283  if (page_get_n_recs(m_cur.block->frame) <= 1) {
284  return(false);
285  }
286 
287  return(page_delete_rec(index, &m_cur, page_zip, offsets));
288  }
289 
290 private:
291  page_cur_t m_cur;
292 };
293 
297 class IndexPurge {
298 public:
304  trx_t* trx,
305  dict_index_t* index) UNIV_NOTHROW
306  :
307  m_trx(trx),
308  m_index(index),
309  m_n_rows(0)
310  {
311  ib_logf(IB_LOG_LEVEL_INFO,
312  "Phase II - Purge records from index %s",
313  index->name);
314  }
315 
317  ~IndexPurge() UNIV_NOTHROW { }
318 
321  dberr_t garbage_collect() UNIV_NOTHROW;
322 
325  ulint get_n_rows() const UNIV_NOTHROW
326  {
327  return(m_n_rows);
328  }
329 
330 private:
333  void open() UNIV_NOTHROW;
334 
337  void close() UNIV_NOTHROW;
338 
342  dberr_t next() UNIV_NOTHROW;
343 
348  void purge_pessimistic_delete() UNIV_NOTHROW;
349 
353  void purge() UNIV_NOTHROW;
354 
355 protected:
356  // Disable copying
357  IndexPurge();
358  IndexPurge(const IndexPurge&);
359  IndexPurge &operator=(const IndexPurge&);
360 
361 private:
362  trx_t* m_trx;
363  mtr_t m_mtr;
364  btr_pcur_t m_pcur;
365  dict_index_t* m_index;
366  ulint m_n_rows;
367 };
368 
372 public:
376  :
377  m_trx(trx),
378  m_space(ULINT_UNDEFINED),
379  m_xdes(),
380  m_xdes_page_no(ULINT_UNDEFINED),
381  m_space_flags(ULINT_UNDEFINED),
382  m_table_flags(ULINT_UNDEFINED) UNIV_NOTHROW { }
383 
386  virtual ~AbstractCallback()
387  {
388  delete [] m_xdes;
389  }
390 
395  virtual dberr_t init(
396  os_offset_t file_size,
397  const buf_block_t* block) UNIV_NOTHROW;
398 
400  bool is_compressed_table() const UNIV_NOTHROW
401  {
402  return(get_zip_size() > 0);
403  }
404 
405 protected:
410  buf_frame_t* get_frame(buf_block_t* block) const UNIV_NOTHROW
411  {
412  if (is_compressed_table()) {
413  return(block->page.zip.data);
414  }
415 
416  return(buf_block_get_frame(block));
417  }
418 
422  dberr_t periodic_check() UNIV_NOTHROW
423  {
424  if (trx_is_interrupted(m_trx)) {
425  return(DB_INTERRUPTED);
426  }
427 
428  return(DB_SUCCESS);
429  }
430 
436  const xdes_t* xdes(
437  ulint page_no,
438  const page_t* page) const UNIV_NOTHROW
439  {
440  ulint offset;
441 
442  offset = xdes_calc_descriptor_index(get_zip_size(), page_no);
443 
444  return(page + XDES_ARR_OFFSET + XDES_SIZE * offset);
445  }
446 
456  dberr_t set_current_xdes(
457  ulint page_no,
458  const page_t* page) UNIV_NOTHROW
459  {
460  m_xdes_page_no = page_no;
461 
462  delete[] m_xdes;
463 
464  m_xdes = 0;
465 
466  ulint state;
467  const xdes_t* xdesc = page + XDES_ARR_OFFSET;
468 
469  state = mach_read_ulint(xdesc + XDES_STATE, MLOG_4BYTES);
470 
471  if (state != XDES_FREE) {
472 
473  m_xdes = new(std::nothrow) xdes_t[m_page_size];
474 
475  /* Trigger OOM */
476  DBUG_EXECUTE_IF("ib_import_OOM_13",
477  delete [] m_xdes; m_xdes = 0;);
478 
479  if (m_xdes == 0) {
480  return(DB_OUT_OF_MEMORY);
481  }
482 
483  memcpy(m_xdes, page, m_page_size);
484  }
485 
486  return(DB_SUCCESS);
487  }
488 
491  bool is_root_page(const page_t* page) const UNIV_NOTHROW
492  {
494 
497  }
498 
503  bool is_free(ulint page_no) const UNIV_NOTHROW
504  {
505  ut_a(xdes_calc_descriptor_page(get_zip_size(), page_no)
506  == m_xdes_page_no);
507 
508  if (m_xdes != 0) {
509  const xdes_t* xdesc = xdes(page_no, m_xdes);
510  ulint pos = page_no % FSP_EXTENT_SIZE;
511 
512  return(xdes_get_bit(xdesc, XDES_FREE_BIT, pos));
513  }
514 
515  /* If the current xdes was free, the page must be free. */
516  return(true);
517  }
518 
519 protected:
522 
524  ulint m_space;
525 
533 
535  ulint m_size;
536 
538  xdes_t* m_xdes;
539 
542 
545 
549 };
550 
555 dberr_t
557  os_offset_t file_size,
558  const buf_block_t* block) UNIV_NOTHROW
559 {
560  const page_t* page = block->frame;
561 
562  m_space_flags = fsp_header_get_flags(page);
563 
564  /* Since we don't know whether it is a compressed table
565  or not, the data is always read into the block->frame. */
566 
567  dberr_t err = set_zip_size(block->frame);
568 
569  if (err != DB_SUCCESS) {
570  return(DB_CORRUPTION);
571  }
572 
573  /* Set the page size used to traverse the tablespace. */
574 
575  m_page_size = (is_compressed_table())
576  ? get_zip_size() : fsp_flags_get_page_size(m_space_flags);
577 
578  if (m_page_size == 0) {
579  ib_logf(IB_LOG_LEVEL_ERROR, "Page size is 0");
580  return(DB_CORRUPTION);
581  } else if (!is_compressed_table() && m_page_size != UNIV_PAGE_SIZE) {
582 
583  ib_logf(IB_LOG_LEVEL_ERROR,
584  "Page size %lu of ibd file is not the same "
585  "as the server page size %lu",
586  m_page_size, UNIV_PAGE_SIZE);
587 
588  return(DB_CORRUPTION);
589 
590  } else if ((file_size % m_page_size)) {
591 
592  ib_logf(IB_LOG_LEVEL_ERROR,
593  "File size " UINT64PF " is not a multiple "
594  "of the page size %lu",
595  (ib_uint64_t) file_size, (ulong) m_page_size);
596 
597  return(DB_CORRUPTION);
598  }
599 
600  ut_a(m_space == ULINT_UNDEFINED);
601 
602  m_size = mach_read_from_4(page + FSP_SIZE);
603  m_free_limit = mach_read_from_4(page + FSP_FREE_LIMIT);
604  m_space = mach_read_from_4(page + FSP_HEADER_OFFSET + FSP_SPACE_ID);
605 
606  if ((err = set_current_xdes(0, page)) != DB_SUCCESS) {
607  return(err);
608  }
609 
610  return(DB_SUCCESS);
611 }
612 
617 
619  struct Index {
620 
621  Index(index_id_t id, ulint page_no)
622  :
623  m_id(id),
624  m_page_no(page_no) { }
625 
626  index_id_t m_id;
627  ulint m_page_no;
628  };
629 
630  typedef std::vector<Index> Indexes;
631 
636  :
637  AbstractCallback(trx),
638  m_table(table) UNIV_NOTHROW { }
639 
641  virtual ~FetchIndexRootPages() UNIV_NOTHROW { }
642 
645  virtual ulint get_space_id() const UNIV_NOTHROW
646  {
647  return(m_space);
648  }
649 
654  dberr_t check_row_format(ulint ibd_table_flags) UNIV_NOTHROW
655  {
656  dberr_t err;
657  rec_format_t ibd_rec_format;
658  rec_format_t table_rec_format;
659 
660  if (!dict_tf_is_valid(ibd_table_flags)) {
661 
662  ib_errf(m_trx->mysql_thd, IB_LOG_LEVEL_ERROR,
663  ER_TABLE_SCHEMA_MISMATCH,
664  ".ibd file has invlad table flags: %lx",
665  ibd_table_flags);
666 
667  return(DB_CORRUPTION);
668  }
669 
670  ibd_rec_format = dict_tf_get_rec_format(ibd_table_flags);
671  table_rec_format = dict_tf_get_rec_format(m_table->flags);
672 
673  if (table_rec_format != ibd_rec_format) {
674 
675  ib_errf(m_trx->mysql_thd, IB_LOG_LEVEL_ERROR,
676  ER_TABLE_SCHEMA_MISMATCH,
677  "Table has %s row format, .ibd "
678  "file has %s row format.",
680  dict_tf_to_row_format_string(ibd_table_flags));
681 
682  err = DB_CORRUPTION;
683  } else {
684  err = DB_SUCCESS;
685  }
686 
687  return(err);
688  }
689 
695  virtual dberr_t operator() (
697  buf_block_t* block) UNIV_NOTHROW;
698 
701  dberr_t build_row_import(row_import* cfg) const UNIV_NOTHROW;
702 
705 
707  Indexes m_indexes;
708 };
709 
718 dberr_t
721  buf_block_t* block) UNIV_NOTHROW
722 {
723  dberr_t err;
724 
725  if ((err = periodic_check()) != DB_SUCCESS) {
726  return(err);
727  }
728 
729  const page_t* page = get_frame(block);
730 
731  ulint page_type = fil_page_get_type(page);
732 
733  if (block->page.offset * m_page_size != offset) {
734  ib_logf(IB_LOG_LEVEL_ERROR,
735  "Page offset doesn't match file offset: "
736  "page offset: %lu, file offset: %lu",
737  (ulint) block->page.offset,
738  (ulint) (offset / m_page_size));
739 
740  err = DB_CORRUPTION;
741  } else if (page_type == FIL_PAGE_TYPE_XDES) {
742  err = set_current_xdes(block->page.offset, page);
743  } else if (page_type == FIL_PAGE_INDEX
744  && !is_free(block->page.offset)
745  && is_root_page(page)) {
746 
747  index_id_t id = btr_page_get_index_id(page);
748  ulint page_no = buf_block_get_page_no(block);
749 
750  m_indexes.push_back(Index(id, page_no));
751 
752  if (m_indexes.size() == 1) {
753 
754  m_table_flags = dict_sys_tables_type_to_tf(
755  m_space_flags,
756  page_is_comp(page) ? DICT_N_COLS_COMPACT : 0);
757 
758  err = check_row_format(m_table_flags);
759  }
760  }
761 
762  return(err);
763 }
764 
768 dberr_t
770 {
771  Indexes::const_iterator end = m_indexes.end();
772 
773  ut_a(cfg->m_table == m_table);
774  cfg->m_page_size = m_page_size;
775  cfg->m_n_indexes = m_indexes.size();
776 
777  if (cfg->m_n_indexes == 0) {
778 
779  ib_logf(IB_LOG_LEVEL_ERROR, "No B+Tree found in tablespace");
780 
781  return(DB_CORRUPTION);
782  }
783 
784  cfg->m_indexes = new(std::nothrow) row_index_t[cfg->m_n_indexes];
785 
786  /* Trigger OOM */
787  DBUG_EXECUTE_IF("ib_import_OOM_11",
788  delete [] cfg->m_indexes; cfg->m_indexes = 0;);
789 
790  if (cfg->m_indexes == 0) {
791  return(DB_OUT_OF_MEMORY);
792  }
793 
794  memset(cfg->m_indexes, 0x0, sizeof(*cfg->m_indexes) * cfg->m_n_indexes);
795 
796  row_index_t* cfg_index = cfg->m_indexes;
797 
798  for (Indexes::const_iterator it = m_indexes.begin();
799  it != end;
800  ++it, ++cfg_index) {
801 
802  char name[BUFSIZ];
803 
804  ut_snprintf(name, sizeof(name), "index" IB_ID_FMT, it->m_id);
805 
806  ulint len = strlen(name) + 1;
807 
808  cfg_index->m_name = new(std::nothrow) byte[len];
809 
810  /* Trigger OOM */
811  DBUG_EXECUTE_IF("ib_import_OOM_12",
812  delete [] cfg_index->m_name;
813  cfg_index->m_name = 0;);
814 
815  if (cfg_index->m_name == 0) {
816  return(DB_OUT_OF_MEMORY);
817  }
818 
819  memcpy(cfg_index->m_name, name, len);
820 
821  cfg_index->m_id = it->m_id;
822 
823  cfg_index->m_space = m_space;
824 
825  cfg_index->m_page_no = it->m_page_no;
826  }
827 
828  return(DB_SUCCESS);
829 }
830 
831 /* Functor that is called for each physical page that is read from the
832 tablespace file.
833 
834  1. Check each page for corruption.
835 
836  2. Update the space id and LSN on every page
837  * For the header page
838  - Validate the flags
839  - Update the LSN
840 
841  3. On Btree pages
842  * Set the index id
843  * Update the max trx id
844  * In a cluster index, update the system columns
845  * In a cluster index, update the BLOB ptr, set the space id
846  * Purge delete marked records, but only if they can be easily
847  removed from the page
848  * Keep a counter of number of rows, ie. non-delete-marked rows
849  * Keep a counter of number of delete marked rows
850  * Keep a counter of number of purge failure
851  * If a page is stamped with an index id that isn't in the .cfg file
852  we assume it is deleted and the page can be ignored.
853 
854  4. Set the page state to dirty so that it will be written to disk.
855 */
857 public:
861  PageConverter(row_import* cfg, trx_t* trx) UNIV_NOTHROW;
862 
863  virtual ~PageConverter() UNIV_NOTHROW
864  {
865  if (m_heap != 0) {
866  mem_heap_free(m_heap);
867  }
868  }
869 
872  virtual ulint get_space_id() const UNIV_NOTHROW
873  {
874  return(m_cfg->m_table->space);
875  }
876 
882  virtual dberr_t operator() (
884  buf_block_t* block) UNIV_NOTHROW;
885 private:
886 
888  enum import_page_status_t {
889  IMPORT_PAGE_STATUS_OK,
890  IMPORT_PAGE_STATUS_ALL_ZERO,
891  IMPORT_PAGE_STATUS_CORRUPTED
892  };
893 
899  dberr_t update_page(
901  ulint& page_type) UNIV_NOTHROW;
902 
903 #if defined UNIV_DEBUG
904 
906  bool trigger_corruption() UNIV_NOTHROW
907  {
908  return(false);
909  }
910  #else
911 #define trigger_corruption() (false)
912 #endif /* UNIV_DEBUG */
913 
918  dberr_t update_index_page(buf_block_t* block) UNIV_NOTHROW;
919 
924  dberr_t update_records(buf_block_t* block) UNIV_NOTHROW;
925 
931  import_page_status_t validate(
933  buf_block_t* page) UNIV_NOTHROW;
934 
939  dberr_t update_header(buf_block_t* block) UNIV_NOTHROW;
940 
947  dberr_t adjust_cluster_index_blob_column(
948  rec_t* rec,
949  const ulint* offsets,
950  ulint i) UNIV_NOTHROW;
951 
958  dberr_t adjust_cluster_index_blob_columns(
959  rec_t* rec,
960  const ulint* offsets) UNIV_NOTHROW;
961 
968  dberr_t adjust_cluster_index_blob_ref(
969  rec_t* rec,
970  const ulint* offsets) UNIV_NOTHROW;
971 
977  bool purge(const ulint* offsets) UNIV_NOTHROW;
978 
986  dberr_t adjust_cluster_record(
987  const dict_index_t* index,
988  rec_t* rec,
989  const ulint* offsets,
990  bool deleted) UNIV_NOTHROW;
991 
995  row_index_t* find_index(index_id_t id) UNIV_NOTHROW
996  {
997  row_index_t* index = &m_cfg->m_indexes[0];
998 
999  for (ulint i = 0; i < m_cfg->m_n_indexes; ++i, ++index) {
1000  if (id == index->m_id) {
1001  return(index);
1002  }
1003  }
1004 
1005  return(0);
1006 
1007  }
1008 private:
1010  row_import* m_cfg;
1011 
1013  row_index_t* m_index;
1014 
1016  lsn_t m_current_lsn;
1017 
1019  page_zip_des_t* m_page_zip_ptr;
1020 
1022  RecIterator m_rec_iter;
1023 
1025  ulint m_offsets_[REC_OFFS_NORMAL_SIZE];
1026 
1028  ulint* m_offsets;
1029 
1031  mem_heap_t* m_heap;
1032 
1034  dict_index_t* m_cluster_index;
1035 };
1036 
1040 {
1041  for (ulint i = 0; m_indexes != 0 && i < m_n_indexes; ++i) {
1042  delete [] m_indexes[i].m_name;
1043 
1044  if (m_indexes[i].m_fields == 0) {
1045  continue;
1046  }
1047 
1048  dict_field_t* fields = m_indexes[i].m_fields;
1049  ulint n_fields = m_indexes[i].m_n_fields;
1050 
1051  for (ulint j = 0; j < n_fields; ++j) {
1052  delete [] fields[j].name;
1053  }
1054 
1055  delete [] fields;
1056  }
1057 
1058  for (ulint i = 0; m_col_names != 0 && i < m_n_cols; ++i) {
1059  delete [] m_col_names[i];
1060  }
1061 
1062  delete [] m_cols;
1063  delete [] m_indexes;
1064  delete [] m_col_names;
1065  delete [] m_table_name;
1066  delete [] m_hostname;
1067 }
1068 
1073 row_index_t*
1075  const char* name) const UNIV_NOTHROW
1076 {
1077  for (ulint i = 0; i < m_n_indexes; ++i) {
1078  const char* index_name;
1079  row_index_t* index = &m_indexes[i];
1080 
1081  index_name = reinterpret_cast<const char*>(index->m_name);
1082 
1083  if (strcmp(index_name, name) == 0) {
1084 
1085  return(index);
1086  }
1087  }
1088 
1089  return(0);
1090 }
1091 
1096 ulint
1098  const char* name) const UNIV_NOTHROW
1099 {
1100  const row_index_t* index = get_index(name);
1101 
1102  ut_a(name != 0);
1103 
1104  return(index->m_stats.m_n_rows);
1105 }
1106 
1111 ulint
1113  const char* name) const UNIV_NOTHROW
1114 {
1115  const row_index_t* index = get_index(name);
1116 
1117  ut_a(name != 0);
1118 
1119  return(index->m_stats.m_n_purge_failed);
1120 }
1121 
1126 ulint
1128  const char* name) const UNIV_NOTHROW
1129 {
1130  for (ulint i = 0; i < m_n_cols; ++i) {
1131  const char* col_name;
1132 
1133  col_name = reinterpret_cast<const char*>(m_col_names[i]);
1134 
1135  if (strcmp(col_name, name) == 0) {
1136  return(i);
1137  }
1138  }
1139 
1140  return(ULINT_UNDEFINED);
1141 }
1142 
1147 const dict_field_t*
1148 row_import::find_field(
1149  const row_index_t* cfg_index,
1150  const char* name) const UNIV_NOTHROW
1151 {
1152  const dict_field_t* field = cfg_index->m_fields;
1153 
1154  for (ulint i = 0; i < cfg_index->m_n_fields; ++i, ++field) {
1155  const char* field_name;
1156 
1157  field_name = reinterpret_cast<const char*>(field->name);
1158 
1159  if (strcmp(field_name, name) == 0) {
1160  return(field);
1161  }
1162  }
1163 
1164  return(0);
1165 }
1166 
1171 dberr_t
1173  THD* thd,
1174  const dict_index_t* index) UNIV_NOTHROW
1175 {
1176  row_index_t* cfg_index;
1177  dberr_t err = DB_SUCCESS;
1178 
1179  cfg_index = get_index(index->name);
1180 
1181  if (cfg_index == 0) {
1182  ib_errf(thd, IB_LOG_LEVEL_ERROR,
1183  ER_TABLE_SCHEMA_MISMATCH,
1184  "Index %s not found in tablespace meta-data file.",
1185  index->name);
1186 
1187  return(DB_ERROR);
1188  }
1189 
1190  cfg_index->m_srv_index = index;
1191 
1192  const dict_field_t* field = index->fields;
1193 
1194  for (ulint i = 0; i < index->n_fields; ++i, ++field) {
1195 
1196  const dict_field_t* cfg_field;
1197 
1198  cfg_field = find_field(cfg_index, field->name);
1199 
1200  if (cfg_field == 0) {
1201  ib_errf(thd, IB_LOG_LEVEL_ERROR,
1202  ER_TABLE_SCHEMA_MISMATCH,
1203  "Index %s field %s not found in tablespace "
1204  "meta-data file.",
1205  index->name, field->name);
1206 
1207  err = DB_ERROR;
1208  } else {
1209 
1210  if (cfg_field->prefix_len != field->prefix_len) {
1211  ib_errf(thd, IB_LOG_LEVEL_ERROR,
1212  ER_TABLE_SCHEMA_MISMATCH,
1213  "Index %s field %s prefix len %lu "
1214  "doesn't match meta-data file value "
1215  "%lu",
1216  index->name, field->name,
1217  (ulong) field->prefix_len,
1218  (ulong) cfg_field->prefix_len);
1219 
1220  err = DB_ERROR;
1221  }
1222 
1223  if (cfg_field->fixed_len != field->fixed_len) {
1224  ib_errf(thd, IB_LOG_LEVEL_ERROR,
1225  ER_TABLE_SCHEMA_MISMATCH,
1226  "Index %s field %s fixed len %lu "
1227  "doesn't match meta-data file value "
1228  "%lu",
1229  index->name, field->name,
1230  (ulong) field->fixed_len,
1231  (ulong) cfg_field->fixed_len);
1232 
1233  err = DB_ERROR;
1234  }
1235  }
1236  }
1237 
1238  return(err);
1239 }
1240 
1246 dberr_t
1248  THD* thd) UNIV_NOTHROW
1249 {
1250  dberr_t err = DB_SUCCESS;
1251  const dict_col_t* col = m_table->cols;
1252 
1253  for (ulint i = 0; i < m_table->n_cols; ++i, ++col) {
1254 
1255  const char* col_name;
1256  ulint cfg_col_index;
1257 
1258  col_name = dict_table_get_col_name(
1259  m_table, dict_col_get_no(col));
1260 
1261  cfg_col_index = find_col(col_name);
1262 
1263  if (cfg_col_index == ULINT_UNDEFINED) {
1264 
1265  ib_errf(thd, IB_LOG_LEVEL_ERROR,
1266  ER_TABLE_SCHEMA_MISMATCH,
1267  "Column %s not found in tablespace.",
1268  col_name);
1269 
1270  err = DB_ERROR;
1271  } else if (cfg_col_index != col->ind) {
1272 
1273  ib_errf(thd, IB_LOG_LEVEL_ERROR,
1274  ER_TABLE_SCHEMA_MISMATCH,
1275  "Column %s ordinal value mismatch, it's at "
1276  "%lu in the table and %lu in the tablespace "
1277  "meta-data file",
1278  col_name,
1279  (ulong) col->ind, (ulong) cfg_col_index);
1280 
1281  err = DB_ERROR;
1282  } else {
1283  const dict_col_t* cfg_col;
1284 
1285  cfg_col = &m_cols[cfg_col_index];
1286  ut_a(cfg_col->ind == cfg_col_index);
1287 
1288  if (cfg_col->prtype != col->prtype) {
1289  ib_errf(thd,
1290  IB_LOG_LEVEL_ERROR,
1291  ER_TABLE_SCHEMA_MISMATCH,
1292  "Column %s precise type mismatch.",
1293  col_name);
1294  err = DB_ERROR;
1295  }
1296 
1297  if (cfg_col->mtype != col->mtype) {
1298  ib_errf(thd,
1299  IB_LOG_LEVEL_ERROR,
1300  ER_TABLE_SCHEMA_MISMATCH,
1301  "Column %s main type mismatch.",
1302  col_name);
1303  err = DB_ERROR;
1304  }
1305 
1306  if (cfg_col->len != col->len) {
1307  ib_errf(thd,
1308  IB_LOG_LEVEL_ERROR,
1309  ER_TABLE_SCHEMA_MISMATCH,
1310  "Column %s length mismatch.",
1311  col_name);
1312  err = DB_ERROR;
1313  }
1314 
1315  if (cfg_col->mbminmaxlen != col->mbminmaxlen) {
1316  ib_errf(thd,
1317  IB_LOG_LEVEL_ERROR,
1318  ER_TABLE_SCHEMA_MISMATCH,
1319  "Column %s multi-byte len mismatch.",
1320  col_name);
1321  err = DB_ERROR;
1322  }
1323 
1324  if (cfg_col->ind != col->ind) {
1325  err = DB_ERROR;
1326  }
1327 
1328  if (cfg_col->ord_part != col->ord_part) {
1329  ib_errf(thd,
1330  IB_LOG_LEVEL_ERROR,
1331  ER_TABLE_SCHEMA_MISMATCH,
1332  "Column %s ordering mismatch.",
1333  col_name);
1334  err = DB_ERROR;
1335  }
1336 
1337  if (cfg_col->max_prefix != col->max_prefix) {
1338  ib_errf(thd,
1339  IB_LOG_LEVEL_ERROR,
1340  ER_TABLE_SCHEMA_MISMATCH,
1341  "Column %s max prefix mismatch.",
1342  col_name);
1343  err = DB_ERROR;
1344  }
1345  }
1346  }
1347 
1348  return(err);
1349 }
1350 
1356 dberr_t
1358  THD* thd) UNIV_NOTHROW
1359 {
1360  /* Do some simple checks. */
1361 
1362  if (m_flags != m_table->flags) {
1363  ib_errf(thd, IB_LOG_LEVEL_ERROR, ER_TABLE_SCHEMA_MISMATCH,
1364  "Table flags don't match, server table has 0x%lx "
1365  "and the meta-data file has 0x%lx",
1366  (ulong) m_table->n_cols, (ulong) m_flags);
1367 
1368  return(DB_ERROR);
1369  } else if (m_table->n_cols != m_n_cols) {
1370  ib_errf(thd, IB_LOG_LEVEL_ERROR, ER_TABLE_SCHEMA_MISMATCH,
1371  "Number of columns don't match, table has %lu "
1372  "columns but the tablespace meta-data file has "
1373  "%lu columns",
1374  (ulong) m_table->n_cols, (ulong) m_n_cols);
1375 
1376  return(DB_ERROR);
1377  } else if (UT_LIST_GET_LEN(m_table->indexes) != m_n_indexes) {
1378 
1379  /* If the number of indexes don't match then it is better
1380  to abort the IMPORT. It is easy for the user to create a
1381  table matching the IMPORT definition. */
1382 
1383  ib_errf(thd, IB_LOG_LEVEL_ERROR, ER_TABLE_SCHEMA_MISMATCH,
1384  "Number of indexes don't match, table has %lu "
1385  "indexes but the tablespace meta-data file has "
1386  "%lu indexes",
1387  (ulong) UT_LIST_GET_LEN(m_table->indexes),
1388  (ulong) m_n_indexes);
1389 
1390  return(DB_ERROR);
1391  }
1392 
1393  dberr_t err = match_table_columns(thd);
1394 
1395  if (err != DB_SUCCESS) {
1396  return(err);
1397  }
1398 
1399  /* Check if the index definitions match. */
1400 
1401  const dict_index_t* index;
1402 
1403  for (index = UT_LIST_GET_FIRST(m_table->indexes);
1404  index != 0;
1405  index = UT_LIST_GET_NEXT(indexes, index)) {
1406 
1407  dberr_t index_err;
1408 
1409  index_err = match_index_columns(thd, index);
1410 
1411  if (index_err != DB_SUCCESS) {
1412  err = index_err;
1413  }
1414  }
1415 
1416  return(err);
1417 }
1418 
1421 void
1423 {
1424  row_index_t* cfg_index = m_indexes;
1425 
1426  for (ulint i = 0; i < m_n_indexes; ++i, ++cfg_index) {
1428 
1429  const char* index_name;
1430 
1431  index_name = reinterpret_cast<const char*>(cfg_index->m_name);
1432 
1433  index = dict_table_get_index_on_name(m_table, index_name);
1434 
1435  /* We've already checked that it exists. */
1436  ut_a(index != 0);
1437 
1438  /* Set the root page number and space id. */
1439  index->space = m_table->space;
1440  index->page = cfg_index->m_page_no;
1441  }
1442 }
1443 
1447 dberr_t
1449 {
1450  row_index_t* cfg_index = m_indexes;
1451 
1452  ut_a(m_n_indexes > 0);
1453 
1454  // TODO: For now use brute force, based on ordinality
1455 
1457 
1458  char table_name[MAX_FULL_NAME_LEN + 1];
1459 
1461  table_name, sizeof(table_name), m_table->name, FALSE);
1462 
1463  ib_logf(IB_LOG_LEVEL_WARN,
1464  "Table %s should have %lu indexes but the tablespace "
1465  "has %lu indexes",
1466  table_name,
1468  m_n_indexes);
1469  }
1470 
1472 
1473  ulint i = 0;
1474  dberr_t err = DB_SUCCESS;
1475 
1477  index != 0;
1478  index = UT_LIST_GET_NEXT(indexes, index)) {
1479 
1480  if (index->type & DICT_FTS) {
1481  index->type |= DICT_CORRUPT;
1482  ib_logf(IB_LOG_LEVEL_WARN,
1483  "Skipping FTS index: %s", index->name);
1484  } else if (i < m_n_indexes) {
1485 
1486  delete [] cfg_index[i].m_name;
1487 
1488  ulint len = strlen(index->name) + 1;
1489 
1490  cfg_index[i].m_name = new(std::nothrow) byte[len];
1491 
1492  /* Trigger OOM */
1493  DBUG_EXECUTE_IF("ib_import_OOM_14",
1494  delete[] cfg_index[i].m_name;
1495  cfg_index[i].m_name = 0;);
1496 
1497  if (cfg_index[i].m_name == 0) {
1498  err = DB_OUT_OF_MEMORY;
1499  break;
1500  }
1501 
1502  memcpy(cfg_index[i].m_name, index->name, len);
1503 
1504  cfg_index[i].m_srv_index = index;
1505 
1506  index->space = m_table->space;
1507  index->page = cfg_index[i].m_page_no;
1508 
1509  ++i;
1510  }
1511  }
1512 
1514 
1515  return(err);
1516 }
1517 
1521 dberr_t
1523 {
1524  dberr_t err;
1525  ibool comp = dict_table_is_comp(m_index->table);
1526 
1527  /* Open the persistent cursor and start the mini-transaction. */
1528 
1529  open();
1530 
1531  while ((err = next()) == DB_SUCCESS) {
1532 
1533  rec_t* rec = btr_pcur_get_rec(&m_pcur);
1534  ibool deleted = rec_get_deleted_flag(rec, comp);
1535 
1536  if (!deleted) {
1537  ++m_n_rows;
1538  } else {
1539  purge();
1540  }
1541  }
1542 
1543  /* Close the persistent cursor and commit the mini-transaction. */
1544 
1545  close();
1546 
1547  return(err == DB_END_OF_INDEX ? DB_SUCCESS : err);
1548 }
1549 
1552 void
1553 IndexPurge::open() UNIV_NOTHROW
1554 {
1555  mtr_start(&m_mtr);
1556 
1557  mtr_set_log_mode(&m_mtr, MTR_LOG_NO_REDO);
1558 
1560  true, m_index, BTR_MODIFY_LEAF, &m_pcur, true, 0, &m_mtr);
1561 }
1562 
1565 void
1566 IndexPurge::close() UNIV_NOTHROW
1567 {
1568  btr_pcur_close(&m_pcur);
1569  mtr_commit(&m_mtr);
1570 }
1571 
1575 dberr_t
1576 IndexPurge::next() UNIV_NOTHROW
1577 {
1579 
1580  /* When switching pages, commit the mini-transaction
1581  in order to release the latch on the old page. */
1582 
1583  if (!btr_pcur_is_after_last_on_page(&m_pcur)) {
1584  return(DB_SUCCESS);
1585  } else if (trx_is_interrupted(m_trx)) {
1586  /* Check after every page because the check
1587  is expensive. */
1588  return(DB_INTERRUPTED);
1589  }
1590 
1591  btr_pcur_store_position(&m_pcur, &m_mtr);
1592 
1593  mtr_commit(&m_mtr);
1594 
1595  mtr_start(&m_mtr);
1596 
1597  mtr_set_log_mode(&m_mtr, MTR_LOG_NO_REDO);
1598 
1599  btr_pcur_restore_position(BTR_MODIFY_LEAF, &m_pcur, &m_mtr);
1600 
1601  if (!btr_pcur_move_to_next_user_rec(&m_pcur, &m_mtr)) {
1602 
1603  return(DB_END_OF_INDEX);
1604  }
1605 
1606  return(DB_SUCCESS);
1607 }
1608 
1613 void
1614 IndexPurge::purge_pessimistic_delete() UNIV_NOTHROW
1615 {
1616  dberr_t err;
1617 
1618  btr_pcur_restore_position(BTR_MODIFY_TREE, &m_pcur, &m_mtr);
1619 
1621  btr_pcur_get_rec(&m_pcur),
1622  dict_table_is_comp(m_index->table)));
1623 
1625  &err, FALSE, btr_pcur_get_btr_cur(&m_pcur), 0, RB_NONE, &m_mtr);
1626 
1627  ut_a(err == DB_SUCCESS);
1628 
1629  /* Reopen the B-tree cursor in BTR_MODIFY_LEAF mode */
1630  mtr_commit(&m_mtr);
1631 }
1632 
1635 void
1636 IndexPurge::purge() UNIV_NOTHROW
1637 {
1638  btr_pcur_store_position(&m_pcur, &m_mtr);
1639 
1640  purge_pessimistic_delete();
1641 
1642  mtr_start(&m_mtr);
1643 
1644  mtr_set_log_mode(&m_mtr, MTR_LOG_NO_REDO);
1645 
1646  btr_pcur_restore_position(BTR_MODIFY_LEAF, &m_pcur, &m_mtr);
1647 }
1648 
1654  row_import* cfg,
1655  trx_t* trx)
1656  :
1657  AbstractCallback(trx),
1658  m_cfg(cfg),
1659  m_page_zip_ptr(0),
1660  m_heap(0) UNIV_NOTHROW
1661 {
1662  m_index = m_cfg->m_indexes;
1663 
1664  m_current_lsn = log_get_lsn();
1665  ut_a(m_current_lsn > 0);
1666 
1667  m_offsets = m_offsets_;
1668  rec_offs_init(m_offsets_);
1669 
1670  m_cluster_index = dict_table_get_first_index(m_cfg->m_table);
1671 }
1672 
1679 dberr_t
1680 PageConverter::adjust_cluster_index_blob_column(
1681  rec_t* rec,
1682  const ulint* offsets,
1683  ulint i) UNIV_NOTHROW
1684 {
1685  ulint len;
1686  byte* field;
1687 
1688  field = rec_get_nth_field(rec, offsets, i, &len);
1689 
1690  DBUG_EXECUTE_IF("ib_import_trigger_corruption_2",
1691  len = BTR_EXTERN_FIELD_REF_SIZE - 1;);
1692 
1693  if (len < BTR_EXTERN_FIELD_REF_SIZE) {
1694 
1695  char index_name[MAX_FULL_NAME_LEN + 1];
1696 
1698  index_name, sizeof(index_name),
1699  m_cluster_index->name, TRUE);
1700 
1701  ib_errf(m_trx->mysql_thd, IB_LOG_LEVEL_ERROR,
1702  ER_INNODB_INDEX_CORRUPT,
1703  "Externally stored column(%lu) has a reference "
1704  "length of %lu in the cluster index %s",
1705  (ulong) i, (ulong) len, index_name);
1706 
1707  return(DB_CORRUPTION);
1708  }
1709 
1711 
1712  if (is_compressed_table()) {
1713  mach_write_to_4(field, get_space_id());
1714 
1716  m_page_zip_ptr, rec, m_cluster_index, offsets, i, 0);
1717  } else {
1718  mlog_write_ulint(field, get_space_id(), MLOG_4BYTES, 0);
1719  }
1720 
1721  return(DB_SUCCESS);
1722 }
1723 
1730 dberr_t
1731 PageConverter::adjust_cluster_index_blob_columns(
1732  rec_t* rec,
1733  const ulint* offsets) UNIV_NOTHROW
1734 {
1736 
1737  /* Adjust the space_id in the BLOB pointers. */
1738 
1739  for (ulint i = 0; i < rec_offs_n_fields(offsets); ++i) {
1740 
1741  /* Only if the column is stored "externally". */
1742 
1743  if (rec_offs_nth_extern(offsets, i)) {
1744  dberr_t err;
1745 
1746  err = adjust_cluster_index_blob_column(rec, offsets, i);
1747 
1748  if (err != DB_SUCCESS) {
1749  return(err);
1750  }
1751  }
1752  }
1753 
1754  return(DB_SUCCESS);
1755 }
1756 
1763 dberr_t
1764 PageConverter::adjust_cluster_index_blob_ref(
1765  rec_t* rec,
1766  const ulint* offsets) UNIV_NOTHROW
1767 {
1769  dberr_t err;
1770 
1771  err = adjust_cluster_index_blob_columns(rec, offsets);
1772 
1773  if (err != DB_SUCCESS) {
1774  return(err);
1775  }
1776  }
1777 
1778  return(DB_SUCCESS);
1779 }
1780 
1786 bool
1787 PageConverter::purge(const ulint* offsets) UNIV_NOTHROW
1788 {
1789  const dict_index_t* index = m_index->m_srv_index;
1790 
1791  /* We can't have a page that is empty and not root. */
1792  if (m_rec_iter.remove(index, m_page_zip_ptr, m_offsets)) {
1793 
1794  ++m_index->m_stats.m_n_purged;
1795 
1796  return(true);
1797  } else {
1798  ++m_index->m_stats.m_n_purge_failed;
1799  }
1800 
1801  return(false);
1802 }
1803 
1810 dberr_t
1811 PageConverter::adjust_cluster_record(
1812  const dict_index_t* index,
1813  rec_t* rec,
1814  const ulint* offsets,
1815  bool deleted) UNIV_NOTHROW
1816 {
1817  dberr_t err;
1818 
1819  if ((err = adjust_cluster_index_blob_ref(rec, offsets)) == DB_SUCCESS) {
1820 
1821  /* Reset DB_TRX_ID and DB_ROLL_PTR. Normally, these fields
1822  are only written in conjunction with other changes to the
1823  record. */
1824 
1826  rec, m_page_zip_ptr, m_cluster_index, m_offsets,
1827  m_trx, 0);
1828  }
1829 
1830  return(err);
1831 }
1832 
1838 dberr_t
1839 PageConverter::update_records(
1840  buf_block_t* block) UNIV_NOTHROW
1841 {
1842  ibool comp = dict_table_is_comp(m_cfg->m_table);
1843  bool clust_index = m_index->m_srv_index == m_cluster_index;
1844 
1845  /* This will also position the cursor on the first user record. */
1846 
1847  m_rec_iter.open(block);
1848 
1849  while (!m_rec_iter.end()) {
1850 
1851  rec_t* rec = m_rec_iter.current();
1852 
1853  /* FIXME: Move out of the loop */
1854 
1855  if (rec_get_status(rec) == REC_STATUS_NODE_PTR) {
1856  break;
1857  }
1858 
1859  ibool deleted = rec_get_deleted_flag(rec, comp);
1860 
1861  /* For the clustered index we have to adjust the BLOB
1862  reference and the system fields irrespective of the
1863  delete marked flag. The adjustment of delete marked
1864  cluster records is required for purge to work later. */
1865 
1866  if (deleted || clust_index) {
1867  m_offsets = rec_get_offsets(
1868  rec, m_index->m_srv_index, m_offsets,
1869  ULINT_UNDEFINED, &m_heap);
1870  }
1871 
1872  if (clust_index) {
1873 
1874  dberr_t err = adjust_cluster_record(
1875  m_index->m_srv_index, rec, m_offsets,
1876  deleted);
1877 
1878  if (err != DB_SUCCESS) {
1879  return(err);
1880  }
1881  }
1882 
1883  /* If it is a delete marked record then try an
1884  optimistic delete. */
1885 
1886  if (deleted) {
1887  /* A successful purge will move the cursor to the
1888  next record. */
1889 
1890  if (!purge(m_offsets)) {
1891  m_rec_iter.next();
1892  }
1893 
1894  ++m_index->m_stats.m_n_deleted;
1895  } else {
1896  ++m_index->m_stats.m_n_rows;
1897  m_rec_iter.next();
1898  }
1899  }
1900 
1901  return(DB_SUCCESS);
1902 }
1903 
1907 dberr_t
1908 PageConverter::update_index_page(
1909  buf_block_t* block) UNIV_NOTHROW
1910 {
1911  index_id_t id;
1913 
1914  if (is_free(buf_block_get_page_no(block))) {
1915  return(DB_SUCCESS);
1916  } else if ((id = btr_page_get_index_id(page)) != m_index->m_id) {
1917 
1918  row_index_t* index = find_index(id);
1919 
1920  if (index == 0) {
1921  m_index = 0;
1922  return(DB_CORRUPTION);
1923  }
1924 
1925  /* Update current index */
1926  m_index = index;
1927  }
1928 
1929  /* If the .cfg file is missing and there is an index mismatch
1930  then ignore the error. */
1931  if (m_cfg->m_missing && (m_index == 0 || m_index->m_srv_index == 0)) {
1932  return(DB_SUCCESS);
1933  }
1934 
1935 #ifdef UNIV_ZIP_DEBUG
1936  ut_a(!is_compressed_table()
1937  || page_zip_validate(m_page_zip_ptr, page, m_index->m_srv_index));
1938 #endif /* UNIV_ZIP_DEBUG */
1939 
1940  /* This has to be written to uncompressed index header. Set it to
1941  the current index id. */
1942  btr_page_set_index_id(
1943  page, m_page_zip_ptr, m_index->m_srv_index->id, 0);
1944 
1945  page_set_max_trx_id(block, m_page_zip_ptr, m_trx->id, 0);
1946 
1947  if (page_is_empty(block->frame)) {
1948 
1949  /* Only a root page can be empty. */
1950  if (!is_root_page(block->frame)) {
1951  // TODO: We should relax this and skip secondary
1952  // indexes. Mark them as corrupt because they can
1953  // always be rebuilt.
1954  return(DB_CORRUPTION);
1955  }
1956 
1957  return(DB_SUCCESS);
1958  }
1959 
1960  return(update_records(block));
1961 }
1962 
1967 dberr_t
1968 PageConverter::update_header(
1969  buf_block_t* block) UNIV_NOTHROW
1970 {
1971  /* Check for valid header */
1972  switch(fsp_header_get_space_id(get_frame(block))) {
1973  case 0:
1974  return(DB_CORRUPTION);
1975  case ULINT_UNDEFINED:
1976  ib_logf(IB_LOG_LEVEL_WARN,
1977  "Space id check in the header failed "
1978  "- ignored");
1979  }
1980 
1981  ulint space_flags = fsp_header_get_flags(get_frame(block));
1982 
1983  if (!fsp_flags_is_valid(space_flags)) {
1984 
1985  ib_logf(IB_LOG_LEVEL_ERROR,
1986  "Unsupported tablespace format %lu",
1987  (ulong) space_flags);
1988 
1989  return(DB_UNSUPPORTED);
1990  }
1991 
1993  get_frame(block) + FIL_PAGE_FILE_FLUSH_LSN, m_current_lsn);
1994 
1995  /* Write space_id to the tablespace header, page 0. */
1997  get_frame(block) + FSP_HEADER_OFFSET + FSP_SPACE_ID,
1998  get_space_id());
1999 
2000  /* This is on every page in the tablespace. */
2003  get_space_id());
2004 
2005  return(DB_SUCCESS);
2006 }
2007 
2012 dberr_t
2013 PageConverter::update_page(
2014  buf_block_t* block,
2015  ulint& page_type) UNIV_NOTHROW
2016 {
2017  dberr_t err = DB_SUCCESS;
2018 
2019  switch (page_type = fil_page_get_type(get_frame(block))) {
2020  case FIL_PAGE_TYPE_FSP_HDR:
2021  /* Work directly on the uncompressed page headers. */
2023  return(update_header(block));
2024 
2025  case FIL_PAGE_INDEX:
2026  /* We need to decompress the contents into block->frame
2027  before we can do any thing with Btree pages. */
2028 
2029  if (is_compressed_table() && !buf_zip_decompress(block, TRUE)) {
2030  return(DB_CORRUPTION);
2031  }
2032 
2033  /* This is on every page in the tablespace. */
2035  get_frame(block)
2036  + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, get_space_id());
2037 
2038  /* Only update the Btree nodes. */
2039  return(update_index_page(block));
2040 
2041  case FIL_PAGE_TYPE_SYS:
2042  /* This is page 0 in the system tablespace. */
2043  return(DB_CORRUPTION);
2044 
2045  case FIL_PAGE_TYPE_XDES:
2046  err = set_current_xdes(
2047  buf_block_get_page_no(block), get_frame(block));
2048  case FIL_PAGE_INODE:
2049  case FIL_PAGE_TYPE_TRX_SYS:
2052  case FIL_PAGE_IBUF_BITMAP:
2053  case FIL_PAGE_TYPE_BLOB:
2054  case FIL_PAGE_TYPE_ZBLOB:
2055  case FIL_PAGE_TYPE_ZBLOB2:
2056 
2057  /* Work directly on the uncompressed page headers. */
2058  /* This is on every page in the tablespace. */
2060  get_frame(block)
2061  + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, get_space_id());
2062 
2063  return(err);
2064  }
2065 
2066  ib_logf(IB_LOG_LEVEL_WARN, "Unknown page type (%lu)", page_type);
2067 
2068  return(DB_CORRUPTION);
2069 }
2070 
2076 PageConverter::import_page_status_t
2077 PageConverter::validate(
2079  buf_block_t* block) UNIV_NOTHROW
2080 {
2081  buf_frame_t* page = get_frame(block);
2082 
2083  /* Check that the page number corresponds to the offset in
2084  the file. Flag as corrupt if it doesn't. Disable the check
2085  for LSN in buf_page_is_corrupted() */
2086 
2087  if (buf_page_is_corrupted(false, page, get_zip_size())
2088  || (page_get_page_no(page) != offset / m_page_size
2089  && page_get_page_no(page) != 0)) {
2090 
2091  return(IMPORT_PAGE_STATUS_CORRUPTED);
2092 
2093  } else if (offset > 0 && page_get_page_no(page) == 0) {
2094  const byte* b = page;
2095  const byte* e = b + m_page_size;
2096 
2097  /* If the page number is zero and offset > 0 then
2098  the entire page MUST consist of zeroes. If not then
2099  we flag it as corrupt. */
2100 
2101  while (b != e) {
2102 
2103  if (*b++ && !trigger_corruption()) {
2104  return(IMPORT_PAGE_STATUS_CORRUPTED);
2105  }
2106  }
2107 
2108  /* The page is all zero: do nothing. */
2109  return(IMPORT_PAGE_STATUS_ALL_ZERO);
2110  }
2111 
2112  return(IMPORT_PAGE_STATUS_OK);
2113 }
2114 
2121 dberr_t
2124  buf_block_t* block) UNIV_NOTHROW
2125 {
2126  ulint page_type;
2127  dberr_t err = DB_SUCCESS;
2128 
2129  if ((err = periodic_check()) != DB_SUCCESS) {
2130  return(err);
2131  }
2132 
2133  if (is_compressed_table()) {
2134  m_page_zip_ptr = &block->page.zip;
2135  } else {
2136  ut_ad(m_page_zip_ptr == 0);
2137  }
2138 
2139  switch(validate(offset, block)) {
2140  case IMPORT_PAGE_STATUS_OK:
2141 
2142  /* We have to decompress the compressed pages before
2143  we can work on them */
2144 
2145  if ((err = update_page(block, page_type)) != DB_SUCCESS) {
2146  return(err);
2147  }
2148 
2149  /* Note: For compressed pages this function will write to the
2150  zip descriptor and for uncompressed pages it will write to
2151  page (ie. the block->frame). Therefore the caller should write
2152  out the descriptor contents and not block->frame for compressed
2153  pages. */
2154 
2155  if (!is_compressed_table() || page_type == FIL_PAGE_INDEX) {
2156 
2158  !is_compressed_table()
2159  ? block->frame : block->page.zip.data,
2160  !is_compressed_table() ? 0 : m_page_zip_ptr,
2161  m_current_lsn);
2162  } else {
2163  /* Calculate and update the checksum of non-btree
2164  pages for compressed tables explicitly here. */
2165 
2167  get_frame(block), get_zip_size(),
2168  m_current_lsn);
2169  }
2170 
2171  break;
2172 
2173  case IMPORT_PAGE_STATUS_ALL_ZERO:
2174  /* The page is all zero: leave it as is. */
2175  break;
2176 
2177  case IMPORT_PAGE_STATUS_CORRUPTED:
2178 
2179  ib_logf(IB_LOG_LEVEL_WARN,
2180  "%s: Page %lu at offset " UINT64PF " looks corrupted.",
2181  m_filepath, (ulong) (offset / m_page_size), offset);
2182 
2183  return(DB_CORRUPTION);
2184  }
2185 
2186  return(err);
2187 }
2188 
2189 /*****************************************************************/
2193 static __attribute__((nonnull))
2194 void
2195 row_import_discard_changes(
2196 /*=======================*/
2197  row_prebuilt_t* prebuilt,
2198  trx_t* trx,
2199  dberr_t err)
2200 {
2201  dict_table_t* table = prebuilt->table;
2202 
2203  ut_a(err != DB_SUCCESS);
2204 
2205  prebuilt->trx->error_info = NULL;
2206 
2207  char table_name[MAX_FULL_NAME_LEN + 1];
2208 
2210  table_name, sizeof(table_name),
2211  prebuilt->table->name, FALSE);
2212 
2213  ib_logf(IB_LOG_LEVEL_INFO,
2214  "Discarding tablespace of table %s: %s",
2215  table_name, ut_strerr(err));
2216 
2217  if (trx->dict_operation_lock_mode != RW_X_LATCH) {
2218  ut_a(trx->dict_operation_lock_mode == 0);
2219  row_mysql_lock_data_dictionary(trx);
2220  }
2221 
2222  ut_a(trx->dict_operation_lock_mode == RW_X_LATCH);
2223 
2224  /* Since we update the index root page numbers on disk after
2225  we've done a successful import. The table will not be loadable.
2226  However, we need to ensure that the in memory root page numbers
2227  are reset to "NULL". */
2228 
2229  for (dict_index_t* index = UT_LIST_GET_FIRST(table->indexes);
2230  index != 0;
2231  index = UT_LIST_GET_NEXT(indexes, index)) {
2232 
2233  index->page = FIL_NULL;
2234  index->space = FIL_NULL;
2235  }
2236 
2237  table->ibd_file_missing = TRUE;
2238 
2239  fil_close_tablespace(trx, table->space);
2240 }
2241 
2242 /*****************************************************************/
2244 static __attribute__((nonnull, warn_unused_result))
2245 dberr_t
2246 row_import_cleanup(
2247 /*===============*/
2248  row_prebuilt_t* prebuilt,
2249  trx_t* trx,
2250  dberr_t err)
2251 {
2252  ut_a(prebuilt->trx != trx);
2253 
2254  if (err != DB_SUCCESS) {
2255  row_import_discard_changes(prebuilt, trx, err);
2256  }
2257 
2258  ut_a(trx->dict_operation_lock_mode == RW_X_LATCH);
2259 
2260  DBUG_EXECUTE_IF("ib_import_before_commit_crash", DBUG_SUICIDE(););
2261 
2262  trx_commit_for_mysql(trx);
2263 
2265 
2266  trx_free_for_mysql(trx);
2267 
2268  prebuilt->trx->op_info = "";
2269 
2270  DBUG_EXECUTE_IF("ib_import_before_checkpoint_crash", DBUG_SUICIDE(););
2271 
2272  log_make_checkpoint_at(LSN_MAX, TRUE);
2273 
2274  return(err);
2275 }
2276 
2277 /*****************************************************************/
2279 static __attribute__((nonnull, warn_unused_result))
2280 dberr_t
2281 row_import_error(
2282 /*=============*/
2283  row_prebuilt_t* prebuilt,
2284  trx_t* trx,
2285  dberr_t err)
2286 {
2287  if (!trx_is_interrupted(trx)) {
2288  char table_name[MAX_FULL_NAME_LEN + 1];
2289 
2291  table_name, sizeof(table_name),
2292  prebuilt->table->name, FALSE);
2293 
2294  ib_senderrf(
2295  trx->mysql_thd, IB_LOG_LEVEL_WARN,
2296  ER_INNODB_IMPORT_ERROR,
2297  table_name, (ulong) err, ut_strerr(err));
2298  }
2299 
2300  return(row_import_cleanup(prebuilt, trx, err));
2301 }
2302 
2303 /*****************************************************************/
2307 static __attribute__((nonnull, warn_unused_result))
2308 dberr_t
2309 row_import_adjust_root_pages_of_secondary_indexes(
2310 /*==============================================*/
2311  row_prebuilt_t* prebuilt,
2313  trx_t* trx,
2315  dict_table_t* table,
2317  const row_import& cfg)
2318 {
2320  ulint n_rows_in_table;
2321  dberr_t err = DB_SUCCESS;
2322 
2323  /* Skip the clustered index. */
2324  index = dict_table_get_first_index(table);
2325 
2326  n_rows_in_table = cfg.get_n_rows(index->name);
2327 
2328  DBUG_EXECUTE_IF("ib_import_sec_rec_count_mismatch_failure",
2329  n_rows_in_table++;);
2330 
2331  /* Adjust the root pages of the secondary indexes only. */
2332  while ((index = dict_table_get_next_index(index)) != NULL) {
2333  char index_name[MAX_FULL_NAME_LEN + 1];
2334 
2336  index_name, sizeof(index_name), index->name, TRUE);
2337 
2338  ut_a(!dict_index_is_clust(index));
2339 
2340  if (!(index->type & DICT_CORRUPT)
2341  && index->space != FIL_NULL
2342  && index->page != FIL_NULL) {
2343 
2344  /* Update the Btree segment headers for index node and
2345  leaf nodes in the root page. Set the new space id. */
2346 
2347  err = btr_root_adjust_on_import(index);
2348  } else {
2349  ib_logf(IB_LOG_LEVEL_WARN,
2350  "Skip adjustment of root pages for "
2351  "index %s.", index->name);
2352 
2353  err = DB_CORRUPTION;
2354  }
2355 
2356  if (err != DB_SUCCESS) {
2357 
2358  if (index->type & DICT_CLUSTERED) {
2359  break;
2360  }
2361 
2362  ib_errf(trx->mysql_thd,
2363  IB_LOG_LEVEL_WARN,
2364  ER_INNODB_INDEX_CORRUPT,
2365  "Index '%s' not found or corrupt, "
2366  "you should recreate this index.",
2367  index_name);
2368 
2369  /* Do not bail out, so that the data
2370  can be recovered. */
2371 
2372  err = DB_SUCCESS;
2373  index->type |= DICT_CORRUPT;
2374  continue;
2375  }
2376 
2377  /* If we failed to purge any records in the index then
2378  do it the hard way.
2379 
2380  TODO: We can do this in the first pass by generating UNDO log
2381  records for the failed rows. */
2382 
2383  if (!cfg.requires_purge(index->name)) {
2384  continue;
2385  }
2386 
2387  IndexPurge purge(trx, index);
2388 
2389  trx->op_info = "secondary: purge delete marked records";
2390 
2391  err = purge.garbage_collect();
2392 
2393  trx->op_info = "";
2394 
2395  if (err != DB_SUCCESS) {
2396  break;
2397  } else if (purge.get_n_rows() != n_rows_in_table) {
2398 
2399  ib_errf(trx->mysql_thd,
2400  IB_LOG_LEVEL_WARN,
2401  ER_INNODB_INDEX_CORRUPT,
2402  "Index '%s' contains %lu entries, "
2403  "should be %lu, you should recreate "
2404  "this index.", index_name,
2405  (ulong) purge.get_n_rows(),
2406  (ulong) n_rows_in_table);
2407 
2408  index->type |= DICT_CORRUPT;
2409 
2410  /* Do not bail out, so that the data
2411  can be recovered. */
2412 
2413  err = DB_SUCCESS;
2414  }
2415  }
2416 
2417  return(err);
2418 }
2419 
2420 /*****************************************************************/
2423 static __attribute__((nonnull, warn_unused_result))
2424 dberr_t
2425 row_import_set_sys_max_row_id(
2426 /*==========================*/
2427  row_prebuilt_t* prebuilt,
2429  const dict_table_t* table)
2430 {
2431  dberr_t err;
2432  const rec_t* rec;
2433  mtr_t mtr;
2434  btr_pcur_t pcur;
2435  row_id_t row_id = 0;
2437 
2438  index = dict_table_get_first_index(table);
2439  ut_a(dict_index_is_clust(index));
2440 
2441  mtr_start(&mtr);
2442 
2443  mtr_set_log_mode(&mtr, MTR_LOG_NO_REDO);
2444 
2446  false, // High end
2447  index,
2449  &pcur,
2450  true, // Init cursor
2451  0, // Leaf level
2452  &mtr);
2453 
2455  rec = btr_pcur_get_rec(&pcur);
2456 
2457  /* Check for empty table. */
2458  if (!page_rec_is_infimum(rec)) {
2459  ulint len;
2460  const byte* field;
2461  mem_heap_t* heap = NULL;
2462  ulint offsets_[1 + REC_OFFS_HEADER_SIZE];
2463  ulint* offsets;
2464 
2465  rec_offs_init(offsets_);
2466 
2467  offsets = rec_get_offsets(
2468  rec, index, offsets_, ULINT_UNDEFINED, &heap);
2469 
2470  field = rec_get_nth_field(
2471  rec, offsets,
2472  dict_index_get_sys_col_pos(index, DATA_ROW_ID),
2473  &len);
2474 
2475  if (len == DATA_ROW_ID_LEN) {
2476  row_id = mach_read_from_6(field);
2477  err = DB_SUCCESS;
2478  } else {
2479  err = DB_CORRUPTION;
2480  }
2481 
2482  if (heap != NULL) {
2483  mem_heap_free(heap);
2484  }
2485  } else {
2486  /* The table is empty. */
2487  err = DB_SUCCESS;
2488  }
2489 
2490  btr_pcur_close(&pcur);
2491  mtr_commit(&mtr);
2492 
2493  DBUG_EXECUTE_IF("ib_import_set_max_rowid_failure",
2494  err = DB_CORRUPTION;);
2495 
2496  if (err != DB_SUCCESS) {
2497  char index_name[MAX_FULL_NAME_LEN + 1];
2498 
2500  index_name, sizeof(index_name), index->name, TRUE);
2501 
2502  ib_errf(prebuilt->trx->mysql_thd,
2503  IB_LOG_LEVEL_WARN,
2504  ER_INNODB_INDEX_CORRUPT,
2505  "Index '%s' corruption detected, invalid DB_ROW_ID "
2506  "in index.", index_name);
2507 
2508  return(err);
2509 
2510  } else if (row_id > 0) {
2511 
2512  /* Update the system row id if the imported index row id is
2513  greater than the max system row id. */
2514 
2515  mutex_enter(&dict_sys->mutex);
2516 
2517  if (row_id >= dict_sys->row_id) {
2518  dict_sys->row_id = row_id + 1;
2520  }
2521 
2522  mutex_exit(&dict_sys->mutex);
2523  }
2524 
2525  return(DB_SUCCESS);
2526 }
2527 
2528 /*****************************************************************/
2531 static
2532 dberr_t
2533 row_import_cfg_read_string(
2534 /*=======================*/
2535  FILE* file,
2536  byte* ptr,
2537  ulint max_len)
2539 {
2540  DBUG_EXECUTE_IF("ib_import_string_read_error",
2541  errno = EINVAL; return(DB_IO_ERROR););
2542 
2543  ulint len = 0;
2544 
2545  while (!feof(file)) {
2546  int ch = fgetc(file);
2547 
2548  if (ch == EOF) {
2549  break;
2550  } else if (ch != 0) {
2551  if (len < max_len) {
2552  ptr[len++] = ch;
2553  } else {
2554  break;
2555  }
2556  /* max_len includes the NUL byte */
2557  } else if (len != max_len - 1) {
2558  break;
2559  } else {
2560  ptr[len] = 0;
2561  return(DB_SUCCESS);
2562  }
2563  }
2564 
2565  errno = EINVAL;
2566 
2567  return(DB_IO_ERROR);
2568 }
2569 
2570 /*********************************************************************/
2573 static __attribute__((nonnull, warn_unused_result))
2574 dberr_t
2575 row_import_cfg_read_index_fields(
2576 /*=============================*/
2577  FILE* file,
2578  THD* thd,
2579  row_index_t* index,
2580  row_import* cfg)
2581 {
2582  byte row[sizeof(ib_uint32_t) * 3];
2583  ulint n_fields = index->m_n_fields;
2584 
2585  index->m_fields = new(std::nothrow) dict_field_t[n_fields];
2586 
2587  /* Trigger OOM */
2588  DBUG_EXECUTE_IF("ib_import_OOM_4",
2589  delete [] index->m_fields; index->m_fields = 0;);
2590 
2591  if (index->m_fields == 0) {
2592  return(DB_OUT_OF_MEMORY);
2593  }
2594 
2595  dict_field_t* field = index->m_fields;
2596 
2597  memset(field, 0x0, sizeof(*field) * n_fields);
2598 
2599  for (ulint i = 0; i < n_fields; ++i, ++field) {
2600  byte* ptr = row;
2601 
2602  /* Trigger EOF */
2603  DBUG_EXECUTE_IF("ib_import_io_read_error_1",
2604  (void) fseek(file, 0L, SEEK_END););
2605 
2606  if (fread(row, 1, sizeof(row), file) != sizeof(row)) {
2607 
2608  ib_senderrf(
2609  thd, IB_LOG_LEVEL_ERROR, ER_IO_READ_ERROR,
2610  errno, strerror(errno),
2611  "while reading index fields.");
2612 
2613  return(DB_IO_ERROR);
2614  }
2615 
2616  field->prefix_len = mach_read_from_4(ptr);
2617  ptr += sizeof(ib_uint32_t);
2618 
2619  field->fixed_len = mach_read_from_4(ptr);
2620  ptr += sizeof(ib_uint32_t);
2621 
2622  /* Include the NUL byte in the length. */
2623  ulint len = mach_read_from_4(ptr);
2624 
2625  byte* name = new(std::nothrow) byte[len];
2626 
2627  /* Trigger OOM */
2628  DBUG_EXECUTE_IF("ib_import_OOM_5", delete [] name; name = 0;);
2629 
2630  if (name == 0) {
2631  return(DB_OUT_OF_MEMORY);
2632  }
2633 
2634  field->name = reinterpret_cast<const char*>(name);
2635 
2636  dberr_t err = row_import_cfg_read_string(file, name, len);
2637 
2638  if (err != DB_SUCCESS) {
2639 
2640  ib_senderrf(
2641  thd, IB_LOG_LEVEL_ERROR, ER_IO_READ_ERROR,
2642  errno, strerror(errno),
2643  "while parsing table name.");
2644 
2645  return(err);
2646  }
2647  }
2648 
2649  return(DB_SUCCESS);
2650 }
2651 
2652 /*****************************************************************/
2656 static __attribute__((nonnull, warn_unused_result))
2657 dberr_t
2658 row_import_read_index_data(
2659 /*=======================*/
2660  FILE* file,
2661  THD* thd,
2662  row_import* cfg)
2663 {
2664  byte* ptr;
2665  row_index_t* cfg_index;
2666  byte row[sizeof(index_id_t) + sizeof(ib_uint32_t) * 9];
2667 
2668  /* FIXME: What is the max value? */
2669  ut_a(cfg->m_n_indexes > 0);
2670  ut_a(cfg->m_n_indexes < 1024);
2671 
2672  cfg->m_indexes = new(std::nothrow) row_index_t[cfg->m_n_indexes];
2673 
2674  /* Trigger OOM */
2675  DBUG_EXECUTE_IF("ib_import_OOM_6",
2676  delete [] cfg->m_indexes; cfg->m_indexes = 0;);
2677 
2678  if (cfg->m_indexes == 0) {
2679  return(DB_OUT_OF_MEMORY);
2680  }
2681 
2682  memset(cfg->m_indexes, 0x0, sizeof(*cfg->m_indexes) * cfg->m_n_indexes);
2683 
2684  cfg_index = cfg->m_indexes;
2685 
2686  for (ulint i = 0; i < cfg->m_n_indexes; ++i, ++cfg_index) {
2687  /* Trigger EOF */
2688  DBUG_EXECUTE_IF("ib_import_io_read_error_2",
2689  (void) fseek(file, 0L, SEEK_END););
2690 
2691  /* Read the index data. */
2692  size_t n_bytes = fread(row, 1, sizeof(row), file);
2693 
2694  /* Trigger EOF */
2695  DBUG_EXECUTE_IF("ib_import_io_read_error",
2696  (void) fseek(file, 0L, SEEK_END););
2697 
2698  if (n_bytes != sizeof(row)) {
2699  char msg[BUFSIZ];
2700 
2701  ut_snprintf(msg, sizeof(msg),
2702  "while reading index meta-data, expected "
2703  "to read %lu bytes but read only %lu "
2704  "bytes",
2705  (ulong) sizeof(row), (ulong) n_bytes);
2706 
2707  ib_senderrf(
2708  thd, IB_LOG_LEVEL_ERROR, ER_IO_READ_ERROR,
2709  errno, strerror(errno), msg);
2710 
2711  ib_logf(IB_LOG_LEVEL_ERROR, "IO Error: %s", msg);
2712 
2713  return(DB_IO_ERROR);
2714  }
2715 
2716  ptr = row;
2717 
2718  cfg_index->m_id = mach_read_from_8(ptr);
2719  ptr += sizeof(index_id_t);
2720 
2721  cfg_index->m_space = mach_read_from_4(ptr);
2722  ptr += sizeof(ib_uint32_t);
2723 
2724  cfg_index->m_page_no = mach_read_from_4(ptr);
2725  ptr += sizeof(ib_uint32_t);
2726 
2727  cfg_index->m_type = mach_read_from_4(ptr);
2728  ptr += sizeof(ib_uint32_t);
2729 
2730  cfg_index->m_trx_id_offset = mach_read_from_4(ptr);
2731  if (cfg_index->m_trx_id_offset != mach_read_from_4(ptr)) {
2732  ut_ad(0);
2733  /* Overflow. Pretend that the clustered index
2734  has a variable-length PRIMARY KEY. */
2735  cfg_index->m_trx_id_offset = 0;
2736  }
2737  ptr += sizeof(ib_uint32_t);
2738 
2739  cfg_index->m_n_user_defined_cols = mach_read_from_4(ptr);
2740  ptr += sizeof(ib_uint32_t);
2741 
2742  cfg_index->m_n_uniq = mach_read_from_4(ptr);
2743  ptr += sizeof(ib_uint32_t);
2744 
2745  cfg_index->m_n_nullable = mach_read_from_4(ptr);
2746  ptr += sizeof(ib_uint32_t);
2747 
2748  cfg_index->m_n_fields = mach_read_from_4(ptr);
2749  ptr += sizeof(ib_uint32_t);
2750 
2751  /* The NUL byte is included in the name length. */
2752  ulint len = mach_read_from_4(ptr);
2753 
2754  if (len > OS_FILE_MAX_PATH) {
2755  ib_errf(thd, IB_LOG_LEVEL_ERROR,
2756  ER_INNODB_INDEX_CORRUPT,
2757  "Index name length (%lu) is too long, "
2758  "the meta-data is corrupt", len);
2759 
2760  return(DB_CORRUPTION);
2761  }
2762 
2763  cfg_index->m_name = new(std::nothrow) byte[len];
2764 
2765  /* Trigger OOM */
2766  DBUG_EXECUTE_IF("ib_import_OOM_7",
2767  delete [] cfg_index->m_name;
2768  cfg_index->m_name = 0;);
2769 
2770  if (cfg_index->m_name == 0) {
2771  return(DB_OUT_OF_MEMORY);
2772  }
2773 
2774  dberr_t err;
2775 
2776  err = row_import_cfg_read_string(file, cfg_index->m_name, len);
2777 
2778  if (err != DB_SUCCESS) {
2779 
2780  ib_senderrf(
2781  thd, IB_LOG_LEVEL_ERROR, ER_IO_READ_ERROR,
2782  errno, strerror(errno),
2783  "while parsing index name.");
2784 
2785  return(err);
2786  }
2787 
2788  err = row_import_cfg_read_index_fields(
2789  file, thd, cfg_index, cfg);
2790 
2791  if (err != DB_SUCCESS) {
2792  return(err);
2793  }
2794 
2795  }
2796 
2797  return(DB_SUCCESS);
2798 }
2799 
2800 /*****************************************************************/
2803 static
2804 dberr_t
2805 row_import_read_indexes(
2806 /*====================*/
2807  FILE* file,
2808  THD* thd,
2809  row_import* cfg)
2810 {
2811  byte row[sizeof(ib_uint32_t)];
2812 
2813  /* Trigger EOF */
2814  DBUG_EXECUTE_IF("ib_import_io_read_error_3",
2815  (void) fseek(file, 0L, SEEK_END););
2816 
2817  /* Read the number of indexes. */
2818  if (fread(row, 1, sizeof(row), file) != sizeof(row)) {
2819  ib_senderrf(
2820  thd, IB_LOG_LEVEL_ERROR, ER_IO_READ_ERROR,
2821  errno, strerror(errno),
2822  "while reading number of indexes.");
2823 
2824  return(DB_IO_ERROR);
2825  }
2826 
2827  cfg->m_n_indexes = mach_read_from_4(row);
2828 
2829  if (cfg->m_n_indexes == 0) {
2830  ib_errf(thd, IB_LOG_LEVEL_ERROR, ER_IO_READ_ERROR,
2831  "Number of indexes in meta-data file is 0");
2832 
2833  return(DB_CORRUPTION);
2834 
2835  } else if (cfg->m_n_indexes > 1024) {
2836  // FIXME: What is the upper limit? */
2837  ib_errf(thd, IB_LOG_LEVEL_ERROR, ER_IO_READ_ERROR,
2838  "Number of indexes in meta-data file is too high: %lu",
2839  (ulong) cfg->m_n_indexes);
2840  cfg->m_n_indexes = 0;
2841 
2842  return(DB_CORRUPTION);
2843  }
2844 
2845  return(row_import_read_index_data(file, thd, cfg));
2846 }
2847 
2848 /*********************************************************************/
2851 static __attribute__((nonnull, warn_unused_result))
2852 dberr_t
2853 row_import_read_columns(
2854 /*====================*/
2855  FILE* file,
2856  THD* thd,
2857  row_import* cfg)
2858 {
2859  dict_col_t* col;
2860  byte row[sizeof(ib_uint32_t) * 8];
2861 
2862  /* FIXME: What should the upper limit be? */
2863  ut_a(cfg->m_n_cols > 0);
2864  ut_a(cfg->m_n_cols < 1024);
2865 
2866  cfg->m_cols = new(std::nothrow) dict_col_t[cfg->m_n_cols];
2867 
2868  /* Trigger OOM */
2869  DBUG_EXECUTE_IF("ib_import_OOM_8",
2870  delete [] cfg->m_cols; cfg->m_cols = 0;);
2871 
2872  if (cfg->m_cols == 0) {
2873  return(DB_OUT_OF_MEMORY);
2874  }
2875 
2876  cfg->m_col_names = new(std::nothrow) byte* [cfg->m_n_cols];
2877 
2878  /* Trigger OOM */
2879  DBUG_EXECUTE_IF("ib_import_OOM_9",
2880  delete [] cfg->m_col_names; cfg->m_col_names = 0;);
2881 
2882  if (cfg->m_col_names == 0) {
2883  return(DB_OUT_OF_MEMORY);
2884  }
2885 
2886  memset(cfg->m_cols, 0x0, sizeof(cfg->m_cols) * cfg->m_n_cols);
2887  memset(cfg->m_col_names, 0x0, sizeof(cfg->m_col_names) * cfg->m_n_cols);
2888 
2889  col = cfg->m_cols;
2890 
2891  for (ulint i = 0; i < cfg->m_n_cols; ++i, ++col) {
2892  byte* ptr = row;
2893 
2894  /* Trigger EOF */
2895  DBUG_EXECUTE_IF("ib_import_io_read_error_4",
2896  (void) fseek(file, 0L, SEEK_END););
2897 
2898  if (fread(row, 1, sizeof(row), file) != sizeof(row)) {
2899  ib_senderrf(
2900  thd, IB_LOG_LEVEL_ERROR, ER_IO_READ_ERROR,
2901  errno, strerror(errno),
2902  "while reading table column meta-data.");
2903 
2904  return(DB_IO_ERROR);
2905  }
2906 
2907  col->prtype = mach_read_from_4(ptr);
2908  ptr += sizeof(ib_uint32_t);
2909 
2910  col->mtype = mach_read_from_4(ptr);
2911  ptr += sizeof(ib_uint32_t);
2912 
2913  col->len = mach_read_from_4(ptr);
2914  ptr += sizeof(ib_uint32_t);
2915 
2916  col->mbminmaxlen = mach_read_from_4(ptr);
2917  ptr += sizeof(ib_uint32_t);
2918 
2919  col->ind = mach_read_from_4(ptr);
2920  ptr += sizeof(ib_uint32_t);
2921 
2922  col->ord_part = mach_read_from_4(ptr);
2923  ptr += sizeof(ib_uint32_t);
2924 
2925  col->max_prefix = mach_read_from_4(ptr);
2926  ptr += sizeof(ib_uint32_t);
2927 
2928  /* Read in the column name as [len, byte array]. The len
2929  includes the NUL byte. */
2930 
2931  ulint len = mach_read_from_4(ptr);
2932 
2933  /* FIXME: What is the maximum column name length? */
2934  if (len == 0 || len > 128) {
2935  ib_errf(thd, IB_LOG_LEVEL_ERROR,
2936  ER_IO_READ_ERROR,
2937  "Column name length %lu, is invalid",
2938  (ulong) len);
2939 
2940  return(DB_CORRUPTION);
2941  }
2942 
2943  cfg->m_col_names[i] = new(std::nothrow) byte[len];
2944 
2945  /* Trigger OOM */
2946  DBUG_EXECUTE_IF("ib_import_OOM_10",
2947  delete [] cfg->m_col_names[i];
2948  cfg->m_col_names[i] = 0;);
2949 
2950  if (cfg->m_col_names[i] == 0) {
2951  return(DB_OUT_OF_MEMORY);
2952  }
2953 
2954  dberr_t err;
2955 
2956  err = row_import_cfg_read_string(
2957  file, cfg->m_col_names[i], len);
2958 
2959  if (err != DB_SUCCESS) {
2960 
2961  ib_senderrf(
2962  thd, IB_LOG_LEVEL_ERROR, ER_IO_READ_ERROR,
2963  errno, strerror(errno),
2964  "while parsing table column name.");
2965 
2966  return(err);
2967  }
2968  }
2969 
2970  return(DB_SUCCESS);
2971 }
2972 
2973 /*****************************************************************/
2976 static __attribute__((nonnull, warn_unused_result))
2977 dberr_t
2978 row_import_read_v1(
2979 /*===============*/
2980  FILE* file,
2981  THD* thd,
2982  row_import* cfg)
2983 {
2984  byte value[sizeof(ib_uint32_t)];
2985 
2986  /* Trigger EOF */
2987  DBUG_EXECUTE_IF("ib_import_io_read_error_5",
2988  (void) fseek(file, 0L, SEEK_END););
2989 
2990  /* Read the hostname where the tablespace was exported. */
2991  if (fread(value, 1, sizeof(value), file) != sizeof(value)) {
2992  ib_senderrf(
2993  thd, IB_LOG_LEVEL_ERROR, ER_IO_READ_ERROR,
2994  errno, strerror(errno),
2995  "while reading meta-data export hostname length.");
2996 
2997  return(DB_IO_ERROR);
2998  }
2999 
3000  ulint len = mach_read_from_4(value);
3001 
3002  /* NUL byte is part of name length. */
3003  cfg->m_hostname = new(std::nothrow) byte[len];
3004 
3005  /* Trigger OOM */
3006  DBUG_EXECUTE_IF("ib_import_OOM_1",
3007  delete [] cfg->m_hostname; cfg->m_hostname = 0;);
3008 
3009  if (cfg->m_hostname == 0) {
3010  return(DB_OUT_OF_MEMORY);
3011  }
3012 
3013  dberr_t err = row_import_cfg_read_string(file, cfg->m_hostname, len);
3014 
3015  if (err != DB_SUCCESS) {
3016 
3017  ib_senderrf(
3018  thd, IB_LOG_LEVEL_ERROR, ER_IO_READ_ERROR,
3019  errno, strerror(errno),
3020  "while parsing export hostname.");
3021 
3022  return(err);
3023  }
3024 
3025  /* Trigger EOF */
3026  DBUG_EXECUTE_IF("ib_import_io_read_error_6",
3027  (void) fseek(file, 0L, SEEK_END););
3028 
3029  /* Read the table name of tablespace that was exported. */
3030  if (fread(value, 1, sizeof(value), file) != sizeof(value)) {
3031  ib_senderrf(
3032  thd, IB_LOG_LEVEL_ERROR, ER_IO_READ_ERROR,
3033  errno, strerror(errno),
3034  "while reading meta-data table name length.");
3035 
3036  return(DB_IO_ERROR);
3037  }
3038 
3039  len = mach_read_from_4(value);
3040 
3041  /* NUL byte is part of name length. */
3042  cfg->m_table_name = new(std::nothrow) byte[len];
3043 
3044  /* Trigger OOM */
3045  DBUG_EXECUTE_IF("ib_import_OOM_2",
3046  delete [] cfg->m_table_name; cfg->m_table_name = 0;);
3047 
3048  if (cfg->m_table_name == 0) {
3049  return(DB_OUT_OF_MEMORY);
3050  }
3051 
3052  err = row_import_cfg_read_string(file, cfg->m_table_name, len);
3053 
3054  if (err != DB_SUCCESS) {
3055  ib_senderrf(
3056  thd, IB_LOG_LEVEL_ERROR, ER_IO_READ_ERROR,
3057  errno, strerror(errno),
3058  "while parsing table name.");
3059 
3060  return(err);
3061  }
3062 
3063  ib_logf(IB_LOG_LEVEL_INFO,
3064  "Importing tablespace for table '%s' that was exported "
3065  "from host '%s'", cfg->m_table_name, cfg->m_hostname);
3066 
3067  byte row[sizeof(ib_uint32_t) * 3];
3068 
3069  /* Trigger EOF */
3070  DBUG_EXECUTE_IF("ib_import_io_read_error_7",
3071  (void) fseek(file, 0L, SEEK_END););
3072 
3073  /* Read the autoinc value. */
3074  if (fread(row, 1, sizeof(ib_uint64_t), file) != sizeof(ib_uint64_t)) {
3075  ib_senderrf(
3076  thd, IB_LOG_LEVEL_ERROR, ER_IO_READ_ERROR,
3077  errno, strerror(errno),
3078  "while reading autoinc value.");
3079 
3080  return(DB_IO_ERROR);
3081  }
3082 
3083  cfg->m_autoinc = mach_read_from_8(row);
3084 
3085  /* Trigger EOF */
3086  DBUG_EXECUTE_IF("ib_import_io_read_error_8",
3087  (void) fseek(file, 0L, SEEK_END););
3088 
3089  /* Read the tablespace page size. */
3090  if (fread(row, 1, sizeof(row), file) != sizeof(row)) {
3091  ib_senderrf(
3092  thd, IB_LOG_LEVEL_ERROR, ER_IO_READ_ERROR,
3093  errno, strerror(errno),
3094  "while reading meta-data header.");
3095 
3096  return(DB_IO_ERROR);
3097  }
3098 
3099  byte* ptr = row;
3100 
3101  cfg->m_page_size = mach_read_from_4(ptr);
3102  ptr += sizeof(ib_uint32_t);
3103 
3104  if (cfg->m_page_size != UNIV_PAGE_SIZE) {
3105 
3106  ib_errf(thd, IB_LOG_LEVEL_ERROR, ER_TABLE_SCHEMA_MISMATCH,
3107  "Tablespace to be imported has a different "
3108  "page size than this server. Server page size "
3109  "is %lu, whereas tablespace page size is %lu",
3110  UNIV_PAGE_SIZE, (ulong) cfg->m_page_size);
3111 
3112  return(DB_ERROR);
3113  }
3114 
3115  cfg->m_flags = mach_read_from_4(ptr);
3116  ptr += sizeof(ib_uint32_t);
3117 
3118  cfg->m_n_cols = mach_read_from_4(ptr);
3119 
3120  if (!dict_tf_is_valid(cfg->m_flags)) {
3121 
3122  return(DB_CORRUPTION);
3123 
3124  } else if ((err = row_import_read_columns(file, thd, cfg))
3125  != DB_SUCCESS) {
3126 
3127  return(err);
3128 
3129  } else if ((err = row_import_read_indexes(file, thd, cfg))
3130  != DB_SUCCESS) {
3131 
3132  return(err);
3133  }
3134 
3135  ut_a(err == DB_SUCCESS);
3136  return(err);
3137 }
3138 
3142 static __attribute__((nonnull, warn_unused_result))
3143 dberr_t
3144 row_import_read_meta_data(
3145 /*======================*/
3146  dict_table_t* table,
3147  FILE* file,
3148  THD* thd,
3149  row_import& cfg)
3150 {
3151  byte row[sizeof(ib_uint32_t)];
3152 
3153  /* Trigger EOF */
3154  DBUG_EXECUTE_IF("ib_import_io_read_error_9",
3155  (void) fseek(file, 0L, SEEK_END););
3156 
3157  if (fread(&row, 1, sizeof(row), file) != sizeof(row)) {
3158  ib_senderrf(
3159  thd, IB_LOG_LEVEL_ERROR, ER_IO_READ_ERROR,
3160  errno, strerror(errno),
3161  "while reading meta-data version.");
3162 
3163  return(DB_IO_ERROR);
3164  }
3165 
3166  cfg.m_version = mach_read_from_4(row);
3167 
3168  /* Check the version number. */
3169  switch (cfg.m_version) {
3171 
3172  return(row_import_read_v1(file, thd, &cfg));
3173  default:
3174  ib_errf(thd, IB_LOG_LEVEL_ERROR, ER_IO_READ_ERROR,
3175  "Unsupported meta-data version number (%lu), "
3176  "file ignored", (ulong) cfg.m_version);
3177  }
3178 
3179  return(DB_ERROR);
3180 }
3181 
3185 static __attribute__((nonnull, warn_unused_result))
3186 dberr_t
3187 row_import_read_cfg(
3188 /*================*/
3189  dict_table_t* table,
3190  THD* thd,
3191  row_import& cfg)
3192 {
3193  dberr_t err;
3194  char name[OS_FILE_MAX_PATH];
3195 
3196  cfg.m_table = table;
3197 
3198  srv_get_meta_data_filename(table, name, sizeof(name));
3199 
3200  FILE* file = fopen(name, "rb");
3201 
3202  if (file == NULL) {
3203  char msg[BUFSIZ];
3204 
3205  ut_snprintf(msg, sizeof(msg),
3206  "Error opening '%s', will attempt to import "
3207  "without schema verification", name);
3208 
3209  ib_senderrf(
3210  thd, IB_LOG_LEVEL_WARN, ER_IO_READ_ERROR,
3211  errno, strerror(errno), msg);
3212 
3213  cfg.m_missing = true;
3214 
3215  err = DB_FAIL;
3216  } else {
3217 
3218  cfg.m_missing = false;
3219 
3220  err = row_import_read_meta_data(table, file, thd, cfg);
3221  fclose(file);
3222  }
3223 
3224  return(err);
3225 }
3226 
3227 /*****************************************************************/
3231 UNIV_INTERN
3232 dberr_t
3234 /*=========================*/
3235  trx_t* trx,
3237  const dict_table_t* table,
3239  bool reset,
3241  bool dict_locked)
3245 {
3246  const dict_index_t* index;
3247  que_t* graph = 0;
3248  dberr_t err = DB_SUCCESS;
3249 
3250  static const char sql[] = {
3251  "PROCEDURE UPDATE_INDEX_ROOT() IS\n"
3252  "BEGIN\n"
3253  "UPDATE SYS_INDEXES\n"
3254  "SET SPACE = :space,\n"
3255  " PAGE_NO = :page,\n"
3256  " TYPE = :type\n"
3257  "WHERE TABLE_ID = :table_id AND ID = :index_id;\n"
3258  "END;\n"};
3259 
3260  if (!dict_locked) {
3261  mutex_enter(&dict_sys->mutex);
3262  }
3263 
3264  for (index = dict_table_get_first_index(table);
3265  index != 0;
3266  index = dict_table_get_next_index(index)) {
3267 
3268  pars_info_t* info;
3269  ib_uint32_t page;
3270  ib_uint32_t space;
3271  ib_uint32_t type;
3272  index_id_t index_id;
3273  table_id_t table_id;
3274 
3275  info = (graph != 0) ? graph->info : pars_info_create();
3276 
3278  reinterpret_cast<byte*>(&type),
3279  index->type);
3280 
3282  reinterpret_cast<byte*>(&page),
3283  reset ? FIL_NULL : index->page);
3284 
3286  reinterpret_cast<byte*>(&space),
3287  reset ? FIL_NULL : index->space);
3288 
3290  reinterpret_cast<byte*>(&index_id),
3291  index->id);
3292 
3294  reinterpret_cast<byte*>(&table_id),
3295  table->id);
3296 
3297  /* If we set the corrupt bit during the IMPORT phase then
3298  we need to update the system tables. */
3299  pars_info_bind_int4_literal(info, "type", &type);
3300  pars_info_bind_int4_literal(info, "space", &space);
3301  pars_info_bind_int4_literal(info, "page", &page);
3302  pars_info_bind_ull_literal(info, "index_id", &index_id);
3303  pars_info_bind_ull_literal(info, "table_id", &table_id);
3304 
3305  if (graph == 0) {
3306  graph = pars_sql(info, sql);
3307  ut_a(graph);
3308  graph->trx = trx;
3309  }
3310 
3311  que_thr_t* thr;
3312 
3313  graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
3314 
3315  ut_a(thr = que_fork_start_command(graph));
3316 
3317  que_run_threads(thr);
3318 
3319  DBUG_EXECUTE_IF("ib_import_internal_error",
3320  trx->error_state = DB_ERROR;);
3321 
3322  err = trx->error_state;
3323 
3324  if (err != DB_SUCCESS) {
3325  char index_name[MAX_FULL_NAME_LEN + 1];
3326 
3328  index_name, sizeof(index_name),
3329  index->name, TRUE);
3330 
3331  ib_errf(trx->mysql_thd, IB_LOG_LEVEL_ERROR,
3332  ER_INTERNAL_ERROR,
3333  "While updating the <space, root page "
3334  "number> of index %s - %s",
3335  index_name, ut_strerr(err));
3336 
3337  break;
3338  }
3339  }
3340 
3341  que_graph_free(graph);
3342 
3343  if (!dict_locked) {
3344  mutex_exit(&dict_sys->mutex);
3345  }
3346 
3347  return(err);
3348 }
3349 
3351 struct discard_t {
3352  ib_uint32_t flags2;
3353  bool state;
3354  ulint n_recs;
3355 };
3356 
3357 /******************************************************************/
3361 static
3362 ibool
3363 row_import_set_discarded(
3364 /*=====================*/
3365  void* row,
3366  void* user_arg)
3367 {
3368  sel_node_t* node = static_cast<sel_node_t*>(row);
3369  discard_t* discard = static_cast<discard_t*>(user_arg);
3370  dfield_t* dfield = que_node_get_val(node->select_list);
3371  dtype_t* type = dfield_get_type(dfield);
3372  ulint len = dfield_get_len(dfield);
3373 
3374  ut_a(dtype_get_mtype(type) == DATA_INT);
3375  ut_a(len == sizeof(ib_uint32_t));
3376 
3377  ulint flags2 = mach_read_from_4(
3378  static_cast<byte*>(dfield_get_data(dfield)));
3379 
3380  if (discard->state) {
3381  flags2 |= DICT_TF2_DISCARDED;
3382  } else {
3383  flags2 &= ~DICT_TF2_DISCARDED;
3384  }
3385 
3386  mach_write_to_4(reinterpret_cast<byte*>(&discard->flags2), flags2);
3387 
3388  ++discard->n_recs;
3389 
3390  /* There should be at most one matching record. */
3391  ut_a(discard->n_recs == 1);
3392 
3393  return(FALSE);
3394 }
3395 
3396 /*****************************************************************/
3399 UNIV_INTERN
3400 dberr_t
3402 /*=============================*/
3403  trx_t* trx,
3405  table_id_t table_id,
3407  bool discarded,
3409  bool dict_locked)
3413 {
3414  pars_info_t* info;
3415  discard_t discard;
3416 
3417  static const char sql[] =
3418  "PROCEDURE UPDATE_DISCARDED_FLAG() IS\n"
3419  "DECLARE FUNCTION my_func;\n"
3420  "DECLARE CURSOR c IS\n"
3421  " SELECT MIX_LEN "
3422  " FROM SYS_TABLES "
3423  " WHERE ID = :table_id FOR UPDATE;"
3424  "\n"
3425  "BEGIN\n"
3426  "OPEN c;\n"
3427  "WHILE 1 = 1 LOOP\n"
3428  " FETCH c INTO my_func();\n"
3429  " IF c % NOTFOUND THEN\n"
3430  " EXIT;\n"
3431  " END IF;\n"
3432  "END LOOP;\n"
3433  "UPDATE SYS_TABLES"
3434  " SET MIX_LEN = :flags2"
3435  " WHERE ID = :table_id;\n"
3436  "CLOSE c;\n"
3437  "END;\n";
3438 
3439  discard.n_recs = 0;
3440  discard.state = discarded;
3441  discard.flags2 = ULINT32_UNDEFINED;
3442 
3443  info = pars_info_create();
3444 
3445  pars_info_add_ull_literal(info, "table_id", table_id);
3446  pars_info_bind_int4_literal(info, "flags2", &discard.flags2);
3447 
3449  info, "my_func", row_import_set_discarded, &discard);
3450 
3451  dberr_t err = que_eval_sql(info, sql, !dict_locked, trx);
3452 
3453  ut_a(discard.n_recs == 1);
3454  ut_a(discard.flags2 != ULINT32_UNDEFINED);
3455 
3456  return(err);
3457 }
3458 
3459 /*****************************************************************/
3463 UNIV_INTERN
3464 dberr_t
3466 /*=================*/
3467  dict_table_t* table,
3468  row_prebuilt_t* prebuilt)
3469 {
3470  dberr_t err;
3471  trx_t* trx;
3472  ib_uint64_t autoinc = 0;
3473  char table_name[MAX_FULL_NAME_LEN + 1];
3474  char* filepath = NULL;
3475 
3477 
3479  table_name, sizeof(table_name), table->name, FALSE);
3480 
3481  ut_a(table->space);
3482  ut_ad(prebuilt->trx);
3483  ut_a(table->ibd_file_missing);
3484 
3485  trx_start_if_not_started(prebuilt->trx);
3486 
3487  trx = trx_allocate_for_mysql();
3488 
3489  /* So that the table is not DROPped during recovery. */
3491 
3492  trx_start_if_not_started(trx);
3493 
3494  /* So that we can send error messages to the user. */
3495  trx->mysql_thd = prebuilt->trx->mysql_thd;
3496 
3497  /* Ensure that the table will be dropped by trx_rollback_active()
3498  in case of a crash. */
3499 
3500  trx->table_id = table->id;
3501 
3502  /* Assign an undo segment for the transaction, so that the
3503  transaction will be recovered after a crash. */
3504 
3505  mutex_enter(&trx->undo_mutex);
3506 
3507  err = trx_undo_assign_undo(trx, TRX_UNDO_UPDATE);
3508 
3509  mutex_exit(&trx->undo_mutex);
3510 
3511  DBUG_EXECUTE_IF("ib_import_undo_assign_failure",
3513 
3514  if (err != DB_SUCCESS) {
3515 
3516  return(row_import_cleanup(prebuilt, trx, err));
3517 
3518  } else if (trx->update_undo == 0) {
3519 
3521  return(row_import_cleanup(prebuilt, trx, err));
3522  }
3523 
3524  prebuilt->trx->op_info = "read meta-data file";
3525 
3526  /* Prevent DDL operations while we are checking. */
3527 
3528  rw_lock_s_lock_func(&dict_operation_lock, 0, __FILE__, __LINE__);
3529 
3530  row_import cfg;
3531 
3532  memset(&cfg, 0x0, sizeof(cfg));
3533 
3534  err = row_import_read_cfg(table, trx->mysql_thd, cfg);
3535 
3536  /* Check if the table column definitions match the contents
3537  of the config file. */
3538 
3539  if (err == DB_SUCCESS) {
3540 
3541  /* We have a schema file, try and match it with the our
3542  data dictionary. */
3543 
3544  err = cfg.match_schema(trx->mysql_thd);
3545 
3546  /* Update index->page and SYS_INDEXES.PAGE_NO to match the
3547  B-tree root page numbers in the tablespace. Use the index
3548  name from the .cfg file to find match. */
3549 
3550  if (err == DB_SUCCESS) {
3551  cfg.set_root_by_name();
3552  autoinc = cfg.m_autoinc;
3553  }
3554 
3555  rw_lock_s_unlock_gen(&dict_operation_lock, 0);
3556 
3557  DBUG_EXECUTE_IF("ib_import_set_index_root_failure",
3559 
3560  } else if (cfg.m_missing) {
3561 
3562  rw_lock_s_unlock_gen(&dict_operation_lock, 0);
3563 
3564  /* We don't have a schema file, we will have to discover
3565  the index root pages from the .ibd file and skip the schema
3566  matching step. */
3567 
3568  ut_a(err == DB_FAIL);
3569 
3570  cfg.m_page_size = UNIV_PAGE_SIZE;
3571 
3572  FetchIndexRootPages fetchIndexRootPages(table, trx);
3573 
3574  err = fil_tablespace_iterate(
3575  table, IO_BUFFER_SIZE(cfg.m_page_size),
3576  fetchIndexRootPages);
3577 
3578  if (err == DB_SUCCESS) {
3579 
3580  err = fetchIndexRootPages.build_row_import(&cfg);
3581 
3582  /* Update index->page and SYS_INDEXES.PAGE_NO
3583  to match the B-tree root page numbers in the
3584  tablespace. */
3585 
3586  if (err == DB_SUCCESS) {
3587  err = cfg.set_root_by_heuristic();
3588  }
3589  }
3590 
3591  } else {
3592  rw_lock_s_unlock_gen(&dict_operation_lock, 0);
3593  }
3594 
3595  if (err != DB_SUCCESS) {
3596  return(row_import_error(prebuilt, trx, err));
3597  }
3598 
3599  prebuilt->trx->op_info = "importing tablespace";
3600 
3601  ib_logf(IB_LOG_LEVEL_INFO, "Phase I - Update all pages");
3602 
3603  /* Iterate over all the pages and do the sanity checking and
3604  the conversion required to import the tablespace. */
3605 
3606  PageConverter converter(&cfg, trx);
3607 
3608  /* Set the IO buffer size in pages. */
3609 
3610  err = fil_tablespace_iterate(
3611  table, IO_BUFFER_SIZE(cfg.m_page_size), converter);
3612 
3613  DBUG_EXECUTE_IF("ib_import_reset_space_and_lsn_failure",
3615 
3616  if (err != DB_SUCCESS) {
3617  char table_name[MAX_FULL_NAME_LEN + 1];
3618 
3620  table_name, sizeof(table_name), table->name, FALSE);
3621 
3622  ib_errf(trx->mysql_thd, IB_LOG_LEVEL_ERROR,
3623  ER_INTERNAL_ERROR,
3624  "Cannot reset LSNs in table '%s' : %s",
3625  table_name, ut_strerr(err));
3626 
3627  return(row_import_cleanup(prebuilt, trx, err));
3628  }
3629 
3630  row_mysql_lock_data_dictionary(trx);
3631 
3632  /* If the table is stored in a remote tablespace, we need to
3633  determine that filepath from the link file and system tables.
3634  Find the space ID in SYS_TABLES since this is an ALTER TABLE. */
3635  if (DICT_TF_HAS_DATA_DIR(table->flags)) {
3636  dict_get_and_save_data_dir_path(table, true);
3637  ut_a(table->data_dir_path);
3638 
3639  filepath = os_file_make_remote_pathname(
3640  table->data_dir_path, table->name, "ibd");
3641  } else {
3642  filepath = fil_make_ibd_name(table->name, false);
3643  }
3644  ut_a(filepath);
3645 
3646  /* Open the tablespace so that we can access via the buffer pool.
3647  We set the 2nd param (fix_dict = true) here because we already
3648  have an x-lock on dict_operation_lock and dict_sys->mutex. */
3649 
3651  true, true, table->space,
3652  dict_tf_to_fsp_flags(table->flags),
3653  table->name, filepath);
3654 
3655  DBUG_EXECUTE_IF("ib_import_open_tablespace_failure",
3656  err = DB_TABLESPACE_NOT_FOUND;);
3657 
3658  if (err != DB_SUCCESS) {
3660 
3661  ib_senderrf(trx->mysql_thd, IB_LOG_LEVEL_ERROR,
3662  ER_FILE_NOT_FOUND,
3663  filepath, err, ut_strerr(err));
3664 
3665  mem_free(filepath);
3666 
3667  return(row_import_cleanup(prebuilt, trx, err));
3668  }
3669 
3671 
3672  mem_free(filepath);
3673 
3674  err = ibuf_check_bitmap_on_import(trx, table->space);
3675 
3676  DBUG_EXECUTE_IF("ib_import_check_bitmap_failure", err = DB_CORRUPTION;);
3677 
3678  if (err != DB_SUCCESS) {
3679  return(row_import_cleanup(prebuilt, trx, err));
3680  }
3681 
3682  /* The first index must always be the clustered index. */
3683 
3684  dict_index_t* index = dict_table_get_first_index(table);
3685 
3686  if (!dict_index_is_clust(index)) {
3687  return(row_import_error(prebuilt, trx, DB_CORRUPTION));
3688  }
3689 
3690  /* Update the Btree segment headers for index node and
3691  leaf nodes in the root page. Set the new space id. */
3692 
3693  err = btr_root_adjust_on_import(index);
3694 
3695  DBUG_EXECUTE_IF("ib_import_cluster_root_adjust_failure",
3696  err = DB_CORRUPTION;);
3697 
3698  if (err != DB_SUCCESS) {
3699  return(row_import_error(prebuilt, trx, err));
3700  }
3701 
3702  if (err != DB_SUCCESS) {
3703  return(row_import_error(prebuilt, trx, err));
3704  } else if (cfg.requires_purge(index->name)) {
3705 
3706  /* Purge any delete-marked records that couldn't be
3707  purged during the page conversion phase from the
3708  cluster index. */
3709 
3710  IndexPurge purge(trx, index);
3711 
3712  trx->op_info = "cluster: purging delete marked records";
3713 
3714  err = purge.garbage_collect();
3715 
3716  trx->op_info = "";
3717  }
3718 
3719  DBUG_EXECUTE_IF("ib_import_cluster_failure", err = DB_CORRUPTION;);
3720 
3721  if (err != DB_SUCCESS) {
3722  return(row_import_error(prebuilt, trx, err));
3723  }
3724 
3725  /* For secondary indexes, purge any records that couldn't be purged
3726  during the page conversion phase. */
3727 
3728  err = row_import_adjust_root_pages_of_secondary_indexes(
3729  prebuilt, trx, table, cfg);
3730 
3731  DBUG_EXECUTE_IF("ib_import_sec_root_adjust_failure",
3732  err = DB_CORRUPTION;);
3733 
3734  if (err != DB_SUCCESS) {
3735  return(row_import_error(prebuilt, trx, err));
3736  }
3737 
3738  /* Ensure that the next available DB_ROW_ID is not smaller than
3739  any DB_ROW_ID stored in the table. */
3740 
3741  if (prebuilt->clust_index_was_generated) {
3742 
3743  err = row_import_set_sys_max_row_id(prebuilt, table);
3744 
3745  if (err != DB_SUCCESS) {
3746  return(row_import_error(prebuilt, trx, err));
3747  }
3748  }
3749 
3750  ib_logf(IB_LOG_LEVEL_INFO, "Phase III - Flush changes to disk");
3751 
3752  /* Ensure that all pages dirtied during the IMPORT make it to disk.
3753  The only dirty pages generated should be from the pessimistic purge
3754  of delete marked records that couldn't be purged in Phase I. */
3755 
3757  prebuilt->table->space, BUF_REMOVE_FLUSH_WRITE, trx);
3758 
3759  if (trx_is_interrupted(trx)) {
3760  ib_logf(IB_LOG_LEVEL_INFO, "Phase III - Flush interrupted");
3761  return(row_import_error(prebuilt, trx, DB_INTERRUPTED));
3762  } else {
3763  ib_logf(IB_LOG_LEVEL_INFO, "Phase IV - Flush complete");
3764  }
3765 
3766  /* The dictionary latches will be released in in row_import_cleanup()
3767  after the transaction commit, for both success and error. */
3768 
3769  row_mysql_lock_data_dictionary(trx);
3770 
3771  /* Update the root pages of the table's indexes. */
3772  err = row_import_update_index_root(trx, table, false, true);
3773 
3774  if (err != DB_SUCCESS) {
3775  return(row_import_error(prebuilt, trx, err));
3776  }
3777 
3778  /* Update the table's discarded flag, unset it. */
3779  err = row_import_update_discarded_flag(trx, table->id, false, true);
3780 
3781  if (err != DB_SUCCESS) {
3782  return(row_import_error(prebuilt, trx, err));
3783  }
3784 
3785  table->ibd_file_missing = false;
3786  table->flags2 &= ~DICT_TF2_DISCARDED;
3787 
3788  if (autoinc != 0) {
3789  char table_name[MAX_FULL_NAME_LEN + 1];
3790 
3792  table_name, sizeof(table_name), table->name, FALSE);
3793 
3794  ib_logf(IB_LOG_LEVEL_INFO, "%s autoinc value set to " IB_ID_FMT,
3795  table_name, autoinc);
3796 
3797  dict_table_autoinc_lock(table);
3798  dict_table_autoinc_initialize(table, autoinc);
3800  }
3801 
3802  ut_a(err == DB_SUCCESS);
3803 
3804  return(row_import_cleanup(prebuilt, trx, err));
3805 }
3806