Drizzled Public API Documentation

row0uins.cc
1 /*****************************************************************************
2 
3 Copyright (C) 1997, 2010, Innobase Oy. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free Software
7 Foundation; version 2 of the License.
8 
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 
13 You should have received a copy of the GNU General Public License along with
14 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15 St, Fifth Floor, Boston, MA 02110-1301 USA
16 
17 *****************************************************************************/
18 
19 /**************************************************/
26 #include "row0uins.h"
27 
28 #ifdef UNIV_NONINL
29 #include "row0uins.ic"
30 #endif
31 
32 #include "dict0dict.h"
33 #include "dict0boot.h"
34 #include "dict0crea.h"
35 #include "trx0undo.h"
36 #include "trx0roll.h"
37 #include "btr0btr.h"
38 #include "mach0data.h"
39 #include "row0undo.h"
40 #include "row0vers.h"
41 #include "trx0trx.h"
42 #include "trx0rec.h"
43 #include "row0row.h"
44 #include "row0upd.h"
45 #include "que0que.h"
46 #include "ibuf0ibuf.h"
47 #include "log0log.h"
48 
49 /*************************************************************************
50 IMPORTANT NOTE: Any operation that generates redo MUST check that there
51 is enough space in the redo log before for that operation. This is
52 done by calling log_free_check(). The reason for checking the
53 availability of the redo log space before the start of the operation is
54 that we MUST not hold any synchonization objects when performing the
55 check.
56 If you make a change in this module make sure that no codepath is
57 introduced where a call to log_free_check() is bypassed. */
58 
59 /*************************************************************************
60 IMPORTANT NOTE: Any operation that generates redo MUST check that there
61 is enough space in the redo log before for that operation. This is
62 done by calling log_free_check(). The reason for checking the
63 availability of the redo log space before the start of the operation is
64 that we MUST not hold any synchonization objects when performing the
65 check.
66 If you make a change in this module make sure that no codepath is
67 introduced where a call to log_free_check() is bypassed. */
68 
69 /***************************************************************/
73 static
74 ulint
75 row_undo_ins_remove_clust_rec(
76 /*==========================*/
77  undo_node_t* node)
78 {
79  btr_cur_t* btr_cur;
80  ibool success;
81  ulint err;
82  ulint n_tries = 0;
83  mtr_t mtr;
84 
85  mtr_start(&mtr);
86 
87  success = btr_pcur_restore_position(BTR_MODIFY_LEAF, &(node->pcur),
88  &mtr);
89  ut_a(success);
90 
91  if (node->table->id == DICT_INDEXES_ID) {
92  ut_ad(node->trx->dict_operation_lock_mode == RW_X_LATCH);
93 
94  /* Drop the index tree associated with the row in
95  SYS_INDEXES table: */
96 
97  dict_drop_index_tree(btr_pcur_get_rec(&(node->pcur)), &mtr);
98 
99  mtr_commit(&mtr);
100 
101  mtr_start(&mtr);
102 
103  success = btr_pcur_restore_position(BTR_MODIFY_LEAF,
104  &(node->pcur), &mtr);
105  ut_a(success);
106  }
107 
108  btr_cur = btr_pcur_get_btr_cur(&(node->pcur));
109 
110  success = btr_cur_optimistic_delete(btr_cur, &mtr);
111 
112  btr_pcur_commit_specify_mtr(&(node->pcur), &mtr);
113 
114  if (success) {
115  trx_undo_rec_release(node->trx, node->undo_no);
116 
117  return(DB_SUCCESS);
118  }
119 retry:
120  /* If did not succeed, try pessimistic descent to tree */
121  mtr_start(&mtr);
122 
123  success = btr_pcur_restore_position(BTR_MODIFY_TREE,
124  &(node->pcur), &mtr);
125  ut_a(success);
126 
127  btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
128  trx_is_recv(node->trx)
129  ? RB_RECOVERY
130  : RB_NORMAL, &mtr);
131 
132  /* The delete operation may fail if we have little
133  file space left: TODO: easiest to crash the database
134  and restart with more file space */
135 
136  if (err == DB_OUT_OF_FILE_SPACE
137  && n_tries < BTR_CUR_RETRY_DELETE_N_TIMES) {
138 
139  btr_pcur_commit_specify_mtr(&(node->pcur), &mtr);
140 
141  n_tries++;
142 
144 
145  goto retry;
146  }
147 
148  btr_pcur_commit_specify_mtr(&(node->pcur), &mtr);
149 
150  trx_undo_rec_release(node->trx, node->undo_no);
151 
152  return(err);
153 }
154 
155 /***************************************************************/
158 static
159 ulint
160 row_undo_ins_remove_sec_low(
161 /*========================*/
162  ulint mode,
165  dict_index_t* index,
166  dtuple_t* entry)
167 {
168  btr_pcur_t pcur;
169  btr_cur_t* btr_cur;
170  ulint err;
171  mtr_t mtr;
172  enum row_search_result search_result;
173 
174  mtr_start(&mtr);
175 
176  btr_cur = btr_pcur_get_btr_cur(&pcur);
177 
178  ut_ad(mode == BTR_MODIFY_TREE || mode == BTR_MODIFY_LEAF);
179 
180  search_result = row_search_index_entry(index, entry, mode,
181  &pcur, &mtr);
182 
183  switch (search_result) {
184  case ROW_NOT_FOUND:
185  err = DB_SUCCESS;
186  goto func_exit;
187  case ROW_FOUND:
188  break;
189  case ROW_BUFFERED:
190  case ROW_NOT_DELETED_REF:
191  /* These are invalid outcomes, because the mode passed
192  to row_search_index_entry() did not include any of the
193  flags BTR_INSERT, BTR_DELETE, or BTR_DELETE_MARK. */
194  ut_error;
195  }
196 
197  if (mode == BTR_MODIFY_LEAF) {
198  err = btr_cur_optimistic_delete(btr_cur, &mtr)
199  ? DB_SUCCESS : DB_FAIL;
200  } else {
201  ut_ad(mode == BTR_MODIFY_TREE);
202 
203  /* No need to distinguish RB_RECOVERY here, because we
204  are deleting a secondary index record: the distinction
205  between RB_NORMAL and RB_RECOVERY only matters when
206  deleting a record that contains externally stored
207  columns. */
208  ut_ad(!dict_index_is_clust(index));
209  btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
210  RB_NORMAL, &mtr);
211  }
212 func_exit:
213  btr_pcur_close(&pcur);
214  mtr_commit(&mtr);
215 
216  return(err);
217 }
218 
219 /***************************************************************/
223 static
224 ulint
225 row_undo_ins_remove_sec(
226 /*====================*/
227  dict_index_t* index,
228  dtuple_t* entry)
229 {
230  ulint err;
231  ulint n_tries = 0;
232 
233  /* Try first optimistic descent to the B-tree */
234 
235  err = row_undo_ins_remove_sec_low(BTR_MODIFY_LEAF, index, entry);
236 
237  if (err == DB_SUCCESS) {
238 
239  return(err);
240  }
241 
242  /* Try then pessimistic descent to the B-tree */
243 retry:
244  err = row_undo_ins_remove_sec_low(BTR_MODIFY_TREE, index, entry);
245 
246  /* The delete operation may fail if we have little
247  file space left: TODO: easiest to crash the database
248  and restart with more file space */
249 
250  if (err != DB_SUCCESS && n_tries < BTR_CUR_RETRY_DELETE_N_TIMES) {
251 
252  n_tries++;
253 
255 
256  goto retry;
257  }
258 
259  return(err);
260 }
261 
262 /***********************************************************/
264 static
265 void
266 row_undo_ins_parse_undo_rec(
267 /*========================*/
268  undo_node_t* node)
269 {
270  dict_index_t* clust_index;
271  byte* ptr;
272  undo_no_t undo_no;
273  table_id_t table_id;
274  ulint type;
275  ulint dummy;
276  ibool dummy_extern;
277 
278  ut_ad(node);
279 
280  ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &dummy,
281  &dummy_extern, &undo_no, &table_id);
282  ut_ad(type == TRX_UNDO_INSERT_REC);
283  node->rec_type = type;
284 
285  node->update = NULL;
286  node->table = dict_table_get_on_id(table_id, node->trx);
287 
288  /* Skip the UNDO if we can't find the table or the .ibd file. */
289  if (UNIV_UNLIKELY(node->table == NULL)) {
290  } else if (UNIV_UNLIKELY(node->table->ibd_file_missing)) {
291  node->table = NULL;
292  } else {
293  clust_index = dict_table_get_first_index(node->table);
294 
295  if (clust_index != NULL) {
297  ptr, clust_index, &node->ref, node->heap);
298  } else {
299  ut_print_timestamp(stderr);
300  fprintf(stderr, " InnoDB: table ");
301  ut_print_name(stderr, node->trx, TRUE,
302  node->table->name);
303  fprintf(stderr, " has no indexes, "
304  "ignoring the table\n");
305 
306  node->table = NULL;
307  }
308  }
309 }
310 
311 /***********************************************************/
318 UNIV_INTERN
319 ulint
321 /*=========*/
322  undo_node_t* node)
323 {
324  ut_ad(node);
325  ut_ad(node->state == UNDO_NODE_INSERT);
326 
327  row_undo_ins_parse_undo_rec(node);
328 
329  if (!node->table || !row_undo_search_clust_to_pcur(node)) {
330  trx_undo_rec_release(node->trx, node->undo_no);
331 
332  return(DB_SUCCESS);
333  }
334 
335  /* Iterate over all the indexes and undo the insert.*/
336 
337  /* Skip the clustered index (the first index) */
338  node->index = dict_table_get_next_index(
339  dict_table_get_first_index(node->table));
340 
341  while (node->index != NULL) {
342  dtuple_t* entry;
343  ulint err;
344 
345  entry = row_build_index_entry(node->row, node->ext,
346  node->index, node->heap);
347  if (UNIV_UNLIKELY(!entry)) {
348  /* The database must have crashed after
349  inserting a clustered index record but before
350  writing all the externally stored columns of
351  that record. Because secondary index entries
352  are inserted after the clustered index record,
353  we may assume that the secondary index record
354  does not exist. However, this situation may
355  only occur during the rollback of incomplete
356  transactions. */
357  ut_a(trx_is_recv(node->trx));
358  } else {
359  log_free_check();
360  err = row_undo_ins_remove_sec(node->index, entry);
361 
362  if (err != DB_SUCCESS) {
363 
364  return(err);
365  }
366  }
367 
368  node->index = dict_table_get_next_index(node->index);
369  }
370 
371  log_free_check();
372  return(row_undo_ins_remove_clust_rec(node));
373 }
UNIV_INTERN byte * trx_undo_rec_get_row_ref(byte *ptr, dict_index_t *index, dtuple_t **ref, mem_heap_t *heap)
Definition: trx0rec.cc:380
dict_index_t * index
Definition: row0undo.h:131
UNIV_INTERN ibool trx_is_recv(const trx_t *trx)
Definition: trx0roll.cc:387
UNIV_INTERN ibool btr_cur_optimistic_delete(btr_cur_t *cursor, mtr_t *mtr)
Definition: btr0cur.cc:2906
trx_undo_rec_t * undo_rec
Definition: row0undo.h:108
UNIV_INTERN dtuple_t * row_build_index_entry(const dtuple_t *row, row_ext_t *ext, dict_index_t *index, mem_heap_t *heap)
Definition: row0row.cc:87
UNIV_INTERN dict_table_t * dict_table_get_on_id(table_id_t table_id, trx_t *trx)
Definition: dict0dict.cc:623
UNIV_INLINE void btr_pcur_close(btr_pcur_t *cursor)
row_ext_t * ext
Definition: row0undo.h:126
mem_heap_t * heap
Definition: row0undo.h:133
dtuple_t * row
Definition: row0undo.h:124
UNIV_INTERN void mtr_commit(mtr_t *mtr) __attribute__((nonnull))
Definition: mtr0mtr.cc:247
UNIV_INLINE void log_free_check(void)
row_search_result
Definition: row0row.h:263
UNIV_INTERN void os_thread_sleep(ulint tm)
Definition: os0thread.cc:265
table_id_t id
Definition: dict0mem.h:477
UNIV_INTERN enum row_search_result row_search_index_entry(dict_index_t *index, const dtuple_t *entry, ulint mode, btr_pcur_t *pcur, mtr_t *mtr)
Definition: row0row.cc:740
UNIV_INLINE ulint dict_index_is_clust(const dict_index_t *index) __attribute__((pure))
dict_table_t * table
Definition: row0undo.h:119
ulint dict_operation_lock_mode
Definition: trx0trx.h:530
#define ut_a(EXPR)
Definition: ut0dbg.h:105
UNIV_INTERN void ut_print_name(FILE *f, struct trx_struct *trx, ibool table_id, const char *name)
Definition: ut0ut.cc:528
UNIV_INTERN ibool btr_cur_pessimistic_delete(ulint *err, ibool has_reserved_extents, btr_cur_t *cursor, enum trx_rb_ctx rb_ctx, mtr_t *mtr)
Definition: btr0cur.cc:2995
#define ut_ad(EXPR)
Definition: ut0dbg.h:127
unsigned ibd_file_missing
Definition: dict0mem.h:490
#define ut_error
Definition: ut0dbg.h:115
dtuple_t * ref
Definition: row0undo.h:123
btr_pcur_t pcur
Definition: row0undo.h:117
UNIV_INTERN void trx_undo_rec_release(trx_t *trx, undo_no_t undo_no)
Definition: trx0roll.cc:1046
UNIV_INTERN void ut_print_timestamp(FILE *file)
Definition: ut0ut.cc:247
UNIV_INLINE void mtr_start(mtr_t *mtr) __attribute__((nonnull))
#define BTR_CUR_RETRY_DELETE_N_TIMES
Definition: btr0cur.h:775
undo_no_t undo_no
Definition: row0undo.h:109
UNIV_INTERN ibool row_undo_search_clust_to_pcur(undo_node_t *node)
Definition: row0undo.cc:162
UNIV_INTERN ulint row_undo_ins(undo_node_t *node)
Definition: row0uins.cc:320
ib_id_t undo_no_t
Definition: trx0types.h:89
#define BTR_CUR_RETRY_SLEEP_TIME
Definition: btr0cur.h:779
UNIV_INLINE void btr_pcur_commit_specify_mtr(btr_pcur_t *pcur, mtr_t *mtr)
UNIV_INTERN byte * trx_undo_rec_get_pars(trx_undo_rec_t *undo_rec, ulint *type, ulint *cmpl_info, ibool *updated_extern, undo_no_t *undo_no, table_id_t *table_id)
Definition: trx0rec.cc:282
upd_t * update
Definition: row0undo.h:121
UNIV_INTERN void dict_drop_index_tree(rec_t *rec, mtr_t *mtr)
Definition: dict0crea.cc:680
enum undo_exec state
Definition: row0undo.h:105