| 1 | /***************************************************************************** |
| 2 | |
| 3 | Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved. |
| 4 | Copyright (c) 2016, MariaDB Corporation. |
| 5 | |
| 6 | This program is free software; you can redistribute it and/or modify it under |
| 7 | the terms of the GNU General Public License as published by the Free Software |
| 8 | Foundation; version 2 of the License. |
| 9 | |
| 10 | This program is distributed in the hope that it will be useful, but WITHOUT |
| 11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 12 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
| 13 | |
| 14 | You should have received a copy of the GNU General Public License along with |
| 15 | this program; if not, write to the Free Software Foundation, Inc., |
| 16 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA |
| 17 | |
| 18 | *****************************************************************************/ |
| 19 | |
| 20 | /**************************************************//** |
| 21 | @file dict/dict0boot.cc |
| 22 | Data dictionary creation and booting |
| 23 | |
| 24 | Created 4/18/1996 Heikki Tuuri |
| 25 | *******************************************************/ |
| 26 | |
| 27 | #include "ha_prototypes.h" |
| 28 | |
| 29 | #include "dict0boot.h" |
| 30 | #include "dict0crea.h" |
| 31 | #include "btr0btr.h" |
| 32 | #include "dict0load.h" |
| 33 | #include "trx0trx.h" |
| 34 | #include "srv0srv.h" |
| 35 | #include "ibuf0ibuf.h" |
| 36 | #include "buf0flu.h" |
| 37 | #include "log0recv.h" |
| 38 | #include "os0file.h" |
| 39 | |
| 40 | /**********************************************************************//** |
| 41 | Gets a pointer to the dictionary header and x-latches its page. |
| 42 | @return pointer to the dictionary header, page x-latched */ |
| 43 | dict_hdr_t* |
| 44 | dict_hdr_get( |
| 45 | /*=========*/ |
| 46 | mtr_t* mtr) /*!< in: mtr */ |
| 47 | { |
| 48 | buf_block_t* block; |
| 49 | dict_hdr_t* ; |
| 50 | |
| 51 | block = buf_page_get(page_id_t(DICT_HDR_SPACE, DICT_HDR_PAGE_NO), |
| 52 | univ_page_size, RW_X_LATCH, mtr); |
| 53 | header = DICT_HDR + buf_block_get_frame(block); |
| 54 | |
| 55 | buf_block_dbg_add_level(block, SYNC_DICT_HEADER); |
| 56 | |
| 57 | return(header); |
| 58 | } |
| 59 | |
| 60 | /**********************************************************************//** |
| 61 | Returns a new table, index, or space id. */ |
| 62 | void |
| 63 | dict_hdr_get_new_id( |
| 64 | /*================*/ |
| 65 | table_id_t* table_id, /*!< out: table id |
| 66 | (not assigned if NULL) */ |
| 67 | index_id_t* index_id, /*!< out: index id |
| 68 | (not assigned if NULL) */ |
| 69 | ulint* space_id, /*!< out: space id |
| 70 | (not assigned if NULL) */ |
| 71 | const dict_table_t* table, /*!< in: table */ |
| 72 | bool disable_redo) /*!< in: if true and table |
| 73 | object is NULL |
| 74 | then disable-redo */ |
| 75 | { |
| 76 | dict_hdr_t* dict_hdr; |
| 77 | ib_id_t id; |
| 78 | mtr_t mtr; |
| 79 | |
| 80 | mtr_start(&mtr); |
| 81 | if (table) { |
| 82 | if (table->is_temporary()) { |
| 83 | mtr.set_log_mode(MTR_LOG_NO_REDO); |
| 84 | } |
| 85 | } else if (disable_redo) { |
| 86 | /* In non-read-only mode we need to ensure that space-id header |
| 87 | page is written to disk else if page is removed from buffer |
| 88 | cache and re-loaded it would assign temporary tablespace id |
| 89 | to another tablespace. |
| 90 | This is not a case with read-only mode as there is no new object |
| 91 | that is created except temporary tablespace. */ |
| 92 | mtr.set_log_mode(srv_read_only_mode |
| 93 | ? MTR_LOG_NONE : MTR_LOG_NO_REDO); |
| 94 | } |
| 95 | |
| 96 | /* Server started and let's say space-id = x |
| 97 | - table created with file-per-table |
| 98 | - space-id = x + 1 |
| 99 | - crash |
| 100 | Case 1: If it was redo logged then we know that it will be |
| 101 | restored to x + 1 |
| 102 | Case 2: if not redo-logged |
| 103 | Header will have the old space-id = x |
| 104 | This is OK because on restart there is no object with |
| 105 | space id = x + 1 |
| 106 | Case 3: |
| 107 | space-id = x (on start) |
| 108 | space-id = x+1 (temp-table allocation) - no redo logging |
| 109 | space-id = x+2 (non-temp-table allocation), this get's |
| 110 | redo logged. |
| 111 | If there is a crash there will be only 2 entries |
| 112 | x (original) and x+2 (new) and disk hdr will be updated |
| 113 | to reflect x + 2 entry. |
| 114 | We cannot allocate the same space id to different objects. */ |
| 115 | dict_hdr = dict_hdr_get(&mtr); |
| 116 | |
| 117 | if (table_id) { |
| 118 | id = mach_read_from_8(dict_hdr + DICT_HDR_TABLE_ID); |
| 119 | id++; |
| 120 | mlog_write_ull(dict_hdr + DICT_HDR_TABLE_ID, id, &mtr); |
| 121 | *table_id = id; |
| 122 | } |
| 123 | |
| 124 | if (index_id) { |
| 125 | id = mach_read_from_8(dict_hdr + DICT_HDR_INDEX_ID); |
| 126 | id++; |
| 127 | mlog_write_ull(dict_hdr + DICT_HDR_INDEX_ID, id, &mtr); |
| 128 | *index_id = id; |
| 129 | } |
| 130 | |
| 131 | if (space_id) { |
| 132 | *space_id = mtr_read_ulint(dict_hdr + DICT_HDR_MAX_SPACE_ID, |
| 133 | MLOG_4BYTES, &mtr); |
| 134 | if (fil_assign_new_space_id(space_id)) { |
| 135 | mlog_write_ulint(dict_hdr + DICT_HDR_MAX_SPACE_ID, |
| 136 | *space_id, MLOG_4BYTES, &mtr); |
| 137 | } |
| 138 | } |
| 139 | |
| 140 | mtr_commit(&mtr); |
| 141 | } |
| 142 | |
| 143 | /**********************************************************************//** |
| 144 | Writes the current value of the row id counter to the dictionary header file |
| 145 | page. */ |
| 146 | void |
| 147 | dict_hdr_flush_row_id(void) |
| 148 | /*=======================*/ |
| 149 | { |
| 150 | dict_hdr_t* dict_hdr; |
| 151 | row_id_t id; |
| 152 | mtr_t mtr; |
| 153 | |
| 154 | ut_ad(mutex_own(&dict_sys->mutex)); |
| 155 | |
| 156 | id = dict_sys->row_id; |
| 157 | |
| 158 | mtr_start(&mtr); |
| 159 | |
| 160 | dict_hdr = dict_hdr_get(&mtr); |
| 161 | |
| 162 | mlog_write_ull(dict_hdr + DICT_HDR_ROW_ID, id, &mtr); |
| 163 | |
| 164 | mtr_commit(&mtr); |
| 165 | } |
| 166 | |
| 167 | /*****************************************************************//** |
| 168 | Creates the file page for the dictionary header. This function is |
| 169 | called only at the database creation. |
| 170 | @return TRUE if succeed */ |
| 171 | static |
| 172 | ibool |
| 173 | dict_hdr_create( |
| 174 | /*============*/ |
| 175 | mtr_t* mtr) /*!< in: mtr */ |
| 176 | { |
| 177 | buf_block_t* block; |
| 178 | dict_hdr_t* ; |
| 179 | ulint root_page_no; |
| 180 | |
| 181 | ut_ad(mtr); |
| 182 | compile_time_assert(DICT_HDR_SPACE == 0); |
| 183 | |
| 184 | /* Create the dictionary header file block in a new, allocated file |
| 185 | segment in the system tablespace */ |
| 186 | block = fseg_create(fil_system.sys_space, 0, |
| 187 | DICT_HDR + DICT_HDR_FSEG_HEADER, mtr); |
| 188 | |
| 189 | ut_a(DICT_HDR_PAGE_NO == block->page.id.page_no()); |
| 190 | |
| 191 | dict_header = dict_hdr_get(mtr); |
| 192 | |
| 193 | /* Start counting row, table, index, and tree ids from |
| 194 | DICT_HDR_FIRST_ID */ |
| 195 | mlog_write_ull(dict_header + DICT_HDR_ROW_ID, |
| 196 | DICT_HDR_FIRST_ID, mtr); |
| 197 | |
| 198 | mlog_write_ull(dict_header + DICT_HDR_TABLE_ID, |
| 199 | DICT_HDR_FIRST_ID, mtr); |
| 200 | |
| 201 | mlog_write_ull(dict_header + DICT_HDR_INDEX_ID, |
| 202 | DICT_HDR_FIRST_ID, mtr); |
| 203 | |
| 204 | mlog_write_ulint(dict_header + DICT_HDR_MAX_SPACE_ID, |
| 205 | 0, MLOG_4BYTES, mtr); |
| 206 | |
| 207 | /* Obsolete, but we must initialize it anyway. */ |
| 208 | mlog_write_ulint(dict_header + DICT_HDR_MIX_ID_LOW, |
| 209 | DICT_HDR_FIRST_ID, MLOG_4BYTES, mtr); |
| 210 | |
| 211 | /* Create the B-tree roots for the clustered indexes of the basic |
| 212 | system tables */ |
| 213 | |
| 214 | /*--------------------------*/ |
| 215 | root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE, |
| 216 | fil_system.sys_space, DICT_TABLES_ID, |
| 217 | dict_ind_redundant, NULL, mtr); |
| 218 | if (root_page_no == FIL_NULL) { |
| 219 | |
| 220 | return(FALSE); |
| 221 | } |
| 222 | |
| 223 | mlog_write_ulint(dict_header + DICT_HDR_TABLES, root_page_no, |
| 224 | MLOG_4BYTES, mtr); |
| 225 | /*--------------------------*/ |
| 226 | root_page_no = btr_create(DICT_UNIQUE, |
| 227 | fil_system.sys_space, DICT_TABLE_IDS_ID, |
| 228 | dict_ind_redundant, NULL, mtr); |
| 229 | if (root_page_no == FIL_NULL) { |
| 230 | |
| 231 | return(FALSE); |
| 232 | } |
| 233 | |
| 234 | mlog_write_ulint(dict_header + DICT_HDR_TABLE_IDS, root_page_no, |
| 235 | MLOG_4BYTES, mtr); |
| 236 | /*--------------------------*/ |
| 237 | root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE, |
| 238 | fil_system.sys_space, DICT_COLUMNS_ID, |
| 239 | dict_ind_redundant, NULL, mtr); |
| 240 | if (root_page_no == FIL_NULL) { |
| 241 | |
| 242 | return(FALSE); |
| 243 | } |
| 244 | |
| 245 | mlog_write_ulint(dict_header + DICT_HDR_COLUMNS, root_page_no, |
| 246 | MLOG_4BYTES, mtr); |
| 247 | /*--------------------------*/ |
| 248 | root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE, |
| 249 | fil_system.sys_space, DICT_INDEXES_ID, |
| 250 | dict_ind_redundant, NULL, mtr); |
| 251 | if (root_page_no == FIL_NULL) { |
| 252 | |
| 253 | return(FALSE); |
| 254 | } |
| 255 | |
| 256 | mlog_write_ulint(dict_header + DICT_HDR_INDEXES, root_page_no, |
| 257 | MLOG_4BYTES, mtr); |
| 258 | /*--------------------------*/ |
| 259 | root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE, |
| 260 | fil_system.sys_space, DICT_FIELDS_ID, |
| 261 | dict_ind_redundant, NULL, mtr); |
| 262 | if (root_page_no == FIL_NULL) { |
| 263 | |
| 264 | return(FALSE); |
| 265 | } |
| 266 | |
| 267 | mlog_write_ulint(dict_header + DICT_HDR_FIELDS, root_page_no, |
| 268 | MLOG_4BYTES, mtr); |
| 269 | /*--------------------------*/ |
| 270 | |
| 271 | return(TRUE); |
| 272 | } |
| 273 | |
| 274 | /*****************************************************************//** |
| 275 | Initializes the data dictionary memory structures when the database is |
| 276 | started. This function is also called when the data dictionary is created. |
| 277 | @return DB_SUCCESS or error code. */ |
| 278 | dberr_t |
| 279 | dict_boot(void) |
| 280 | /*===========*/ |
| 281 | { |
| 282 | dict_table_t* table; |
| 283 | dict_index_t* index; |
| 284 | dict_hdr_t* dict_hdr; |
| 285 | mem_heap_t* heap; |
| 286 | mtr_t mtr; |
| 287 | |
| 288 | /* Be sure these constants do not ever change. To avoid bloat, |
| 289 | only check the *NUM_FIELDS* in each table */ |
| 290 | |
| 291 | ut_ad(DICT_NUM_COLS__SYS_TABLES == 8); |
| 292 | ut_ad(DICT_NUM_FIELDS__SYS_TABLES == 10); |
| 293 | ut_ad(DICT_NUM_FIELDS__SYS_TABLE_IDS == 2); |
| 294 | ut_ad(DICT_NUM_COLS__SYS_COLUMNS == 7); |
| 295 | ut_ad(DICT_NUM_FIELDS__SYS_COLUMNS == 9); |
| 296 | ut_ad(DICT_NUM_COLS__SYS_INDEXES == 8); |
| 297 | ut_ad(DICT_NUM_FIELDS__SYS_INDEXES == 10); |
| 298 | ut_ad(DICT_NUM_COLS__SYS_FIELDS == 3); |
| 299 | ut_ad(DICT_NUM_FIELDS__SYS_FIELDS == 5); |
| 300 | ut_ad(DICT_NUM_COLS__SYS_FOREIGN == 4); |
| 301 | ut_ad(DICT_NUM_FIELDS__SYS_FOREIGN == 6); |
| 302 | ut_ad(DICT_NUM_FIELDS__SYS_FOREIGN_FOR_NAME == 2); |
| 303 | ut_ad(DICT_NUM_COLS__SYS_FOREIGN_COLS == 4); |
| 304 | ut_ad(DICT_NUM_FIELDS__SYS_FOREIGN_COLS == 6); |
| 305 | |
| 306 | mtr_start(&mtr); |
| 307 | |
| 308 | /* Create the hash tables etc. */ |
| 309 | dict_init(); |
| 310 | |
| 311 | heap = mem_heap_create(450); |
| 312 | |
| 313 | mutex_enter(&dict_sys->mutex); |
| 314 | |
| 315 | /* Get the dictionary header */ |
| 316 | dict_hdr = dict_hdr_get(&mtr); |
| 317 | |
| 318 | /* Because we only write new row ids to disk-based data structure |
| 319 | (dictionary header) when it is divisible by |
| 320 | DICT_HDR_ROW_ID_WRITE_MARGIN, in recovery we will not recover |
| 321 | the latest value of the row id counter. Therefore we advance |
| 322 | the counter at the database startup to avoid overlapping values. |
| 323 | Note that when a user after database startup first time asks for |
| 324 | a new row id, then because the counter is now divisible by |
| 325 | ..._MARGIN, it will immediately be updated to the disk-based |
| 326 | header. */ |
| 327 | |
| 328 | dict_sys->row_id = DICT_HDR_ROW_ID_WRITE_MARGIN |
| 329 | + ut_uint64_align_up(mach_read_from_8(dict_hdr + DICT_HDR_ROW_ID), |
| 330 | DICT_HDR_ROW_ID_WRITE_MARGIN); |
| 331 | |
| 332 | /* Insert into the dictionary cache the descriptions of the basic |
| 333 | system tables */ |
| 334 | /*-------------------------*/ |
| 335 | table = dict_mem_table_create("SYS_TABLES" , fil_system.sys_space, |
| 336 | 8, 0, 0, 0); |
| 337 | |
| 338 | dict_mem_table_add_col(table, heap, "NAME" , DATA_BINARY, 0, |
| 339 | MAX_FULL_NAME_LEN); |
| 340 | dict_mem_table_add_col(table, heap, "ID" , DATA_BINARY, 0, 8); |
| 341 | /* ROW_FORMAT = (N_COLS >> 31) ? COMPACT : REDUNDANT */ |
| 342 | dict_mem_table_add_col(table, heap, "N_COLS" , DATA_INT, 0, 4); |
| 343 | /* The low order bit of TYPE is always set to 1. If ROW_FORMAT |
| 344 | is not REDUNDANT or COMPACT, this field matches table->flags. */ |
| 345 | dict_mem_table_add_col(table, heap, "TYPE" , DATA_INT, 0, 4); |
| 346 | dict_mem_table_add_col(table, heap, "MIX_ID" , DATA_BINARY, 0, 0); |
| 347 | /* MIX_LEN may contain additional table flags when |
| 348 | ROW_FORMAT!=REDUNDANT. */ |
| 349 | dict_mem_table_add_col(table, heap, "MIX_LEN" , DATA_INT, 0, 4); |
| 350 | dict_mem_table_add_col(table, heap, "CLUSTER_NAME" , DATA_BINARY, 0, 0); |
| 351 | dict_mem_table_add_col(table, heap, "SPACE" , DATA_INT, 0, 4); |
| 352 | |
| 353 | table->id = DICT_TABLES_ID; |
| 354 | |
| 355 | dict_table_add_system_columns(table, heap); |
| 356 | table->add_to_cache(); |
| 357 | dict_sys->sys_tables = table; |
| 358 | mem_heap_empty(heap); |
| 359 | |
| 360 | index = dict_mem_index_create(table, "CLUST_IND" , |
| 361 | DICT_UNIQUE | DICT_CLUSTERED, 1); |
| 362 | |
| 363 | dict_mem_index_add_field(index, "NAME" , 0); |
| 364 | |
| 365 | index->id = DICT_TABLES_ID; |
| 366 | index = dict_index_add_to_cache( |
| 367 | index, mach_read_from_4(dict_hdr + DICT_HDR_TABLES)); |
| 368 | ut_a(index); |
| 369 | ut_ad(!table->is_instant()); |
| 370 | table->indexes.start->n_core_null_bytes = UT_BITS_IN_BYTES( |
| 371 | unsigned(table->indexes.start->n_nullable)); |
| 372 | |
| 373 | /*-------------------------*/ |
| 374 | index = dict_mem_index_create(table, "ID_IND" , DICT_UNIQUE, 1); |
| 375 | dict_mem_index_add_field(index, "ID" , 0); |
| 376 | |
| 377 | index->id = DICT_TABLE_IDS_ID; |
| 378 | index = dict_index_add_to_cache( |
| 379 | index, mach_read_from_4(dict_hdr + DICT_HDR_TABLE_IDS)); |
| 380 | ut_a(index); |
| 381 | |
| 382 | /*-------------------------*/ |
| 383 | table = dict_mem_table_create("SYS_COLUMNS" , fil_system.sys_space, |
| 384 | 7, 0, 0, 0); |
| 385 | |
| 386 | dict_mem_table_add_col(table, heap, "TABLE_ID" , DATA_BINARY, 0, 8); |
| 387 | dict_mem_table_add_col(table, heap, "POS" , DATA_INT, 0, 4); |
| 388 | dict_mem_table_add_col(table, heap, "NAME" , DATA_BINARY, 0, 0); |
| 389 | dict_mem_table_add_col(table, heap, "MTYPE" , DATA_INT, 0, 4); |
| 390 | dict_mem_table_add_col(table, heap, "PRTYPE" , DATA_INT, 0, 4); |
| 391 | dict_mem_table_add_col(table, heap, "LEN" , DATA_INT, 0, 4); |
| 392 | dict_mem_table_add_col(table, heap, "PREC" , DATA_INT, 0, 4); |
| 393 | |
| 394 | table->id = DICT_COLUMNS_ID; |
| 395 | |
| 396 | dict_table_add_system_columns(table, heap); |
| 397 | table->add_to_cache(); |
| 398 | dict_sys->sys_columns = table; |
| 399 | mem_heap_empty(heap); |
| 400 | |
| 401 | index = dict_mem_index_create(table, "CLUST_IND" , |
| 402 | DICT_UNIQUE | DICT_CLUSTERED, 2); |
| 403 | |
| 404 | dict_mem_index_add_field(index, "TABLE_ID" , 0); |
| 405 | dict_mem_index_add_field(index, "POS" , 0); |
| 406 | |
| 407 | index->id = DICT_COLUMNS_ID; |
| 408 | index = dict_index_add_to_cache( |
| 409 | index, mach_read_from_4(dict_hdr + DICT_HDR_COLUMNS)); |
| 410 | ut_a(index); |
| 411 | ut_ad(!table->is_instant()); |
| 412 | table->indexes.start->n_core_null_bytes = UT_BITS_IN_BYTES( |
| 413 | unsigned(table->indexes.start->n_nullable)); |
| 414 | |
| 415 | /*-------------------------*/ |
| 416 | table = dict_mem_table_create("SYS_INDEXES" , fil_system.sys_space, |
| 417 | DICT_NUM_COLS__SYS_INDEXES, 0, 0, 0); |
| 418 | |
| 419 | dict_mem_table_add_col(table, heap, "TABLE_ID" , DATA_BINARY, 0, 8); |
| 420 | dict_mem_table_add_col(table, heap, "ID" , DATA_BINARY, 0, 8); |
| 421 | dict_mem_table_add_col(table, heap, "NAME" , DATA_BINARY, 0, 0); |
| 422 | dict_mem_table_add_col(table, heap, "N_FIELDS" , DATA_INT, 0, 4); |
| 423 | dict_mem_table_add_col(table, heap, "TYPE" , DATA_INT, 0, 4); |
| 424 | /* SYS_INDEXES.SPACE is redundant and not being read; |
| 425 | SYS_TABLES.SPACE is being used instead. */ |
| 426 | dict_mem_table_add_col(table, heap, "SPACE" , DATA_INT, 0, 4); |
| 427 | dict_mem_table_add_col(table, heap, "PAGE_NO" , DATA_INT, 0, 4); |
| 428 | dict_mem_table_add_col(table, heap, "MERGE_THRESHOLD" , DATA_INT, 0, 4); |
| 429 | |
| 430 | table->id = DICT_INDEXES_ID; |
| 431 | |
| 432 | dict_table_add_system_columns(table, heap); |
| 433 | /* The column SYS_INDEXES.MERGE_THRESHOLD was "instantly" |
| 434 | added in MySQL 5.7 and MariaDB 10.2.2. Assign it DEFAULT NULL. |
| 435 | Because of file format compatibility, we must treat SYS_INDEXES |
| 436 | as a special case, relaxing some debug assertions |
| 437 | for DICT_INDEXES_ID. */ |
| 438 | dict_table_get_nth_col(table, DICT_COL__SYS_INDEXES__MERGE_THRESHOLD) |
| 439 | ->def_val.len = UNIV_SQL_NULL; |
| 440 | table->add_to_cache(); |
| 441 | dict_sys->sys_indexes = table; |
| 442 | mem_heap_empty(heap); |
| 443 | |
| 444 | index = dict_mem_index_create(table, "CLUST_IND" , |
| 445 | DICT_UNIQUE | DICT_CLUSTERED, 2); |
| 446 | |
| 447 | dict_mem_index_add_field(index, "TABLE_ID" , 0); |
| 448 | dict_mem_index_add_field(index, "ID" , 0); |
| 449 | |
| 450 | index->id = DICT_INDEXES_ID; |
| 451 | index = dict_index_add_to_cache( |
| 452 | index, mach_read_from_4(dict_hdr + DICT_HDR_INDEXES)); |
| 453 | ut_a(index); |
| 454 | ut_ad(!table->is_instant()); |
| 455 | table->indexes.start->n_core_null_bytes = UT_BITS_IN_BYTES( |
| 456 | unsigned(table->indexes.start->n_nullable)); |
| 457 | |
| 458 | /*-------------------------*/ |
| 459 | table = dict_mem_table_create("SYS_FIELDS" , fil_system.sys_space, |
| 460 | 3, 0, 0, 0); |
| 461 | |
| 462 | dict_mem_table_add_col(table, heap, "INDEX_ID" , DATA_BINARY, 0, 8); |
| 463 | dict_mem_table_add_col(table, heap, "POS" , DATA_INT, 0, 4); |
| 464 | dict_mem_table_add_col(table, heap, "COL_NAME" , DATA_BINARY, 0, 0); |
| 465 | |
| 466 | table->id = DICT_FIELDS_ID; |
| 467 | |
| 468 | dict_table_add_system_columns(table, heap); |
| 469 | table->add_to_cache(); |
| 470 | dict_sys->sys_fields = table; |
| 471 | mem_heap_free(heap); |
| 472 | |
| 473 | index = dict_mem_index_create(table, "CLUST_IND" , |
| 474 | DICT_UNIQUE | DICT_CLUSTERED, 2); |
| 475 | |
| 476 | dict_mem_index_add_field(index, "INDEX_ID" , 0); |
| 477 | dict_mem_index_add_field(index, "POS" , 0); |
| 478 | |
| 479 | index->id = DICT_FIELDS_ID; |
| 480 | index = dict_index_add_to_cache( |
| 481 | index, mach_read_from_4(dict_hdr + DICT_HDR_FIELDS)); |
| 482 | ut_a(index); |
| 483 | ut_ad(!table->is_instant()); |
| 484 | table->indexes.start->n_core_null_bytes = UT_BITS_IN_BYTES( |
| 485 | unsigned(table->indexes.start->n_nullable)); |
| 486 | |
| 487 | mtr_commit(&mtr); |
| 488 | |
| 489 | /*-------------------------*/ |
| 490 | |
| 491 | /* Initialize the insert buffer table and index for each tablespace */ |
| 492 | |
| 493 | dberr_t err = DB_SUCCESS; |
| 494 | |
| 495 | err = ibuf_init_at_db_start(); |
| 496 | |
| 497 | if (err == DB_SUCCESS) { |
| 498 | if (srv_read_only_mode |
| 499 | && srv_force_recovery != SRV_FORCE_NO_LOG_REDO |
| 500 | && !ibuf_is_empty()) { |
| 501 | |
| 502 | if (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE) { |
| 503 | ib::error() << "Change buffer must be empty when" |
| 504 | " --innodb-read-only is set!" |
| 505 | "You can try to recover the database with innodb_force_recovery=5" ; |
| 506 | |
| 507 | err = DB_ERROR; |
| 508 | } else { |
| 509 | ib::warn() << "Change buffer not empty when --innodb-read-only " |
| 510 | "is set! but srv_force_recovery = " << srv_force_recovery |
| 511 | << " , ignoring." ; |
| 512 | } |
| 513 | } |
| 514 | |
| 515 | if (err == DB_SUCCESS) { |
| 516 | /* Load definitions of other indexes on system tables */ |
| 517 | |
| 518 | dict_load_sys_table(dict_sys->sys_tables); |
| 519 | dict_load_sys_table(dict_sys->sys_columns); |
| 520 | dict_load_sys_table(dict_sys->sys_indexes); |
| 521 | dict_load_sys_table(dict_sys->sys_fields); |
| 522 | } |
| 523 | } |
| 524 | |
| 525 | mutex_exit(&dict_sys->mutex); |
| 526 | |
| 527 | return(err); |
| 528 | } |
| 529 | |
| 530 | /*****************************************************************//** |
| 531 | Inserts the basic system table data into themselves in the database |
| 532 | creation. */ |
| 533 | static |
| 534 | void |
| 535 | dict_insert_initial_data(void) |
| 536 | /*==========================*/ |
| 537 | { |
| 538 | /* Does nothing yet */ |
| 539 | } |
| 540 | |
| 541 | /*****************************************************************//** |
| 542 | Creates and initializes the data dictionary at the server bootstrap. |
| 543 | @return DB_SUCCESS or error code. */ |
| 544 | dberr_t |
| 545 | dict_create(void) |
| 546 | /*=============*/ |
| 547 | { |
| 548 | mtr_t mtr; |
| 549 | |
| 550 | mtr_start(&mtr); |
| 551 | |
| 552 | dict_hdr_create(&mtr); |
| 553 | |
| 554 | mtr_commit(&mtr); |
| 555 | |
| 556 | dberr_t err = dict_boot(); |
| 557 | |
| 558 | if (err == DB_SUCCESS) { |
| 559 | dict_insert_initial_data(); |
| 560 | } |
| 561 | |
| 562 | return(err); |
| 563 | } |
| 564 | |