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.

1520 lines
39 KiB

17 years ago
9 years ago
17 years ago
17 years ago
16 years ago
10 years ago
16 years ago
15 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
15 years ago
15 years ago
16 years ago
15 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
16 years ago
15 years ago
15 years ago
15 years ago
16 years ago
16 years ago
16 years ago
15 years ago
15 years ago
15 years ago
16 years ago
15 years ago
15 years ago
15 years ago
15 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
15 years ago
16 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
9 years ago
15 years ago
9 years ago
15 years ago
15 years ago
16 years ago
16 years ago
15 years ago
16 years ago
15 years ago
16 years ago
15 years ago
16 years ago
15 years ago
16 years ago
15 years ago
16 years ago
16 years ago
16 years ago
15 years ago
16 years ago
15 years ago
16 years ago
16 years ago
15 years ago
16 years ago
15 years ago
16 years ago
15 years ago
16 years ago
15 years ago
16 years ago
15 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
10 years ago
16 years ago
10 years ago
16 years ago
16 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
9 years ago
9 years ago
9 years ago
  1. /*****************************************************************************
  2. Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
  3. Copyright (c) 2017, MariaDB Corporation.
  4. This program is free software; you can redistribute it and/or modify it under
  5. the terms of the GNU General Public License as published by the Free Software
  6. Foundation; version 2 of the License.
  7. This program is distributed in the hope that it will be useful, but WITHOUT
  8. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  9. FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License along with
  11. this program; if not, write to the Free Software Foundation, Inc.,
  12. 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
  13. *****************************************************************************/
  14. /**************************************************//**
  15. @file trx/trx0sys.cc
  16. Transaction system
  17. Created 3/26/1996 Heikki Tuuri
  18. *******************************************************/
  19. #include "trx0sys.h"
  20. #ifdef UNIV_NONINL
  21. #include "trx0sys.ic"
  22. #endif
  23. #ifdef UNIV_HOTBACKUP
  24. #include "fsp0types.h"
  25. #else /* !UNIV_HOTBACKUP */
  26. #include "fsp0fsp.h"
  27. #include "mtr0log.h"
  28. #include "mtr0log.h"
  29. #include "trx0trx.h"
  30. #include "trx0rseg.h"
  31. #include "trx0undo.h"
  32. #include "srv0srv.h"
  33. #include "srv0start.h"
  34. #include "trx0purge.h"
  35. #include "log0log.h"
  36. #include "log0recv.h"
  37. #include "os0file.h"
  38. #include "read0read.h"
  39. #ifdef WITH_WSREP
  40. #include "ha_prototypes.h" /* wsrep_is_wsrep_xid() */
  41. #endif /* */
  42. #include <mysql/service_wsrep.h>
  43. /** The file format tag structure with id and name. */
  44. struct file_format_t {
  45. ulint id; /*!< id of the file format */
  46. const char* name; /*!< text representation of the
  47. file format */
  48. ib_mutex_t mutex; /*!< covers changes to the above
  49. fields */
  50. };
  51. /** The transaction system */
  52. UNIV_INTERN trx_sys_t* trx_sys = NULL;
  53. /** In a MySQL replication slave, in crash recovery we store the master log
  54. file name and position here. */
  55. /* @{ */
  56. /** Master binlog file name */
  57. UNIV_INTERN char trx_sys_mysql_master_log_name[TRX_SYS_MYSQL_LOG_NAME_LEN];
  58. /** Master binlog file position. We have successfully got the updates
  59. up to this position. -1 means that no crash recovery was needed, or
  60. there was no master log position info inside InnoDB.*/
  61. UNIV_INTERN ib_int64_t trx_sys_mysql_master_log_pos = -1;
  62. /* @} */
  63. /** If this MySQL server uses binary logging, after InnoDB has been inited
  64. and if it has done a crash recovery, we store the binlog file name and position
  65. here. */
  66. /* @{ */
  67. /** Binlog file name */
  68. UNIV_INTERN char trx_sys_mysql_bin_log_name[TRX_SYS_MYSQL_LOG_NAME_LEN];
  69. /** Binlog file position, or -1 if unknown */
  70. UNIV_INTERN ib_int64_t trx_sys_mysql_bin_log_pos = -1;
  71. /* @} */
  72. #endif /* !UNIV_HOTBACKUP */
  73. /** List of animal names representing file format. */
  74. static const char* file_format_name_map[] = {
  75. "Antelope",
  76. "Barracuda",
  77. "Cheetah",
  78. "Dragon",
  79. "Elk",
  80. "Fox",
  81. "Gazelle",
  82. "Hornet",
  83. "Impala",
  84. "Jaguar",
  85. "Kangaroo",
  86. "Leopard",
  87. "Moose",
  88. "Nautilus",
  89. "Ocelot",
  90. "Porpoise",
  91. "Quail",
  92. "Rabbit",
  93. "Shark",
  94. "Tiger",
  95. "Urchin",
  96. "Viper",
  97. "Whale",
  98. "Xenops",
  99. "Yak",
  100. "Zebra"
  101. };
  102. /** The number of elements in the file format name array. */
  103. static const ulint FILE_FORMAT_NAME_N
  104. = sizeof(file_format_name_map) / sizeof(file_format_name_map[0]);
  105. #ifdef UNIV_PFS_MUTEX
  106. /* Key to register the mutex with performance schema */
  107. UNIV_INTERN mysql_pfs_key_t file_format_max_mutex_key;
  108. UNIV_INTERN mysql_pfs_key_t trx_sys_mutex_key;
  109. #endif /* UNIV_PFS_RWLOCK */
  110. #ifndef UNIV_HOTBACKUP
  111. #ifdef UNIV_DEBUG
  112. /* Flag to control TRX_RSEG_N_SLOTS behavior debugging. */
  113. UNIV_INTERN uint trx_rseg_n_slots_debug = 0;
  114. #endif
  115. /** This is used to track the maximum file format id known to InnoDB. It's
  116. updated via SET GLOBAL innodb_file_format_max = 'x' or when we open
  117. or create a table. */
  118. static file_format_t file_format_max;
  119. #ifdef UNIV_DEBUG
  120. /****************************************************************//**
  121. Checks whether a trx is in one of rw_trx_list or ro_trx_list.
  122. @return TRUE if is in */
  123. UNIV_INTERN
  124. ibool
  125. trx_in_trx_list(
  126. /*============*/
  127. const trx_t* in_trx) /*!< in: transaction */
  128. {
  129. const trx_t* trx;
  130. trx_list_t* trx_list;
  131. /* Non-locking autocommits should not hold any locks. */
  132. assert_trx_in_list(in_trx);
  133. trx_list = in_trx->read_only
  134. ? &trx_sys->ro_trx_list : &trx_sys->rw_trx_list;
  135. ut_ad(mutex_own(&trx_sys->mutex));
  136. ut_ad(trx_assert_started(in_trx));
  137. for (trx = UT_LIST_GET_FIRST(*trx_list);
  138. trx != NULL && trx != in_trx;
  139. trx = UT_LIST_GET_NEXT(trx_list, trx)) {
  140. assert_trx_in_list(trx);
  141. ut_ad(trx->read_only == (trx_list == &trx_sys->ro_trx_list));
  142. }
  143. return(trx != NULL);
  144. }
  145. #endif /* UNIV_DEBUG */
  146. /*****************************************************************//**
  147. Writes the value of max_trx_id to the file based trx system header. */
  148. UNIV_INTERN
  149. void
  150. trx_sys_flush_max_trx_id(void)
  151. /*==========================*/
  152. {
  153. mtr_t mtr;
  154. trx_sysf_t* sys_header;
  155. ut_ad(mutex_own(&trx_sys->mutex));
  156. if (!srv_read_only_mode) {
  157. mtr_start(&mtr);
  158. sys_header = trx_sysf_get(&mtr);
  159. mlog_write_ull(
  160. sys_header + TRX_SYS_TRX_ID_STORE,
  161. trx_sys->max_trx_id, &mtr);
  162. mtr_commit(&mtr);
  163. }
  164. }
  165. /*****************************************************************//**
  166. Updates the offset information about the end of the MySQL binlog entry
  167. which corresponds to the transaction just being committed. In a MySQL
  168. replication slave updates the latest master binlog position up to which
  169. replication has proceeded. */
  170. UNIV_INTERN
  171. void
  172. trx_sys_update_mysql_binlog_offset(
  173. /*===============================*/
  174. const char* file_name,/*!< in: MySQL log file name */
  175. ib_int64_t offset, /*!< in: position in that log file */
  176. ulint field, /*!< in: offset of the MySQL log info field in
  177. the trx sys header */
  178. #ifdef WITH_WSREP
  179. trx_sysf_t* sys_header, /*!< in: trx sys header */
  180. #endif /* WITH_WSREP */
  181. mtr_t* mtr) /*!< in: mtr */
  182. {
  183. #ifndef WITH_WSREP
  184. trx_sysf_t* sys_header;
  185. #endif /* !WITH_WSREP */
  186. if (ut_strlen(file_name) >= TRX_SYS_MYSQL_LOG_NAME_LEN) {
  187. /* We cannot fit the name to the 512 bytes we have reserved */
  188. return;
  189. }
  190. #ifndef WITH_WSREP
  191. sys_header = trx_sysf_get(mtr);
  192. #endif /* !WITH_WSREP */
  193. if (mach_read_from_4(sys_header + field
  194. + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD)
  195. != TRX_SYS_MYSQL_LOG_MAGIC_N) {
  196. mlog_write_ulint(sys_header + field
  197. + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD,
  198. TRX_SYS_MYSQL_LOG_MAGIC_N,
  199. MLOG_4BYTES, mtr);
  200. }
  201. if (0 != strcmp((char*) (sys_header + field + TRX_SYS_MYSQL_LOG_NAME),
  202. file_name)) {
  203. mlog_write_string(sys_header + field
  204. + TRX_SYS_MYSQL_LOG_NAME,
  205. (byte*) file_name, 1 + ut_strlen(file_name),
  206. mtr);
  207. }
  208. if (mach_read_from_4(sys_header + field
  209. + TRX_SYS_MYSQL_LOG_OFFSET_HIGH) > 0
  210. || (offset >> 32) > 0) {
  211. mlog_write_ulint(sys_header + field
  212. + TRX_SYS_MYSQL_LOG_OFFSET_HIGH,
  213. (ulint)(offset >> 32),
  214. MLOG_4BYTES, mtr);
  215. }
  216. mlog_write_ulint(sys_header + field
  217. + TRX_SYS_MYSQL_LOG_OFFSET_LOW,
  218. (ulint)(offset & 0xFFFFFFFFUL),
  219. MLOG_4BYTES, mtr);
  220. }
  221. /*****************************************************************//**
  222. Stores the MySQL binlog offset info in the trx system header if
  223. the magic number shows it valid, and print the info to stderr */
  224. UNIV_INTERN
  225. void
  226. trx_sys_print_mysql_binlog_offset(void)
  227. /*===================================*/
  228. {
  229. trx_sysf_t* sys_header;
  230. mtr_t mtr;
  231. ulint trx_sys_mysql_bin_log_pos_high;
  232. ulint trx_sys_mysql_bin_log_pos_low;
  233. mtr_start(&mtr);
  234. sys_header = trx_sysf_get(&mtr);
  235. if (mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO
  236. + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD)
  237. != TRX_SYS_MYSQL_LOG_MAGIC_N) {
  238. mtr_commit(&mtr);
  239. return;
  240. }
  241. trx_sys_mysql_bin_log_pos_high = mach_read_from_4(
  242. sys_header + TRX_SYS_MYSQL_LOG_INFO
  243. + TRX_SYS_MYSQL_LOG_OFFSET_HIGH);
  244. trx_sys_mysql_bin_log_pos_low = mach_read_from_4(
  245. sys_header + TRX_SYS_MYSQL_LOG_INFO
  246. + TRX_SYS_MYSQL_LOG_OFFSET_LOW);
  247. trx_sys_mysql_bin_log_pos
  248. = (((ib_int64_t) trx_sys_mysql_bin_log_pos_high) << 32)
  249. + (ib_int64_t) trx_sys_mysql_bin_log_pos_low;
  250. ut_memcpy(trx_sys_mysql_bin_log_name,
  251. sys_header + TRX_SYS_MYSQL_LOG_INFO
  252. + TRX_SYS_MYSQL_LOG_NAME, TRX_SYS_MYSQL_LOG_NAME_LEN);
  253. fprintf(stderr,
  254. "InnoDB: Last MySQL binlog file position %lu %lu,"
  255. " file name %s\n",
  256. trx_sys_mysql_bin_log_pos_high, trx_sys_mysql_bin_log_pos_low,
  257. trx_sys_mysql_bin_log_name);
  258. mtr_commit(&mtr);
  259. }
  260. #ifdef WITH_WSREP
  261. #ifdef UNIV_DEBUG
  262. static long long trx_sys_cur_xid_seqno = -1;
  263. static unsigned char trx_sys_cur_xid_uuid[16];
  264. /** Read WSREP XID seqno */
  265. static inline long long read_wsrep_xid_seqno(const XID* xid)
  266. {
  267. long long seqno;
  268. memcpy(&seqno, xid->data + 24, sizeof(long long));
  269. return seqno;
  270. }
  271. /** Read WSREP XID UUID */
  272. static inline void read_wsrep_xid_uuid(const XID* xid, unsigned char* buf)
  273. {
  274. memcpy(buf, xid->data + 8, 16);
  275. }
  276. #endif /* UNIV_DEBUG */
  277. /** Update WSREP XID info in sys_header of TRX_SYS_PAGE_NO = 5.
  278. @param[in] xid Transaction XID
  279. @param[in,out] sys_header sys_header
  280. @param[in] mtr minitransaction */
  281. UNIV_INTERN
  282. void
  283. trx_sys_update_wsrep_checkpoint(
  284. const XID* xid,
  285. trx_sysf_t* sys_header,
  286. mtr_t* mtr)
  287. {
  288. #ifdef UNIV_DEBUG
  289. if (xid->formatID != -1
  290. && mach_read_from_4(sys_header + TRX_SYS_WSREP_XID_INFO
  291. + TRX_SYS_WSREP_XID_MAGIC_N_FLD)
  292. == TRX_SYS_WSREP_XID_MAGIC_N) {
  293. /* Check that seqno is monotonically increasing */
  294. unsigned char xid_uuid[16];
  295. long long xid_seqno = read_wsrep_xid_seqno(xid);
  296. read_wsrep_xid_uuid(xid, xid_uuid);
  297. if (!memcmp(xid_uuid, trx_sys_cur_xid_uuid, 8)) {
  298. ut_ad(xid_seqno > trx_sys_cur_xid_seqno);
  299. trx_sys_cur_xid_seqno = xid_seqno;
  300. } else {
  301. memcpy(trx_sys_cur_xid_uuid, xid_uuid, 16);
  302. }
  303. trx_sys_cur_xid_seqno = xid_seqno;
  304. }
  305. #endif /* UNIV_DEBUG */
  306. ut_ad(xid && mtr);
  307. ut_a(xid->formatID == -1 || wsrep_is_wsrep_xid((const XID *)xid));
  308. if (mach_read_from_4(sys_header + TRX_SYS_WSREP_XID_INFO
  309. + TRX_SYS_WSREP_XID_MAGIC_N_FLD)
  310. != TRX_SYS_WSREP_XID_MAGIC_N) {
  311. mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO
  312. + TRX_SYS_WSREP_XID_MAGIC_N_FLD,
  313. TRX_SYS_WSREP_XID_MAGIC_N,
  314. MLOG_4BYTES, mtr);
  315. }
  316. mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO
  317. + TRX_SYS_WSREP_XID_FORMAT,
  318. (int)xid->formatID,
  319. MLOG_4BYTES, mtr);
  320. mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO
  321. + TRX_SYS_WSREP_XID_GTRID_LEN,
  322. (int)xid->gtrid_length,
  323. MLOG_4BYTES, mtr);
  324. mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO
  325. + TRX_SYS_WSREP_XID_BQUAL_LEN,
  326. (int)xid->bqual_length,
  327. MLOG_4BYTES, mtr);
  328. mlog_write_string(sys_header + TRX_SYS_WSREP_XID_INFO
  329. + TRX_SYS_WSREP_XID_DATA,
  330. (const unsigned char*) xid->data,
  331. XIDDATASIZE, mtr);
  332. }
  333. /** Read WSREP XID from sys_header of TRX_SYS_PAGE_NO = 5.
  334. @param[out] xid Transaction XID
  335. @retval true if found, false if not */
  336. UNIV_INTERN
  337. bool
  338. trx_sys_read_wsrep_checkpoint(XID* xid)
  339. {
  340. trx_sysf_t* sys_header;
  341. mtr_t mtr;
  342. ulint magic;
  343. ut_ad(xid);
  344. mtr_start(&mtr);
  345. sys_header = trx_sysf_get(&mtr);
  346. if ((magic = mach_read_from_4(sys_header + TRX_SYS_WSREP_XID_INFO
  347. + TRX_SYS_WSREP_XID_MAGIC_N_FLD))
  348. != TRX_SYS_WSREP_XID_MAGIC_N) {
  349. memset(xid, 0, sizeof(*xid));
  350. xid->formatID = -1;
  351. trx_sys_update_wsrep_checkpoint(xid, sys_header, &mtr);
  352. mtr_commit(&mtr);
  353. return false;
  354. }
  355. xid->formatID = (int)mach_read_from_4(
  356. sys_header
  357. + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_FORMAT);
  358. xid->gtrid_length = (int)mach_read_from_4(
  359. sys_header
  360. + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_GTRID_LEN);
  361. xid->bqual_length = (int)mach_read_from_4(
  362. sys_header
  363. + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_BQUAL_LEN);
  364. ut_memcpy(xid->data,
  365. sys_header + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_DATA,
  366. XIDDATASIZE);
  367. mtr_commit(&mtr);
  368. return true;
  369. }
  370. #endif /* WITH_WSREP */
  371. /*****************************************************************//**
  372. Prints to stderr the MySQL master log offset info in the trx system header if
  373. the magic number shows it valid. */
  374. UNIV_INTERN
  375. void
  376. trx_sys_print_mysql_master_log_pos(void)
  377. /*====================================*/
  378. {
  379. trx_sysf_t* sys_header;
  380. mtr_t mtr;
  381. mtr_start(&mtr);
  382. sys_header = trx_sysf_get(&mtr);
  383. if (mach_read_from_4(sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
  384. + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD)
  385. != TRX_SYS_MYSQL_LOG_MAGIC_N) {
  386. mtr_commit(&mtr);
  387. return;
  388. }
  389. fprintf(stderr,
  390. "InnoDB: In a MySQL replication slave the last"
  391. " master binlog file\n"
  392. "InnoDB: position %lu %lu, file name %s\n",
  393. (ulong) mach_read_from_4(sys_header
  394. + TRX_SYS_MYSQL_MASTER_LOG_INFO
  395. + TRX_SYS_MYSQL_LOG_OFFSET_HIGH),
  396. (ulong) mach_read_from_4(sys_header
  397. + TRX_SYS_MYSQL_MASTER_LOG_INFO
  398. + TRX_SYS_MYSQL_LOG_OFFSET_LOW),
  399. sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
  400. + TRX_SYS_MYSQL_LOG_NAME);
  401. /* Copy the master log position info to global variables we can
  402. use in ha_innobase.cc to initialize glob_mi to right values */
  403. ut_memcpy(trx_sys_mysql_master_log_name,
  404. sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
  405. + TRX_SYS_MYSQL_LOG_NAME,
  406. TRX_SYS_MYSQL_LOG_NAME_LEN);
  407. trx_sys_mysql_master_log_pos
  408. = (((ib_int64_t) mach_read_from_4(
  409. sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
  410. + TRX_SYS_MYSQL_LOG_OFFSET_HIGH)) << 32)
  411. + ((ib_int64_t) mach_read_from_4(
  412. sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
  413. + TRX_SYS_MYSQL_LOG_OFFSET_LOW));
  414. mtr_commit(&mtr);
  415. }
  416. /****************************************************************//**
  417. Looks for a free slot for a rollback segment in the trx system file copy.
  418. @return slot index or ULINT_UNDEFINED if not found */
  419. UNIV_INTERN
  420. ulint
  421. trx_sysf_rseg_find_free(
  422. /*====================*/
  423. mtr_t* mtr) /*!< in: mtr */
  424. {
  425. ulint i;
  426. trx_sysf_t* sys_header;
  427. sys_header = trx_sysf_get(mtr);
  428. for (i = 0; i < TRX_SYS_N_RSEGS; i++) {
  429. ulint page_no;
  430. page_no = trx_sysf_rseg_get_page_no(sys_header, i, mtr);
  431. if (page_no == FIL_NULL) {
  432. return(i);
  433. }
  434. }
  435. return(ULINT_UNDEFINED);
  436. }
  437. /*****************************************************************//**
  438. Creates the file page for the transaction system. This function is called only
  439. at the database creation, before trx_sys_init. */
  440. static
  441. void
  442. trx_sysf_create(
  443. /*============*/
  444. mtr_t* mtr) /*!< in: mtr */
  445. {
  446. trx_sysf_t* sys_header;
  447. ulint slot_no;
  448. buf_block_t* block;
  449. page_t* page;
  450. ulint page_no;
  451. byte* ptr;
  452. ulint len;
  453. ut_ad(mtr);
  454. /* Note that below we first reserve the file space x-latch, and
  455. then enter the kernel: we must do it in this order to conform
  456. to the latching order rules. */
  457. mtr_x_lock(fil_space_get_latch(TRX_SYS_SPACE, NULL), mtr);
  458. /* Create the trx sys file block in a new allocated file segment */
  459. block = fseg_create(TRX_SYS_SPACE, 0, TRX_SYS + TRX_SYS_FSEG_HEADER,
  460. mtr);
  461. buf_block_dbg_add_level(block, SYNC_TRX_SYS_HEADER);
  462. ut_a(buf_block_get_page_no(block) == TRX_SYS_PAGE_NO);
  463. page = buf_block_get_frame(block);
  464. mlog_write_ulint(page + FIL_PAGE_TYPE, FIL_PAGE_TYPE_TRX_SYS,
  465. MLOG_2BYTES, mtr);
  466. /* Reset the doublewrite buffer magic number to zero so that we
  467. know that the doublewrite buffer has not yet been created (this
  468. suppresses a Valgrind warning) */
  469. mlog_write_ulint(page + TRX_SYS_DOUBLEWRITE
  470. + TRX_SYS_DOUBLEWRITE_MAGIC, 0, MLOG_4BYTES, mtr);
  471. sys_header = trx_sysf_get(mtr);
  472. /* Start counting transaction ids from number 1 up */
  473. mach_write_to_8(sys_header + TRX_SYS_TRX_ID_STORE, 1);
  474. /* Reset the rollback segment slots. Old versions of InnoDB
  475. define TRX_SYS_N_RSEGS as 256 (TRX_SYS_OLD_N_RSEGS) and expect
  476. that the whole array is initialized. */
  477. ptr = TRX_SYS_RSEGS + sys_header;
  478. len = ut_max(TRX_SYS_OLD_N_RSEGS, TRX_SYS_N_RSEGS)
  479. * TRX_SYS_RSEG_SLOT_SIZE;
  480. memset(ptr, 0xff, len);
  481. ptr += len;
  482. ut_a(ptr <= page + (UNIV_PAGE_SIZE - FIL_PAGE_DATA_END));
  483. /* Initialize all of the page. This part used to be uninitialized. */
  484. memset(ptr, 0, UNIV_PAGE_SIZE - FIL_PAGE_DATA_END + page - ptr);
  485. mlog_log_string(sys_header, UNIV_PAGE_SIZE - FIL_PAGE_DATA_END
  486. + page - sys_header, mtr);
  487. /* Create the first rollback segment in the SYSTEM tablespace */
  488. slot_no = trx_sysf_rseg_find_free(mtr);
  489. page_no = trx_rseg_header_create(TRX_SYS_SPACE, 0, ULINT_MAX, slot_no,
  490. mtr);
  491. ut_a(slot_no == TRX_SYS_SYSTEM_RSEG_ID);
  492. ut_a(page_no == FSP_FIRST_RSEG_PAGE_NO);
  493. }
  494. /*****************************************************************//**
  495. Compare two trx_rseg_t instances on last_trx_no. */
  496. static
  497. int
  498. trx_rseg_compare_last_trx_no(
  499. /*=========================*/
  500. const void* p1, /*!< in: elem to compare */
  501. const void* p2) /*!< in: elem to compare */
  502. {
  503. ib_int64_t cmp;
  504. const rseg_queue_t* rseg_q1 = (const rseg_queue_t*) p1;
  505. const rseg_queue_t* rseg_q2 = (const rseg_queue_t*) p2;
  506. cmp = rseg_q1->trx_no - rseg_q2->trx_no;
  507. if (cmp < 0) {
  508. return(-1);
  509. } else if (cmp > 0) {
  510. return(1);
  511. }
  512. return(0);
  513. }
  514. /*****************************************************************//**
  515. Creates and initializes the central memory structures for the transaction
  516. system. This is called when the database is started.
  517. @return min binary heap of rsegs to purge */
  518. UNIV_INTERN
  519. ib_bh_t*
  520. trx_sys_init_at_db_start(void)
  521. /*==========================*/
  522. {
  523. mtr_t mtr;
  524. ib_bh_t* ib_bh;
  525. trx_sysf_t* sys_header;
  526. ib_uint64_t rows_to_undo = 0;
  527. const char* unit = "";
  528. /* We create the min binary heap here and pass ownership to
  529. purge when we init the purge sub-system. Purge is responsible
  530. for freeing the binary heap. */
  531. ib_bh = ib_bh_create(
  532. trx_rseg_compare_last_trx_no,
  533. sizeof(rseg_queue_t), TRX_SYS_N_RSEGS);
  534. mtr_start(&mtr);
  535. /* Allocate the trx descriptors array */
  536. trx_sys->descriptors = static_cast<trx_id_t*>(
  537. ut_malloc(sizeof(trx_id_t) *
  538. TRX_DESCR_ARRAY_INITIAL_SIZE));
  539. trx_sys->descr_n_max = TRX_DESCR_ARRAY_INITIAL_SIZE;
  540. trx_sys->descr_n_used = 0;
  541. srv_descriptors_memory = TRX_DESCR_ARRAY_INITIAL_SIZE *
  542. sizeof(trx_id_t);
  543. sys_header = trx_sysf_get(&mtr);
  544. if (srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN) {
  545. trx_rseg_array_init(sys_header, ib_bh, &mtr);
  546. }
  547. /* VERY important: after the database is started, max_trx_id value is
  548. divisible by TRX_SYS_TRX_ID_WRITE_MARGIN, and the 'if' in
  549. trx_sys_get_new_trx_id will evaluate to TRUE when the function
  550. is first time called, and the value for trx id will be written
  551. to the disk-based header! Thus trx id values will not overlap when
  552. the database is repeatedly started! */
  553. trx_sys->max_trx_id = 2 * TRX_SYS_TRX_ID_WRITE_MARGIN
  554. + ut_uint64_align_up(mach_read_from_8(sys_header
  555. + TRX_SYS_TRX_ID_STORE),
  556. TRX_SYS_TRX_ID_WRITE_MARGIN);
  557. ut_d(trx_sys->rw_max_trx_id = trx_sys->max_trx_id);
  558. UT_LIST_INIT(trx_sys->mysql_trx_list);
  559. trx_dummy_sess = sess_open();
  560. trx_lists_init_at_db_start();
  561. /* This S lock is not strictly required, it is here only to satisfy
  562. the debug code (assertions). We are still running in single threaded
  563. bootstrap mode. */
  564. mutex_enter(&trx_sys->mutex);
  565. ut_a(UT_LIST_GET_LEN(trx_sys->ro_trx_list) == 0);
  566. if (UT_LIST_GET_LEN(trx_sys->rw_trx_list) > 0) {
  567. const trx_t* trx;
  568. for (trx = UT_LIST_GET_FIRST(trx_sys->rw_trx_list);
  569. trx != NULL;
  570. trx = UT_LIST_GET_NEXT(trx_list, trx)) {
  571. ut_ad(trx->is_recovered);
  572. assert_trx_in_rw_list(trx);
  573. if (trx_state_eq(trx, TRX_STATE_ACTIVE)) {
  574. rows_to_undo += trx->undo_no;
  575. }
  576. }
  577. if (rows_to_undo > 1000000000) {
  578. unit = "M";
  579. rows_to_undo = rows_to_undo / 1000000;
  580. }
  581. fprintf(stderr,
  582. "InnoDB: %lu transaction(s) which must be"
  583. " rolled back or cleaned up\n"
  584. "InnoDB: in total %lu%s row operations to undo\n",
  585. (ulong) UT_LIST_GET_LEN(trx_sys->rw_trx_list),
  586. (ulong) rows_to_undo, unit);
  587. fprintf(stderr, "InnoDB: Trx id counter is " TRX_ID_FMT "\n",
  588. trx_sys->max_trx_id);
  589. }
  590. mutex_exit(&trx_sys->mutex);
  591. UT_LIST_INIT(trx_sys->view_list);
  592. mtr_commit(&mtr);
  593. return(ib_bh);
  594. }
  595. /*****************************************************************//**
  596. Creates the trx_sys instance and initializes ib_bh and mutex. */
  597. UNIV_INTERN
  598. void
  599. trx_sys_create(void)
  600. /*================*/
  601. {
  602. ut_ad(trx_sys == NULL);
  603. trx_sys = static_cast<trx_sys_t*>(mem_zalloc(sizeof(*trx_sys)));
  604. mutex_create(trx_sys_mutex_key, &trx_sys->mutex, SYNC_TRX_SYS);
  605. }
  606. /*****************************************************************//**
  607. Creates and initializes the transaction system at the database creation. */
  608. UNIV_INTERN
  609. void
  610. trx_sys_create_sys_pages(void)
  611. /*==========================*/
  612. {
  613. mtr_t mtr;
  614. mtr_start(&mtr);
  615. trx_sysf_create(&mtr);
  616. mtr_commit(&mtr);
  617. }
  618. /*****************************************************************//**
  619. Update the file format tag.
  620. @return always TRUE */
  621. static
  622. ibool
  623. trx_sys_file_format_max_write(
  624. /*==========================*/
  625. ulint format_id, /*!< in: file format id */
  626. const char** name) /*!< out: max file format name, can
  627. be NULL */
  628. {
  629. mtr_t mtr;
  630. byte* ptr;
  631. buf_block_t* block;
  632. ib_uint64_t tag_value;
  633. mtr_start(&mtr);
  634. block = buf_page_get(
  635. TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO, RW_X_LATCH, &mtr);
  636. file_format_max.id = format_id;
  637. file_format_max.name = trx_sys_file_format_id_to_name(format_id);
  638. ptr = buf_block_get_frame(block) + TRX_SYS_FILE_FORMAT_TAG;
  639. tag_value = format_id + TRX_SYS_FILE_FORMAT_TAG_MAGIC_N;
  640. if (name) {
  641. *name = file_format_max.name;
  642. }
  643. mlog_write_ull(ptr, tag_value, &mtr);
  644. mtr_commit(&mtr);
  645. return(TRUE);
  646. }
  647. /*****************************************************************//**
  648. Read the file format tag.
  649. @return the file format or ULINT_UNDEFINED if not set. */
  650. static
  651. ulint
  652. trx_sys_file_format_max_read(void)
  653. /*==============================*/
  654. {
  655. mtr_t mtr;
  656. const byte* ptr;
  657. const buf_block_t* block;
  658. ib_id_t file_format_id;
  659. /* Since this is called during the startup phase it's safe to
  660. read the value without a covering mutex. */
  661. mtr_start(&mtr);
  662. block = buf_page_get(
  663. TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO, RW_X_LATCH, &mtr);
  664. ptr = buf_block_get_frame(block) + TRX_SYS_FILE_FORMAT_TAG;
  665. file_format_id = mach_read_from_8(ptr);
  666. mtr_commit(&mtr);
  667. file_format_id -= TRX_SYS_FILE_FORMAT_TAG_MAGIC_N;
  668. if (file_format_id >= FILE_FORMAT_NAME_N) {
  669. /* Either it has never been tagged, or garbage in it. */
  670. return(ULINT_UNDEFINED);
  671. }
  672. return((ulint) file_format_id);
  673. }
  674. /*****************************************************************//**
  675. Get the name representation of the file format from its id.
  676. @return pointer to the name */
  677. UNIV_INTERN
  678. const char*
  679. trx_sys_file_format_id_to_name(
  680. /*===========================*/
  681. const ulint id) /*!< in: id of the file format */
  682. {
  683. ut_a(id < FILE_FORMAT_NAME_N);
  684. return(file_format_name_map[id]);
  685. }
  686. /*****************************************************************//**
  687. Check for the max file format tag stored on disk. Note: If max_format_id
  688. is == UNIV_FORMAT_MAX + 1 then we only print a warning.
  689. @return DB_SUCCESS or error code */
  690. UNIV_INTERN
  691. dberr_t
  692. trx_sys_file_format_max_check(
  693. /*==========================*/
  694. ulint max_format_id) /*!< in: max format id to check */
  695. {
  696. ulint format_id;
  697. /* Check the file format in the tablespace. Do not try to
  698. recover if the file format is not supported by the engine
  699. unless forced by the user. */
  700. format_id = trx_sys_file_format_max_read();
  701. if (format_id == ULINT_UNDEFINED) {
  702. /* Format ID was not set. Set it to minimum possible
  703. value. */
  704. format_id = UNIV_FORMAT_MIN;
  705. }
  706. ib_logf(IB_LOG_LEVEL_INFO,
  707. "Highest supported file format is %s.",
  708. trx_sys_file_format_id_to_name(UNIV_FORMAT_MAX));
  709. if (format_id > UNIV_FORMAT_MAX) {
  710. ut_a(format_id < FILE_FORMAT_NAME_N);
  711. ib_logf(max_format_id <= UNIV_FORMAT_MAX
  712. ? IB_LOG_LEVEL_ERROR : IB_LOG_LEVEL_WARN,
  713. "The system tablespace is in a file "
  714. "format that this version doesn't support - %s.",
  715. trx_sys_file_format_id_to_name(format_id));
  716. if (max_format_id <= UNIV_FORMAT_MAX) {
  717. return(DB_ERROR);
  718. }
  719. }
  720. format_id = (format_id > max_format_id) ? format_id : max_format_id;
  721. /* We don't need a mutex here, as this function should only
  722. be called once at start up. */
  723. file_format_max.id = format_id;
  724. file_format_max.name = trx_sys_file_format_id_to_name(format_id);
  725. return(DB_SUCCESS);
  726. }
  727. /*****************************************************************//**
  728. Set the file format id unconditionally except if it's already the
  729. same value.
  730. @return TRUE if value updated */
  731. UNIV_INTERN
  732. ibool
  733. trx_sys_file_format_max_set(
  734. /*========================*/
  735. ulint format_id, /*!< in: file format id */
  736. const char** name) /*!< out: max file format name or
  737. NULL if not needed. */
  738. {
  739. ibool ret = FALSE;
  740. ut_a(format_id <= UNIV_FORMAT_MAX);
  741. mutex_enter(&file_format_max.mutex);
  742. /* Only update if not already same value. */
  743. if (format_id != file_format_max.id) {
  744. ret = trx_sys_file_format_max_write(format_id, name);
  745. }
  746. mutex_exit(&file_format_max.mutex);
  747. return(ret);
  748. }
  749. /********************************************************************//**
  750. Tags the system table space with minimum format id if it has not been
  751. tagged yet.
  752. WARNING: This function is only called during the startup and AFTER the
  753. redo log application during recovery has finished. */
  754. UNIV_INTERN
  755. void
  756. trx_sys_file_format_tag_init(void)
  757. /*==============================*/
  758. {
  759. ulint format_id;
  760. format_id = trx_sys_file_format_max_read();
  761. /* If format_id is not set then set it to the minimum. */
  762. if (format_id == ULINT_UNDEFINED) {
  763. trx_sys_file_format_max_set(UNIV_FORMAT_MIN, NULL);
  764. }
  765. }
  766. /********************************************************************//**
  767. Update the file format tag in the system tablespace only if the given
  768. format id is greater than the known max id.
  769. @return TRUE if format_id was bigger than the known max id */
  770. UNIV_INTERN
  771. ibool
  772. trx_sys_file_format_max_upgrade(
  773. /*============================*/
  774. const char** name, /*!< out: max file format name */
  775. ulint format_id) /*!< in: file format identifier */
  776. {
  777. ibool ret = FALSE;
  778. ut_a(name);
  779. ut_a(file_format_max.name != NULL);
  780. ut_a(format_id <= UNIV_FORMAT_MAX);
  781. mutex_enter(&file_format_max.mutex);
  782. if (format_id > file_format_max.id) {
  783. ret = trx_sys_file_format_max_write(format_id, name);
  784. }
  785. mutex_exit(&file_format_max.mutex);
  786. return(ret);
  787. }
  788. /*****************************************************************//**
  789. Get the name representation of the file format from its id.
  790. @return pointer to the max format name */
  791. UNIV_INTERN
  792. const char*
  793. trx_sys_file_format_max_get(void)
  794. /*=============================*/
  795. {
  796. return(file_format_max.name);
  797. }
  798. /*****************************************************************//**
  799. Initializes the tablespace tag system. */
  800. UNIV_INTERN
  801. void
  802. trx_sys_file_format_init(void)
  803. /*==========================*/
  804. {
  805. mutex_create(file_format_max_mutex_key,
  806. &file_format_max.mutex, SYNC_FILE_FORMAT_TAG);
  807. /* We don't need a mutex here, as this function should only
  808. be called once at start up. */
  809. file_format_max.id = UNIV_FORMAT_MIN;
  810. file_format_max.name = trx_sys_file_format_id_to_name(
  811. file_format_max.id);
  812. }
  813. /*****************************************************************//**
  814. Closes the tablespace tag system. */
  815. UNIV_INTERN
  816. void
  817. trx_sys_file_format_close(void)
  818. /*===========================*/
  819. {
  820. /* Does nothing at the moment */
  821. }
  822. /*********************************************************************
  823. Creates the rollback segments.
  824. @return number of rollback segments that are active. */
  825. UNIV_INTERN
  826. ulint
  827. trx_sys_create_rsegs(
  828. /*=================*/
  829. ulint n_spaces, /*!< number of tablespaces for UNDO logs */
  830. ulint n_rsegs) /*!< number of rollback segments to create */
  831. {
  832. mtr_t mtr;
  833. ulint n_used;
  834. ut_a(n_spaces < TRX_SYS_N_RSEGS);
  835. ut_a(n_rsegs <= TRX_SYS_N_RSEGS);
  836. if (srv_read_only_mode) {
  837. return(ULINT_UNDEFINED);
  838. }
  839. /* This is executed in single-threaded mode therefore it is not
  840. necessary to use the same mtr in trx_rseg_create(). n_used cannot
  841. change while the function is executing. */
  842. mtr_start(&mtr);
  843. n_used = trx_sysf_rseg_find_free(&mtr);
  844. mtr_commit(&mtr);
  845. if (n_used == ULINT_UNDEFINED) {
  846. n_used = TRX_SYS_N_RSEGS;
  847. }
  848. /* Do not create additional rollback segments if innodb_force_recovery
  849. has been set and the database was not shutdown cleanly. */
  850. if (!srv_force_recovery && !recv_needed_recovery && n_used < n_rsegs) {
  851. ulint i;
  852. ulint new_rsegs = n_rsegs - n_used;
  853. for (i = 0; i < new_rsegs; ++i) {
  854. ulint space_id;
  855. space_id = (n_spaces == 0) ? 0
  856. : (srv_undo_space_id_start + i % n_spaces);
  857. /* Tablespace 0 is the system tablespace. */
  858. if (trx_rseg_create(space_id) != NULL) {
  859. ++n_used;
  860. } else {
  861. break;
  862. }
  863. }
  864. }
  865. ib_logf(IB_LOG_LEVEL_INFO,
  866. "%lu rollback segment(s) are active.", n_used);
  867. return(n_used);
  868. }
  869. #else /* !UNIV_HOTBACKUP */
  870. /*****************************************************************//**
  871. Prints to stderr the MySQL binlog info in the system header if the
  872. magic number shows it valid. */
  873. UNIV_INTERN
  874. void
  875. trx_sys_print_mysql_binlog_offset_from_page(
  876. /*========================================*/
  877. const byte* page) /*!< in: buffer containing the trx
  878. system header page, i.e., page number
  879. TRX_SYS_PAGE_NO in the tablespace */
  880. {
  881. const trx_sysf_t* sys_header;
  882. sys_header = page + TRX_SYS;
  883. if (mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO
  884. + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD)
  885. == TRX_SYS_MYSQL_LOG_MAGIC_N) {
  886. fprintf(stderr,
  887. "mysqlbackup: Last MySQL binlog file position %lu %lu,"
  888. " file name %s\n",
  889. (ulong) mach_read_from_4(
  890. sys_header + TRX_SYS_MYSQL_LOG_INFO
  891. + TRX_SYS_MYSQL_LOG_OFFSET_HIGH),
  892. (ulong) mach_read_from_4(
  893. sys_header + TRX_SYS_MYSQL_LOG_INFO
  894. + TRX_SYS_MYSQL_LOG_OFFSET_LOW),
  895. sys_header + TRX_SYS_MYSQL_LOG_INFO
  896. + TRX_SYS_MYSQL_LOG_NAME);
  897. }
  898. }
  899. /*****************************************************************//**
  900. Reads the file format id from the first system table space file.
  901. Even if the call succeeds and returns TRUE, the returned format id
  902. may be ULINT_UNDEFINED signalling that the format id was not present
  903. in the data file.
  904. @return TRUE if call succeeds */
  905. UNIV_INTERN
  906. ibool
  907. trx_sys_read_file_format_id(
  908. /*========================*/
  909. const char *pathname, /*!< in: pathname of the first system
  910. table space file */
  911. ulint *format_id) /*!< out: file format of the system table
  912. space */
  913. {
  914. os_file_t file;
  915. ibool success;
  916. byte buf[UNIV_PAGE_SIZE * 2];
  917. page_t* page = ut_align(buf, UNIV_PAGE_SIZE);
  918. const byte* ptr;
  919. ib_id_t file_format_id;
  920. *format_id = ULINT_UNDEFINED;
  921. file = os_file_create_simple_no_error_handling(
  922. innodb_file_data_key,
  923. pathname,
  924. OS_FILE_OPEN,
  925. OS_FILE_READ_ONLY,
  926. &success
  927. );
  928. if (!success) {
  929. /* The following call prints an error message */
  930. os_file_get_last_error(true);
  931. ut_print_timestamp(stderr);
  932. fprintf(stderr,
  933. " mysqlbackup: Error: trying to read system "
  934. "tablespace file format,\n"
  935. " mysqlbackup: but could not open the tablespace "
  936. "file %s!\n", pathname);
  937. return(FALSE);
  938. }
  939. /* Read the page on which file format is stored */
  940. success = os_file_read_no_error_handling(
  941. file, page, TRX_SYS_PAGE_NO * UNIV_PAGE_SIZE, UNIV_PAGE_SIZE);
  942. if (!success) {
  943. /* The following call prints an error message */
  944. os_file_get_last_error(true);
  945. ut_print_timestamp(stderr);
  946. fprintf(stderr,
  947. " mysqlbackup: Error: trying to read system "
  948. "tablespace file format,\n"
  949. " mysqlbackup: but failed to read the tablespace "
  950. "file %s!\n", pathname);
  951. os_file_close(file);
  952. return(FALSE);
  953. }
  954. os_file_close(file);
  955. /* get the file format from the page */
  956. ptr = page + TRX_SYS_FILE_FORMAT_TAG;
  957. file_format_id = mach_read_from_8(ptr);
  958. file_format_id -= TRX_SYS_FILE_FORMAT_TAG_MAGIC_N;
  959. if (file_format_id >= FILE_FORMAT_NAME_N) {
  960. /* Either it has never been tagged, or garbage in it. */
  961. return(TRUE);
  962. }
  963. *format_id = (ulint) file_format_id;
  964. return(TRUE);
  965. }
  966. /*****************************************************************//**
  967. Reads the file format id from the given per-table data file.
  968. @return TRUE if call succeeds */
  969. UNIV_INTERN
  970. ibool
  971. trx_sys_read_pertable_file_format_id(
  972. /*=================================*/
  973. const char *pathname, /*!< in: pathname of a per-table
  974. datafile */
  975. ulint *format_id) /*!< out: file format of the per-table
  976. data file */
  977. {
  978. os_file_t file;
  979. ibool success;
  980. byte buf[UNIV_PAGE_SIZE * 2];
  981. page_t* page = ut_align(buf, UNIV_PAGE_SIZE);
  982. const byte* ptr;
  983. ib_uint32_t flags;
  984. *format_id = ULINT_UNDEFINED;
  985. file = os_file_create_simple_no_error_handling(
  986. innodb_file_data_key,
  987. pathname,
  988. OS_FILE_OPEN,
  989. OS_FILE_READ_ONLY,
  990. &success
  991. );
  992. if (!success) {
  993. /* The following call prints an error message */
  994. os_file_get_last_error(true);
  995. ut_print_timestamp(stderr);
  996. fprintf(stderr,
  997. " mysqlbackup: Error: trying to read per-table "
  998. "tablespace format,\n"
  999. " mysqlbackup: but could not open the tablespace "
  1000. "file %s!\n", pathname);
  1001. return(FALSE);
  1002. }
  1003. /* Read the first page of the per-table datafile */
  1004. success = os_file_read_no_error_handling(file, page, 0, UNIV_PAGE_SIZE);
  1005. if (!success) {
  1006. /* The following call prints an error message */
  1007. os_file_get_last_error(true);
  1008. ut_print_timestamp(stderr);
  1009. fprintf(stderr,
  1010. " mysqlbackup: Error: trying to per-table data file "
  1011. "format,\n"
  1012. " mysqlbackup: but failed to read the tablespace "
  1013. "file %s!\n", pathname);
  1014. os_file_close(file);
  1015. return(FALSE);
  1016. }
  1017. os_file_close(file);
  1018. /* get the file format from the page */
  1019. ptr = page + 54;
  1020. flags = mach_read_from_4(ptr);
  1021. if (!fsp_flags_is_valid(flags) {
  1022. /* bad tablespace flags */
  1023. return(FALSE);
  1024. }
  1025. *format_id = FSP_FLAGS_GET_POST_ANTELOPE(flags);
  1026. return(TRUE);
  1027. }
  1028. /*****************************************************************//**
  1029. Get the name representation of the file format from its id.
  1030. @return pointer to the name */
  1031. UNIV_INTERN
  1032. const char*
  1033. trx_sys_file_format_id_to_name(
  1034. /*===========================*/
  1035. const ulint id) /*!< in: id of the file format */
  1036. {
  1037. if (!(id < FILE_FORMAT_NAME_N)) {
  1038. /* unknown id */
  1039. return("Unknown");
  1040. }
  1041. return(file_format_name_map[id]);
  1042. }
  1043. #endif /* !UNIV_HOTBACKUP */
  1044. #ifndef UNIV_HOTBACKUP
  1045. /*********************************************************************
  1046. Shutdown/Close the transaction system. */
  1047. UNIV_INTERN
  1048. void
  1049. trx_sys_close(void)
  1050. /*===============*/
  1051. {
  1052. ulint i;
  1053. trx_t* trx;
  1054. read_view_t* view;
  1055. ut_ad(trx_sys != NULL);
  1056. ut_ad(srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS);
  1057. /* Check that all read views are closed except read view owned
  1058. by a purge. */
  1059. mutex_enter(&trx_sys->mutex);
  1060. if (UT_LIST_GET_LEN(trx_sys->view_list) > 1) {
  1061. fprintf(stderr,
  1062. "InnoDB: Error: all read views were not closed"
  1063. " before shutdown:\n"
  1064. "InnoDB: %lu read views open \n",
  1065. UT_LIST_GET_LEN(trx_sys->view_list) - 1);
  1066. }
  1067. mutex_exit(&trx_sys->mutex);
  1068. sess_close(trx_dummy_sess);
  1069. trx_dummy_sess = NULL;
  1070. trx_purge_sys_close();
  1071. /* Free the double write data structures. */
  1072. if (buf_dblwr) {
  1073. buf_dblwr_free();
  1074. }
  1075. /* Only prepared transactions may be left in the system. Free them. */
  1076. ut_a(UT_LIST_GET_LEN(trx_sys->rw_trx_list) == trx_sys->n_prepared_trx
  1077. || srv_read_only_mode
  1078. || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO
  1079. || srv_apply_log_only);
  1080. while ((trx = UT_LIST_GET_FIRST(trx_sys->rw_trx_list)) != NULL) {
  1081. trx_free_prepared(trx);
  1082. }
  1083. /* There can't be any active transactions. */
  1084. for (i = 0; i < TRX_SYS_N_RSEGS; ++i) {
  1085. trx_rseg_t* rseg;
  1086. rseg = trx_sys->rseg_array[i];
  1087. if (rseg != NULL) {
  1088. trx_rseg_mem_free(rseg);
  1089. } else {
  1090. break;
  1091. }
  1092. }
  1093. view = UT_LIST_GET_FIRST(trx_sys->view_list);
  1094. while (view != NULL) {
  1095. read_view_t* prev_view = view;
  1096. view = UT_LIST_GET_NEXT(view_list, prev_view);
  1097. /* Views are allocated from the trx_sys->global_read_view_heap.
  1098. So, we simply remove the element here. */
  1099. UT_LIST_REMOVE(view_list, trx_sys->view_list, prev_view);
  1100. }
  1101. if (!srv_apply_log_only) {
  1102. ut_a(UT_LIST_GET_LEN(trx_sys->view_list) == 0);
  1103. ut_a(UT_LIST_GET_LEN(trx_sys->ro_trx_list) == 0);
  1104. ut_a(UT_LIST_GET_LEN(trx_sys->rw_trx_list) == 0);
  1105. ut_a(UT_LIST_GET_LEN(trx_sys->mysql_trx_list) == 0);
  1106. }
  1107. mutex_free(&trx_sys->mutex);
  1108. ut_ad(trx_sys->descr_n_used == 0);
  1109. ut_free(trx_sys->descriptors);
  1110. mem_free(trx_sys);
  1111. trx_sys = NULL;
  1112. }
  1113. /** @brief Convert an undo log to TRX_UNDO_PREPARED state on shutdown.
  1114. If any prepared ACTIVE transactions exist, and their rollback was
  1115. prevented by innodb_force_recovery, we convert these transactions to
  1116. XA PREPARE state in the main-memory data structures, so that shutdown
  1117. will proceed normally. These transactions will again recover as ACTIVE
  1118. on the next restart, and they will be rolled back unless
  1119. innodb_force_recovery prevents it again.
  1120. @param[in] trx transaction
  1121. @param[in,out] undo undo log to convert to TRX_UNDO_PREPARED */
  1122. static
  1123. void
  1124. trx_undo_fake_prepared(
  1125. const trx_t* trx,
  1126. trx_undo_t* undo)
  1127. {
  1128. ut_ad(srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO);
  1129. ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE));
  1130. ut_ad(trx->is_recovered);
  1131. if (undo != NULL) {
  1132. ut_ad(undo->state == TRX_UNDO_ACTIVE);
  1133. undo->state = TRX_UNDO_PREPARED;
  1134. }
  1135. }
  1136. /*********************************************************************
  1137. Check if there are any active (non-prepared) transactions.
  1138. @return total number of active transactions or 0 if none */
  1139. UNIV_INTERN
  1140. ulint
  1141. trx_sys_any_active_transactions(void)
  1142. /*=================================*/
  1143. {
  1144. if (srv_apply_log_only) {
  1145. return(0);
  1146. }
  1147. mutex_enter(&trx_sys->mutex);
  1148. ulint total_trx = UT_LIST_GET_LEN(trx_sys->mysql_trx_list);
  1149. if (total_trx == 0) {
  1150. total_trx = UT_LIST_GET_LEN(trx_sys->rw_trx_list);
  1151. ut_a(total_trx >= trx_sys->n_prepared_trx);
  1152. if (total_trx > trx_sys->n_prepared_trx
  1153. && srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO) {
  1154. for (trx_t* trx = UT_LIST_GET_FIRST(
  1155. trx_sys->rw_trx_list);
  1156. trx != NULL;
  1157. trx = UT_LIST_GET_NEXT(trx_list, trx)) {
  1158. if (!trx_state_eq(trx, TRX_STATE_ACTIVE)
  1159. || !trx->is_recovered) {
  1160. continue;
  1161. }
  1162. /* This was a recovered transaction
  1163. whose rollback was disabled by
  1164. the innodb_force_recovery setting.
  1165. Pretend that it is in XA PREPARE
  1166. state so that shutdown will work. */
  1167. trx_undo_fake_prepared(
  1168. trx, trx->insert_undo);
  1169. trx_undo_fake_prepared(
  1170. trx, trx->update_undo);
  1171. trx->state = TRX_STATE_PREPARED;
  1172. trx_sys->n_prepared_trx++;
  1173. trx_sys->n_prepared_recovered_trx++;
  1174. }
  1175. }
  1176. ut_a(total_trx >= trx_sys->n_prepared_trx);
  1177. total_trx -= trx_sys->n_prepared_trx;
  1178. }
  1179. mutex_exit(&trx_sys->mutex);
  1180. return(total_trx);
  1181. }
  1182. #ifdef UNIV_DEBUG
  1183. /*************************************************************//**
  1184. Validate the trx_list_t.
  1185. @return TRUE if valid. */
  1186. static
  1187. ibool
  1188. trx_sys_validate_trx_list_low(
  1189. /*===========================*/
  1190. trx_list_t* trx_list) /*!< in: &trx_sys->ro_trx_list
  1191. or &trx_sys->rw_trx_list */
  1192. {
  1193. const trx_t* trx;
  1194. const trx_t* prev_trx = NULL;
  1195. ut_ad(mutex_own(&trx_sys->mutex));
  1196. ut_ad(trx_list == &trx_sys->ro_trx_list
  1197. || trx_list == &trx_sys->rw_trx_list);
  1198. for (trx = UT_LIST_GET_FIRST(*trx_list);
  1199. trx != NULL;
  1200. prev_trx = trx, trx = UT_LIST_GET_NEXT(trx_list, prev_trx)) {
  1201. assert_trx_in_list(trx);
  1202. ut_ad(trx->read_only == (trx_list == &trx_sys->ro_trx_list));
  1203. ut_a(prev_trx == NULL || prev_trx->id > trx->id);
  1204. }
  1205. return(TRUE);
  1206. }
  1207. /*************************************************************//**
  1208. Validate the trx_sys_t::ro_trx_list and trx_sys_t::rw_trx_list.
  1209. @return TRUE if lists are valid. */
  1210. UNIV_INTERN
  1211. ibool
  1212. trx_sys_validate_trx_list(void)
  1213. /*===========================*/
  1214. {
  1215. ut_ad(mutex_own(&trx_sys->mutex));
  1216. ut_a(trx_sys_validate_trx_list_low(&trx_sys->ro_trx_list));
  1217. ut_a(trx_sys_validate_trx_list_low(&trx_sys->rw_trx_list));
  1218. return(TRUE);
  1219. }
  1220. #endif /* UNIV_DEBUG */
  1221. #endif /* !UNIV_HOTBACKUP */