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.

386 lines
9.6 KiB

17 years ago
17 years ago
17 years ago
17 years ago
  1. /*****************************************************************************
  2. Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
  3. This program is free software; you can redistribute it and/or modify it under
  4. the terms of the GNU General Public License as published by the Free Software
  5. Foundation; version 2 of the License.
  6. This program is distributed in the hope that it will be useful, but WITHOUT
  7. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License along with
  10. this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  11. Place, Suite 330, Boston, MA 02111-1307 USA
  12. *****************************************************************************/
  13. /******************************************************
  14. Mini-transaction buffer
  15. Created 11/26/1995 Heikki Tuuri
  16. *******************************************************/
  17. #include "mtr0mtr.h"
  18. #ifdef UNIV_NONINL
  19. #include "mtr0mtr.ic"
  20. #endif
  21. #include "buf0buf.h"
  22. #include "page0types.h"
  23. #include "mtr0log.h"
  24. #include "log0log.h"
  25. /*********************************************************************
  26. Releases the item in the slot given. */
  27. UNIV_INLINE
  28. void
  29. mtr_memo_slot_release(
  30. /*==================*/
  31. mtr_t* mtr, /* in: mtr */
  32. mtr_memo_slot_t* slot) /* in: memo slot */
  33. {
  34. void* object;
  35. ulint type;
  36. ut_ad(mtr && slot);
  37. object = slot->object;
  38. type = slot->type;
  39. if (UNIV_LIKELY(object != NULL)) {
  40. if (type <= MTR_MEMO_BUF_FIX) {
  41. buf_page_release((buf_block_t*)object, type, mtr);
  42. } else if (type == MTR_MEMO_S_LOCK) {
  43. rw_lock_s_unlock((rw_lock_t*)object);
  44. #ifdef UNIV_DEBUG
  45. } else if (type != MTR_MEMO_X_LOCK) {
  46. ut_ad(type == MTR_MEMO_MODIFY);
  47. ut_ad(mtr_memo_contains(mtr, object,
  48. MTR_MEMO_PAGE_X_FIX));
  49. #endif /* UNIV_DEBUG */
  50. } else {
  51. rw_lock_x_unlock((rw_lock_t*)object);
  52. }
  53. }
  54. slot->object = NULL;
  55. }
  56. /**************************************************************
  57. Releases the mlocks and other objects stored in an mtr memo. They are released
  58. in the order opposite to which they were pushed to the memo. NOTE! It is
  59. essential that the x-rw-lock on a modified buffer page is not released before
  60. buf_page_note_modification is called for that page! Otherwise, some thread
  61. might race to modify it, and the flush list sort order on lsn would be
  62. destroyed. */
  63. UNIV_INLINE
  64. void
  65. mtr_memo_pop_all(
  66. /*=============*/
  67. mtr_t* mtr) /* in: mtr */
  68. {
  69. mtr_memo_slot_t* slot;
  70. dyn_array_t* memo;
  71. ulint offset;
  72. ut_ad(mtr);
  73. ut_ad(mtr->magic_n == MTR_MAGIC_N);
  74. ut_ad(mtr->state == MTR_COMMITTING); /* Currently only used in
  75. commit */
  76. memo = &(mtr->memo);
  77. offset = dyn_array_get_data_size(memo);
  78. while (offset > 0) {
  79. offset -= sizeof(mtr_memo_slot_t);
  80. slot = dyn_array_get_element(memo, offset);
  81. mtr_memo_slot_release(mtr, slot);
  82. }
  83. }
  84. UNIV_INLINE
  85. void
  86. mtr_memo_note_modification_all(
  87. /*===========================*/
  88. mtr_t* mtr) /* in: mtr */
  89. {
  90. mtr_memo_slot_t* slot;
  91. dyn_array_t* memo;
  92. ulint offset;
  93. ut_ad(mtr);
  94. ut_ad(mtr->magic_n == MTR_MAGIC_N);
  95. ut_ad(mtr->state == MTR_COMMITTING); /* Currently only used in
  96. commit */
  97. ut_ad(mtr->modifications);
  98. memo = &(mtr->memo);
  99. offset = dyn_array_get_data_size(memo);
  100. while (offset > 0) {
  101. offset -= sizeof(mtr_memo_slot_t);
  102. slot = dyn_array_get_element(memo, offset);
  103. if (UNIV_LIKELY(slot->object != NULL) &&
  104. slot->type == MTR_MEMO_PAGE_X_FIX) {
  105. buf_flush_note_modification(
  106. (buf_block_t*)slot->object, mtr);
  107. }
  108. }
  109. }
  110. /****************************************************************
  111. Writes the contents of a mini-transaction log, if any, to the database log. */
  112. static
  113. void
  114. mtr_log_reserve_and_write(
  115. /*======================*/
  116. mtr_t* mtr) /* in: mtr */
  117. {
  118. dyn_array_t* mlog;
  119. dyn_block_t* block;
  120. ulint data_size;
  121. ibool success;
  122. byte* first_data;
  123. ut_ad(mtr);
  124. mlog = &(mtr->log);
  125. first_data = dyn_block_get_data(mlog);
  126. if (mtr->n_log_recs > 1) {
  127. mlog_catenate_ulint(mtr, MLOG_MULTI_REC_END, MLOG_1BYTE);
  128. } else {
  129. *first_data = (byte)((ulint)*first_data
  130. | MLOG_SINGLE_REC_FLAG);
  131. }
  132. if (mlog->heap == NULL) {
  133. mtr->end_lsn = log_reserve_and_write_fast(
  134. first_data, dyn_block_get_used(mlog),
  135. &(mtr->start_lsn), &success);
  136. if (success) {
  137. return;
  138. }
  139. }
  140. data_size = dyn_array_get_data_size(mlog);
  141. /* Open the database log for log_write_low */
  142. mtr->start_lsn = log_reserve_and_open(data_size);
  143. if (mtr->log_mode == MTR_LOG_ALL) {
  144. block = mlog;
  145. while (block != NULL) {
  146. log_write_low(dyn_block_get_data(block),
  147. dyn_block_get_used(block));
  148. block = dyn_array_get_next_block(mlog, block);
  149. }
  150. } else {
  151. ut_ad(mtr->log_mode == MTR_LOG_NONE);
  152. /* Do nothing */
  153. }
  154. mtr->end_lsn = log_close();
  155. }
  156. /*******************************************************************
  157. Commits a mini-transaction. */
  158. UNIV_INTERN
  159. void
  160. mtr_commit(
  161. /*=======*/
  162. mtr_t* mtr) /* in: mini-transaction */
  163. {
  164. ibool write_log;
  165. ut_ad(mtr);
  166. ut_ad(mtr->magic_n == MTR_MAGIC_N);
  167. ut_ad(mtr->state == MTR_ACTIVE);
  168. ut_d(mtr->state = MTR_COMMITTING);
  169. write_log = mtr->modifications && mtr->n_log_recs;
  170. if (write_log) {
  171. mtr_log_reserve_and_write(mtr);
  172. mtr_memo_note_modification_all(mtr);
  173. }
  174. /* We first update the modification info to buffer pages, and only
  175. after that release the log mutex: this guarantees that when the log
  176. mutex is free, all buffer pages contain an up-to-date info of their
  177. modifications. This fact is used in making a checkpoint when we look
  178. at the oldest modification of any page in the buffer pool. It is also
  179. required when we insert modified buffer pages in to the flush list
  180. which must be sorted on oldest_modification. */
  181. if (write_log) {
  182. log_release();
  183. }
  184. /* All unlocking has been moved here, after log_sys mutex release. */
  185. mtr_memo_pop_all(mtr);
  186. ut_d(mtr->state = MTR_COMMITTED);
  187. dyn_array_free(&(mtr->memo));
  188. dyn_array_free(&(mtr->log));
  189. }
  190. /**************************************************************
  191. Releases the latches stored in an mtr memo down to a savepoint.
  192. NOTE! The mtr must not have made changes to buffer pages after the
  193. savepoint, as these can be handled only by mtr_commit. */
  194. UNIV_INTERN
  195. void
  196. mtr_rollback_to_savepoint(
  197. /*======================*/
  198. mtr_t* mtr, /* in: mtr */
  199. ulint savepoint) /* in: savepoint */
  200. {
  201. mtr_memo_slot_t* slot;
  202. dyn_array_t* memo;
  203. ulint offset;
  204. ut_ad(mtr);
  205. ut_ad(mtr->magic_n == MTR_MAGIC_N);
  206. ut_ad(mtr->state == MTR_ACTIVE);
  207. memo = &(mtr->memo);
  208. offset = dyn_array_get_data_size(memo);
  209. ut_ad(offset >= savepoint);
  210. while (offset > savepoint) {
  211. offset -= sizeof(mtr_memo_slot_t);
  212. slot = dyn_array_get_element(memo, offset);
  213. ut_ad(slot->type != MTR_MEMO_MODIFY);
  214. mtr_memo_slot_release(mtr, slot);
  215. }
  216. }
  217. /*******************************************************
  218. Releases an object in the memo stack. */
  219. UNIV_INTERN
  220. void
  221. mtr_memo_release(
  222. /*=============*/
  223. mtr_t* mtr, /* in: mtr */
  224. void* object, /* in: object */
  225. ulint type) /* in: object type: MTR_MEMO_S_LOCK, ... */
  226. {
  227. mtr_memo_slot_t* slot;
  228. dyn_array_t* memo;
  229. ulint offset;
  230. ut_ad(mtr);
  231. ut_ad(mtr->magic_n == MTR_MAGIC_N);
  232. ut_ad(mtr->state == MTR_ACTIVE);
  233. memo = &(mtr->memo);
  234. offset = dyn_array_get_data_size(memo);
  235. while (offset > 0) {
  236. offset -= sizeof(mtr_memo_slot_t);
  237. slot = dyn_array_get_element(memo, offset);
  238. if ((object == slot->object) && (type == slot->type)) {
  239. if (mtr->modifications &&
  240. UNIV_LIKELY(slot->object != NULL) &&
  241. slot->type == MTR_MEMO_PAGE_X_FIX) {
  242. buf_flush_note_modification(
  243. (buf_block_t*)slot->object, mtr);
  244. }
  245. mtr_memo_slot_release(mtr, slot);
  246. break;
  247. }
  248. }
  249. }
  250. /************************************************************
  251. Reads 1 - 4 bytes from a file page buffered in the buffer pool. */
  252. UNIV_INTERN
  253. ulint
  254. mtr_read_ulint(
  255. /*===========*/
  256. /* out: value read */
  257. const byte* ptr, /* in: pointer from where to read */
  258. ulint type, /* in: MLOG_1BYTE, MLOG_2BYTES, MLOG_4BYTES */
  259. mtr_t* mtr __attribute__((unused)))
  260. /* in: mini-transaction handle */
  261. {
  262. ut_ad(mtr->state == MTR_ACTIVE);
  263. ut_ad(mtr_memo_contains_page(mtr, ptr, MTR_MEMO_PAGE_S_FIX)
  264. || mtr_memo_contains_page(mtr, ptr, MTR_MEMO_PAGE_X_FIX));
  265. if (type == MLOG_1BYTE) {
  266. return(mach_read_from_1(ptr));
  267. } else if (type == MLOG_2BYTES) {
  268. return(mach_read_from_2(ptr));
  269. } else {
  270. ut_ad(type == MLOG_4BYTES);
  271. return(mach_read_from_4(ptr));
  272. }
  273. }
  274. /************************************************************
  275. Reads 8 bytes from a file page buffered in the buffer pool. */
  276. UNIV_INTERN
  277. dulint
  278. mtr_read_dulint(
  279. /*============*/
  280. /* out: value read */
  281. const byte* ptr, /* in: pointer from where to read */
  282. mtr_t* mtr __attribute__((unused)))
  283. /* in: mini-transaction handle */
  284. {
  285. ut_ad(mtr->state == MTR_ACTIVE);
  286. ut_ad(mtr_memo_contains_page(mtr, ptr, MTR_MEMO_PAGE_S_FIX)
  287. || mtr_memo_contains_page(mtr, ptr, MTR_MEMO_PAGE_X_FIX));
  288. return(mach_read_from_8(ptr));
  289. }
  290. #ifdef UNIV_DEBUG
  291. /**************************************************************
  292. Checks if memo contains the given page. */
  293. UNIV_INTERN
  294. ibool
  295. mtr_memo_contains_page(
  296. /*===================*/
  297. /* out: TRUE if contains */
  298. mtr_t* mtr, /* in: mtr */
  299. const byte* ptr, /* in: pointer to buffer frame */
  300. ulint type) /* in: type of object */
  301. {
  302. return(mtr_memo_contains(mtr, buf_block_align(ptr), type));
  303. }
  304. /*************************************************************
  305. Prints info of an mtr handle. */
  306. UNIV_INTERN
  307. void
  308. mtr_print(
  309. /*======*/
  310. mtr_t* mtr) /* in: mtr */
  311. {
  312. fprintf(stderr,
  313. "Mini-transaction handle: memo size %lu bytes"
  314. " log size %lu bytes\n",
  315. (ulong) dyn_array_get_data_size(&(mtr->memo)),
  316. (ulong) dyn_array_get_data_size(&(mtr->log)));
  317. }
  318. #endif /* UNIV_DEBUG */