~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

Removing global errbuff and cleaning up two remaining instances that referenced it.

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
Fresh insert undo
 
21
 
 
22
Created 2/25/1997 Heikki Tuuri
 
23
*******************************************************/
 
24
 
 
25
#include "row0uins.h"
 
26
 
 
27
#ifdef UNIV_NONINL
 
28
#include "row0uins.ic"
 
29
#endif
 
30
 
 
31
#include "dict0dict.h"
 
32
#include "dict0boot.h"
 
33
#include "dict0crea.h"
 
34
#include "trx0undo.h"
 
35
#include "trx0roll.h"
 
36
#include "btr0btr.h"
 
37
#include "mach0data.h"
 
38
#include "row0undo.h"
 
39
#include "row0vers.h"
 
40
#include "trx0trx.h"
 
41
#include "trx0rec.h"
 
42
#include "row0row.h"
 
43
#include "row0upd.h"
 
44
#include "que0que.h"
 
45
#include "ibuf0ibuf.h"
 
46
#include "log0log.h"
 
47
 
 
48
/*******************************************************************
 
49
Removes a clustered index record. The pcur in node was positioned on the
 
50
record, now it is detached. */
 
51
static
 
52
ulint
 
53
row_undo_ins_remove_clust_rec(
 
54
/*==========================*/
 
55
                                /* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
 
56
        undo_node_t*    node)   /* in: undo node */
 
57
{
 
58
        btr_cur_t*      btr_cur;
 
59
        ibool           success;
 
60
        ulint           err;
 
61
        ulint           n_tries         = 0;
 
62
        mtr_t           mtr;
 
63
 
 
64
        mtr_start(&mtr);
 
65
 
 
66
        success = btr_pcur_restore_position(BTR_MODIFY_LEAF, &(node->pcur),
 
67
                                            &mtr);
 
68
        ut_a(success);
 
69
 
 
70
        if (ut_dulint_cmp(node->table->id, DICT_INDEXES_ID) == 0) {
 
71
                ut_ad(node->trx->dict_operation_lock_mode == RW_X_LATCH);
 
72
 
 
73
                /* Drop the index tree associated with the row in
 
74
                SYS_INDEXES table: */
 
75
 
 
76
                dict_drop_index_tree(btr_pcur_get_rec(&(node->pcur)), &mtr);
 
77
 
 
78
                mtr_commit(&mtr);
 
79
 
 
80
                mtr_start(&mtr);
 
81
 
 
82
                success = btr_pcur_restore_position(BTR_MODIFY_LEAF,
 
83
                                                    &(node->pcur), &mtr);
 
84
                ut_a(success);
 
85
        }
 
86
 
 
87
        btr_cur = btr_pcur_get_btr_cur(&(node->pcur));
 
88
 
 
89
        success = btr_cur_optimistic_delete(btr_cur, &mtr);
 
90
 
 
91
        btr_pcur_commit_specify_mtr(&(node->pcur), &mtr);
 
92
 
 
93
        if (success) {
 
94
                trx_undo_rec_release(node->trx, node->undo_no);
 
95
 
 
96
                return(DB_SUCCESS);
 
97
        }
 
98
retry:
 
99
        /* If did not succeed, try pessimistic descent to tree */
 
100
        mtr_start(&mtr);
 
101
 
 
102
        success = btr_pcur_restore_position(BTR_MODIFY_TREE,
 
103
                                            &(node->pcur), &mtr);
 
104
        ut_a(success);
 
105
 
 
106
        btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
 
107
                                   trx_is_recv(node->trx)
 
108
                                   ? RB_RECOVERY
 
109
                                   : RB_NORMAL, &mtr);
 
110
 
 
111
        /* The delete operation may fail if we have little
 
112
        file space left: TODO: easiest to crash the database
 
113
        and restart with more file space */
 
114
 
 
115
        if (err == DB_OUT_OF_FILE_SPACE
 
116
            && n_tries < BTR_CUR_RETRY_DELETE_N_TIMES) {
 
117
 
 
118
                btr_pcur_commit_specify_mtr(&(node->pcur), &mtr);
 
119
 
 
120
                n_tries++;
 
121
 
 
122
                os_thread_sleep(BTR_CUR_RETRY_SLEEP_TIME);
 
123
 
 
124
                goto retry;
 
125
        }
 
126
 
 
127
        btr_pcur_commit_specify_mtr(&(node->pcur), &mtr);
 
128
 
 
129
        trx_undo_rec_release(node->trx, node->undo_no);
 
130
 
 
131
        return(err);
 
132
}
 
133
 
 
134
/*******************************************************************
 
135
Removes a secondary index entry if found. */
 
136
static
 
137
ulint
 
138
row_undo_ins_remove_sec_low(
 
139
/*========================*/
 
140
                                /* out: DB_SUCCESS, DB_FAIL, or
 
141
                                DB_OUT_OF_FILE_SPACE */
 
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
static
 
202
ulint
 
203
row_undo_ins_remove_sec(
 
204
/*====================*/
 
205
                                /* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
 
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
        dulint          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
UNIV_INTERN
 
297
ulint
 
298
row_undo_ins(
 
299
/*=========*/
 
300
                                /* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
 
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
}