~ubuntu-branches/ubuntu/trusty/drizzle/trusty

« back to all changes in this revision

Viewing changes to plugin/innobase/row/row0uins.c

  • Committer: Bazaar Package Importer
  • Author(s): Monty Taylor
  • Date: 2010-03-18 12:12:31 UTC
  • Revision ID: james.westby@ubuntu.com-20100318121231-k6g1xe6cshbwa0f8
Tags: upstream-2010.03.1347
ImportĀ upstreamĀ versionĀ 2010.03.1347

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************
 
2
 
 
3
Copyright (c) 1997, 2009, 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., 59 Temple
 
15
Place, Suite 330, Boston, MA 02111-1307 USA
 
16
 
 
17
*****************************************************************************/
 
18
 
 
19
/**************************************************//**
 
20
@file row/row0uins.c
 
21
Fresh insert undo
 
22
 
 
23
Created 2/25/1997 Heikki Tuuri
 
24
*******************************************************/
 
25
 
 
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
Removes a clustered index record. The pcur in node was positioned on the
 
51
record, now it is detached.
 
52
@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
 
53
static
 
54
ulint
 
55
row_undo_ins_remove_clust_rec(
 
56
/*==========================*/
 
57
        undo_node_t*    node)   /*!< in: undo node */
 
58
{
 
59
        btr_cur_t*      btr_cur;
 
60
        ibool           success;
 
61
        ulint           err;
 
62
        ulint           n_tries         = 0;
 
63
        mtr_t           mtr;
 
64
 
 
65
        mtr_start(&mtr);
 
66
 
 
67
        success = btr_pcur_restore_position(BTR_MODIFY_LEAF, &(node->pcur),
 
68
                                            &mtr);
 
69
        ut_a(success);
 
70
 
 
71
        if (ut_dulint_cmp(node->table->id, DICT_INDEXES_ID) == 0) {
 
72
                ut_ad(node->trx->dict_operation_lock_mode == RW_X_LATCH);
 
73
 
 
74
                /* Drop the index tree associated with the row in
 
75
                SYS_INDEXES table: */
 
76
 
 
77
                dict_drop_index_tree(btr_pcur_get_rec(&(node->pcur)), &mtr);
 
78
 
 
79
                mtr_commit(&mtr);
 
80
 
 
81
                mtr_start(&mtr);
 
82
 
 
83
                success = btr_pcur_restore_position(BTR_MODIFY_LEAF,
 
84
                                                    &(node->pcur), &mtr);
 
85
                ut_a(success);
 
86
        }
 
87
 
 
88
        btr_cur = btr_pcur_get_btr_cur(&(node->pcur));
 
89
 
 
90
        success = btr_cur_optimistic_delete(btr_cur, &mtr);
 
91
 
 
92
        btr_pcur_commit_specify_mtr(&(node->pcur), &mtr);
 
93
 
 
94
        if (success) {
 
95
                trx_undo_rec_release(node->trx, node->undo_no);
 
96
 
 
97
                return(DB_SUCCESS);
 
98
        }
 
99
retry:
 
100
        /* If did not succeed, try pessimistic descent to tree */
 
101
        mtr_start(&mtr);
 
102
 
 
103
        success = btr_pcur_restore_position(BTR_MODIFY_TREE,
 
104
                                            &(node->pcur), &mtr);
 
105
        ut_a(success);
 
106
 
 
107
        btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
 
108
                                   trx_is_recv(node->trx)
 
109
                                   ? RB_RECOVERY
 
110
                                   : RB_NORMAL, &mtr);
 
111
 
 
112
        /* The delete operation may fail if we have little
 
113
        file space left: TODO: easiest to crash the database
 
114
        and restart with more file space */
 
115
 
 
116
        if (err == DB_OUT_OF_FILE_SPACE
 
117
            && n_tries < BTR_CUR_RETRY_DELETE_N_TIMES) {
 
118
 
 
119
                btr_pcur_commit_specify_mtr(&(node->pcur), &mtr);
 
120
 
 
121
                n_tries++;
 
122
 
 
123
                os_thread_sleep(BTR_CUR_RETRY_SLEEP_TIME);
 
124
 
 
125
                goto retry;
 
126
        }
 
127
 
 
128
        btr_pcur_commit_specify_mtr(&(node->pcur), &mtr);
 
129
 
 
130
        trx_undo_rec_release(node->trx, node->undo_no);
 
