1
/*****************************************************************************
3
Copyright (C) 1996, 2010, Innobase Oy. All Rights Reserved.
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.
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.
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., 51 Franklin
15
St, Fifth Floor, Boston, MA 02110-1301 USA
17
*****************************************************************************/
19
/**************************************************//**
20
@file dict/dict0boot.c
21
Data dictionary creation and booting
23
Created 4/18/1996 Heikki Tuuri
24
*******************************************************/
26
#include "dict0boot.h"
29
#include "dict0boot.ic"
32
#include "dict0crea.h"
34
#include "dict0load.h"
35
#include "dict0load.h"
38
#include "ibuf0ibuf.h"
43
/**********************************************************************//**
44
Gets a pointer to the dictionary header and x-latches its page.
45
@return pointer to the dictionary header, page x-latched */
50
mtr_t* mtr) /*!< in: mtr */
55
block = buf_page_get(DICT_HDR_SPACE, 0, DICT_HDR_PAGE_NO,
57
header = DICT_HDR + buf_block_get_frame(block);
59
buf_block_dbg_add_level(block, SYNC_DICT_HEADER);
64
/**********************************************************************//**
65
Returns a new table, index, or space id. */
70
table_id_t* table_id, /*!< out: table id
71
(not assigned if NULL) */
72
index_id_t* index_id, /*!< out: index id
73
(not assigned if NULL) */
74
ulint* space_id) /*!< out: space id
75
(not assigned if NULL) */
83
dict_hdr = dict_hdr_get(&mtr);
86
id = mach_read_from_8(dict_hdr + DICT_HDR_TABLE_ID);
88
mlog_write_ull(dict_hdr + DICT_HDR_TABLE_ID, id, &mtr);
93
id = mach_read_from_8(dict_hdr + DICT_HDR_INDEX_ID);
95
mlog_write_ull(dict_hdr + DICT_HDR_INDEX_ID, id, &mtr);
100
*space_id = mtr_read_ulint(dict_hdr + DICT_HDR_MAX_SPACE_ID,
102
if (fil_assign_new_space_id(space_id)) {
103
mlog_write_ulint(dict_hdr + DICT_HDR_MAX_SPACE_ID,
104
*space_id, MLOG_4BYTES, &mtr);
111
/**********************************************************************//**
112
Writes the current value of the row id counter to the dictionary header file
116
dict_hdr_flush_row_id(void)
117
/*=======================*/
119
dict_hdr_t* dict_hdr;
123
ut_ad(mutex_own(&(dict_sys->mutex)));
125
id = dict_sys->row_id;
129
dict_hdr = dict_hdr_get(&mtr);
131
mlog_write_ull(dict_hdr + DICT_HDR_ROW_ID, id, &mtr);
136
/*****************************************************************//**
137
Creates the file page for the dictionary header. This function is
138
called only at the database creation.
139
@return TRUE if succeed */
144
mtr_t* mtr) /*!< in: mtr */
147
dict_hdr_t* dict_header;
152
/* Create the dictionary header file block in a new, allocated file
153
segment in the system tablespace */
154
block = fseg_create(DICT_HDR_SPACE, 0,
155
DICT_HDR + DICT_HDR_FSEG_HEADER, mtr);
157
ut_a(DICT_HDR_PAGE_NO == buf_block_get_page_no(block));
159
dict_header = dict_hdr_get(mtr);
161
/* Start counting row, table, index, and tree ids from
163
mlog_write_ull(dict_header + DICT_HDR_ROW_ID,
164
DICT_HDR_FIRST_ID, mtr);
166
mlog_write_ull(dict_header + DICT_HDR_TABLE_ID,
167
DICT_HDR_FIRST_ID, mtr);
169
mlog_write_ull(dict_header + DICT_HDR_INDEX_ID,
170
DICT_HDR_FIRST_ID, mtr);
172
mlog_write_ulint(dict_header + DICT_HDR_MAX_SPACE_ID,
173
0, MLOG_4BYTES, mtr);
175
/* Obsolete, but we must initialize it anyway. */
176
mlog_write_ulint(dict_header + DICT_HDR_MIX_ID_LOW,
177
DICT_HDR_FIRST_ID, MLOG_4BYTES, mtr);
179
/* Create the B-tree roots for the clustered indexes of the basic
182
/*--------------------------*/
183
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
184
DICT_HDR_SPACE, 0, DICT_TABLES_ID,
185
dict_ind_redundant, mtr);
186
if (root_page_no == FIL_NULL) {
191
mlog_write_ulint(dict_header + DICT_HDR_TABLES, root_page_no,
193
/*--------------------------*/
194
root_page_no = btr_create(DICT_UNIQUE, DICT_HDR_SPACE, 0,
196
dict_ind_redundant, mtr);
197
if (root_page_no == FIL_NULL) {
202
mlog_write_ulint(dict_header + DICT_HDR_TABLE_IDS, root_page_no,
204
/*--------------------------*/
205
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
206
DICT_HDR_SPACE, 0, DICT_COLUMNS_ID,
207
dict_ind_redundant, mtr);
208
if (root_page_no == FIL_NULL) {
213
mlog_write_ulint(dict_header + DICT_HDR_COLUMNS, root_page_no,
215
/*--------------------------*/
216
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
217
DICT_HDR_SPACE, 0, DICT_INDEXES_ID,
218
dict_ind_redundant, mtr);
219
if (root_page_no == FIL_NULL) {
224
mlog_write_ulint(dict_header + DICT_HDR_INDEXES, root_page_no,
226
/*--------------------------*/
227
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
228
DICT_HDR_SPACE, 0, DICT_FIELDS_ID,
229
dict_ind_redundant, mtr);
230
if (root_page_no == FIL_NULL) {
235
mlog_write_ulint(dict_header + DICT_HDR_FIELDS, root_page_no,
237
/*--------------------------*/
242
/*****************************************************************//**
243
Initializes the data dictionary memory structures when the database is
244
started. This function is also called when the data dictionary is created. */
252
dict_hdr_t* dict_hdr;
259
/* Create the hash tables etc. */
262
heap = mem_heap_create(450);
264
mutex_enter(&(dict_sys->mutex));
266
/* Get the dictionary header */
267
dict_hdr = dict_hdr_get(&mtr);
269
/* Because we only write new row ids to disk-based data structure
270
(dictionary header) when it is divisible by
271
DICT_HDR_ROW_ID_WRITE_MARGIN, in recovery we will not recover
272
the latest value of the row id counter. Therefore we advance
273
the counter at the database startup to avoid overlapping values.
274
Note that when a user after database startup first time asks for
275
a new row id, then because the counter is now divisible by
276
..._MARGIN, it will immediately be updated to the disk-based
279
dict_sys->row_id = DICT_HDR_ROW_ID_WRITE_MARGIN
280
+ ut_uint64_align_up(mach_read_from_8(dict_hdr + DICT_HDR_ROW_ID),
281
DICT_HDR_ROW_ID_WRITE_MARGIN);
283
/* Insert into the dictionary cache the descriptions of the basic
285
/*-------------------------*/
286
table = dict_mem_table_create("SYS_TABLES", DICT_HDR_SPACE, 8, 0);
288
dict_mem_table_add_col(table, heap, "NAME", DATA_BINARY, 0, 0);
289
dict_mem_table_add_col(table, heap, "ID", DATA_BINARY, 0, 0);
290
/* ROW_FORMAT = (N_COLS >> 31) ? COMPACT : REDUNDANT */
291
dict_mem_table_add_col(table, heap, "N_COLS", DATA_INT, 0, 4);
292
/* TYPE is either DICT_TABLE_ORDINARY, or (TYPE & DICT_TF_COMPACT)
293
and (TYPE & DICT_TF_FORMAT_MASK) are nonzero and TYPE = table->flags */
294
dict_mem_table_add_col(table, heap, "TYPE", DATA_INT, 0, 4);
295
dict_mem_table_add_col(table, heap, "MIX_ID", DATA_BINARY, 0, 0);
296
/* MIX_LEN may contain additional table flags when
297
ROW_FORMAT!=REDUNDANT. Currently, these flags include
298
DICT_TF2_TEMPORARY. */
299
dict_mem_table_add_col(table, heap, "MIX_LEN", DATA_INT, 0, 4);
300
dict_mem_table_add_col(table, heap, "CLUSTER_NAME", DATA_BINARY, 0, 0);
301
dict_mem_table_add_col(table, heap, "SPACE", DATA_INT, 0, 4);
303
table->id = DICT_TABLES_ID;
305
dict_table_add_to_cache(table, heap);
306
dict_sys->sys_tables = table;
307
mem_heap_empty(heap);
309
index = dict_mem_index_create("SYS_TABLES", "CLUST_IND",
311
DICT_UNIQUE | DICT_CLUSTERED, 1);
313
dict_mem_index_add_field(index, "NAME", 0);
315
index->id = DICT_TABLES_ID;
317
error = dict_index_add_to_cache(table, index,
318
mtr_read_ulint(dict_hdr
322
ut_a(error == DB_SUCCESS);
324
/*-------------------------*/
325
index = dict_mem_index_create("SYS_TABLES", "ID_IND",
326
DICT_HDR_SPACE, DICT_UNIQUE, 1);
327
dict_mem_index_add_field(index, "ID", 0);
329
index->id = DICT_TABLE_IDS_ID;
330
error = dict_index_add_to_cache(table, index,
331
mtr_read_ulint(dict_hdr
332
+ DICT_HDR_TABLE_IDS,
335
ut_a(error == DB_SUCCESS);
337
/*-------------------------*/
338
table = dict_mem_table_create("SYS_COLUMNS", DICT_HDR_SPACE, 7, 0);
340
dict_mem_table_add_col(table, heap, "TABLE_ID", DATA_BINARY, 0, 0);
341
dict_mem_table_add_col(table, heap, "POS", DATA_INT, 0, 4);
342
dict_mem_table_add_col(table, heap, "NAME", DATA_BINARY, 0, 0);
343
dict_mem_table_add_col(table, heap, "MTYPE", DATA_INT, 0, 4);
344
dict_mem_table_add_col(table, heap, "PRTYPE", DATA_INT, 0, 4);
345
dict_mem_table_add_col(table, heap, "LEN", DATA_INT, 0, 4);
346
dict_mem_table_add_col(table, heap, "PREC", DATA_INT, 0, 4);
348
table->id = DICT_COLUMNS_ID;
350
dict_table_add_to_cache(table, heap);
351
dict_sys->sys_columns = table;
352
mem_heap_empty(heap);
354
index = dict_mem_index_create("SYS_COLUMNS", "CLUST_IND",
356
DICT_UNIQUE | DICT_CLUSTERED, 2);
358
dict_mem_index_add_field(index, "TABLE_ID", 0);
359
dict_mem_index_add_field(index, "POS", 0);
361
index->id = DICT_COLUMNS_ID;
362
error = dict_index_add_to_cache(table, index,
363
mtr_read_ulint(dict_hdr
367
ut_a(error == DB_SUCCESS);
369
/*-------------------------*/
370
table = dict_mem_table_create("SYS_INDEXES", DICT_HDR_SPACE, 7, 0);
372
dict_mem_table_add_col(table, heap, "TABLE_ID", DATA_BINARY, 0, 0);
373
dict_mem_table_add_col(table, heap, "ID", DATA_BINARY, 0, 0);
374
dict_mem_table_add_col(table, heap, "NAME", DATA_BINARY, 0, 0);
375
dict_mem_table_add_col(table, heap, "N_FIELDS", DATA_INT, 0, 4);
376
dict_mem_table_add_col(table, heap, "TYPE", DATA_INT, 0, 4);
377
dict_mem_table_add_col(table, heap, "SPACE", DATA_INT, 0, 4);
378
dict_mem_table_add_col(table, heap, "PAGE_NO", DATA_INT, 0, 4);
380
/* The '+ 2' below comes from the fields DB_TRX_ID, DB_ROLL_PTR */
381
#if DICT_SYS_INDEXES_PAGE_NO_FIELD != 6 + 2
382
#error "DICT_SYS_INDEXES_PAGE_NO_FIELD != 6 + 2"
384
#if DICT_SYS_INDEXES_SPACE_NO_FIELD != 5 + 2
385
#error "DICT_SYS_INDEXES_SPACE_NO_FIELD != 5 + 2"
387
#if DICT_SYS_INDEXES_TYPE_FIELD != 4 + 2
388
#error "DICT_SYS_INDEXES_TYPE_FIELD != 4 + 2"
390
#if DICT_SYS_INDEXES_NAME_FIELD != 2 + 2
391
#error "DICT_SYS_INDEXES_NAME_FIELD != 2 + 2"
394
table->id = DICT_INDEXES_ID;
395
dict_table_add_to_cache(table, heap);
396
dict_sys->sys_indexes = table;
397
mem_heap_empty(heap);
399
index = dict_mem_index_create("SYS_INDEXES", "CLUST_IND",
401
DICT_UNIQUE | DICT_CLUSTERED, 2);
403
dict_mem_index_add_field(index, "TABLE_ID", 0);
404
dict_mem_index_add_field(index, "ID", 0);
406
index->id = DICT_INDEXES_ID;
407
error = dict_index_add_to_cache(table, index,
408
mtr_read_ulint(dict_hdr
412
ut_a(error == DB_SUCCESS);
414
/*-------------------------*/
415
table = dict_mem_table_create("SYS_FIELDS", DICT_HDR_SPACE, 3, 0);
417
dict_mem_table_add_col(table, heap, "INDEX_ID", DATA_BINARY, 0, 0);
418
dict_mem_table_add_col(table, heap, "POS", DATA_INT, 0, 4);
419
dict_mem_table_add_col(table, heap, "COL_NAME", DATA_BINARY, 0, 0);
421
table->id = DICT_FIELDS_ID;
422
dict_table_add_to_cache(table, heap);
423
dict_sys->sys_fields = table;
426
index = dict_mem_index_create("SYS_FIELDS", "CLUST_IND",
428
DICT_UNIQUE | DICT_CLUSTERED, 2);
430
dict_mem_index_add_field(index, "INDEX_ID", 0);
431
dict_mem_index_add_field(index, "POS", 0);
433
index->id = DICT_FIELDS_ID;
434
error = dict_index_add_to_cache(table, index,
435
mtr_read_ulint(dict_hdr
439
ut_a(error == DB_SUCCESS);
442
/*-------------------------*/
444
/* Initialize the insert buffer table and index for each tablespace */
446
ibuf_init_at_db_start();
448
/* Load definitions of other indexes on system tables */
450
dict_load_sys_table(dict_sys->sys_tables);
451
dict_load_sys_table(dict_sys->sys_columns);
452
dict_load_sys_table(dict_sys->sys_indexes);
453
dict_load_sys_table(dict_sys->sys_fields);
455
mutex_exit(&(dict_sys->mutex));
458
/*****************************************************************//**
459
Inserts the basic system table data into themselves in the database
463
dict_insert_initial_data(void)
464
/*==========================*/
466
/* Does nothing yet */
469
/*****************************************************************//**
470
Creates and initializes the data dictionary at the database creation. */
480
dict_hdr_create(&mtr);
486
dict_insert_initial_data();