You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1317 lines
35 KiB

20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
20 years ago
  1. /******************************************************
  2. Transaction system
  3. (c) 1996 Innobase Oy
  4. Created 3/26/1996 Heikki Tuuri
  5. *******************************************************/
  6. #include "trx0sys.h"
  7. #ifdef UNIV_NONINL
  8. #include "trx0sys.ic"
  9. #endif
  10. #include "fsp0fsp.h"
  11. #include "mtr0mtr.h"
  12. #include "trx0trx.h"
  13. #include "trx0rseg.h"
  14. #include "trx0undo.h"
  15. #include "srv0srv.h"
  16. #include "trx0purge.h"
  17. #include "log0log.h"
  18. #include "os0file.h"
  19. /* The file format tag structure with id and name. */
  20. struct file_format_struct {
  21. uint id; /* id of the file format */
  22. const char* name; /* text representation of the
  23. file format */
  24. mutex_t mutex; /* covers changes to the above
  25. fields */
  26. };
  27. typedef struct file_format_struct file_format_t;
  28. /* The transaction system */
  29. UNIV_INTERN trx_sys_t* trx_sys = NULL;
  30. UNIV_INTERN trx_doublewrite_t* trx_doublewrite = NULL;
  31. /* The following is set to TRUE when we are upgrading from the old format data
  32. files to the new >= 4.1.x format multiple tablespaces format data files */
  33. UNIV_INTERN ibool trx_doublewrite_must_reset_space_ids = FALSE;
  34. /* The following is TRUE when we are using the database in the new format,
  35. i.e., we have successfully upgraded, or have created a new database
  36. installation */
  37. UNIV_INTERN ibool trx_sys_multiple_tablespace_format = FALSE;
  38. /* In a MySQL replication slave, in crash recovery we store the master log
  39. file name and position here. We have successfully got the updates to InnoDB
  40. up to this position. If .._pos is -1, it means no crash recovery was needed,
  41. or there was no master log position info inside InnoDB. */
  42. UNIV_INTERN char trx_sys_mysql_master_log_name[TRX_SYS_MYSQL_LOG_NAME_LEN];
  43. UNIV_INTERN ib_int64_t trx_sys_mysql_master_log_pos = -1;
  44. /* If this MySQL server uses binary logging, after InnoDB has been inited
  45. and if it has done a crash recovery, we store the binlog file name and position
  46. here. If .._pos is -1, it means there was no binlog position info inside
  47. InnoDB. */
  48. UNIV_INTERN char trx_sys_mysql_bin_log_name[TRX_SYS_MYSQL_LOG_NAME_LEN];
  49. UNIV_INTERN ib_int64_t trx_sys_mysql_bin_log_pos = -1;
  50. /* List of animal names representing file format. */
  51. static const char* file_format_name_map[] = {
  52. "Antelope",
  53. "Barracuda",
  54. "Cheetah",
  55. "Dragon",
  56. "Elk",
  57. "Fox",
  58. "Gazelle",
  59. "Hornet",
  60. "Impala",
  61. "Jaguar",
  62. "Kangaroo",
  63. "Leopard",
  64. "Moose",
  65. "Nautilus",
  66. "Ocelot",
  67. "Porpoise",
  68. "Quail",
  69. "Rabbit",
  70. "Shark",
  71. "Tiger",
  72. "Urchin",
  73. "Viper",
  74. "Whale",
  75. "Xenops",
  76. "Yak",
  77. "Zebra"
  78. };
  79. /* The number of elements in the file format name array. */
  80. static const ulint FILE_FORMAT_NAME_N =
  81. sizeof(file_format_name_map) / sizeof(file_format_name_map[0]);
  82. /* This is used to track the maximum file format id known to InnoDB. It's
  83. updated via SET GLOBAL innodb_file_format_check = 'x' or when we open
  84. or create a table. */
  85. static file_format_t file_format_max;
  86. /********************************************************************
  87. Determines if a page number is located inside the doublewrite buffer. */
  88. UNIV_INTERN
  89. ibool
  90. trx_doublewrite_page_inside(
  91. /*========================*/
  92. /* out: TRUE if the location is inside
  93. the two blocks of the doublewrite buffer */
  94. ulint page_no) /* in: page number */
  95. {
  96. if (trx_doublewrite == NULL) {
  97. return(FALSE);
  98. }
  99. if (page_no >= trx_doublewrite->block1
  100. && page_no < trx_doublewrite->block1
  101. + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) {
  102. return(TRUE);
  103. }
  104. if (page_no >= trx_doublewrite->block2
  105. && page_no < trx_doublewrite->block2
  106. + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) {
  107. return(TRUE);
  108. }
  109. return(FALSE);
  110. }
  111. /********************************************************************
  112. Creates or initialializes the doublewrite buffer at a database start. */
  113. static
  114. void
  115. trx_doublewrite_init(
  116. /*=================*/
  117. byte* doublewrite) /* in: pointer to the doublewrite buf
  118. header on trx sys page */
  119. {
  120. trx_doublewrite = mem_alloc(sizeof(trx_doublewrite_t));
  121. /* Since we now start to use the doublewrite buffer, no need to call
  122. fsync() after every write to a data file */
  123. #ifdef UNIV_DO_FLUSH
  124. os_do_not_call_flush_at_each_write = TRUE;
  125. #endif /* UNIV_DO_FLUSH */
  126. mutex_create(&trx_doublewrite->mutex, SYNC_DOUBLEWRITE);
  127. trx_doublewrite->first_free = 0;
  128. trx_doublewrite->block1 = mach_read_from_4(
  129. doublewrite + TRX_SYS_DOUBLEWRITE_BLOCK1);
  130. trx_doublewrite->block2 = mach_read_from_4(
  131. doublewrite + TRX_SYS_DOUBLEWRITE_BLOCK2);
  132. trx_doublewrite->write_buf_unaligned = ut_malloc(
  133. (1 + 2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) * UNIV_PAGE_SIZE);
  134. trx_doublewrite->write_buf = ut_align(
  135. trx_doublewrite->write_buf_unaligned, UNIV_PAGE_SIZE);
  136. trx_doublewrite->buf_block_arr = mem_alloc(
  137. 2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * sizeof(void*));
  138. }
  139. /********************************************************************
  140. Marks the trx sys header when we have successfully upgraded to the >= 4.1.x
  141. multiple tablespace format. */
  142. UNIV_INTERN
  143. void
  144. trx_sys_mark_upgraded_to_multiple_tablespaces(void)
  145. /*===============================================*/
  146. {
  147. buf_block_t* block;
  148. byte* doublewrite;
  149. mtr_t mtr;
  150. /* We upgraded to 4.1.x and reset the space id fields in the
  151. doublewrite buffer. Let us mark to the trx_sys header that the upgrade
  152. has been done. */
  153. mtr_start(&mtr);
  154. block = buf_page_get(TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO,
  155. RW_X_LATCH, &mtr);
  156. buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
  157. doublewrite = buf_block_get_frame(block) + TRX_SYS_DOUBLEWRITE;
  158. mlog_write_ulint(doublewrite + TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED,
  159. TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N,
  160. MLOG_4BYTES, &mtr);
  161. mtr_commit(&mtr);
  162. /* Flush the modified pages to disk and make a checkpoint */
  163. log_make_checkpoint_at(IB_ULONGLONG_MAX, TRUE);
  164. trx_sys_multiple_tablespace_format = TRUE;
  165. }
  166. /********************************************************************
  167. Creates the doublewrite buffer to a new InnoDB installation. The header of the
  168. doublewrite buffer is placed on the trx system header page. */
  169. UNIV_INTERN
  170. void
  171. trx_sys_create_doublewrite_buf(void)
  172. /*================================*/
  173. {
  174. buf_block_t* block;
  175. buf_block_t* block2;
  176. buf_block_t* new_block;
  177. byte* doublewrite;
  178. byte* fseg_header;
  179. ulint page_no;
  180. ulint prev_page_no;
  181. ulint i;
  182. mtr_t mtr;
  183. if (trx_doublewrite) {
  184. /* Already inited */
  185. return;
  186. }
  187. start_again:
  188. mtr_start(&mtr);
  189. block = buf_page_get(TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO,
  190. RW_X_LATCH, &mtr);
  191. buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
  192. doublewrite = buf_block_get_frame(block) + TRX_SYS_DOUBLEWRITE;
  193. if (mach_read_from_4(doublewrite + TRX_SYS_DOUBLEWRITE_MAGIC)
  194. == TRX_SYS_DOUBLEWRITE_MAGIC_N) {
  195. /* The doublewrite buffer has already been created:
  196. just read in some numbers */
  197. trx_doublewrite_init(doublewrite);
  198. mtr_commit(&mtr);
  199. } else {
  200. fprintf(stderr,
  201. "InnoDB: Doublewrite buffer not found:"
  202. " creating new\n");
  203. if (buf_pool_get_curr_size()
  204. < ((2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE
  205. + FSP_EXTENT_SIZE / 2 + 100)
  206. * UNIV_PAGE_SIZE)) {
  207. fprintf(stderr,
  208. "InnoDB: Cannot create doublewrite buffer:"
  209. " you must\n"
  210. "InnoDB: increase your buffer pool size.\n"
  211. "InnoDB: Cannot continue operation.\n");
  212. exit(1);
  213. }
  214. block2 = fseg_create(TRX_SYS_SPACE, TRX_SYS_PAGE_NO,
  215. TRX_SYS_DOUBLEWRITE
  216. + TRX_SYS_DOUBLEWRITE_FSEG, &mtr);
  217. /* fseg_create acquires a second latch on the page,
  218. therefore we must declare it: */
  219. buf_block_dbg_add_level(block2, SYNC_NO_ORDER_CHECK);
  220. if (block2 == NULL) {
  221. fprintf(stderr,
  222. "InnoDB: Cannot create doublewrite buffer:"
  223. " you must\n"
  224. "InnoDB: increase your tablespace size.\n"
  225. "InnoDB: Cannot continue operation.\n");
  226. /* We exit without committing the mtr to prevent
  227. its modifications to the database getting to disk */
  228. exit(1);
  229. }
  230. fseg_header = buf_block_get_frame(block)
  231. + TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_FSEG;
  232. prev_page_no = 0;
  233. for (i = 0; i < 2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE
  234. + FSP_EXTENT_SIZE / 2; i++) {
  235. page_no = fseg_alloc_free_page(fseg_header,
  236. prev_page_no + 1,
  237. FSP_UP, &mtr);
  238. if (page_no == FIL_NULL) {
  239. fprintf(stderr,
  240. "InnoDB: Cannot create doublewrite"
  241. " buffer: you must\n"
  242. "InnoDB: increase your"
  243. " tablespace size.\n"
  244. "InnoDB: Cannot continue operation.\n"
  245. );
  246. exit(1);
  247. }
  248. /* We read the allocated pages to the buffer pool;
  249. when they are written to disk in a flush, the space
  250. id and page number fields are also written to the
  251. pages. When we at database startup read pages
  252. from the doublewrite buffer, we know that if the
  253. space id and page number in them are the same as
  254. the page position in the tablespace, then the page
  255. has not been written to in doublewrite. */
  256. new_block = buf_page_get(TRX_SYS_SPACE, 0, page_no,
  257. RW_X_LATCH, &mtr);
  258. buf_block_dbg_add_level(new_block,
  259. SYNC_NO_ORDER_CHECK);
  260. /* Make a dummy change to the page to ensure it will
  261. be written to disk in a flush */
  262. mlog_write_ulint(buf_block_get_frame(new_block)
  263. + FIL_PAGE_DATA,
  264. TRX_SYS_DOUBLEWRITE_MAGIC_N,
  265. MLOG_4BYTES, &mtr);
  266. if (i == FSP_EXTENT_SIZE / 2) {
  267. mlog_write_ulint(doublewrite
  268. + TRX_SYS_DOUBLEWRITE_BLOCK1,
  269. page_no, MLOG_4BYTES, &mtr);
  270. mlog_write_ulint(doublewrite
  271. + TRX_SYS_DOUBLEWRITE_REPEAT
  272. + TRX_SYS_DOUBLEWRITE_BLOCK1,
  273. page_no, MLOG_4BYTES, &mtr);
  274. } else if (i == FSP_EXTENT_SIZE / 2
  275. + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) {
  276. mlog_write_ulint(doublewrite
  277. + TRX_SYS_DOUBLEWRITE_BLOCK2,
  278. page_no, MLOG_4BYTES, &mtr);
  279. mlog_write_ulint(doublewrite
  280. + TRX_SYS_DOUBLEWRITE_REPEAT
  281. + TRX_SYS_DOUBLEWRITE_BLOCK2,
  282. page_no, MLOG_4BYTES, &mtr);
  283. } else if (i > FSP_EXTENT_SIZE / 2) {
  284. ut_a(page_no == prev_page_no + 1);
  285. }
  286. prev_page_no = page_no;
  287. }
  288. mlog_write_ulint(doublewrite + TRX_SYS_DOUBLEWRITE_MAGIC,
  289. TRX_SYS_DOUBLEWRITE_MAGIC_N,
  290. MLOG_4BYTES, &mtr);
  291. mlog_write_ulint(doublewrite + TRX_SYS_DOUBLEWRITE_MAGIC
  292. + TRX_SYS_DOUBLEWRITE_REPEAT,
  293. TRX_SYS_DOUBLEWRITE_MAGIC_N,
  294. MLOG_4BYTES, &mtr);
  295. mlog_write_ulint(doublewrite
  296. + TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED,
  297. TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N,
  298. MLOG_4BYTES, &mtr);
  299. mtr_commit(&mtr);
  300. /* Flush the modified pages to disk and make a checkpoint */
  301. log_make_checkpoint_at(IB_ULONGLONG_MAX, TRUE);
  302. fprintf(stderr, "InnoDB: Doublewrite buffer created\n");
  303. trx_sys_multiple_tablespace_format = TRUE;
  304. goto start_again;
  305. }
  306. }
  307. /********************************************************************
  308. At a database startup initializes the doublewrite buffer memory structure if
  309. we already have a doublewrite buffer created in the data files. If we are
  310. upgrading to an InnoDB version which supports multiple tablespaces, then this
  311. function performs the necessary update operations. If we are in a crash
  312. recovery, this function uses a possible doublewrite buffer to restore
  313. half-written pages in the data files. */
  314. UNIV_INTERN
  315. void
  316. trx_sys_doublewrite_init_or_restore_pages(
  317. /*======================================*/
  318. ibool restore_corrupt_pages)
  319. {
  320. byte* buf;
  321. byte* read_buf;
  322. byte* unaligned_read_buf;
  323. ulint block1;
  324. ulint block2;
  325. ulint source_page_no;
  326. byte* page;
  327. byte* doublewrite;
  328. ulint space_id;
  329. ulint page_no;
  330. ulint i;
  331. /* We do the file i/o past the buffer pool */
  332. unaligned_read_buf = ut_malloc(2 * UNIV_PAGE_SIZE);
  333. read_buf = ut_align(unaligned_read_buf, UNIV_PAGE_SIZE);
  334. /* Read the trx sys header to check if we are using the doublewrite
  335. buffer */
  336. fil_io(OS_FILE_READ, TRUE, TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO, 0,
  337. UNIV_PAGE_SIZE, read_buf, NULL);
  338. doublewrite = read_buf + TRX_SYS_DOUBLEWRITE;
  339. if (mach_read_from_4(doublewrite + TRX_SYS_DOUBLEWRITE_MAGIC)
  340. == TRX_SYS_DOUBLEWRITE_MAGIC_N) {
  341. /* The doublewrite buffer has been created */
  342. trx_doublewrite_init(doublewrite);
  343. block1 = trx_doublewrite->block1;
  344. block2 = trx_doublewrite->block2;
  345. buf = trx_doublewrite->write_buf;
  346. } else {
  347. goto leave_func;
  348. }
  349. if (mach_read_from_4(doublewrite + TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED)
  350. != TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N) {
  351. /* We are upgrading from a version < 4.1.x to a version where
  352. multiple tablespaces are supported. We must reset the space id
  353. field in the pages in the doublewrite buffer because starting
  354. from this version the space id is stored to
  355. FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID. */
  356. trx_doublewrite_must_reset_space_ids = TRUE;
  357. fprintf(stderr,
  358. "InnoDB: Resetting space id's in the"
  359. " doublewrite buffer\n");
  360. } else {
  361. trx_sys_multiple_tablespace_format = TRUE;
  362. }
  363. /* Read the pages from the doublewrite buffer to memory */
  364. fil_io(OS_FILE_READ, TRUE, TRX_SYS_SPACE, 0, block1, 0,
  365. TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * UNIV_PAGE_SIZE,
  366. buf, NULL);
  367. fil_io(OS_FILE_READ, TRUE, TRX_SYS_SPACE, 0, block2, 0,
  368. TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * UNIV_PAGE_SIZE,
  369. buf + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * UNIV_PAGE_SIZE,
  370. NULL);
  371. /* Check if any of these pages is half-written in data files, in the
  372. intended position */
  373. page = buf;
  374. for (i = 0; i < TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * 2; i++) {
  375. page_no = mach_read_from_4(page + FIL_PAGE_OFFSET);
  376. if (trx_doublewrite_must_reset_space_ids) {
  377. space_id = 0;
  378. mach_write_to_4(page
  379. + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 0);
  380. /* We do not need to calculate new checksums for the
  381. pages because the field .._SPACE_ID does not affect
  382. them. Write the page back to where we read it from. */
  383. if (i < TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) {
  384. source_page_no = block1 + i;
  385. } else {
  386. source_page_no = block2
  387. + i - TRX_SYS_DOUBLEWRITE_BLOCK_SIZE;
  388. }
  389. fil_io(OS_FILE_WRITE, TRUE, 0, 0, source_page_no, 0,
  390. UNIV_PAGE_SIZE, page, NULL);
  391. /* printf("Resetting space id in page %lu\n",
  392. source_page_no); */
  393. } else {
  394. space_id = mach_read_from_4(
  395. page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
  396. }
  397. if (!restore_corrupt_pages) {
  398. /* The database was shut down gracefully: no need to
  399. restore pages */
  400. } else if (!fil_tablespace_exists_in_mem(space_id)) {
  401. /* Maybe we have dropped the single-table tablespace
  402. and this page once belonged to it: do nothing */
  403. } else if (!fil_check_adress_in_tablespace(space_id,
  404. page_no)) {
  405. fprintf(stderr,
  406. "InnoDB: Warning: a page in the"
  407. " doublewrite buffer is not within space\n"
  408. "InnoDB: bounds; space id %lu"
  409. " page number %lu, page %lu in"
  410. " doublewrite buf.\n",
  411. (ulong) space_id, (ulong) page_no, (ulong) i);
  412. } else if (space_id == TRX_SYS_SPACE
  413. && ((page_no >= block1
  414. && page_no
  415. < block1 + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE)
  416. || (page_no >= block2
  417. && page_no
  418. < (block2
  419. + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE)))) {
  420. /* It is an unwritten doublewrite buffer page:
  421. do nothing */
  422. } else {
  423. ulint zip_size = fil_space_get_zip_size(space_id);
  424. /* Read in the actual page from the file */
  425. fil_io(OS_FILE_READ, TRUE, space_id, zip_size,
  426. page_no, 0,
  427. zip_size ? zip_size : UNIV_PAGE_SIZE,
  428. read_buf, NULL);
  429. /* Check if the page is corrupt */
  430. if (UNIV_UNLIKELY
  431. (buf_page_is_corrupted(read_buf, zip_size))) {
  432. fprintf(stderr,
  433. "InnoDB: Warning: database page"
  434. " corruption or a failed\n"
  435. "InnoDB: file read of"
  436. " space %lu page %lu.\n"
  437. "InnoDB: Trying to recover it from"
  438. " the doublewrite buffer.\n",
  439. (ulong) space_id, (ulong) page_no);
  440. if (buf_page_is_corrupted(page, zip_size)) {
  441. fprintf(stderr,
  442. "InnoDB: Dump of the page:\n");
  443. buf_page_print(read_buf, zip_size);
  444. fprintf(stderr,
  445. "InnoDB: Dump of"
  446. " corresponding page"
  447. " in doublewrite buffer:\n");
  448. buf_page_print(page, zip_size);
  449. fprintf(stderr,
  450. "InnoDB: Also the page in the"
  451. " doublewrite buffer"
  452. " is corrupt.\n"
  453. "InnoDB: Cannot continue"
  454. " operation.\n"
  455. "InnoDB: You can try to"
  456. " recover the database"
  457. " with the my.cnf\n"
  458. "InnoDB: option:\n"
  459. "InnoDB: set-variable="
  460. "innodb_force_recovery=6\n");
  461. exit(1);
  462. }
  463. /* Write the good page from the
  464. doublewrite buffer to the intended
  465. position */
  466. fil_io(OS_FILE_WRITE, TRUE, space_id,
  467. zip_size, page_no, 0,
  468. zip_size ? zip_size : UNIV_PAGE_SIZE,
  469. page, NULL);
  470. fprintf(stderr,
  471. "InnoDB: Recovered the page from"
  472. " the doublewrite buffer.\n");
  473. }
  474. }
  475. page += UNIV_PAGE_SIZE;
  476. }
  477. fil_flush_file_spaces(FIL_TABLESPACE);
  478. leave_func:
  479. ut_free(unaligned_read_buf);
  480. }
  481. /********************************************************************
  482. Checks that trx is in the trx list. */
  483. UNIV_INTERN
  484. ibool
  485. trx_in_trx_list(
  486. /*============*/
  487. /* out: TRUE if is in */
  488. trx_t* in_trx) /* in: trx */
  489. {
  490. trx_t* trx;
  491. ut_ad(mutex_own(&(kernel_mutex)));
  492. trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
  493. while (trx != NULL) {
  494. if (trx == in_trx) {
  495. return(TRUE);
  496. }
  497. trx = UT_LIST_GET_NEXT(trx_list, trx);
  498. }
  499. return(FALSE);
  500. }
  501. /*********************************************************************
  502. Writes the value of max_trx_id to the file based trx system header. */
  503. UNIV_INTERN
  504. void
  505. trx_sys_flush_max_trx_id(void)
  506. /*==========================*/
  507. {
  508. trx_sysf_t* sys_header;
  509. mtr_t mtr;
  510. ut_ad(mutex_own(&kernel_mutex));
  511. mtr_start(&mtr);
  512. sys_header = trx_sysf_get(&mtr);
  513. mlog_write_dulint(sys_header + TRX_SYS_TRX_ID_STORE,
  514. trx_sys->max_trx_id, &mtr);
  515. mtr_commit(&mtr);
  516. }
  517. /*********************************************************************
  518. Updates the offset information about the end of the MySQL binlog entry
  519. which corresponds to the transaction just being committed. In a MySQL
  520. replication slave updates the latest master binlog position up to which
  521. replication has proceeded. */
  522. UNIV_INTERN
  523. void
  524. trx_sys_update_mysql_binlog_offset(
  525. /*===============================*/
  526. const char* file_name,/* in: MySQL log file name */
  527. ib_int64_t offset, /* in: position in that log file */
  528. ulint field, /* in: offset of the MySQL log info field in
  529. the trx sys header */
  530. mtr_t* mtr) /* in: mtr */
  531. {
  532. trx_sysf_t* sys_header;
  533. if (ut_strlen(file_name) >= TRX_SYS_MYSQL_LOG_NAME_LEN) {
  534. /* We cannot fit the name to the 512 bytes we have reserved */
  535. return;
  536. }
  537. sys_header = trx_sysf_get(mtr);
  538. if (mach_read_from_4(sys_header + field
  539. + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD)
  540. != TRX_SYS_MYSQL_LOG_MAGIC_N) {
  541. mlog_write_ulint(sys_header + field
  542. + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD,
  543. TRX_SYS_MYSQL_LOG_MAGIC_N,
  544. MLOG_4BYTES, mtr);
  545. }
  546. if (0 != strcmp((char*) (sys_header + field + TRX_SYS_MYSQL_LOG_NAME),
  547. file_name)) {
  548. mlog_write_string(sys_header + field
  549. + TRX_SYS_MYSQL_LOG_NAME,
  550. (byte*) file_name, 1 + ut_strlen(file_name),
  551. mtr);
  552. }
  553. if (mach_read_from_4(sys_header + field
  554. + TRX_SYS_MYSQL_LOG_OFFSET_HIGH) > 0
  555. || (offset >> 32) > 0) {
  556. mlog_write_ulint(sys_header + field
  557. + TRX_SYS_MYSQL_LOG_OFFSET_HIGH,
  558. (ulint)(offset >> 32),
  559. MLOG_4BYTES, mtr);
  560. }
  561. mlog_write_ulint(sys_header + field
  562. + TRX_SYS_MYSQL_LOG_OFFSET_LOW,
  563. (ulint)(offset & 0xFFFFFFFFUL),
  564. MLOG_4BYTES, mtr);
  565. }
  566. #ifdef UNIV_HOTBACKUP
  567. /*********************************************************************
  568. Prints to stderr the MySQL binlog info in the system header if the
  569. magic number shows it valid. */
  570. UNIV_INTERN
  571. void
  572. trx_sys_print_mysql_binlog_offset_from_page(
  573. /*========================================*/
  574. const byte* page) /* in: buffer containing the trx
  575. system header page, i.e., page number
  576. TRX_SYS_PAGE_NO in the tablespace */
  577. {
  578. const trx_sysf_t* sys_header;
  579. sys_header = page + TRX_SYS;
  580. if (mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO
  581. + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD)
  582. == TRX_SYS_MYSQL_LOG_MAGIC_N) {
  583. fprintf(stderr,
  584. "ibbackup: Last MySQL binlog file position %lu %lu,"
  585. " file name %s\n",
  586. (ulong) mach_read_from_4(
  587. sys_header + TRX_SYS_MYSQL_LOG_INFO
  588. + TRX_SYS_MYSQL_LOG_OFFSET_HIGH),
  589. (ulong) mach_read_from_4(
  590. sys_header + TRX_SYS_MYSQL_LOG_INFO
  591. + TRX_SYS_MYSQL_LOG_OFFSET_LOW),
  592. sys_header + TRX_SYS_MYSQL_LOG_INFO
  593. + TRX_SYS_MYSQL_LOG_NAME);
  594. }
  595. }
  596. #endif /* UNIV_HOTBACKUP */
  597. /*********************************************************************
  598. Stores the MySQL binlog offset info in the trx system header if
  599. the magic number shows it valid, and print the info to stderr */
  600. UNIV_INTERN
  601. void
  602. trx_sys_print_mysql_binlog_offset(void)
  603. /*===================================*/
  604. {
  605. trx_sysf_t* sys_header;
  606. mtr_t mtr;
  607. ulint trx_sys_mysql_bin_log_pos_high;
  608. ulint trx_sys_mysql_bin_log_pos_low;
  609. mtr_start(&mtr);
  610. sys_header = trx_sysf_get(&mtr);
  611. if (mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO
  612. + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD)
  613. != TRX_SYS_MYSQL_LOG_MAGIC_N) {
  614. mtr_commit(&mtr);
  615. return;
  616. }
  617. trx_sys_mysql_bin_log_pos_high = mach_read_from_4(
  618. sys_header + TRX_SYS_MYSQL_LOG_INFO
  619. + TRX_SYS_MYSQL_LOG_OFFSET_HIGH);
  620. trx_sys_mysql_bin_log_pos_low = mach_read_from_4(
  621. sys_header + TRX_SYS_MYSQL_LOG_INFO
  622. + TRX_SYS_MYSQL_LOG_OFFSET_LOW);
  623. trx_sys_mysql_bin_log_pos
  624. = (((ib_int64_t)trx_sys_mysql_bin_log_pos_high) << 32)
  625. + (ib_int64_t)trx_sys_mysql_bin_log_pos_low;
  626. ut_memcpy(trx_sys_mysql_bin_log_name,
  627. sys_header + TRX_SYS_MYSQL_LOG_INFO
  628. + TRX_SYS_MYSQL_LOG_NAME, TRX_SYS_MYSQL_LOG_NAME_LEN);
  629. fprintf(stderr,
  630. "InnoDB: Last MySQL binlog file position %lu %lu,"
  631. " file name %s\n",
  632. trx_sys_mysql_bin_log_pos_high, trx_sys_mysql_bin_log_pos_low,
  633. trx_sys_mysql_bin_log_name);
  634. mtr_commit(&mtr);
  635. }
  636. /*********************************************************************
  637. Prints to stderr the MySQL master log offset info in the trx system header if
  638. the magic number shows it valid. */
  639. UNIV_INTERN
  640. void
  641. trx_sys_print_mysql_master_log_pos(void)
  642. /*====================================*/
  643. {
  644. trx_sysf_t* sys_header;
  645. mtr_t mtr;
  646. mtr_start(&mtr);
  647. sys_header = trx_sysf_get(&mtr);
  648. if (mach_read_from_4(sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
  649. + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD)
  650. != TRX_SYS_MYSQL_LOG_MAGIC_N) {
  651. mtr_commit(&mtr);
  652. return;
  653. }
  654. fprintf(stderr,
  655. "InnoDB: In a MySQL replication slave the last"
  656. " master binlog file\n"
  657. "InnoDB: position %lu %lu, file name %s\n",
  658. (ulong) mach_read_from_4(sys_header
  659. + TRX_SYS_MYSQL_MASTER_LOG_INFO
  660. + TRX_SYS_MYSQL_LOG_OFFSET_HIGH),
  661. (ulong) mach_read_from_4(sys_header
  662. + TRX_SYS_MYSQL_MASTER_LOG_INFO
  663. + TRX_SYS_MYSQL_LOG_OFFSET_LOW),
  664. sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
  665. + TRX_SYS_MYSQL_LOG_NAME);
  666. /* Copy the master log position info to global variables we can
  667. use in ha_innobase.cc to initialize glob_mi to right values */
  668. ut_memcpy(trx_sys_mysql_master_log_name,
  669. sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
  670. + TRX_SYS_MYSQL_LOG_NAME,
  671. TRX_SYS_MYSQL_LOG_NAME_LEN);
  672. trx_sys_mysql_master_log_pos
  673. = (((ib_int64_t) mach_read_from_4(
  674. sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
  675. + TRX_SYS_MYSQL_LOG_OFFSET_HIGH)) << 32)
  676. + ((ib_int64_t) mach_read_from_4(
  677. sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
  678. + TRX_SYS_MYSQL_LOG_OFFSET_LOW));
  679. mtr_commit(&mtr);
  680. }
  681. /********************************************************************
  682. Looks for a free slot for a rollback segment in the trx system file copy. */
  683. UNIV_INTERN
  684. ulint
  685. trx_sysf_rseg_find_free(
  686. /*====================*/
  687. /* out: slot index or ULINT_UNDEFINED if not found */
  688. mtr_t* mtr) /* in: mtr */
  689. {
  690. trx_sysf_t* sys_header;
  691. ulint page_no;
  692. ulint i;
  693. ut_ad(mutex_own(&(kernel_mutex)));
  694. sys_header = trx_sysf_get(mtr);
  695. for (i = 0; i < TRX_SYS_N_RSEGS; i++) {
  696. page_no = trx_sysf_rseg_get_page_no(sys_header, i, mtr);
  697. if (page_no == FIL_NULL) {
  698. return(i);
  699. }
  700. }
  701. return(ULINT_UNDEFINED);
  702. }
  703. /*********************************************************************
  704. Creates the file page for the transaction system. This function is called only
  705. at the database creation, before trx_sys_init. */
  706. static
  707. void
  708. trx_sysf_create(
  709. /*============*/
  710. mtr_t* mtr) /* in: mtr */
  711. {
  712. trx_sysf_t* sys_header;
  713. ulint slot_no;
  714. buf_block_t* block;
  715. page_t* page;
  716. ulint page_no;
  717. ulint i;
  718. ut_ad(mtr);
  719. /* Note that below we first reserve the file space x-latch, and
  720. then enter the kernel: we must do it in this order to conform
  721. to the latching order rules. */
  722. mtr_x_lock(fil_space_get_latch(TRX_SYS_SPACE, NULL), mtr);
  723. mutex_enter(&kernel_mutex);
  724. /* Create the trx sys file block in a new allocated file segment */
  725. block = fseg_create(TRX_SYS_SPACE, 0, TRX_SYS + TRX_SYS_FSEG_HEADER,
  726. mtr);
  727. buf_block_dbg_add_level(block, SYNC_TRX_SYS_HEADER);
  728. ut_a(buf_block_get_page_no(block) == TRX_SYS_PAGE_NO);
  729. page = buf_block_get_frame(block);
  730. mlog_write_ulint(page + FIL_PAGE_TYPE, FIL_PAGE_TYPE_TRX_SYS,
  731. MLOG_2BYTES, mtr);
  732. /* Reset the doublewrite buffer magic number to zero so that we
  733. know that the doublewrite buffer has not yet been created (this
  734. suppresses a Valgrind warning) */
  735. mlog_write_ulint(page + TRX_SYS_DOUBLEWRITE
  736. + TRX_SYS_DOUBLEWRITE_MAGIC, 0, MLOG_4BYTES, mtr);
  737. sys_header = trx_sysf_get(mtr);
  738. /* Start counting transaction ids from number 1 up */
  739. mlog_write_dulint(sys_header + TRX_SYS_TRX_ID_STORE,
  740. ut_dulint_create(0, 1), mtr);
  741. /* Reset the rollback segment slots */
  742. for (i = 0; i < TRX_SYS_N_RSEGS; i++) {
  743. trx_sysf_rseg_set_space(sys_header, i, ULINT_UNDEFINED, mtr);
  744. trx_sysf_rseg_set_page_no(sys_header, i, FIL_NULL, mtr);
  745. }
  746. /* The remaining area (up to the page trailer) is uninitialized.
  747. Silence Valgrind warnings about it. */
  748. UNIV_MEM_VALID(sys_header + (TRX_SYS_RSEGS
  749. + TRX_SYS_N_RSEGS * TRX_SYS_RSEG_SLOT_SIZE
  750. + TRX_SYS_RSEG_SPACE),
  751. (UNIV_PAGE_SIZE - FIL_PAGE_DATA_END
  752. - (TRX_SYS_RSEGS
  753. + TRX_SYS_N_RSEGS * TRX_SYS_RSEG_SLOT_SIZE
  754. + TRX_SYS_RSEG_SPACE))
  755. + page - sys_header);
  756. /* Create the first rollback segment in the SYSTEM tablespace */
  757. page_no = trx_rseg_header_create(TRX_SYS_SPACE, 0, ULINT_MAX, &slot_no,
  758. mtr);
  759. ut_a(slot_no == TRX_SYS_SYSTEM_RSEG_ID);
  760. ut_a(page_no != FIL_NULL);
  761. mutex_exit(&kernel_mutex);
  762. }
  763. /*********************************************************************
  764. Creates and initializes the central memory structures for the transaction
  765. system. This is called when the database is started. */
  766. UNIV_INTERN
  767. void
  768. trx_sys_init_at_db_start(void)
  769. /*==========================*/
  770. {
  771. trx_sysf_t* sys_header;
  772. ib_int64_t rows_to_undo = 0;
  773. const char* unit = "";
  774. trx_t* trx;
  775. mtr_t mtr;
  776. mtr_start(&mtr);
  777. ut_ad(trx_sys == NULL);
  778. mutex_enter(&kernel_mutex);
  779. trx_sys = mem_alloc(sizeof(trx_sys_t));
  780. sys_header = trx_sysf_get(&mtr);
  781. trx_rseg_list_and_array_init(sys_header, &mtr);
  782. trx_sys->latest_rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
  783. /* VERY important: after the database is started, max_trx_id value is
  784. divisible by TRX_SYS_TRX_ID_WRITE_MARGIN, and the 'if' in
  785. trx_sys_get_new_trx_id will evaluate to TRUE when the function
  786. is first time called, and the value for trx id will be written
  787. to the disk-based header! Thus trx id values will not overlap when
  788. the database is repeatedly started! */
  789. trx_sys->max_trx_id = ut_dulint_add(
  790. ut_dulint_align_up(mtr_read_dulint(
  791. sys_header
  792. + TRX_SYS_TRX_ID_STORE, &mtr),
  793. TRX_SYS_TRX_ID_WRITE_MARGIN),
  794. 2 * TRX_SYS_TRX_ID_WRITE_MARGIN);
  795. UT_LIST_INIT(trx_sys->mysql_trx_list);
  796. trx_dummy_sess = sess_open();
  797. trx_lists_init_at_db_start();
  798. if (UT_LIST_GET_LEN(trx_sys->trx_list) > 0) {
  799. trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
  800. for (;;) {
  801. if ( trx->conc_state != TRX_PREPARED) {
  802. rows_to_undo += ut_conv_dulint_to_longlong(
  803. trx->undo_no);
  804. }
  805. trx = UT_LIST_GET_NEXT(trx_list, trx);
  806. if (!trx) {
  807. break;
  808. }
  809. }
  810. if (rows_to_undo > 1000000000) {
  811. unit = "M";
  812. rows_to_undo = rows_to_undo / 1000000;
  813. }
  814. fprintf(stderr,
  815. "InnoDB: %lu transaction(s) which must be"
  816. " rolled back or cleaned up\n"
  817. "InnoDB: in total %lu%s row operations to undo\n",
  818. (ulong) UT_LIST_GET_LEN(trx_sys->trx_list),
  819. (ulong) rows_to_undo, unit);
  820. fprintf(stderr, "InnoDB: Trx id counter is " TRX_ID_FMT "\n",
  821. TRX_ID_PREP_PRINTF(trx_sys->max_trx_id));
  822. }
  823. UT_LIST_INIT(trx_sys->view_list);
  824. trx_purge_sys_create();
  825. mutex_exit(&kernel_mutex);
  826. mtr_commit(&mtr);
  827. }
  828. /*********************************************************************
  829. Creates and initializes the transaction system at the database creation. */
  830. UNIV_INTERN
  831. void
  832. trx_sys_create(void)
  833. /*================*/
  834. {
  835. mtr_t mtr;
  836. mtr_start(&mtr);
  837. trx_sysf_create(&mtr);
  838. mtr_commit(&mtr);
  839. trx_sys_init_at_db_start();
  840. }
  841. /*********************************************************************
  842. Update the file format tag. */
  843. static
  844. ibool
  845. trx_sys_file_format_max_write(
  846. /*==========================*/
  847. /* out: always TRUE */
  848. ulint format_id, /* in: file format id */
  849. char** name) /* out: max file format name, can
  850. be NULL */
  851. {
  852. mtr_t mtr;
  853. byte* ptr;
  854. buf_block_t* block;
  855. ulint tag_value_low;
  856. mtr_start(&mtr);
  857. block = buf_page_get(
  858. TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO, RW_X_LATCH, &mtr);
  859. file_format_max.id = format_id;
  860. file_format_max.name = trx_sys_file_format_id_to_name(format_id);
  861. ptr = buf_block_get_frame(block) + TRX_SYS_FILE_FORMAT_TAG;
  862. tag_value_low = format_id + TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_LOW;
  863. if (name) {
  864. *name = (char*) file_format_max.name;
  865. }
  866. mlog_write_dulint(
  867. ptr,
  868. ut_dulint_create(TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_HIGH,
  869. tag_value_low),
  870. &mtr);
  871. mtr_commit(&mtr);
  872. return(TRUE);
  873. }
  874. /*********************************************************************
  875. Read the file format tag. */
  876. static
  877. ulint
  878. trx_sys_file_format_max_read(void)
  879. /*==============================*/
  880. /* out: the file format or
  881. ULINT_UNDEFINED if not set. */
  882. {
  883. mtr_t mtr;
  884. const byte* ptr;
  885. const buf_block_t* block;
  886. ulint format_id;
  887. dulint file_format_id;
  888. /* Since this is called during the startup phase it's safe to
  889. read the value without a covering mutex. */
  890. mtr_start(&mtr);
  891. block = buf_page_get(
  892. TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO, RW_X_LATCH, &mtr);
  893. ptr = buf_block_get_frame(block) + TRX_SYS_FILE_FORMAT_TAG;
  894. file_format_id = mach_read_from_8(ptr);
  895. mtr_commit(&mtr);
  896. format_id = file_format_id.low - TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_LOW;
  897. if (file_format_id.high != TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_HIGH
  898. || format_id >= FILE_FORMAT_NAME_N) {
  899. /* Either it has never been tagged, or garbage in it. */
  900. return(ULINT_UNDEFINED);
  901. }
  902. return(format_id);
  903. }
  904. /*********************************************************************
  905. Get the name representation of the file format from its id. */
  906. UNIV_INTERN
  907. const char*
  908. trx_sys_file_format_id_to_name(
  909. /*===========================*/
  910. /* out: pointer to the name */
  911. const uint id) /* in: id of the file format */
  912. {
  913. ut_a(id < FILE_FORMAT_NAME_N);
  914. return(file_format_name_map[id]);
  915. }
  916. /*********************************************************************
  917. Check for the max file format tag stored on disk. Note: If max_format_id
  918. is == DICT_TF_FORMAT_MAX + 1 then we only print a warning. */
  919. UNIV_INTERN
  920. ulint
  921. trx_sys_file_format_max_check(
  922. /*==========================*/
  923. /* out: DB_SUCCESS or error code */
  924. ulint max_format_id) /* in: max format id to check */
  925. {
  926. ulint format_id;
  927. /* Check the file format in the tablespace. Do not try to
  928. recover if the file format is not supported by the engine
  929. unless forced by the user. */
  930. format_id = trx_sys_file_format_max_read();
  931. if (format_id == ULINT_UNDEFINED) {
  932. /* Format ID was not set. Set it to minimum possible
  933. value. */
  934. format_id = DICT_TF_FORMAT_51;
  935. }
  936. ut_print_timestamp(stderr);
  937. fprintf(stderr,
  938. " InnoDB: highest supported file format is %s.\n",
  939. trx_sys_file_format_id_to_name(DICT_TF_FORMAT_MAX));
  940. if (format_id > DICT_TF_FORMAT_MAX) {
  941. ut_a(format_id < FILE_FORMAT_NAME_N);
  942. ut_print_timestamp(stderr);
  943. fprintf(stderr,
  944. " InnoDB: %s: the system tablespace is in a file "
  945. "format that this version doesn't support - %s\n",
  946. ((max_format_id <= DICT_TF_FORMAT_MAX)
  947. ? "Error" : "Warning"),
  948. trx_sys_file_format_id_to_name(format_id));
  949. if (max_format_id <= DICT_TF_FORMAT_MAX) {
  950. return(DB_ERROR);
  951. }
  952. }
  953. format_id = (format_id > max_format_id) ? format_id : max_format_id;
  954. /* We don't need a mutex here, as this function should only
  955. be called once at start up. */
  956. file_format_max.id = format_id;
  957. file_format_max.name = trx_sys_file_format_id_to_name(format_id);
  958. return(DB_SUCCESS);
  959. }
  960. /*********************************************************************
  961. Set the file format id unconditionally except if it's already the
  962. same value. */
  963. UNIV_INTERN
  964. ibool
  965. trx_sys_file_format_max_set(
  966. /*========================*/
  967. /* out: TRUE if value updated */
  968. ulint format_id, /* in: file format id */
  969. char** name) /* out: max file format name or
  970. NULL if not needed. */
  971. {
  972. ibool ret = FALSE;
  973. ut_a(format_id <= DICT_TF_FORMAT_MAX);
  974. mutex_enter(&file_format_max.mutex);
  975. /* Only update if not already same value. */
  976. if (format_id != file_format_max.id) {
  977. ret = trx_sys_file_format_max_write(format_id, name);
  978. }
  979. mutex_exit(&file_format_max.mutex);
  980. return(ret);
  981. }
  982. /************************************************************************
  983. Tags the system table space with minimum format id if it has not been
  984. tagged yet.
  985. WARNING: This function is only called during the startup and AFTER the
  986. redo log application during recovery has finished. */
  987. UNIV_INTERN
  988. void
  989. trx_sys_file_format_tag_init(void)
  990. /*==============================*/
  991. {
  992. ulint format_id;
  993. format_id = trx_sys_file_format_max_read();
  994. /* If format_id is not set then set it to the minimum. */
  995. if (format_id == ULINT_UNDEFINED) {
  996. trx_sys_file_format_max_set(DICT_TF_FORMAT_51, NULL);
  997. }
  998. }
  999. /************************************************************************
  1000. Update the file format tag in the tablespace only if the given format id
  1001. is greater than the known max id. */
  1002. UNIV_INTERN
  1003. ibool
  1004. trx_sys_file_format_max_update(
  1005. /*===========================*/
  1006. uint flags, /* in: flags of the table.*/
  1007. char** name) /* out: max file format name */
  1008. {
  1009. ulint format_id;
  1010. ibool ret = FALSE;
  1011. format_id = (flags & DICT_TF_FORMAT_MASK) >> DICT_TF_FORMAT_SHIFT;
  1012. ut_a(name);
  1013. ut_a(file_format_max.name != NULL);
  1014. ut_a(format_id <= DICT_TF_FORMAT_MAX);
  1015. mutex_enter(&file_format_max.mutex);
  1016. if (format_id > file_format_max.id) {
  1017. ret = trx_sys_file_format_max_write(format_id, name);
  1018. }
  1019. mutex_exit(&file_format_max.mutex);
  1020. return(ret);
  1021. }
  1022. /*********************************************************************
  1023. Get the name representation of the file format from its id. */
  1024. UNIV_INTERN
  1025. const char*
  1026. trx_sys_file_format_max_get(void)
  1027. /*=============================*/
  1028. /* out: pointer to the max format name */
  1029. {
  1030. return(file_format_max.name);
  1031. }
  1032. /*********************************************************************
  1033. Initializes the tablespace tag system. */
  1034. UNIV_INTERN
  1035. void
  1036. trx_sys_file_format_init(void)
  1037. /*==========================*/
  1038. {
  1039. mutex_create(&file_format_max.mutex, SYNC_FILE_FORMAT_TAG);
  1040. /* We don't need a mutex here, as this function should only
  1041. be called once at start up. */
  1042. file_format_max.id = DICT_TF_FORMAT_51;
  1043. file_format_max.name = trx_sys_file_format_id_to_name(
  1044. file_format_max.id);
  1045. }
  1046. /*********************************************************************
  1047. Closes the tablespace tag system. */
  1048. UNIV_INTERN
  1049. void
  1050. trx_sys_file_format_close(void)
  1051. /*===========================*/
  1052. {
  1053. /* Does nothing at the moment */
  1054. }