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

MySQL数据库

开发平台:

Visual C++

  1. /******************************************************
  2. Purge obsolete records
  3. (c) 1997 Innobase Oy
  4. Created 3/14/1997 Heikki Tuuri
  5. *******************************************************/
  6. #include "row0purge.h"
  7. #ifdef UNIV_NONINL
  8. #include "row0purge.ic"
  9. #endif
  10. #include "fsp0fsp.h"
  11. #include "mach0data.h"
  12. #include "trx0rseg.h"
  13. #include "trx0trx.h"
  14. #include "trx0roll.h"
  15. #include "trx0undo.h"
  16. #include "trx0purge.h"
  17. #include "trx0rec.h"
  18. #include "que0que.h"
  19. #include "row0row.h"
  20. #include "row0upd.h"
  21. #include "row0vers.h"
  22. #include "log0log.h"
  23. /************************************************************************
  24. Creates a purge node to a query graph. */
  25. purge_node_t*
  26. row_purge_node_create(
  27. /*==================*/
  28. /* out, own: purge node */
  29. que_thr_t* parent, /* in: parent node, i.e., a thr node */
  30. mem_heap_t* heap) /* in: memory heap where created */
  31. {
  32. purge_node_t* node;
  33. ut_ad(parent && heap);
  34. node = mem_heap_alloc(heap, sizeof(purge_node_t));
  35. node->common.type = QUE_NODE_PURGE;
  36. node->common.parent = parent;
  37. node->heap = mem_heap_create(256);
  38. return(node);
  39. }
  40. /***************************************************************
  41. Repositions the pcur in the purge node on the clustered index record,
  42. if found. */
  43. static
  44. ibool
  45. row_purge_reposition_pcur(
  46. /*======================*/
  47. /* out: TRUE if the record was found */
  48. ulint mode, /* in: latching mode */
  49. purge_node_t* node, /* in: row purge node */
  50. mtr_t* mtr) /* in: mtr */
  51. {
  52. ibool found;
  53. if (node->found_clust) {
  54. found = btr_pcur_restore_position(mode, &(node->pcur), mtr);
  55. return(found);
  56. }
  57. found = row_search_on_row_ref(&(node->pcur), mode, node->table,
  58. node->ref, mtr);
  59. node->found_clust = found;
  60. if (found) {
  61. btr_pcur_store_position(&(node->pcur), mtr);
  62. }
  63. return(found);
  64. }
  65. /***************************************************************
  66. Removes a delete marked clustered index record if possible. */
  67. static
  68. ibool
  69. row_purge_remove_clust_if_poss_low(
  70. /*===============================*/
  71. /* out: TRUE if success, or if not found, or
  72. if modified after the delete marking */
  73. purge_node_t* node, /* in: row purge node */
  74. que_thr_t* thr, /* in: query thread */
  75. ulint mode) /* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */
  76. {
  77. dict_index_t* index;
  78. btr_pcur_t* pcur;
  79. btr_cur_t* btr_cur;
  80. ibool success;
  81. ulint err;
  82. mtr_t mtr;
  83. UT_NOT_USED(thr);
  84. index = dict_table_get_first_index(node->table);
  85. pcur = &(node->pcur);
  86. btr_cur = btr_pcur_get_btr_cur(pcur);
  87. mtr_start(&mtr);
  88. success = row_purge_reposition_pcur(mode, node, &mtr);
  89. if (!success) {
  90. /* The record is already removed */
  91. btr_pcur_commit_specify_mtr(pcur, &mtr);
  92. return(TRUE);
  93. }
  94. if (0 != ut_dulint_cmp(node->roll_ptr,
  95. row_get_rec_roll_ptr(btr_pcur_get_rec(pcur), index))) {
  96. /* Someone else has modified the record later: do not remove */
  97. btr_pcur_commit_specify_mtr(pcur, &mtr);
  98. return(TRUE);
  99. }
  100. if (mode == BTR_MODIFY_LEAF) {
  101. success = btr_cur_optimistic_delete(btr_cur, &mtr);
  102. } else {
  103. ut_ad(mode == BTR_MODIFY_TREE);
  104. btr_cur_pessimistic_delete(&err, FALSE, btr_cur, &mtr);
  105. if (err == DB_SUCCESS) {
  106. success = TRUE;
  107. } else if (err == DB_OUT_OF_FILE_SPACE) {
  108. success = FALSE;
  109. } else {
  110. ut_a(0);
  111. }
  112. }
  113. btr_pcur_commit_specify_mtr(pcur, &mtr);
  114. return(success);
  115. }
  116. /***************************************************************
  117. Removes a clustered index record if it has not been modified after the delete
  118. marking. */
  119. static
  120. void
  121. row_purge_remove_clust_if_poss(
  122. /*===========================*/
  123. purge_node_t* node, /* in: row purge node */
  124. que_thr_t* thr) /* in: query thread */
  125. {
  126. ibool success;
  127. ulint n_tries = 0;
  128. /* printf("Purge: Removing clustered recordn"); */
  129. success = row_purge_remove_clust_if_poss_low(node, thr,
  130. BTR_MODIFY_LEAF);
  131. if (success) {
  132. return;
  133. }
  134. retry:
  135. success = row_purge_remove_clust_if_poss_low(node, thr,
  136. BTR_MODIFY_TREE);
  137. /* The delete operation may fail if we have little
  138. file space left: TODO: easiest to crash the database
  139. and restart with more file space */
  140. if (!success && n_tries < BTR_CUR_RETRY_DELETE_N_TIMES) {
  141. n_tries++;
  142. os_thread_sleep(BTR_CUR_RETRY_SLEEP_TIME);
  143. goto retry;
  144. }
  145. ut_a(success);
  146. }
  147.  
  148. /***************************************************************
  149. Removes a secondary index entry if possible. */
  150. static
  151. ibool
  152. row_purge_remove_sec_if_poss_low(
  153. /*=============================*/
  154. /* out: TRUE if success or if not found */
  155. purge_node_t* node, /* in: row purge node */
  156. que_thr_t* thr, /* in: query thread */
  157. dict_index_t* index, /* in: index */
  158. dtuple_t* entry, /* in: index entry */
  159. ulint mode) /* in: latch mode BTR_MODIFY_LEAF or
  160. BTR_MODIFY_TREE */
  161. {
  162. btr_pcur_t pcur;
  163. btr_cur_t* btr_cur;
  164. ibool success;
  165. ibool old_has;
  166. ibool found;
  167. ulint err;
  168. mtr_t mtr;
  169. mtr_t mtr_vers;
  170. UT_NOT_USED(thr);
  171. log_free_check();
  172. mtr_start(&mtr);
  173. found = row_search_index_entry(index, entry, mode, &pcur, &mtr);
  174. if (!found) {
  175. /* Not found */
  176. /* FIXME: printf("PURGE:........sec entry not foundn"); */
  177. /* dtuple_print(entry); */
  178. btr_pcur_close(&pcur);
  179. mtr_commit(&mtr);
  180. return(TRUE);
  181. }
  182. btr_cur = btr_pcur_get_btr_cur(&pcur);
  183. /* We should remove the index record if no later version of the row,
  184. which cannot be purged yet, requires its existence. If some requires,
  185. we should do nothing. */
  186. mtr_start(&mtr_vers);
  187. success = row_purge_reposition_pcur(BTR_SEARCH_LEAF, node, &mtr_vers);
  188. if (success) {
  189. old_has = row_vers_old_has_index_entry(TRUE,
  190. btr_pcur_get_rec(&(node->pcur)),
  191. &mtr_vers, index, entry);
  192. }
  193. btr_pcur_commit_specify_mtr(&(node->pcur), &mtr_vers);
  194. if (!success || !old_has) {
  195. /* Remove the index record */
  196. if (mode == BTR_MODIFY_LEAF) {
  197. success = btr_cur_optimistic_delete(btr_cur, &mtr);
  198. } else {
  199. ut_ad(mode == BTR_MODIFY_TREE);
  200. btr_cur_pessimistic_delete(&err, FALSE, btr_cur, &mtr);
  201. if (err == DB_SUCCESS) {
  202. success = TRUE;
  203. } else if (err == DB_OUT_OF_FILE_SPACE) {
  204. success = FALSE;
  205. } else {
  206. ut_a(0);
  207. }
  208. }
  209. }
  210. btr_pcur_close(&pcur);
  211. mtr_commit(&mtr);
  212. return(success);
  213. }
  214. /***************************************************************
  215. Removes a secondary index entry if possible. */
  216. UNIV_INLINE
  217. void
  218. row_purge_remove_sec_if_poss(
  219. /*=========================*/
  220. purge_node_t* node, /* in: row purge node */
  221. que_thr_t* thr, /* in: query thread */
  222. dict_index_t* index, /* in: index */
  223. dtuple_t* entry) /* in: index entry */
  224. {
  225. ibool success;
  226. ulint n_tries = 0;
  227. /* printf("Purge: Removing secondary recordn"); */
  228. success = row_purge_remove_sec_if_poss_low(node, thr, index, entry,
  229. BTR_MODIFY_LEAF);
  230. if (success) {
  231. return;
  232. }
  233. retry:
  234. success = row_purge_remove_sec_if_poss_low(node, thr, index, entry,
  235. BTR_MODIFY_TREE);
  236. /* The delete operation may fail if we have little
  237. file space left: TODO: easiest to crash the database
  238. and restart with more file space */
  239. if (!success && n_tries < BTR_CUR_RETRY_DELETE_N_TIMES) {
  240. n_tries++;
  241. os_thread_sleep(BTR_CUR_RETRY_SLEEP_TIME);
  242. goto retry;
  243. }
  244. ut_a(success);
  245. }
  246. /***************************************************************
  247. Purges a delete marking of a record. */
  248. static
  249. void
  250. row_purge_del_mark(
  251. /*===============*/
  252. purge_node_t* node, /* in: row purge node */
  253. que_thr_t* thr) /* in: query thread */
  254. {
  255. mem_heap_t* heap;
  256. dtuple_t* entry;
  257. dict_index_t* index;
  258. ut_ad(node && thr);
  259. heap = mem_heap_create(1024);
  260. while (node->index != NULL) {
  261. index = node->index;
  262. /* Build the index entry */
  263. entry = row_build_index_entry(node->row, index, heap);
  264. row_purge_remove_sec_if_poss(node, thr, index, entry);
  265. node->index = dict_table_get_next_index(node->index);
  266. }
  267. mem_heap_free(heap);
  268. row_purge_remove_clust_if_poss(node, thr);
  269. }
  270. /***************************************************************
  271. Purges an update of an existing record. */
  272. static
  273. void
  274. row_purge_upd_exist(
  275. /*================*/
  276. purge_node_t* node, /* in: row purge node */
  277. que_thr_t* thr) /* in: query thread */
  278. {
  279. mem_heap_t* heap;
  280. dtuple_t* entry;
  281. dict_index_t* index;
  282. ut_ad(node && thr);
  283. heap = mem_heap_create(1024);
  284. while (node->index != NULL) {
  285. index = node->index;
  286. if (row_upd_changes_ord_field(NULL, node->index,
  287. node->update)) {
  288. /* Build the older version of the index entry */
  289. entry = row_build_index_entry(node->row, index, heap);
  290. row_purge_remove_sec_if_poss(node, thr, index, entry);
  291. }
  292. node->index = dict_table_get_next_index(node->index);
  293. }
  294. mem_heap_free(heap);
  295. }
  296. /***************************************************************
  297. Parses the row reference and other info in a modify undo log record. */
  298. static
  299. ibool
  300. row_purge_parse_undo_rec(
  301. /*=====================*/
  302. /* out: TRUE if purge operation required */
  303. purge_node_t* node, /* in: row undo node */
  304. que_thr_t* thr) /* in: query thread */
  305. {
  306. dict_index_t* clust_index;
  307. byte* ptr;
  308. dulint undo_no;
  309. dulint table_id;
  310. dulint trx_id;
  311. dulint roll_ptr;
  312. ulint info_bits;
  313. ulint type;
  314. ulint cmpl_info;
  315. ut_ad(node && thr);
  316. ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &cmpl_info,
  317. &undo_no, &table_id);
  318. node->rec_type = type;
  319. if (type == TRX_UNDO_UPD_DEL_REC) {
  320. return(FALSE);
  321. }     
  322. ptr = trx_undo_update_rec_get_sys_cols(ptr, &trx_id, &roll_ptr,
  323. &info_bits);
  324. node->table = NULL;
  325. if (type == TRX_UNDO_UPD_EXIST_REC
  326. && cmpl_info & UPD_NODE_NO_ORD_CHANGE) {
  327.      /* Purge requires no changes to indexes: we may return */
  328.      return(FALSE);
  329. }
  330. /* NOTE that the table has to be explicitly released later */
  331. /* TODO: currently nothing prevents dropping of table when purge
  332. is accessing it! */
  333.   mutex_enter(&(dict_sys->mutex));
  334. node->table = dict_table_get_on_id_low(table_id, thr_get_trx(thr));
  335. rw_lock_x_lock(&(purge_sys->purge_is_running));
  336.   mutex_exit(&(dict_sys->mutex));
  337. if (node->table == NULL) {
  338. /* The table has been dropped: no need to do purge */
  339. rw_lock_x_unlock(&(purge_sys->purge_is_running));
  340. return(FALSE);
  341. }
  342. clust_index = dict_table_get_first_index(node->table);
  343. ptr = trx_undo_rec_get_row_ref(ptr, clust_index, &(node->ref),
  344. node->heap);
  345. ptr = trx_undo_update_rec_get_update(ptr, clust_index, type, trx_id,
  346. roll_ptr, info_bits, node->heap,
  347. &(node->update));
  348. /* Read to the partial row the fields that occur in indexes */
  349. ptr = trx_undo_rec_get_partial_row(ptr, clust_index, &(node->row),
  350. node->heap);
  351. return(TRUE);
  352. }
  353. /***************************************************************
  354. Fetches an undo log record and does the purge for the recorded operation.
  355. If none left, or the current purge completed, returns the control to the
  356. parent node, which is always a query thread node. */
  357. static
  358. ulint
  359. row_purge(
  360. /*======*/
  361. /* out: DB_SUCCESS if operation successfully
  362. completed, else error code */
  363. purge_node_t* node, /* in: row purge node */
  364. que_thr_t* thr) /* in: query thread */
  365. {
  366. dulint roll_ptr;
  367. ibool purge_needed;
  368. ut_ad(node && thr);
  369. node->undo_rec = trx_purge_fetch_next_rec(&roll_ptr,
  370. &(node->reservation),
  371. node->heap);
  372. if (!node->undo_rec) {
  373. /* Purge completed for this query thread */
  374. thr->run_node = que_node_get_parent(node);
  375. return(DB_SUCCESS);
  376. }
  377. node->roll_ptr = roll_ptr;
  378. if (node->undo_rec == &trx_purge_dummy_rec) {
  379. purge_needed = FALSE;
  380. } else {
  381. purge_needed = row_purge_parse_undo_rec(node, thr);
  382. }
  383. if (purge_needed) {
  384. node->found_clust = FALSE;
  385. node->index = dict_table_get_next_index(
  386. dict_table_get_first_index(node->table));
  387. if (node->rec_type == TRX_UNDO_UPD_EXIST_REC) {
  388. row_purge_upd_exist(node, thr);
  389. } else {
  390. ut_ad(node->rec_type == TRX_UNDO_DEL_MARK_REC);
  391. row_purge_del_mark(node, thr);
  392. }
  393. if (node->found_clust) {
  394. btr_pcur_close(&(node->pcur));
  395. }
  396. rw_lock_x_unlock(&(purge_sys->purge_is_running));
  397. }
  398. /* Do some cleanup */
  399. trx_purge_rec_release(node->reservation);
  400. mem_heap_empty(node->heap);
  401. thr->run_node = node;
  402. return(DB_SUCCESS);
  403. }
  404. /***************************************************************
  405. Does the purge operation for a single undo log record. This is a high-level
  406. function used in an SQL execution graph. */
  407. que_thr_t*
  408. row_purge_step(
  409. /*===========*/
  410. /* out: query thread to run next or NULL */
  411. que_thr_t* thr) /* in: query thread */
  412. {
  413. purge_node_t* node;
  414. ulint err;
  415. ut_ad(thr);
  416. node = thr->run_node;
  417. ut_ad(que_node_get_type(node) == QUE_NODE_PURGE);
  418. err = row_purge(node, thr);
  419. ut_ad(err == DB_SUCCESS);
  420. return(thr);