1 /*****************************************************************************
2
3 Copyright (c) 1996, 2010, Innobase Oy. 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 St, Fifth Floor, Boston, MA 02110-1301 USA
16
17 *****************************************************************************/
18
19 /**************************************************//**
20 @file dict/dict0boot.c
21 Data dictionary creation and booting
22
23 Created 4/18/1996 Heikki Tuuri
24 *******************************************************/
25
26 #include "dict0boot.h"
27
28 #ifdef UNIV_NONINL
29 #include "dict0boot.ic"
30 #endif
31
32 #include "dict0crea.h"
33 #include "btr0btr.h"
34 #include "dict0load.h"
35 #include "dict0load.h"
36 #include "trx0trx.h"
37 #include "srv0srv.h"
38 #include "ibuf0ibuf.h"
39 #include "buf0flu.h"
40 #include "log0recv.h"
41 #include "os0file.h"
42
43 /**********************************************************************//**
44 Gets a pointer to the dictionary header and x-latches its page.
45 @return pointer to the dictionary header, page x-latched */
46 UNIV_INTERN
47 dict_hdr_t*
dict_hdr_get(mtr_t * mtr)48 dict_hdr_get(
49 /*=========*/
50 mtr_t* mtr) /*!< in: mtr */
51 {
52 buf_block_t* block;
53 dict_hdr_t* header;
54
55 block = buf_page_get(DICT_HDR_SPACE, 0, DICT_HDR_PAGE_NO,
56 RW_X_LATCH, mtr);
57 header = DICT_HDR + buf_block_get_frame(block);
58
59 buf_block_dbg_add_level(block, SYNC_DICT_HEADER);
60
61 return(header);
62 }
63
64 /**********************************************************************//**
65 Returns a new table, index, or space id. */
66 UNIV_INTERN
67 void
dict_hdr_get_new_id(table_id_t * table_id,index_id_t * index_id,ulint * space_id)68 dict_hdr_get_new_id(
69 /*================*/
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) */
76 {
77 dict_hdr_t* dict_hdr;
78 ib_id_t id;
79 mtr_t mtr;
80
81 mtr_start(&mtr);
82
83 dict_hdr = dict_hdr_get(&mtr);
84
85 if (table_id) {
86 id = mach_read_from_8(dict_hdr + DICT_HDR_TABLE_ID);
87 id++;
88 mlog_write_ull(dict_hdr + DICT_HDR_TABLE_ID, id, &mtr);
89 *table_id = id;
90 }
91
92 if (index_id) {
93 id = mach_read_from_8(dict_hdr + DICT_HDR_INDEX_ID);
94 id++;
95 mlog_write_ull(dict_hdr + DICT_HDR_INDEX_ID, id, &mtr);
96 *index_id = id;
97 }
98
99 if (space_id) {
100 *space_id = mtr_read_ulint(dict_hdr + DICT_HDR_MAX_SPACE_ID,
101 MLOG_4BYTES, &mtr);
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);
105 }
106 }
107
108 mtr_commit(&mtr);
109 }
110
111 /**********************************************************************//**
112 Writes the current value of the row id counter to the dictionary header file
113 page. */
114 UNIV_INTERN
115 void
dict_hdr_flush_row_id(void)116 dict_hdr_flush_row_id(void)
117 /*=======================*/
118 {
119 dict_hdr_t* dict_hdr;
120 row_id_t id;
121 mtr_t mtr;
122
123 ut_ad(mutex_own(&(dict_sys->mutex)));
124
125 id = dict_sys->row_id;
126
127 mtr_start(&mtr);
128
129 dict_hdr = dict_hdr_get(&mtr);
130
131 mlog_write_ull(dict_hdr + DICT_HDR_ROW_ID, id, &mtr);
132
133 mtr_commit(&mtr);
134 }
135
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 */
140 static
141 ibool
dict_hdr_create(mtr_t * mtr)142 dict_hdr_create(
143 /*============*/
144 mtr_t* mtr) /*!< in: mtr */
145 {
146 buf_block_t* block;
147 dict_hdr_t* dict_header;
148 ulint root_page_no;
149
150 ut_ad(mtr);
151
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);
156
157 ut_a(DICT_HDR_PAGE_NO == buf_block_get_page_no(block));
158
159 dict_header = dict_hdr_get(mtr);
160
161 /* Start counting row, table, index, and tree ids from
162 DICT_HDR_FIRST_ID */
163 mlog_write_ull(dict_header + DICT_HDR_ROW_ID,
164 DICT_HDR_FIRST_ID, mtr);
165
166 mlog_write_ull(dict_header + DICT_HDR_TABLE_ID,
167 DICT_HDR_FIRST_ID, mtr);
168
169 mlog_write_ull(dict_header + DICT_HDR_INDEX_ID,
170 DICT_HDR_FIRST_ID, mtr);
171
172 mlog_write_ulint(dict_header + DICT_HDR_MAX_SPACE_ID,
173 0, MLOG_4BYTES, mtr);
174
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);
178
179 /* Create the B-tree roots for the clustered indexes of the basic
180 system tables */
181
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) {
187
188 return(FALSE);
189 }
190
191 mlog_write_ulint(dict_header + DICT_HDR_TABLES, root_page_no,
192 MLOG_4BYTES, mtr);
193 /*--------------------------*/
194 root_page_no = btr_create(DICT_UNIQUE, DICT_HDR_SPACE, 0,
195 DICT_TABLE_IDS_ID,
196 dict_ind_redundant, mtr);
197 if (root_page_no == FIL_NULL) {
198
199 return(FALSE);
200 }
201
202 mlog_write_ulint(dict_header + DICT_HDR_TABLE_IDS, root_page_no,
203 MLOG_4BYTES, mtr);
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) {
209
210 return(FALSE);
211 }
212
213 mlog_write_ulint(dict_header + DICT_HDR_COLUMNS, root_page_no,
214 MLOG_4BYTES, mtr);
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) {
220
221 return(FALSE);
222 }
223
224 mlog_write_ulint(dict_header + DICT_HDR_INDEXES, root_page_no,
225 MLOG_4BYTES, mtr);
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) {
231
232 return(FALSE);
233 }
234
235 mlog_write_ulint(dict_header + DICT_HDR_FIELDS, root_page_no,
236 MLOG_4BYTES, mtr);
237 /*--------------------------*/
238
239 return(TRUE);
240 }
241
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. */
245 UNIV_INTERN
246 void
dict_boot(void)247 dict_boot(void)
248 /*===========*/
249 {
250 dict_table_t* table;
251 dict_index_t* index;
252 dict_hdr_t* dict_hdr;
253 mem_heap_t* heap;
254 mtr_t mtr;
255 ulint error;
256
257 mtr_start(&mtr);
258
259 /* Create the hash tables etc. */
260 dict_init();
261
262 heap = mem_heap_create(450);
263
264 mutex_enter(&(dict_sys->mutex));
265
266 /* Get the dictionary header */
267 dict_hdr = dict_hdr_get(&mtr);
268
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
277 header. */
278
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);
282
283 /* Insert into the dictionary cache the descriptions of the basic
284 system tables */
285 /*-------------------------*/
286 table = dict_mem_table_create("SYS_TABLES", DICT_HDR_SPACE, 8, 0);
287
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);
302
303 table->id = DICT_TABLES_ID;
304
305 dict_table_add_to_cache(table, heap);
306 dict_sys->sys_tables = table;
307 mem_heap_empty(heap);
308
309 index = dict_mem_index_create("SYS_TABLES", "CLUST_IND",
310 DICT_HDR_SPACE,
311 DICT_UNIQUE | DICT_CLUSTERED, 1);
312
313 dict_mem_index_add_field(index, "NAME", 0);
314
315 index->id = DICT_TABLES_ID;
316
317 error = dict_index_add_to_cache(table, index,
318 mtr_read_ulint(dict_hdr
319 + DICT_HDR_TABLES,
320 MLOG_4BYTES, &mtr),
321 FALSE);
322 ut_a(error == DB_SUCCESS);
323
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);
328
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,
333 MLOG_4BYTES, &mtr),
334 FALSE);
335 ut_a(error == DB_SUCCESS);
336
337 /*-------------------------*/
338 table = dict_mem_table_create("SYS_COLUMNS", DICT_HDR_SPACE, 7, 0);
339
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);
347
348 table->id = DICT_COLUMNS_ID;
349
350 dict_table_add_to_cache(table, heap);
351 dict_sys->sys_columns = table;
352 mem_heap_empty(heap);
353
354 index = dict_mem_index_create("SYS_COLUMNS", "CLUST_IND",
355 DICT_HDR_SPACE,
356 DICT_UNIQUE | DICT_CLUSTERED, 2);
357
358 dict_mem_index_add_field(index, "TABLE_ID", 0);
359 dict_mem_index_add_field(index, "POS", 0);
360
361 index->id = DICT_COLUMNS_ID;
362 error = dict_index_add_to_cache(table, index,
363 mtr_read_ulint(dict_hdr
364 + DICT_HDR_COLUMNS,
365 MLOG_4BYTES, &mtr),
366 FALSE);
367 ut_a(error == DB_SUCCESS);
368
369 /*-------------------------*/
370 table = dict_mem_table_create("SYS_INDEXES", DICT_HDR_SPACE, 7, 0);
371
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);
379
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"
383 #endif
384 #if DICT_SYS_INDEXES_SPACE_NO_FIELD != 5 + 2
385 #error "DICT_SYS_INDEXES_SPACE_NO_FIELD != 5 + 2"
386 #endif
387 #if DICT_SYS_INDEXES_TYPE_FIELD != 4 + 2
388 #error "DICT_SYS_INDEXES_TYPE_FIELD != 4 + 2"
389 #endif
390 #if DICT_SYS_INDEXES_NAME_FIELD != 2 + 2
391 #error "DICT_SYS_INDEXES_NAME_FIELD != 2 + 2"
392 #endif
393
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);
398
399 index = dict_mem_index_create("SYS_INDEXES", "CLUST_IND",
400 DICT_HDR_SPACE,
401 DICT_UNIQUE | DICT_CLUSTERED, 2);
402
403 dict_mem_index_add_field(index, "TABLE_ID", 0);
404 dict_mem_index_add_field(index, "ID", 0);
405
406 index->id = DICT_INDEXES_ID;
407 error = dict_index_add_to_cache(table, index,
408 mtr_read_ulint(dict_hdr
409 + DICT_HDR_INDEXES,
410 MLOG_4BYTES, &mtr),
411 FALSE);
412 ut_a(error == DB_SUCCESS);
413
414 /*-------------------------*/
415 table = dict_mem_table_create("SYS_FIELDS", DICT_HDR_SPACE, 3, 0);
416
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);
420
421 table->id = DICT_FIELDS_ID;
422 dict_table_add_to_cache(table, heap);
423 dict_sys->sys_fields = table;
424 mem_heap_free(heap);
425
426 index = dict_mem_index_create("SYS_FIELDS", "CLUST_IND",
427 DICT_HDR_SPACE,
428 DICT_UNIQUE | DICT_CLUSTERED, 2);
429
430 dict_mem_index_add_field(index, "INDEX_ID", 0);
431 dict_mem_index_add_field(index, "POS", 0);
432
433 index->id = DICT_FIELDS_ID;
434 error = dict_index_add_to_cache(table, index,
435 mtr_read_ulint(dict_hdr
436 + DICT_HDR_FIELDS,
437 MLOG_4BYTES, &mtr),
438 FALSE);
439 ut_a(error == DB_SUCCESS);
440
441 mtr_commit(&mtr);
442 /*-------------------------*/
443
444 /* Initialize the insert buffer table and index for each tablespace */
445
446 ibuf_init_at_db_start();
447
448 /* Load definitions of other indexes on system tables */
449
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);
454
455 mutex_exit(&(dict_sys->mutex));
456 }
457
458 /*****************************************************************//**
459 Inserts the basic system table data into themselves in the database
460 creation. */
461 static
462 void
dict_insert_initial_data(void)463 dict_insert_initial_data(void)
464 /*==========================*/
465 {
466 /* Does nothing yet */
467 }
468
469 /*****************************************************************//**
470 Creates and initializes the data dictionary at the database creation. */
471 UNIV_INTERN
472 void
dict_create(void)473 dict_create(void)
474 /*=============*/
475 {
476 mtr_t mtr;
477
478 mtr_start(&mtr);
479
480 dict_hdr_create(&mtr);
481
482 mtr_commit(&mtr);
483
484 dict_boot();
485
486 dict_insert_initial_data();
487 }
488