131
 
 
132
        return(err);
 
133
}
 
134
 
 
135
/***************************************************************//**
 
136
Removes a secondary index entry if found.
 
137
@return DB_SUCCESS, DB_FAIL, or DB_OUT_OF_FILE_SPACE */
 
138
static
 
139
ulint
 
140
row_undo_ins_remove_sec_low(
 
141
/*========================*/
 
142
        ulint           mode,   /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
 
143
                                depending on whether we wish optimistic or
 
144
                                pessimistic descent down the index tree */
 
145
        dict_index_t*   index,  /*!< in: index */
 
146
        dtuple_t*       entry)  /*!< in: index entry to remove */
 
147
{
 
148
        btr_pcur_t      pcur;
 
149
        btr_cur_t*      btr_cur;
 
150
        ibool           found;
 
151
        ibool           success;
 
152
        ulint           err;
 
153
        mtr_t           mtr;
 
154
 
 
155
        log_free_check();
 
156
        mtr_start(&mtr);
 
157
 
 
158
        found = row_search_index_entry(index, entry, mode, &pcur, &mtr);
 
159
 
 
160
        btr_cur = btr_pcur_get_btr_cur(&pcur);
 
161
 
 
162
        if (!found) {
 
163
                /* Not found */
 
164
 
 
165
                btr_pcur_close(&pcur);
 
166
                mtr_commit(&mtr);
 
167
 
 
168
                return(DB_SUCCESS);
 
169
        }
 
170
 
 
171
        if (mode == BTR_MODIFY_LEAF) {
 
172
                success = btr_cur_optimistic_delete(btr_cur, &mtr);
 
173
 
 
174
                if (success) {
 
175
                        err = DB_SUCCESS;
 
176
                } else {
 
177
                        err = DB_FAIL;
 
178
                }
 
179
        } else {
 
180
                ut_ad(mode == BTR_MODIFY_TREE);
 
181
 
 
182
                /* No need to distinguish RB_RECOVERY here, because we
 
183
                are deleting a secondary index record: the distinction
 
184
                between RB_NORMAL and RB_RECOVERY only matters when
 
185
                deleting a record that contains externally stored
 
186
                columns. */
 
187
                ut_ad(!dict_index_is_clust(index));
 
188
                btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
 
189
                                           RB_NORMAL, &mtr);
 
190
        }
 
191
 
 
192
        btr_pcur_close(&pcur);
 
193
        mtr_commit(&mtr);
 
194
 
 
195
        return(err);
 
196
}
 
197
 
 
198
/***************************************************************//**
 
199
Removes a secondary index entry from the index if found. Tries first
 
200
optimistic, then pessimistic descent down the tree.
 
201
@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
 
202
static
 
203
ulint
 
204
row_undo_ins_remove_sec(
 
205
/*====================*/
 
206
        dict_index_t*   index,  /*!< in: index */
 
207
        dtuple_t*       entry)  /*!< in: index entry to insert */
 
208
{
 
209
        ulint   err;
 
210
        ulint   n_tries = 0;
 
211
 
 
212
        /* Try first optimistic descent to the B-tree */
 
213
 
 
214
        err = row_undo_ins_remove_sec_low(BTR_MODIFY_LEAF, index, entry);
 
215
 
 
216
        if (err == DB_SUCCESS) {
 
217
 
 
218
                return(err);
 
219
        }
 
220
 
 
221
        /* Try then pessimistic descent to the B-tree */
 
222
retry:
 
223
        err = row_undo_ins_remove_sec_low(BTR_MODIFY_TREE, index, entry);
 
224
 
 
225
        /* The delete operation may fail if we have little
 
226
        file space left: TODO: easiest to crash the database
 
227
        and restart with more file space */
 
228
 
 
229
        if (err != DB_SUCCESS && n_tries < BTR_CUR_RETRY_DELETE_N_TIMES) {
 
230
 
 
231
                n_tries++;
 
232
 
 
233
                os_thread_sleep(BTR_CUR_RETRY_SLEEP_TIME);
 
234
 
 
235
                goto retry;
 
236
        }
 
237
 
 
238
        return(err);
 
239
}
 
240
 
 
241
/***********************************************************//**
 
242
Parses the row reference and other info in a fresh insert undo record. */
 
243
static
 
244
void
 
