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