Drizzled Public API Documentation

mtr0mtr.cc
00001 /*****************************************************************************
00002 
00003 Copyright (C) 1995, 2009, 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 "mtr0mtr.h"
00027 
00028 #ifdef UNIV_NONINL
00029 #include "mtr0mtr.ic"
00030 #endif
00031 
00032 #include "buf0buf.h"
00033 #include "buf0flu.h"
00034 #include "page0types.h"
00035 #include "mtr0log.h"
00036 #include "log0log.h"
00037 
00038 #ifndef UNIV_HOTBACKUP
00039 # include "log0recv.h"
00040 /*****************************************************************/
00042 static
00043 void
00044 mtr_memo_slot_release(
00045 /*==================*/
00046   mtr_t*      mtr,  
00047   mtr_memo_slot_t*  slot) 
00048 {
00049   void* object;
00050   ulint type;
00051 
00052   ut_ad(mtr);
00053   ut_ad(slot);
00054 
00055 #ifndef UNIV_DEBUG
00056   UT_NOT_USED(mtr);
00057 #endif /* UNIV_DEBUG */
00058 
00059   object = slot->object;
00060   type = slot->type;
00061 
00062   if (UNIV_LIKELY(object != NULL)) {
00063     if (type <= MTR_MEMO_BUF_FIX) {
00064       buf_page_release((buf_block_t*)object, type);
00065     } else if (type == MTR_MEMO_S_LOCK) {
00066       rw_lock_s_unlock((rw_lock_t*)object);
00067 #ifdef UNIV_DEBUG
00068     } else if (type != MTR_MEMO_X_LOCK) {
00069       ut_ad(type == MTR_MEMO_MODIFY);
00070       ut_ad(mtr_memo_contains(mtr, object,
00071             MTR_MEMO_PAGE_X_FIX));
00072 #endif /* UNIV_DEBUG */
00073     } else {
00074       rw_lock_x_unlock((rw_lock_t*)object);
00075     }
00076   }
00077 
00078   slot->object = NULL;
00079 }
00080 
00081 /**********************************************************/
00085 static
00086 void
00087 mtr_memo_pop_all(
00088 /*=============*/
00089   mtr_t*  mtr)  
00090 {
00091   mtr_memo_slot_t* slot;
00092   dyn_array_t*  memo;
00093   ulint   offset;
00094 
00095   ut_ad(mtr);
00096   ut_ad(mtr->magic_n == MTR_MAGIC_N);
00097   ut_ad(mtr->state == MTR_COMMITTING); /* Currently only used in
00098                commit */
00099   memo = &(mtr->memo);
00100 
00101   offset = dyn_array_get_data_size(memo);
00102 
00103   while (offset > 0) {
00104     offset -= sizeof(mtr_memo_slot_t);
00105     slot = static_cast<mtr_memo_slot_t *>(dyn_array_get_element(memo, offset));
00106 
00107     mtr_memo_slot_release(mtr, slot);
00108   }
00109 }
00110 
00111 /*****************************************************************/
00113 static
00114 void
00115 mtr_memo_slot_note_modification(
00116 /*============================*/
00117   mtr_t*      mtr,  
00118   mtr_memo_slot_t*  slot) 
00119 {
00120   ut_ad(mtr);
00121   ut_ad(mtr->magic_n == MTR_MAGIC_N);
00122   ut_ad(mtr->modifications);
00123 
00124   if (slot->object != NULL && slot->type == MTR_MEMO_PAGE_X_FIX) {
00125     buf_block_t*  block = (buf_block_t*) slot->object;
00126 
00127 #ifdef UNIV_DEBUG
00128     ut_ad(log_flush_order_mutex_own());
00129 #endif /* UNIV_DEBUG */
00130     buf_flush_note_modification(block, mtr);
00131   }
00132 }
00133 
00134 /**********************************************************/
00141 static
00142 void
00143 mtr_memo_note_modifications(
00144 /*========================*/
00145   mtr_t*  mtr)  
00146 {
00147   dyn_array_t*  memo;
00148   ulint   offset;
00149 
00150   ut_ad(mtr);
00151   ut_ad(mtr->magic_n == MTR_MAGIC_N);
00152   ut_ad(mtr->state == MTR_COMMITTING); /* Currently only used in
00153                commit */
00154   memo = &mtr->memo;
00155 
00156   offset = dyn_array_get_data_size(memo);
00157 
00158   while (offset > 0) {
00159     mtr_memo_slot_t* slot;
00160 
00161     offset -= sizeof(mtr_memo_slot_t);
00162     slot = static_cast<mtr_memo_slot_t *>(dyn_array_get_element(memo, offset));
00163 
00164     mtr_memo_slot_note_modification(mtr, slot);
00165   }
00166 }
00167 
00168 /************************************************************/
00170 static
00171 void
00172 mtr_log_reserve_and_write(
00173 /*======================*/
00174   mtr_t*  mtr)  
00175 {
00176   dyn_array_t*  mlog;
00177   dyn_block_t*  block;
00178   ulint   data_size;
00179   byte*   first_data;
00180 
00181   ut_ad(mtr);
00182 
00183   mlog = &(mtr->log);
00184 
00185   first_data = dyn_block_get_data(mlog);
00186 
00187   if (mtr->n_log_recs > 1) {
00188     mlog_catenate_ulint(mtr, MLOG_MULTI_REC_END, MLOG_1BYTE);
00189   } else {
00190     *first_data = (byte)((ulint)*first_data
00191              | MLOG_SINGLE_REC_FLAG);
00192   }
00193 
00194   if (mlog->heap == NULL) {
00195     mtr->end_lsn = log_reserve_and_write_fast(
00196       first_data, dyn_block_get_used(mlog),
00197       &mtr->start_lsn);
00198     if (mtr->end_lsn) {
00199 
00200       /* Success. We have the log mutex.
00201       Add pages to flush list and exit */
00202       goto func_exit;
00203     }
00204   }
00205 
00206   data_size = dyn_array_get_data_size(mlog);
00207 
00208   /* Open the database log for log_write_low */
00209   mtr->start_lsn = log_reserve_and_open(data_size);
00210 
00211   if (mtr->log_mode == MTR_LOG_ALL) {
00212 
00213     block = mlog;
00214 
00215     while (block != NULL) {
00216       log_write_low(dyn_block_get_data(block),
00217               dyn_block_get_used(block));
00218       block = dyn_array_get_next_block(mlog, block);
00219     }
00220   } else {
00221     ut_ad(mtr->log_mode == MTR_LOG_NONE);
00222     /* Do nothing */
00223   }
00224 
00225   mtr->end_lsn = log_close();
00226 
00227 func_exit:
00228   log_flush_order_mutex_enter();
00229 
00230   /* It is now safe to release the log mutex because the
00231   flush_order mutex will ensure that we are the first one
00232   to insert into the flush list. */
00233   log_release();
00234 
00235   if (mtr->modifications) {
00236     mtr_memo_note_modifications(mtr);
00237   }
00238 
00239   log_flush_order_mutex_exit();
00240 }
00241 #endif /* !UNIV_HOTBACKUP */
00242 
00243 /***************************************************************/
00245 UNIV_INTERN
00246 void
00247 mtr_commit(
00248 /*=======*/
00249   mtr_t*  mtr)  
00250 {
00251   ut_ad(mtr);
00252   ut_ad(mtr->magic_n == MTR_MAGIC_N);
00253   ut_ad(mtr->state == MTR_ACTIVE);
00254   ut_d(mtr->state = MTR_COMMITTING);
00255 
00256 #ifndef UNIV_HOTBACKUP
00257   /* This is a dirty read, for debugging. */
00258   ut_ad(!recv_no_log_write);
00259 
00260   if (mtr->modifications && mtr->n_log_recs) {
00261     mtr_log_reserve_and_write(mtr);
00262   }
00263 
00264   mtr_memo_pop_all(mtr);
00265 #endif /* !UNIV_HOTBACKUP */
00266 
00267   ut_d(mtr->state = MTR_COMMITTED);
00268   dyn_array_free(&(mtr->memo));
00269   dyn_array_free(&(mtr->log));
00270 }
00271 
00272 #ifndef UNIV_HOTBACKUP
00273 /**********************************************************/
00277 UNIV_INTERN
00278 void
00279 mtr_rollback_to_savepoint(
00280 /*======================*/
00281   mtr_t*  mtr,    
00282   ulint savepoint)  
00283 {
00284   mtr_memo_slot_t* slot;
00285   dyn_array_t*  memo;
00286   ulint   offset;
00287 
00288   ut_ad(mtr);
00289   ut_ad(mtr->magic_n == MTR_MAGIC_N);
00290   ut_ad(mtr->state == MTR_ACTIVE);
00291 
00292   memo = &(mtr->memo);
00293 
00294   offset = dyn_array_get_data_size(memo);
00295   ut_ad(offset >= savepoint);
00296 
00297   while (offset > savepoint) {
00298     offset -= sizeof(mtr_memo_slot_t);
00299 
00300     slot = static_cast<mtr_memo_slot_t *>(dyn_array_get_element(memo, offset));
00301 
00302     ut_ad(slot->type != MTR_MEMO_MODIFY);
00303 
00304     /* We do not call mtr_memo_slot_note_modification()
00305     because there MUST be no changes made to the buffer
00306     pages after the savepoint */
00307     mtr_memo_slot_release(mtr, slot);
00308   }
00309 }
00310 
00311 /***************************************************/
00313 UNIV_INTERN
00314 void
00315 mtr_memo_release(
00316 /*=============*/
00317   mtr_t*  mtr,  
00318   void* object, 
00319   ulint type) 
00320 {
00321   mtr_memo_slot_t* slot;
00322   dyn_array_t*  memo;
00323   ulint   offset;
00324 
00325   ut_ad(mtr);
00326   ut_ad(mtr->magic_n == MTR_MAGIC_N);
00327   ut_ad(mtr->state == MTR_ACTIVE);
00328 
00329   memo = &(mtr->memo);
00330 
00331   offset = dyn_array_get_data_size(memo);
00332 
00333   log_flush_order_mutex_enter();
00334   while (offset > 0) {
00335     offset -= sizeof(mtr_memo_slot_t);
00336 
00337     slot = static_cast<mtr_memo_slot_t *>(dyn_array_get_element(memo, offset));
00338 
00339     if (object == slot->object && type == slot->type) {
00340 
00341       /* We cannot release a page that has been written
00342       to in the middle of a mini-transaction. */
00343 
00344       ut_ad(!(mtr->modifications
00345               && slot->type == MTR_MEMO_PAGE_X_FIX));
00346 
00347       mtr_memo_slot_release(mtr, slot);
00348 
00349       break;
00350     }
00351   }
00352   log_flush_order_mutex_exit();
00353 }
00354 #endif /* !UNIV_HOTBACKUP */
00355 
00356 /********************************************************/
00359 UNIV_INTERN
00360 ulint
00361 mtr_read_ulint(
00362 /*===========*/
00363   const byte* ptr,  
00364   ulint   type, 
00365   mtr_t*    /*mtr __attribute__((unused))*/)
00367 {
00368   ut_ad(mtr->state == MTR_ACTIVE);
00369   ut_ad(mtr_memo_contains_page(mtr, ptr, MTR_MEMO_PAGE_S_FIX)
00370         || mtr_memo_contains_page(mtr, ptr, MTR_MEMO_PAGE_X_FIX));
00371   if (type == MLOG_1BYTE) {
00372     return(mach_read_from_1(ptr));
00373   } else if (type == MLOG_2BYTES) {
00374     return(mach_read_from_2(ptr));
00375   } else {
00376     ut_ad(type == MLOG_4BYTES);
00377     return(mach_read_from_4(ptr));
00378   }
00379 }
00380 
00381 #ifdef UNIV_DEBUG
00382 # ifndef UNIV_HOTBACKUP
00383 /**********************************************************/
00386 UNIV_INTERN
00387 ibool
00388 mtr_memo_contains_page(
00389 /*===================*/
00390   mtr_t*    mtr,  
00391   const byte* ptr,  
00392   ulint   type) 
00393 {
00394   return(mtr_memo_contains(mtr, buf_block_align(ptr), type));
00395 }
00396 
00397 /*********************************************************/
00399 UNIV_INTERN
00400 void
00401 mtr_print(
00402 /*======*/
00403   mtr_t*  mtr)  
00404 {
00405   fprintf(stderr,
00406     "Mini-transaction handle: memo size %lu bytes"
00407     " log size %lu bytes\n",
00408     (ulong) dyn_array_get_data_size(&(mtr->memo)),
00409     (ulong) dyn_array_get_data_size(&(mtr->log)));
00410 }
00411 # endif /* !UNIV_HOTBACKUP */
00412 #endif /* UNIV_DEBUG */