245
row_undo_ins_parse_undo_rec(
 
246
/*========================*/
 
247
        undo_node_t*    node)   /*!< in/out: row undo node */
 
248
{
 
249
        dict_index_t*   clust_index;
 
250
        byte*           ptr;
 
251
        undo_no_t       undo_no;
 
252
        dulint          table_id;
 
253
        ulint           type;
 
254
        ulint           dummy;
 
255
        ibool           dummy_extern;
 
256
 
 
257
        ut_ad(node);
 
258
 
 
259
        ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &dummy,
 
260
                                    &dummy_extern, &undo_no, &table_id);
 
261
        ut_ad(type == TRX_UNDO_INSERT_REC);
 
262
        node->rec_type = type;
 
263
 
 
264
        node->update = NULL;
 
265
        node->table = dict_table_get_on_id(table_id, node->trx);
 
266
 
 
267
        /* Skip the UNDO if we can't find the table or the .ibd file. */
 
268
        if (UNIV_UNLIKELY(node->table == NULL)) {
 
269
        } else if (UNIV_UNLIKELY(node->table->ibd_file_missing)) {
 
270
                node->table = NULL;
 
271
        } else {
 
272
                clust_index = dict_table_get_first_index(node->table);
 
273
 
 
274
                if (clust_index != NULL) {
 
275
                        ptr = trx_undo_rec_get_row_ref(
 
276
                                ptr, clust_index, &node->ref, node->heap);
 
277
                } else {
 
278
                        ut_print_timestamp(stderr);
 
279
                        fprintf(stderr, "  InnoDB: table ");
 
280
                        ut_print_name(stderr, node->trx, TRUE,
 
281
                                      node->table->name);
 
282
                        fprintf(stderr, " has no indexes, "
 
283
                                "ignoring the table\n");
 
284
 
 
285
                        node->table = NULL;
 
286
                }
 
287
        }
 
288
}
 
289
 
 
290
/***********************************************************//**
 
291
Undoes a fresh insert of a row to a table. A fresh insert means that
 
292
the same clustered index unique key did not have any record, even delete
 
293
marked, at the time of the insert.  InnoDB is eager in a rollback:
 
294
if it figures out that an index record will be removed in the purge
 
295
anyway, it will remove it in the rollback.
 
296
@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
 
297
UNIV_INTERN
 
298
ulint
 
299
row_undo_ins(
 
300
/*=========*/
 
301
        undo_node_t*    node)   /*!< in: row undo node */
 
302
{
 
303
        ut_ad(node);
 
304
        ut_ad(node->state == UNDO_NODE_INSERT);
 
305
 
 
306
        row_undo_ins_parse_undo_rec(node);
 
307
 
 
308
        if (!node->table || !row_undo_search_clust_to_pcur(node)) {
 
309
                trx_undo_rec_release(node->trx, node->undo_no);
 
310
 
 
311
                return(DB_SUCCESS);
 
312
        }
 
313
 
 
314
        /* Iterate over all the indexes and undo the insert.*/
 
315
 
 
316
        /* Skip the clustered index (the first index) */
 
317
        node->index = dict_table_get_next_index(
 
318
                dict_table_get_first_index(node->table));
 
319
 
 
320
        while (node->index != NULL) {
 
321
                dtuple_t*       entry;
 
322
                ulint           err;
 
323
 
 
324
                entry = row_build_index_entry(node->row, node->ext,
 
325
                                              node->index, node->heap);
 
326
                if (UNIV_UNLIKELY(!entry)) {
 
327
                        /* The database must have crashed after
 
328
                        inserting a clustered index record but before
 
329
                        writing all the externally stored columns of
 
330
                        that record.  Because secondary index entries
 
331
                        are inserted after the clustered index record,
 
332
                        we may assume that the secondary index record
 
333
                        does not exist.  However, this situation may
 
334
                        only occur during the rollback of incomplete
 
335
                        transactions. */
 
336
                        ut_a(trx_is_recv(node->trx));
 
337
                } else {
 
338
                        err = row_undo_ins_remove_sec(node->index, entry);
 
339
 
 
340
                        if (err != DB_SUCCESS) {
 
341
 
 
342
                                return(err);
 
343
                        }
 
344
                }
 
345
 
 
346
                node->index = dict_table_get_next_index(node->index);
 
347
        }
 
348
 
 
349
        return(row_undo_ins_remove_clust_rec(node));
 
350
}