row0vers.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:11k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /******************************************************
  2. Row versions
  3. (c) 1997 Innobase Oy
  4. Created 2/6/1997 Heikki Tuuri
  5. *******************************************************/
  6. #include "row0vers.h"
  7. #ifdef UNIV_NONINL
  8. #include "row0vers.ic"
  9. #endif
  10. #include "dict0dict.h"
  11. #include "dict0boot.h"
  12. #include "btr0btr.h"
  13. #include "mach0data.h"
  14. #include "trx0rseg.h"
  15. #include "trx0trx.h"
  16. #include "trx0roll.h"
  17. #include "trx0undo.h"
  18. #include "trx0purge.h"
  19. #include "trx0rec.h"
  20. #include "que0que.h"
  21. #include "row0row.h"
  22. #include "row0upd.h"
  23. #include "rem0cmp.h"
  24. #include "read0read.h"
  25. /*********************************************************************
  26. Finds out if an active transaction has inserted or modified a secondary
  27. index record. NOTE: the kernel mutex is temporarily released in this
  28. function! */
  29. trx_t*
  30. row_vers_impl_x_locked_off_kernel(
  31. /*==============================*/
  32. /* out: NULL if committed, else the active
  33. transaction; NOTE that the kernel mutex is
  34. temporarily released! */
  35. rec_t* rec, /* in: record in a secondary index */
  36. dict_index_t* index) /* in: the secondary index */
  37. {
  38. dict_index_t* clust_index;
  39. rec_t* clust_rec;
  40. rec_t* version;
  41. rec_t* prev_version;
  42. dulint trx_id;
  43. dulint prev_trx_id;
  44. mem_heap_t* heap;
  45. mem_heap_t* heap2;
  46. dtuple_t* row;
  47. dtuple_t* entry = NULL; /* assignment to eliminate compiler
  48. warning */
  49. trx_t* trx;
  50. ibool vers_del;
  51. ibool rec_del;
  52. ulint err;
  53. mtr_t mtr;
  54. ut_ad(mutex_own(&kernel_mutex));
  55. ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));
  56. mutex_exit(&kernel_mutex);
  57. mtr_start(&mtr);
  58. /* Search for the clustered index record: this is a time-consuming
  59. operation: therefore we release the kernel mutex; also, the release
  60. is required by the latching order convention. The latch on the
  61. clustered index locks the top of the stack of versions. We also
  62. reserve purge_latch to lock the bottom of the version stack. */
  63. clust_rec = row_get_clust_rec(BTR_SEARCH_LEAF, rec, index,
  64. &clust_index, &mtr);
  65. ut_a(clust_rec);
  66. trx_id = row_get_rec_trx_id(clust_rec, clust_index);
  67. mtr_s_lock(&(purge_sys->latch), &mtr);
  68. mutex_enter(&kernel_mutex);
  69. if (!trx_is_active(trx_id)) {
  70. /* The transaction that modified or inserted clust_rec is no
  71. longer active: no implicit lock on rec */
  72. mtr_commit(&mtr);
  73. return(NULL);
  74. }
  75. /* We look up if some earlier version of the clustered index record
  76. would require rec to be in a different state (delete marked or
  77. unmarked, or not existing). If there is such a version, then rec was
  78. modified by the trx_id transaction, and it has an implicit x-lock on
  79. rec. Note that if clust_rec itself would require rec to be in a
  80. different state, then the trx_id transaction has not yet had time to
  81. modify rec, and does not necessarily have an implicit x-lock on rec. */
  82. rec_del = rec_get_deleted_flag(rec);
  83. trx = NULL;
  84. version = clust_rec;
  85. heap = NULL;
  86. for (;;) {
  87. mutex_exit(&kernel_mutex);
  88. /* While we retrieve an earlier version of clust_rec, we
  89. release the kernel mutex, because it may take time to access
  90. the disk. After the release, we have to check if the trx_id
  91. transaction is still active. We keep the semaphore in mtr on
  92. the clust_rec page, so that no other transaction can update
  93. it and get an implicit x-lock on rec. */
  94. heap2 = heap;
  95. heap = mem_heap_create(1024);
  96. err = trx_undo_prev_version_build(clust_rec, &mtr, version,
  97. clust_index, heap,
  98. &prev_version);
  99. if (heap2) {
  100. mem_heap_free(heap2); /* version was stored in heap2,
  101. if heap2 != NULL */
  102. }
  103. if (prev_version) {
  104. row = row_build(ROW_COPY_POINTERS, clust_index,
  105. prev_version, heap);
  106. entry = row_build_index_entry(row, index, heap);
  107. }
  108. mutex_enter(&kernel_mutex);
  109. if (!trx_is_active(trx_id)) {
  110. /* Transaction no longer active: no implicit x-lock */
  111. break;
  112. }
  113. /* If the transaction is still active, the previous version
  114. of clust_rec must be accessible if not a fresh insert; we
  115. may assert the following: */
  116. ut_ad(err == DB_SUCCESS);
  117. if (prev_version == NULL) {
  118. /* It was a freshly inserted version: there is an
  119. implicit x-lock on rec */
  120. trx = trx_get_on_id(trx_id);
  121. break;
  122. }
  123. /* If we get here, we know that the trx_id transaction is
  124. still active and it has modified prev_version. Let us check
  125. if prev_version would require rec to be in a different state. */
  126. vers_del = rec_get_deleted_flag(prev_version);
  127. if (0 == cmp_dtuple_rec(entry, rec)) {
  128. /* The delete marks of rec and prev_version should be
  129. equal for rec to be in the state required by
  130. prev_version */
  131. if (rec_del != vers_del) {
  132. trx = trx_get_on_id(trx_id);
  133. break;
  134. }
  135. } else if (!rec_del) {
  136. /* The delete mark should be set in rec for it to be
  137. in the state required by prev_version */
  138. trx = trx_get_on_id(trx_id);
  139. break;
  140. }
  141. prev_trx_id = row_get_rec_trx_id(prev_version, clust_index);
  142. if (0 != ut_dulint_cmp(trx_id, prev_trx_id)) {
  143. /* The versions modified by the trx_id transaction end
  144. to prev_version: no implicit x-lock */
  145. break;
  146. }
  147. version = prev_version;
  148. }/* for (;;) */
  149. mtr_commit(&mtr);
  150. mem_heap_free(heap);
  151. return(trx);
  152. }
  153. /*********************************************************************
  154. Finds out if we must preserve a delete marked earlier version of a clustered
  155. index record, because it is >= the purge view. */
  156. ibool
  157. row_vers_must_preserve_del_marked(
  158. /*==============================*/
  159. /* out: TRUE if earlier version should be preserved */
  160. dulint trx_id, /* in: transaction id in the version */
  161. mtr_t* mtr) /* in: mtr holding the latch on the clustered index
  162. record; it will also hold the latch on purge_view */
  163. {
  164. ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));
  165. mtr_s_lock(&(purge_sys->latch), mtr);
  166. if (trx_purge_update_undo_must_exist(trx_id)) {
  167. /* A purge operation is not yet allowed to remove this
  168. delete marked record */
  169. return(TRUE);
  170. }
  171. return(FALSE);
  172. }
  173. /*********************************************************************
  174. Finds out if a version of the record, where the version >= the current
  175. purge view, should have ientry as its secondary index entry. We check
  176. if there is any not delete marked version of the record where the trx
  177. id >= purge view, and the secondary index entry == ientry; exactly in
  178. this case we return TRUE. */
  179. ibool
  180. row_vers_old_has_index_entry(
  181. /*=========================*/
  182. /* out: TRUE if earlier version should have */
  183. ibool also_curr,/* in: TRUE if also rec is included in the
  184. versions to search; otherwise only versions
  185. prior to it are searched */
  186. rec_t* rec, /* in: record in the clustered index; the
  187. caller must have a latch on the page */
  188. mtr_t* mtr, /* in: mtr holding the latch on rec; it will
  189. also hold the latch on purge_view */
  190. dict_index_t* index, /* in: the secondary index */
  191. dtuple_t* ientry) /* in: the secondary index entry */
  192. {
  193. rec_t* version;
  194. rec_t* prev_version;
  195. dict_index_t* clust_index;
  196. mem_heap_t* heap;
  197. mem_heap_t* heap2;
  198. dtuple_t* row;
  199. dtuple_t* entry;
  200. ulint err;
  201. ut_ad(mtr_memo_contains(mtr, buf_block_align(rec), MTR_MEMO_PAGE_X_FIX)
  202.     || mtr_memo_contains(mtr, buf_block_align(rec),
  203. MTR_MEMO_PAGE_S_FIX));
  204. ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));
  205. mtr_s_lock(&(purge_sys->latch), mtr);
  206. clust_index = dict_table_get_first_index(index->table);
  207. if (also_curr && !rec_get_deleted_flag(rec)) {
  208. heap = mem_heap_create(1024);
  209. row = row_build(ROW_COPY_POINTERS, clust_index, rec, heap);
  210. entry = row_build_index_entry(row, index, heap);
  211. if (dtuple_datas_are_equal(ientry, entry)) {
  212. mem_heap_free(heap);
  213. return(TRUE);
  214. }
  215. mem_heap_free(heap);
  216. }
  217. version = rec;
  218. heap = NULL;
  219. for (;;) {
  220. heap2 = heap;
  221. heap = mem_heap_create(1024);
  222. err = trx_undo_prev_version_build(rec, mtr, version,
  223. clust_index, heap,
  224. &prev_version);
  225. if (heap2) {
  226. mem_heap_free(heap2); /* version was stored in heap2,
  227. if heap2 != NULL */
  228. }
  229. if ((err != DB_SUCCESS) || !prev_version) {
  230. /* Versions end here */
  231. mem_heap_free(heap);
  232. return(FALSE);
  233. }
  234. if (!rec_get_deleted_flag(prev_version)) {
  235. row = row_build(ROW_COPY_POINTERS, clust_index,
  236. prev_version, heap);
  237. entry = row_build_index_entry(row, index, heap);
  238. if (dtuple_datas_are_equal(ientry, entry)) {
  239. mem_heap_free(heap);
  240. return(TRUE);
  241. }
  242. }
  243. version = prev_version;
  244. }
  245. }
  246. /*********************************************************************
  247. Constructs the version of a clustered index record which a consistent
  248. read should see. We assume that the trx id stored in rec is such that
  249. the consistent read should not see rec in its present version. */
  250. ulint
  251. row_vers_build_for_consistent_read(
  252. /*===============================*/
  253. /* out: DB_SUCCESS or DB_MISSING_HISTORY */
  254. rec_t* rec, /* in: record in a clustered index; the
  255. caller must have a latch on the page; this
  256. latch locks the top of the stack of versions
  257. of this records */
  258. mtr_t* mtr, /* in: mtr holding the latch on rec */
  259. dict_index_t* index, /* in: the clustered index */
  260. read_view_t* view, /* in: the consistent read view */
  261. mem_heap_t* in_heap,/* in: memory heap from which the memory for
  262. old_vers is allocated; memory for possible
  263. intermediate versions is allocated and freed
  264. locally within the function */
  265. rec_t** old_vers)/* out, own: old version, or NULL if the
  266. record does not exist in the view, that is,
  267. it was freshly inserted afterwards */
  268. {
  269. rec_t* version;
  270. rec_t* prev_version;
  271. dulint prev_trx_id;
  272. mem_heap_t* heap;
  273. mem_heap_t* heap2;
  274. byte* buf;
  275. ulint err;
  276. ut_ad(index->type & DICT_CLUSTERED);
  277. ut_ad(mtr_memo_contains(mtr, buf_block_align(rec), MTR_MEMO_PAGE_X_FIX)
  278.     || mtr_memo_contains(mtr, buf_block_align(rec),
  279. MTR_MEMO_PAGE_S_FIX));
  280. ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));
  281. ut_ad(!read_view_sees_trx_id(view, row_get_rec_trx_id(rec, index)));
  282. rw_lock_s_lock(&(purge_sys->latch));
  283. version = rec;
  284. heap = NULL;
  285. for (;;) {
  286. heap2 = heap;
  287. heap = mem_heap_create(1024);
  288. err = trx_undo_prev_version_build(rec, mtr, version, index,
  289. heap, &prev_version);
  290. if (heap2) {
  291. mem_heap_free(heap2); /* version was stored in heap2,
  292. if heap2 != NULL */
  293. }
  294. if (err != DB_SUCCESS) {
  295. break;
  296. }
  297. if (prev_version == NULL) {
  298. /* It was a freshly inserted version */
  299. *old_vers = NULL;
  300. err = DB_SUCCESS;
  301. break;
  302. }
  303. prev_trx_id = row_get_rec_trx_id(prev_version, index);
  304. if (read_view_sees_trx_id(view, prev_trx_id)) {
  305. /* The view already sees this version: we can copy
  306. it to in_heap and return */
  307. buf = mem_heap_alloc(in_heap, rec_get_size(
  308. prev_version));
  309. *old_vers = rec_copy(buf, prev_version);
  310. err = DB_SUCCESS;
  311. break;
  312. }
  313. version = prev_version;
  314. }/* for (;;) */
  315. mem_heap_free(heap);
  316. rw_lock_s_unlock(&(purge_sys->latch));
  317. return(err);
  318. }