Drizzled Public API Documentation

trx0rseg.cc
00001 /*****************************************************************************
00002 
00003 Copyright (C) 1996, 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 "trx0rseg.h"
00027 
00028 #ifdef UNIV_NONINL
00029 #include "trx0rseg.ic"
00030 #endif
00031 
00032 #include "trx0undo.h"
00033 #include "fut0lst.h"
00034 #include "srv0srv.h"
00035 #include "trx0purge.h"
00036 
00037 #ifdef UNIV_PFS_MUTEX
00038 /* Key to register rseg_mutex_key with performance schema */
00039 UNIV_INTERN mysql_pfs_key_t rseg_mutex_key;
00040 #endif /* UNIV_PFS_MUTEX */
00041 
00042 /******************************************************************/
00045 UNIV_INTERN
00046 trx_rseg_t*
00047 trx_rseg_get_on_id(
00048 /*===============*/
00049   ulint id) 
00050 {
00051   trx_rseg_t* rseg;
00052 
00053   rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
00054 
00055   while (rseg && rseg->id != id) {
00056     rseg = UT_LIST_GET_NEXT(rseg_list, rseg);
00057   }
00058 
00059   return(rseg);
00060 }
00061 
00062 /****************************************************************/
00066 UNIV_INTERN
00067 ulint
00068 trx_rseg_header_create(
00069 /*===================*/
00070   ulint space,    
00071   ulint zip_size, 
00073   ulint max_size, 
00074   ulint rseg_slot_no, 
00075   mtr_t*  mtr)    
00076 {
00077   ulint   page_no;
00078   trx_rsegf_t*  rsegf;
00079   trx_sysf_t* sys_header;
00080   ulint   i;
00081   buf_block_t*  block;
00082 
00083   ut_ad(mtr);
00084   ut_ad(mutex_own(&kernel_mutex));
00085   ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL),
00086         MTR_MEMO_X_LOCK));
00087 
00088   /* Allocate a new file segment for the rollback segment */
00089   block = fseg_create(space, 0,
00090           TRX_RSEG + TRX_RSEG_FSEG_HEADER, mtr);
00091 
00092   if (block == NULL) {
00093     /* No space left */
00094 
00095     return(FIL_NULL);
00096   }
00097 
00098   buf_block_dbg_add_level(block, SYNC_RSEG_HEADER_NEW);
00099 
00100   page_no = buf_block_get_page_no(block);
00101 
00102   /* Get the rollback segment file page */
00103   rsegf = trx_rsegf_get_new(space, zip_size, page_no, mtr);
00104 
00105   /* Initialize max size field */
00106   mlog_write_ulint(rsegf + TRX_RSEG_MAX_SIZE, max_size,
00107        MLOG_4BYTES, mtr);
00108 
00109   /* Initialize the history list */
00110 
00111   mlog_write_ulint(rsegf + TRX_RSEG_HISTORY_SIZE, 0, MLOG_4BYTES, mtr);
00112   flst_init(rsegf + TRX_RSEG_HISTORY, mtr);
00113 
00114   /* Reset the undo log slots */
00115   for (i = 0; i < TRX_RSEG_N_SLOTS; i++) {
00116 
00117     trx_rsegf_set_nth_undo(rsegf, i, FIL_NULL, mtr);
00118   }
00119 
00120   /* Add the rollback segment info to the free slot in
00121   the trx system header */
00122 
00123   sys_header = trx_sysf_get(mtr);
00124 
00125   trx_sysf_rseg_set_space(sys_header, rseg_slot_no, space, mtr);
00126   trx_sysf_rseg_set_page_no(sys_header, rseg_slot_no, page_no, mtr);
00127 
00128   return(page_no);
00129 }
00130 
00131 /***********************************************************************/
00133 UNIV_INTERN
00134 void
00135 trx_rseg_mem_free(
00136 /*==============*/
00137   trx_rseg_t* rseg) /* in, own: instance to free */
00138 {
00139   trx_undo_t* undo;
00140 
00141   mutex_free(&rseg->mutex);
00142 
00143         if (! srv_apply_log_only) {
00144   /* There can't be any active transactions. */
00145   ut_a(UT_LIST_GET_LEN(rseg->update_undo_list) == 0);
00146   ut_a(UT_LIST_GET_LEN(rseg->insert_undo_list) == 0);
00147         }
00148 
00149   undo = UT_LIST_GET_FIRST(rseg->update_undo_cached);
00150 
00151   while (undo != NULL) {
00152     trx_undo_t* prev_undo = undo;
00153 
00154     undo = UT_LIST_GET_NEXT(undo_list, undo);
00155     UT_LIST_REMOVE(undo_list, rseg->update_undo_cached, prev_undo);
00156 
00157     trx_undo_mem_free(prev_undo);
00158   }
00159 
00160   undo = UT_LIST_GET_FIRST(rseg->insert_undo_cached);
00161 
00162   while (undo != NULL) {
00163     trx_undo_t* prev_undo = undo;
00164 
00165     undo = UT_LIST_GET_NEXT(undo_list, undo);
00166     UT_LIST_REMOVE(undo_list, rseg->insert_undo_cached, prev_undo);
00167 
00168     trx_undo_mem_free(prev_undo);
00169   }
00170 
00171   trx_sys_set_nth_rseg(trx_sys, rseg->id, NULL);
00172 
00173   mem_free(rseg);
00174 }
00175 
00176 /***************************************************************************
00177 Creates and initializes a rollback segment object. The values for the
00178 fields are read from the header. The object is inserted to the rseg
00179 list of the trx system object and a pointer is inserted in the rseg
00180 array in the trx system object.
00181 @return own: rollback segment object */
00182 static
00183 trx_rseg_t*
00184 trx_rseg_mem_create(
00185 /*================*/
00186   ulint id,   
00187   ulint space,    
00188   ulint zip_size, 
00190   ulint page_no,  
00191   mtr_t*  mtr)    
00192 {
00193   ulint   len;
00194   trx_rseg_t* rseg;
00195   fil_addr_t  node_addr;
00196   trx_rsegf_t*  rseg_header;
00197   trx_ulogf_t*  undo_log_hdr;
00198   ulint   sum_of_undo_sizes;
00199 
00200   ut_ad(mutex_own(&kernel_mutex));
00201 
00202         void *rseg_buf= mem_zalloc(sizeof(trx_rseg_t));
00203   rseg = static_cast<trx_rseg_t *>(rseg_buf);
00204 
00205   rseg->id = id;
00206   rseg->space = space;
00207   rseg->zip_size = zip_size;
00208   rseg->page_no = page_no;
00209 
00210   mutex_create(rseg_mutex_key, &rseg->mutex, SYNC_RSEG);
00211 
00212   UT_LIST_ADD_LAST(rseg_list, trx_sys->rseg_list, rseg);
00213 
00214   trx_sys_set_nth_rseg(trx_sys, id, rseg);
00215 
00216   rseg_header = trx_rsegf_get_new(space, zip_size, page_no, mtr);
00217 
00218   rseg->max_size = mtr_read_ulint(rseg_header + TRX_RSEG_MAX_SIZE,
00219           MLOG_4BYTES, mtr);
00220 
00221   /* Initialize the undo log lists according to the rseg header */
00222 
00223   sum_of_undo_sizes = trx_undo_lists_init(rseg);
00224 
00225   rseg->curr_size = mtr_read_ulint(rseg_header + TRX_RSEG_HISTORY_SIZE,
00226            MLOG_4BYTES, mtr)
00227     + 1 + sum_of_undo_sizes;
00228 
00229   len = flst_get_len(rseg_header + TRX_RSEG_HISTORY, mtr);
00230   if (len > 0) {
00231     trx_sys->rseg_history_len += len;
00232 
00233     node_addr = trx_purge_get_log_from_hist(
00234       flst_get_last(rseg_header + TRX_RSEG_HISTORY, mtr));
00235     rseg->last_page_no = node_addr.page;
00236     rseg->last_offset = node_addr.boffset;
00237 
00238     undo_log_hdr = trx_undo_page_get(rseg->space, rseg->zip_size,
00239              node_addr.page,
00240              mtr) + node_addr.boffset;
00241 
00242     rseg->last_trx_no = mach_read_from_8(
00243       undo_log_hdr + TRX_UNDO_TRX_NO);
00244     rseg->last_del_marks = mtr_read_ulint(
00245       undo_log_hdr + TRX_UNDO_DEL_MARKS, MLOG_2BYTES, mtr);
00246   } else {
00247     rseg->last_page_no = FIL_NULL;
00248   }
00249 
00250   return(rseg);
00251 }
00252 
00253 /********************************************************************
00254 Creates the memory copies for the rollback segments and initializes the
00255 rseg list and array in trx_sys at a database startup. */
00256 static
00257 void
00258 trx_rseg_create_instance(
00259 /*=====================*/
00260   trx_sysf_t* sys_header, 
00261   mtr_t*    mtr)    
00262 {
00263   ulint   i;
00264 
00265   for (i = 0; i < TRX_SYS_N_RSEGS; i++) {
00266     ulint page_no;
00267 
00268     page_no = trx_sysf_rseg_get_page_no(sys_header, i, mtr);
00269 
00270     if (page_no == FIL_NULL) {
00271       trx_sys_set_nth_rseg(trx_sys, i, NULL);
00272     } else {
00273       ulint   space;
00274       ulint   zip_size;
00275       trx_rseg_t* rseg = NULL;
00276 
00277       ut_a(!trx_rseg_get_on_id(i));
00278 
00279       space = trx_sysf_rseg_get_space(sys_header, i, mtr);
00280 
00281       zip_size = space ? fil_space_get_zip_size(space) : 0;
00282 
00283       rseg = trx_rseg_mem_create(
00284         i, space, zip_size, page_no, mtr);
00285 
00286       ut_a(rseg->id == i);
00287     }
00288   }
00289 }
00290 
00291 /*********************************************************************
00292 Creates a rollback segment.
00293 @return pointer to new rollback segment if create successful */
00294 UNIV_INTERN
00295 trx_rseg_t*
00296 trx_rseg_create(void)
00297 /*=================*/
00298 {
00299   mtr_t   mtr;
00300   ulint   slot_no;
00301   trx_rseg_t* rseg = NULL;
00302 
00303   mtr_start(&mtr);
00304 
00305   /* To obey the latching order, acquire the file space
00306   x-latch before the kernel mutex. */
00307   mtr_x_lock(fil_space_get_latch(TRX_SYS_SPACE, NULL), &mtr);
00308 
00309   mutex_enter(&kernel_mutex);
00310 
00311   slot_no = trx_sysf_rseg_find_free(&mtr);
00312 
00313   if (slot_no != ULINT_UNDEFINED) {
00314     ulint   space;
00315     ulint   page_no;
00316     ulint   zip_size;
00317     trx_sysf_t* sys_header;
00318 
00319     page_no = trx_rseg_header_create(
00320       TRX_SYS_SPACE, 0, ULINT_MAX, slot_no, &mtr);
00321 
00322     ut_a(page_no != FIL_NULL);
00323 
00324     ut_ad(!trx_rseg_get_on_id(slot_no));
00325 
00326     sys_header = trx_sysf_get(&mtr);
00327 
00328     space = trx_sysf_rseg_get_space(sys_header, slot_no, &mtr);
00329 
00330     zip_size = space ? fil_space_get_zip_size(space) : 0;
00331 
00332     rseg = trx_rseg_mem_create(
00333       slot_no, space, zip_size, page_no, &mtr);
00334   }
00335 
00336   mutex_exit(&kernel_mutex);
00337   mtr_commit(&mtr);
00338 
00339   return(rseg);
00340 }
00341 
00342 /********************************************************************
00343 Initialize the rollback instance list. */
00344 UNIV_INTERN
00345 void
00346 trx_rseg_list_and_array_init(
00347 /*=========================*/
00348   trx_sysf_t* sys_header, /* in: trx system header */
00349   mtr_t*    mtr)    /* in: mtr */
00350 {
00351   UT_LIST_INIT(trx_sys->rseg_list);
00352 
00353   trx_sys->rseg_history_len = 0;
00354 
00355   trx_rseg_create_instance(sys_header, mtr);
00356 }
00357