Drizzled Public API Documentation

row0uins.cc

00001 /*****************************************************************************
00002 
00003 Copyright (C) 1997, 2010, Innobase Oy. All Rights Reserved.
00004 
00005 This program is free software; you can redistribute it and/or modify it under
00006 the terms of the GNU General Public License as published by the Free Software
00007 Foundation; version 2 of the License.
00008 
00009 This program is distributed in the hope that it will be useful, but WITHOUT
00010 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00011 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
00012 
00013 You should have received a copy of the GNU General Public License along with
00014 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
00015 St, Fifth Floor, Boston, MA 02110-1301 USA
00016 
00017 *****************************************************************************/
00018 
00019 /**************************************************/
00026 #include "row0uins.h"
00027 
00028 #ifdef UNIV_NONINL
00029 #include "row0uins.ic"
00030 #endif
00031 
00032 #include "dict0dict.h"
00033 #include "dict0boot.h"
00034 #include "dict0crea.h"
00035 #include "trx0undo.h"
00036 #include "trx0roll.h"
00037 #include "btr0btr.h"
00038 #include "mach0data.h"
00039 #include "row0undo.h"
00040 #include "row0vers.h"
00041 #include "trx0trx.h"
00042 #include "trx0rec.h"
00043 #include "row0row.h"
00044 #include "row0upd.h"
00045 #include "que0que.h"
00046 #include "ibuf0ibuf.h"
00047 #include "log0log.h"
00048 
00049 /*************************************************************************
00050 IMPORTANT NOTE: Any operation that generates redo MUST check that there
00051 is enough space in the redo log before for that operation. This is
00052 done by calling log_free_check(). The reason for checking the
00053 availability of the redo log space before the start of the operation is
00054 that we MUST not hold any synchonization objects when performing the
00055 check.
00056 If you make a change in this module make sure that no codepath is
00057 introduced where a call to log_free_check() is bypassed. */
00058 
00059 /*************************************************************************
00060 IMPORTANT NOTE: Any operation that generates redo MUST check that there
00061 is enough space in the redo log before for that operation. This is
00062 done by calling log_free_check(). The reason for checking the
00063 availability of the redo log space before the start of the operation is
00064 that we MUST not hold any synchonization objects when performing the
00065 check.
00066 If you make a change in this module make sure that no codepath is
00067 introduced where a call to log_free_check() is bypassed. */
00068 
00069 /***************************************************************/
00073 static
00074 ulint
00075 row_undo_ins_remove_clust_rec(
00076 /*==========================*/
00077   undo_node_t*  node) 
00078 {
00079   btr_cur_t*  btr_cur;
00080   ibool   success;
00081   ulint   err;
00082   ulint   n_tries   = 0;
00083   mtr_t   mtr;
00084 
00085   mtr_start(&mtr);
00086 
00087   success = btr_pcur_restore_position(BTR_MODIFY_LEAF, &(node->pcur),
00088               &mtr);
00089   ut_a(success);
00090 
00091   if (node->table->id == DICT_INDEXES_ID) {
00092     ut_ad(node->trx->dict_operation_lock_mode == RW_X_LATCH);
00093 
00094     /* Drop the index tree associated with the row in
00095     SYS_INDEXES table: */
00096 
00097     dict_drop_index_tree(btr_pcur_get_rec(&(node->pcur)), &mtr);
00098 
00099     mtr_commit(&mtr);
00100 
00101     mtr_start(&mtr);
00102 
00103     success = btr_pcur_restore_position(BTR_MODIFY_LEAF,
00104                 &(node->pcur), &mtr);
00105     ut_a(success);
00106   }
00107 
00108   btr_cur = btr_pcur_get_btr_cur(&(node->pcur));
00109 
00110   success = btr_cur_optimistic_delete(btr_cur, &mtr);
00111 
00112   btr_pcur_commit_specify_mtr(&(node->pcur), &mtr);
00113 
00114   if (success) {
00115     trx_undo_rec_release(node->trx, node->undo_no);
00116 
00117     return(DB_SUCCESS);
00118   }
00119 retry:
00120   /* If did not succeed, try pessimistic descent to tree */
00121   mtr_start(&mtr);
00122 
00123   success = btr_pcur_restore_position(BTR_MODIFY_TREE,
00124               &(node->pcur), &mtr);
00125   ut_a(success);
00126 
00127   btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
00128            trx_is_recv(node->trx)
00129            ? RB_RECOVERY
00130            : RB_NORMAL, &mtr);
00131 
00132   /* The delete operation may fail if we have little
00133   file space left: TODO: easiest to crash the database
00134   and restart with more file space */
00135 
00136   if (err == DB_OUT_OF_FILE_SPACE
00137       && n_tries < BTR_CUR_RETRY_DELETE_N_TIMES) {
00138 
00139     btr_pcur_commit_specify_mtr(&(node->pcur), &mtr);
00140 
00141     n_tries++;
00142 
00143     os_thread_sleep(BTR_CUR_RETRY_SLEEP_TIME);
00144 
00145     goto retry;
00146   }
00147 
00148   btr_pcur_commit_specify_mtr(&(node->pcur), &mtr);
00149 
00150   trx_undo_rec_release(node->trx, node->undo_no);
00151 
00152   return(err);
00153 }
00154 
00155 /***************************************************************/
00158 static
00159 ulint
00160 row_undo_ins_remove_sec_low(
00161 /*========================*/
00162   ulint   mode, 
00165   dict_index_t* index,  
00166   dtuple_t* entry)  
00167 {
00168   btr_pcur_t    pcur;
00169   btr_cur_t*    btr_cur;
00170   ulint     err;
00171   mtr_t     mtr;
00172   enum row_search_result  search_result;
00173 
00174   mtr_start(&mtr);
00175 
00176   btr_cur = btr_pcur_get_btr_cur(&pcur);
00177 
00178   ut_ad(mode == BTR_MODIFY_TREE || mode == BTR_MODIFY_LEAF);
00179 
00180   search_result = row_search_index_entry(index, entry, mode,
00181                  &pcur, &mtr);
00182 
00183   switch (search_result) {
00184   case ROW_NOT_FOUND:
00185     err = DB_SUCCESS;
00186     goto func_exit;
00187   case ROW_FOUND:
00188     break;
00189   case ROW_BUFFERED:
00190   case ROW_NOT_DELETED_REF:
00191     /* These are invalid outcomes, because the mode passed
00192     to row_search_index_entry() did not include any of the
00193     flags BTR_INSERT, BTR_DELETE, or BTR_DELETE_MARK. */
00194     ut_error;
00195   }
00196 
00197   if (mode == BTR_MODIFY_LEAF) {
00198     err = btr_cur_optimistic_delete(btr_cur, &mtr)
00199       ? DB_SUCCESS : DB_FAIL;
00200   } else {
00201     ut_ad(mode == BTR_MODIFY_TREE);
00202 
00203     /* No need to distinguish RB_RECOVERY here, because we
00204     are deleting a secondary index record: the distinction
00205     between RB_NORMAL and RB_RECOVERY only matters when
00206     deleting a record that contains externally stored
00207     columns. */
00208     ut_ad(!dict_index_is_clust(index));
00209     btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
00210              RB_NORMAL, &mtr);
00211   }
00212 func_exit:
00213   btr_pcur_close(&pcur);
00214   mtr_commit(&mtr);
00215 
00216   return(err);
00217 }
00218 
00219 /***************************************************************/
00223 static
00224 ulint
00225 row_undo_ins_remove_sec(
00226 /*====================*/
00227   dict_index_t* index,  
00228   dtuple_t* entry)  
00229 {
00230   ulint err;
00231   ulint n_tries = 0;
00232 
00233   /* Try first optimistic descent to the B-tree */
00234 
00235   err = row_undo_ins_remove_sec_low(BTR_MODIFY_LEAF, index, entry);
00236 
00237   if (err == DB_SUCCESS) {
00238 
00239     return(err);
00240   }
00241 
00242   /* Try then pessimistic descent to the B-tree */
00243 retry:
00244   err = row_undo_ins_remove_sec_low(BTR_MODIFY_TREE, index, entry);
00245 
00246   /* The delete operation may fail if we have little
00247   file space left: TODO: easiest to crash the database
00248   and restart with more file space */
00249 
00250   if (err != DB_SUCCESS && n_tries < BTR_CUR_RETRY_DELETE_N_TIMES) {
00251 
00252     n_tries++;
00253 
00254     os_thread_sleep(BTR_CUR_RETRY_SLEEP_TIME);
00255 
00256     goto retry;
00257   }
00258 
00259   return(err);
00260 }
00261 
00262 /***********************************************************/
00264 static
00265 void
00266 row_undo_ins_parse_undo_rec(
00267 /*========================*/
00268   undo_node_t*  node) 
00269 {
00270   dict_index_t* clust_index;
00271   byte*   ptr;
00272   undo_no_t undo_no;
00273   table_id_t  table_id;
00274   ulint   type;
00275   ulint   dummy;
00276   ibool   dummy_extern;
00277 
00278   ut_ad(node);
00279 
00280   ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &dummy,
00281             &dummy_extern, &undo_no, &table_id);
00282   ut_ad(type == TRX_UNDO_INSERT_REC);
00283   node->rec_type = type;
00284 
00285   node->update = NULL;
00286   node->table = dict_table_get_on_id(table_id, node->trx);
00287 
00288   /* Skip the UNDO if we can't find the table or the .ibd file. */
00289   if (UNIV_UNLIKELY(node->table == NULL)) {
00290   } else if (UNIV_UNLIKELY(node->table->ibd_file_missing)) {
00291     node->table = NULL;
00292   } else {
00293     clust_index = dict_table_get_first_index(node->table);
00294 
00295     if (clust_index != NULL) {
00296       ptr = trx_undo_rec_get_row_ref(
00297         ptr, clust_index, &node->ref, node->heap);
00298     } else {
00299       ut_print_timestamp(stderr);
00300       fprintf(stderr, "  InnoDB: table ");
00301       ut_print_name(stderr, node->trx, TRUE,
00302               node->table->name);
00303       fprintf(stderr, " has no indexes, "
00304         "ignoring the table\n");
00305 
00306       node->table = NULL;
00307     }
00308   }
00309 }
00310 
00311 /***********************************************************/
00318 UNIV_INTERN
00319 ulint
00320 row_undo_ins(
00321 /*=========*/
00322   undo_node_t*  node) 
00323 {
00324   ut_ad(node);
00325   ut_ad(node->state == UNDO_NODE_INSERT);
00326 
00327   row_undo_ins_parse_undo_rec(node);
00328 
00329   if (!node->table || !row_undo_search_clust_to_pcur(node)) {
00330     trx_undo_rec_release(node->trx, node->undo_no);
00331 
00332     return(DB_SUCCESS);
00333   }
00334 
00335   /* Iterate over all the indexes and undo the insert.*/
00336 
00337   /* Skip the clustered index (the first index) */
00338   node->index = dict_table_get_next_index(
00339     dict_table_get_first_index(node->table));
00340 
00341   while (node->index != NULL) {
00342     dtuple_t* entry;
00343     ulint   err;
00344 
00345     entry = row_build_index_entry(node->row, node->ext,
00346                 node->index, node->heap);
00347     if (UNIV_UNLIKELY(!entry)) {
00348       /* The database must have crashed after
00349       inserting a clustered index record but before
00350       writing all the externally stored columns of
00351       that record.  Because secondary index entries
00352       are inserted after the clustered index record,
00353       we may assume that the secondary index record
00354       does not exist.  However, this situation may
00355       only occur during the rollback of incomplete
00356       transactions. */
00357       ut_a(trx_is_recv(node->trx));
00358     } else {
00359       log_free_check();
00360       err = row_undo_ins_remove_sec(node->index, entry);
00361 
00362       if (err != DB_SUCCESS) {
00363 
00364         return(err);
00365       }
00366     }
00367 
00368     node->index = dict_table_get_next_index(node->index);
00369   }
00370 
00371   log_free_check();
00372   return(row_undo_ins_remove_clust_rec(node));
00373 }