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   /* There can't be any active transactions. */
00144   ut_a(UT_LIST_GET_LEN(rseg->update_undo_list) == 0);
00145   ut_a(UT_LIST_GET_LEN(rseg->insert_undo_list) == 0);
00146 
00147   undo = UT_LIST_GET_FIRST(rseg->update_undo_cached);
00148 
00149   while (undo != NULL) {
00150     trx_undo_t* prev_undo = undo;
00151 
00152     undo = UT_LIST_GET_NEXT(undo_list, undo);
00153     UT_LIST_REMOVE(undo_list, rseg->update_undo_cached, prev_undo);
00154 
00155     trx_undo_mem_free(prev_undo);
00156   }
00157 
00158   undo = UT_LIST_GET_FIRST(rseg->insert_undo_cached);
00159 
00160   while (undo != NULL) {
00161     trx_undo_t* prev_undo = undo;
00162 
00163     undo = UT_LIST_GET_NEXT(undo_list, undo);
00164     UT_LIST_REMOVE(undo_list, rseg->insert_undo_cached, prev_undo);
00165 
00166     trx_undo_mem_free(prev_undo);
00167   }
00168 
00169   trx_sys_set_nth_rseg(trx_sys, rseg->id, NULL);
00170 
00171   mem_free(rseg);
00172 }
00173 
00174 /***************************************************************************
00175 Creates and initializes a rollback segment object. The values for the
00176 fields are read from the header. The object is inserted to the rseg
00177 list of the trx system object and a pointer is inserted in the rseg
00178 array in the trx system object.
00179 @return own: rollback segment object */
00180 static
00181 trx_rseg_t*
00182 trx_rseg_mem_create(
00183 /*================*/
00184   ulint id,   
00185   ulint space,    
00186   ulint zip_size, 
00188   ulint page_no,  
00189   mtr_t*  mtr)    
00190 {
00191   ulint   len;
00192   trx_rseg_t* rseg;
00193   fil_addr_t  node_addr;
00194   trx_rsegf_t*  rseg_header;
00195   trx_ulogf_t*  undo_log_hdr;
00196   ulint   sum_of_undo_sizes;
00197 
00198   ut_ad(mutex_own(&kernel_mutex));
00199 
00200         void *rseg_buf= mem_zalloc(sizeof(trx_rseg_t));
00201   rseg = static_cast<trx_rseg_t *>(rseg_buf);
00202 
00203   rseg->id = id;
00204   rseg->space = space;
00205   rseg->zip_size = zip_size;
00206   rseg->page_no = page_no;
00207 
00208   mutex_create(rseg_mutex_key, &rseg->mutex, SYNC_RSEG);
00209 
00210   UT_LIST_ADD_LAST(rseg_list, trx_sys->rseg_list, rseg);
00211 
00212   trx_sys_set_nth_rseg(trx_sys, id, rseg);
00213 
00214   rseg_header = trx_rsegf_get_new(space, zip_size, page_no, mtr);
00215 
00216   rseg->max_size = mtr_read_ulint(rseg_header + TRX_RSEG_MAX_SIZE,
00217           MLOG_4BYTES, mtr);
00218 
00219   /* Initialize the undo log lists according to the rseg header */
00220 
00221   sum_of_undo_sizes = trx_undo_lists_init(rseg);
00222 
00223   rseg->curr_size = mtr_read_ulint(rseg_header + TRX_RSEG_HISTORY_SIZE,
00224            MLOG_4BYTES, mtr)
00225     + 1 + sum_of_undo_sizes;
00226 
00227   len = flst_get_len(rseg_header + TRX_RSEG_HISTORY, mtr);
00228   if (len > 0) {
00229     trx_sys->rseg_history_len += len;
00230 
00231     node_addr = trx_purge_get_log_from_hist(
00232       flst_get_last(rseg_header + TRX_RSEG_HISTORY, mtr));
00233     rseg->last_page_no = node_addr.page;
00234     rseg->last_offset = node_addr.boffset;
00235 
00236     undo_log_hdr = trx_undo_page_get(rseg->space, rseg->zip_size,
00237              node_addr.page,
00238              mtr) + node_addr.boffset;
00239 
00240     rseg->last_trx_no = mach_read_from_8(
00241       undo_log_hdr + TRX_UNDO_TRX_NO);
00242     rseg->last_del_marks = mtr_read_ulint(
00243       undo_log_hdr + TRX_UNDO_DEL_MARKS, MLOG_2BYTES, mtr);
00244   } else {
00245     rseg->last_page_no = FIL_NULL;
00246   }
00247 
00248   return(rseg);
00249 }
00250 
00251 /********************************************************************
00252 Creates the memory copies for the rollback segments and initializes the
00253 rseg list and array in trx_sys at a database startup. */
00254 static
00255 void
00256 trx_rseg_create_instance(
00257 /*=====================*/
00258   trx_sysf_t* sys_header, 
00259   mtr_t*    mtr)    
00260 {
00261   ulint   i;
00262 
00263   for (i = 0; i < TRX_SYS_N_RSEGS; i++) {
00264     ulint page_no;
00265 
00266     page_no = trx_sysf_rseg_get_page_no(sys_header, i, mtr);
00267 
00268     if (page_no == FIL_NULL) {
00269       trx_sys_set_nth_rseg(trx_sys, i, NULL);
00270     } else {
00271       ulint   space;
00272       ulint   zip_size;
00273       trx_rseg_t* rseg = NULL;
00274 
00275       ut_a(!trx_rseg_get_on_id(i));
00276 
00277       space = trx_sysf_rseg_get_space(sys_header, i, mtr);
00278 
00279       zip_size = space ? fil_space_get_zip_size(space) : 0;
00280 
00281       rseg = trx_rseg_mem_create(
00282         i, space, zip_size, page_no, mtr);
00283 
00284       ut_a(rseg->id == i);
00285     }
00286   }
00287 }
00288 
00289 /*********************************************************************
00290 Creates a rollback segment.
00291 @return pointer to new rollback segment if create successful */
00292 UNIV_INTERN
00293 trx_rseg_t*
00294 trx_rseg_create(void)
00295 /*=================*/
00296 {
00297   mtr_t   mtr;
00298   ulint   slot_no;
00299   trx_rseg_t* rseg = NULL;
00300 
00301   mtr_start(&mtr);
00302 
00303   /* To obey the latching order, acquire the file space
00304   x-latch before the kernel mutex. */
00305   mtr_x_lock(fil_space_get_latch(TRX_SYS_SPACE, NULL), &mtr);
00306 
00307   mutex_enter(&kernel_mutex);
00308 
00309   slot_no = trx_sysf_rseg_find_free(&mtr);
00310 
00311   if (slot_no != ULINT_UNDEFINED) {
00312     ulint   space;
00313     ulint   page_no;
00314     ulint   zip_size;
00315     trx_sysf_t* sys_header;
00316 
00317     page_no = trx_rseg_header_create(
00318       TRX_SYS_SPACE, 0, ULINT_MAX, slot_no, &mtr);
00319 
00320     ut_a(page_no != FIL_NULL);
00321 
00322     ut_ad(!trx_rseg_get_on_id(slot_no));
00323 
00324     sys_header = trx_sysf_get(&mtr);
00325 
00326     space = trx_sysf_rseg_get_space(sys_header, slot_no, &mtr);
00327 
00328     zip_size = space ? fil_space_get_zip_size(space) : 0;
00329 
00330     rseg = trx_rseg_mem_create(
00331       slot_no, space, zip_size, page_no, &mtr);
00332   }
00333 
00334   mutex_exit(&kernel_mutex);
00335   mtr_commit(&mtr);
00336 
00337   return(rseg);
00338 }
00339 
00340 /********************************************************************
00341 Initialize the rollback instance list. */
00342 UNIV_INTERN
00343 void
00344 trx_rseg_list_and_array_init(
00345 /*=========================*/
00346   trx_sysf_t* sys_header, /* in: trx system header */
00347   mtr_t*    mtr)    /* in: mtr */
00348 {
00349   UT_LIST_INIT(trx_sys->rseg_list);
00350 
00351   trx_sys->rseg_history_len = 0;
00352 
00353   trx_rseg_create_instance(sys_header, mtr);
00354 }
00355