Drizzled Public API Documentation

trx0sys.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 "trx0sys.h"
00027 
00028 #ifdef UNIV_NONINL
00029 #include "trx0sys.ic"
00030 #endif
00031 
00032 #ifndef UNIV_HOTBACKUP
00033 #include "fsp0fsp.h"
00034 #include "mtr0log.h"
00035 #include "mtr0log.h"
00036 #include "trx0trx.h"
00037 #include "trx0rseg.h"
00038 #include "trx0undo.h"
00039 #include "srv0srv.h"
00040 #include "trx0purge.h"
00041 #include "log0log.h"
00042 #include "log0recv.h"
00043 #include "os0file.h"
00044 #include "read0read.h"
00045 
00047 struct file_format_struct {
00048   ulint   id;   
00049   const char* name;   
00051   mutex_t   mutex;    
00053 };
00054 
00055 #include <drizzled/errmsg_print.h>
00056 
00058 typedef struct file_format_struct file_format_t;
00059 
00061 UNIV_INTERN trx_sys_t*    trx_sys   = NULL;
00063 UNIV_INTERN trx_doublewrite_t*  trx_doublewrite = NULL;
00064 
00067 UNIV_INTERN ibool trx_doublewrite_must_reset_space_ids  = FALSE;
00069 UNIV_INTERN ibool trx_doublewrite_buf_is_being_created = FALSE;
00070 
00074 UNIV_INTERN ibool trx_sys_multiple_tablespace_format  = FALSE;
00075 
00078 /* @{ */
00080 UNIV_INTERN char  trx_sys_mysql_master_log_name[TRX_SYS_MYSQL_LOG_NAME_LEN];
00084 UNIV_INTERN ib_int64_t  trx_sys_mysql_master_log_pos  = -1;
00085 /* @} */
00086 
00090 /* @{ */
00092 UNIV_INTERN char  trx_sys_mysql_bin_log_name[TRX_SYS_MYSQL_LOG_NAME_LEN];
00094 UNIV_INTERN ib_int64_t  trx_sys_mysql_bin_log_pos = -1;
00095 
00096 UNIV_INTERN drizzled::atomic<uint64_t> trx_sys_commit_id;
00097 
00098 /* @} */
00099 #endif /* !UNIV_HOTBACKUP */
00100 
00102 static const char*  file_format_name_map[] = {
00103   "Antelope",
00104   "Barracuda",
00105   "Cheetah",
00106   "Dragon",
00107   "Elk",
00108   "Fox",
00109   "Gazelle",
00110   "Hornet",
00111   "Impala",
00112   "Jaguar",
00113   "Kangaroo",
00114   "Leopard",
00115   "Moose",
00116   "Nautilus",
00117   "Ocelot",
00118   "Porpoise",
00119   "Quail",
00120   "Rabbit",
00121   "Shark",
00122   "Tiger",
00123   "Urchin",
00124   "Viper",
00125   "Whale",
00126   "Xenops",
00127   "Yak",
00128   "Zebra"
00129 };
00130 
00132 static const ulint  FILE_FORMAT_NAME_N
00133   = sizeof(file_format_name_map) / sizeof(file_format_name_map[0]);
00134 
00135 #ifdef UNIV_PFS_MUTEX
00136 /* Key to register the mutex with performance schema */
00137 UNIV_INTERN mysql_pfs_key_t trx_doublewrite_mutex_key;
00138 UNIV_INTERN mysql_pfs_key_t file_format_max_mutex_key;
00139 #endif /* UNIV_PFS_MUTEX */
00140 
00141 #ifndef UNIV_HOTBACKUP
00142 
00145 static  file_format_t file_format_max;
00146 
00147 /****************************************************************/
00151 UNIV_INTERN
00152 ibool
00153 trx_doublewrite_page_inside(
00154 /*========================*/
00155   ulint page_no)  
00156 {
00157   if (trx_doublewrite == NULL) {
00158 
00159     return(FALSE);
00160   }
00161 
00162   if (page_no >= trx_doublewrite->block1
00163       && page_no < trx_doublewrite->block1
00164       + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) {
00165     return(TRUE);
00166   }
00167 
00168   if (page_no >= trx_doublewrite->block2
00169       && page_no < trx_doublewrite->block2
00170       + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) {
00171     return(TRUE);
00172   }
00173 
00174   return(FALSE);
00175 }
00176 
00177 /****************************************************************/
00179 static
00180 void
00181 trx_doublewrite_init(
00182 /*=================*/
00183   byte* doublewrite)  
00185 {
00186   trx_doublewrite = static_cast<trx_doublewrite_t *>(mem_alloc(sizeof(trx_doublewrite_t)));
00187 
00188   /* Since we now start to use the doublewrite buffer, no need to call
00189   fsync() after every write to a data file */
00190 #ifdef UNIV_DO_FLUSH
00191   os_do_not_call_flush_at_each_write = TRUE;
00192 #endif /* UNIV_DO_FLUSH */
00193 
00194   mutex_create(trx_doublewrite_mutex_key,
00195          &trx_doublewrite->mutex, SYNC_DOUBLEWRITE);
00196 
00197   trx_doublewrite->first_free = 0;
00198 
00199   trx_doublewrite->block1 = mach_read_from_4(
00200     doublewrite + TRX_SYS_DOUBLEWRITE_BLOCK1);
00201   trx_doublewrite->block2 = mach_read_from_4(
00202     doublewrite + TRX_SYS_DOUBLEWRITE_BLOCK2);
00203         trx_doublewrite->write_buf_unaligned = static_cast<byte *>(ut_malloc(
00204                                                                              (1 + 2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) * UNIV_PAGE_SIZE));
00205 
00206         trx_doublewrite->write_buf = static_cast<byte *>(ut_align(
00207                                                                   trx_doublewrite->write_buf_unaligned, UNIV_PAGE_SIZE));
00208         trx_doublewrite->buf_block_arr = static_cast<buf_page_t **>(mem_alloc(
00209                                                                              2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * sizeof(void*)));
00210 }
00211 
00212 /****************************************************************/
00215 UNIV_INTERN
00216 void
00217 trx_sys_mark_upgraded_to_multiple_tablespaces(void)
00218 /*===============================================*/
00219 {
00220   buf_block_t*  block;
00221   byte*   doublewrite;
00222   mtr_t   mtr;
00223 
00224   /* We upgraded to 4.1.x and reset the space id fields in the
00225   doublewrite buffer. Let us mark to the trx_sys header that the upgrade
00226   has been done. */
00227 
00228   mtr_start(&mtr);
00229 
00230   block = buf_page_get(TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO,
00231            RW_X_LATCH, &mtr);
00232   buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
00233 
00234   doublewrite = buf_block_get_frame(block) + TRX_SYS_DOUBLEWRITE;
00235 
00236   mlog_write_ulint(doublewrite + TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED,
00237        TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N,
00238        MLOG_4BYTES, &mtr);
00239   mtr_commit(&mtr);
00240 
00241   /* Flush the modified pages to disk and make a checkpoint */
00242   log_make_checkpoint_at(IB_ULONGLONG_MAX, TRUE);
00243 
00244   trx_sys_multiple_tablespace_format = TRUE;
00245 }
00246 
00247 /****************************************************************/
00250 UNIV_INTERN
00251 void
00252 trx_sys_create_doublewrite_buf(void)
00253 /*================================*/
00254 {
00255   buf_block_t*  block;
00256   buf_block_t*  block2;
00257 #ifdef UNIV_SYNC_DEBUG
00258   buf_block_t*  new_block;
00259 #endif /* UNIV_SYNC_DEBUG */
00260   byte* doublewrite;
00261   byte* fseg_header;
00262   ulint page_no;
00263   ulint prev_page_no;
00264   ulint i;
00265   mtr_t mtr;
00266 
00267   if (trx_doublewrite) {
00268     /* Already inited */
00269 
00270     return;
00271   }
00272 
00273 start_again:
00274   mtr_start(&mtr);
00275   trx_doublewrite_buf_is_being_created = TRUE;
00276 
00277   block = buf_page_get(TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO,
00278            RW_X_LATCH, &mtr);
00279   buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
00280 
00281   doublewrite = buf_block_get_frame(block) + TRX_SYS_DOUBLEWRITE;
00282 
00283   if (mach_read_from_4(doublewrite + TRX_SYS_DOUBLEWRITE_MAGIC)
00284       == TRX_SYS_DOUBLEWRITE_MAGIC_N) {
00285     /* The doublewrite buffer has already been created:
00286     just read in some numbers */
00287 
00288     trx_doublewrite_init(doublewrite);
00289 
00290     mtr_commit(&mtr);
00291     trx_doublewrite_buf_is_being_created = FALSE;
00292   } else {
00293     fprintf(stderr,
00294       "InnoDB: Doublewrite buffer not found:"
00295       " creating new\n");
00296 
00297     if (buf_pool_get_curr_size()
00298         < ((2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE
00299       + FSP_EXTENT_SIZE / 2 + 100)
00300            * UNIV_PAGE_SIZE)) {
00301       fprintf(stderr,
00302         "InnoDB: Cannot create doublewrite buffer:"
00303         " you must\n"
00304         "InnoDB: increase your buffer pool size.\n"
00305         "InnoDB: Cannot continue operation.\n");
00306 
00307       exit(1);
00308     }
00309 
00310     block2 = fseg_create(TRX_SYS_SPACE, TRX_SYS_PAGE_NO,
00311              TRX_SYS_DOUBLEWRITE
00312              + TRX_SYS_DOUBLEWRITE_FSEG, &mtr);
00313 
00314     /* fseg_create acquires a second latch on the page,
00315     therefore we must declare it: */
00316 
00317     buf_block_dbg_add_level(block2, SYNC_NO_ORDER_CHECK);
00318 
00319     if (block2 == NULL) {
00320       fprintf(stderr,
00321         "InnoDB: Cannot create doublewrite buffer:"
00322         " you must\n"
00323         "InnoDB: increase your tablespace size.\n"
00324         "InnoDB: Cannot continue operation.\n");
00325 
00326       /* We exit without committing the mtr to prevent
00327       its modifications to the database getting to disk */
00328 
00329       exit(1);
00330     }
00331 
00332     fseg_header = buf_block_get_frame(block)
00333       + TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_FSEG;
00334     prev_page_no = 0;
00335 
00336     for (i = 0; i < 2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE
00337            + FSP_EXTENT_SIZE / 2; i++) {
00338       page_no = fseg_alloc_free_page(fseg_header,
00339                    prev_page_no + 1,
00340                    FSP_UP, &mtr);
00341       if (page_no == FIL_NULL) {
00342         fprintf(stderr,
00343           "InnoDB: Cannot create doublewrite"
00344           " buffer: you must\n"
00345           "InnoDB: increase your"
00346           " tablespace size.\n"
00347           "InnoDB: Cannot continue operation.\n"
00348           );
00349 
00350         exit(1);
00351       }
00352 
00353       /* We read the allocated pages to the buffer pool;
00354       when they are written to disk in a flush, the space
00355       id and page number fields are also written to the
00356       pages. When we at database startup read pages
00357       from the doublewrite buffer, we know that if the
00358       space id and page number in them are the same as
00359       the page position in the tablespace, then the page
00360       has not been written to in doublewrite. */
00361 
00362 #ifdef UNIV_SYNC_DEBUG
00363       new_block =
00364 #endif /* UNIV_SYNC_DEBUG */
00365       buf_page_get(TRX_SYS_SPACE, 0, page_no,
00366              RW_X_LATCH, &mtr);
00367       buf_block_dbg_add_level(new_block,
00368             SYNC_NO_ORDER_CHECK);
00369 
00370       if (i == FSP_EXTENT_SIZE / 2) {
00371         ut_a(page_no == FSP_EXTENT_SIZE);
00372         mlog_write_ulint(doublewrite
00373              + TRX_SYS_DOUBLEWRITE_BLOCK1,
00374              page_no, MLOG_4BYTES, &mtr);
00375         mlog_write_ulint(doublewrite
00376              + TRX_SYS_DOUBLEWRITE_REPEAT
00377              + TRX_SYS_DOUBLEWRITE_BLOCK1,
00378              page_no, MLOG_4BYTES, &mtr);
00379       } else if (i == FSP_EXTENT_SIZE / 2
00380            + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) {
00381         ut_a(page_no == 2 * FSP_EXTENT_SIZE);
00382         mlog_write_ulint(doublewrite
00383              + TRX_SYS_DOUBLEWRITE_BLOCK2,
00384              page_no, MLOG_4BYTES, &mtr);
00385         mlog_write_ulint(doublewrite
00386              + TRX_SYS_DOUBLEWRITE_REPEAT
00387              + TRX_SYS_DOUBLEWRITE_BLOCK2,
00388              page_no, MLOG_4BYTES, &mtr);
00389       } else if (i > FSP_EXTENT_SIZE / 2) {
00390         ut_a(page_no == prev_page_no + 1);
00391       }
00392 
00393       prev_page_no = page_no;
00394     }
00395 
00396     mlog_write_ulint(doublewrite + TRX_SYS_DOUBLEWRITE_MAGIC,
00397          TRX_SYS_DOUBLEWRITE_MAGIC_N,
00398          MLOG_4BYTES, &mtr);
00399     mlog_write_ulint(doublewrite + TRX_SYS_DOUBLEWRITE_MAGIC
00400          + TRX_SYS_DOUBLEWRITE_REPEAT,
00401          TRX_SYS_DOUBLEWRITE_MAGIC_N,
00402          MLOG_4BYTES, &mtr);
00403 
00404     mlog_write_ulint(doublewrite
00405          + TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED,
00406          TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N,
00407          MLOG_4BYTES, &mtr);
00408     mtr_commit(&mtr);
00409 
00410     /* Flush the modified pages to disk and make a checkpoint */
00411     log_make_checkpoint_at(IB_ULONGLONG_MAX, TRUE);
00412 
00413     fprintf(stderr, "InnoDB: Doublewrite buffer created\n");
00414 
00415     trx_sys_multiple_tablespace_format = TRUE;
00416 
00417     goto start_again;
00418   }
00419 }
00420 
00421 /****************************************************************/
00428 UNIV_INTERN
00429 void
00430 trx_sys_doublewrite_init_or_restore_pages(
00431 /*======================================*/
00432   ibool restore_corrupt_pages)  
00433 {
00434   byte* buf;
00435   byte* read_buf;
00436   byte* unaligned_read_buf;
00437   ulint block1;
00438   ulint block2;
00439   ulint source_page_no;
00440   byte* page;
00441   byte* doublewrite;
00442   ulint space_id;
00443   ulint page_no;
00444   ulint i;
00445 
00446   /* We do the file i/o past the buffer pool */
00447 
00448         unaligned_read_buf = static_cast<byte *>(ut_malloc(2 * UNIV_PAGE_SIZE));
00449         read_buf = static_cast<byte *>(ut_align(unaligned_read_buf, UNIV_PAGE_SIZE));
00450 
00451   /* Read the trx sys header to check if we are using the doublewrite
00452   buffer */
00453 
00454   fil_io(OS_FILE_READ, TRUE, TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO, 0,
00455          UNIV_PAGE_SIZE, read_buf, NULL);
00456   doublewrite = read_buf + TRX_SYS_DOUBLEWRITE;
00457 
00458   if (mach_read_from_4(doublewrite + TRX_SYS_DOUBLEWRITE_MAGIC)
00459       == TRX_SYS_DOUBLEWRITE_MAGIC_N) {
00460     /* The doublewrite buffer has been created */
00461 
00462     trx_doublewrite_init(doublewrite);
00463 
00464     block1 = trx_doublewrite->block1;
00465     block2 = trx_doublewrite->block2;
00466 
00467     buf = trx_doublewrite->write_buf;
00468   } else {
00469     goto leave_func;
00470   }
00471 
00472   if (mach_read_from_4(doublewrite + TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED)
00473       != TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N) {
00474 
00475     /* We are upgrading from a version < 4.1.x to a version where
00476     multiple tablespaces are supported. We must reset the space id
00477     field in the pages in the doublewrite buffer because starting
00478     from this version the space id is stored to
00479     FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID. */
00480 
00481     trx_doublewrite_must_reset_space_ids = TRUE;
00482 
00483     fprintf(stderr,
00484       "InnoDB: Resetting space id's in the"
00485       " doublewrite buffer\n");
00486   } else {
00487     trx_sys_multiple_tablespace_format = TRUE;
00488   }
00489 
00490   /* Read the pages from the doublewrite buffer to memory */
00491 
00492   fil_io(OS_FILE_READ, TRUE, TRX_SYS_SPACE, 0, block1, 0,
00493          TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * UNIV_PAGE_SIZE,
00494          buf, NULL);
00495   fil_io(OS_FILE_READ, TRUE, TRX_SYS_SPACE, 0, block2, 0,
00496          TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * UNIV_PAGE_SIZE,
00497          buf + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * UNIV_PAGE_SIZE,
00498          NULL);
00499   /* Check if any of these pages is half-written in data files, in the
00500   intended position */
00501 
00502   page = buf;
00503 
00504   for (i = 0; i < TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * 2; i++) {
00505 
00506     page_no = mach_read_from_4(page + FIL_PAGE_OFFSET);
00507 
00508     if (trx_doublewrite_must_reset_space_ids) {
00509 
00510       space_id = 0;
00511       mach_write_to_4(page
00512           + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 0);
00513       /* We do not need to calculate new checksums for the
00514       pages because the field .._SPACE_ID does not affect
00515       them. Write the page back to where we read it from. */
00516 
00517       if (i < TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) {
00518         source_page_no = block1 + i;
00519       } else {
00520         source_page_no = block2
00521           + i - TRX_SYS_DOUBLEWRITE_BLOCK_SIZE;
00522       }
00523 
00524       fil_io(OS_FILE_WRITE, TRUE, 0, 0, source_page_no, 0,
00525              UNIV_PAGE_SIZE, page, NULL);
00526       /* printf("Resetting space id in page %lu\n",
00527       source_page_no); */
00528     } else {
00529       space_id = mach_read_from_4(
00530         page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
00531     }
00532 
00533     if (!restore_corrupt_pages) {
00534       /* The database was shut down gracefully: no need to
00535       restore pages */
00536 
00537     } else if (!fil_tablespace_exists_in_mem(space_id)) {
00538       /* Maybe we have dropped the single-table tablespace
00539       and this page once belonged to it: do nothing */
00540 
00541     } else if (!fil_check_adress_in_tablespace(space_id,
00542                  page_no)) {
00543       fprintf(stderr,
00544         "InnoDB: Warning: a page in the"
00545         " doublewrite buffer is not within space\n"
00546         "InnoDB: bounds; space id %lu"
00547         " page number %lu, page %lu in"
00548         " doublewrite buf.\n",
00549         (ulong) space_id, (ulong) page_no, (ulong) i);
00550 
00551     } else if (space_id == TRX_SYS_SPACE
00552          && ((page_no >= block1
00553         && page_no
00554         < block1 + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE)
00555              || (page_no >= block2
00556            && page_no
00557            < (block2
00558               + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE)))) {
00559 
00560       /* It is an unwritten doublewrite buffer page:
00561       do nothing */
00562     } else {
00563       ulint zip_size = fil_space_get_zip_size(space_id);
00564 
00565       /* Read in the actual page from the file */
00566       fil_io(OS_FILE_READ, TRUE, space_id, zip_size,
00567              page_no, 0,
00568              zip_size ? zip_size : UNIV_PAGE_SIZE,
00569              read_buf, NULL);
00570 
00571       /* Check if the page is corrupt */
00572 
00573       if (UNIV_UNLIKELY
00574           (buf_page_is_corrupted(read_buf, zip_size))) {
00575 
00576         fprintf(stderr,
00577           "InnoDB: Warning: database page"
00578           " corruption or a failed\n"
00579           "InnoDB: file read of"
00580           " space %lu page %lu.\n"
00581           "InnoDB: Trying to recover it from"
00582           " the doublewrite buffer.\n",
00583           (ulong) space_id, (ulong) page_no);
00584 
00585         if (buf_page_is_corrupted(page, zip_size)) {
00586           fprintf(stderr,
00587             "InnoDB: Dump of the page:\n");
00588           buf_page_print(read_buf, zip_size);
00589           fprintf(stderr,
00590             "InnoDB: Dump of"
00591             " corresponding page"
00592             " in doublewrite buffer:\n");
00593           buf_page_print(page, zip_size);
00594 
00595           fprintf(stderr,
00596             "InnoDB: Also the page in the"
00597             " doublewrite buffer"
00598             " is corrupt.\n"
00599             "InnoDB: Cannot continue"
00600             " operation.\n"
00601             "InnoDB: You can try to"
00602             " recover the database"
00603             " with the my.cnf\n"
00604             "InnoDB: option:\n"
00605             "InnoDB:"
00606             " innodb_force_recovery=6\n");
00607           exit(1);
00608         }
00609 
00610         /* Write the good page from the
00611         doublewrite buffer to the intended
00612         position */
00613 
00614         fil_io(OS_FILE_WRITE, TRUE, space_id,
00615                zip_size, page_no, 0,
00616                zip_size ? zip_size : UNIV_PAGE_SIZE,
00617                page, NULL);
00618         fprintf(stderr,
00619           "InnoDB: Recovered the page from"
00620           " the doublewrite buffer.\n");
00621       }
00622     }
00623 
00624     page += UNIV_PAGE_SIZE;
00625   }
00626 
00627   fil_flush_file_spaces(FIL_TABLESPACE);
00628 
00629 leave_func:
00630   ut_free(unaligned_read_buf);
00631 }
00632 
00633 /****************************************************************/
00636 UNIV_INTERN
00637 ibool
00638 trx_in_trx_list(
00639 /*============*/
00640   trx_t*  in_trx) 
00641 {
00642   trx_t*  trx;
00643 
00644   ut_ad(mutex_own(&(kernel_mutex)));
00645 
00646   trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
00647 
00648   while (trx != NULL) {
00649 
00650     if (trx == in_trx) {
00651 
00652       return(TRUE);
00653     }
00654 
00655     trx = UT_LIST_GET_NEXT(trx_list, trx);
00656   }
00657 
00658   return(FALSE);
00659 }
00660 
00661 /*****************************************************************/
00663 UNIV_INTERN
00664 void
00665 trx_sys_flush_max_trx_id(void)
00666 /*==========================*/
00667 {
00668   trx_sysf_t* sys_header;
00669   mtr_t   mtr;
00670 
00671   ut_ad(mutex_own(&kernel_mutex));
00672 
00673   mtr_start(&mtr);
00674 
00675   sys_header = trx_sysf_get(&mtr);
00676 
00677   mlog_write_ull(sys_header + TRX_SYS_TRX_ID_STORE,
00678            trx_sys->max_trx_id, &mtr);
00679   mtr_commit(&mtr);
00680 }
00681 
00682 UNIV_INTERN
00683 void
00684 trx_sys_flush_commit_id(uint64_t commit_id, ulint field, mtr_t* mtr)
00685 {
00686   trx_sysf_t*     sys_header;
00687   
00688   sys_header = trx_sysf_get(mtr);
00689 
00690   mlog_write_ull(sys_header + field + TRX_SYS_DRIZZLE_MAX_COMMIT_ID, 
00691            commit_id, mtr);
00692 }
00693 
00694 
00695 UNIV_INTERN
00696 void
00697 trx_sys_read_commit_id(void)
00698 /*===================================*/
00699 {
00700   trx_sysf_t*     sys_header;
00701   mtr_t           mtr;
00702 
00703   mtr_start(&mtr);
00704 
00705   sys_header = trx_sysf_get(&mtr);
00706 
00707   trx_sys_commit_id = mach_read_from_8(sys_header + TRX_SYS_DRIZZLE_LOG_INFO 
00708                + TRX_SYS_DRIZZLE_MAX_COMMIT_ID);
00709 
00710   mtr_commit(&mtr);
00711 }
00712 
00713 /****************************************************************/
00716 UNIV_INTERN
00717 ulint
00718 trx_sysf_rseg_find_free(
00719 /*====================*/
00720   mtr_t*  mtr)  
00721 {
00722   trx_sysf_t* sys_header;
00723   ulint   page_no;
00724   ulint   i;
00725 
00726   ut_ad(mutex_own(&(kernel_mutex)));
00727 
00728   sys_header = trx_sysf_get(mtr);
00729 
00730   for (i = 0; i < TRX_SYS_N_RSEGS; i++) {
00731 
00732     page_no = trx_sysf_rseg_get_page_no(sys_header, i, mtr);
00733 
00734     if (page_no == FIL_NULL) {
00735 
00736       return(i);
00737     }
00738   }
00739 
00740   return(ULINT_UNDEFINED);
00741 }
00742 
00743 /*****************************************************************/
00746 static
00747 void
00748 trx_sysf_create(
00749 /*============*/
00750   mtr_t*  mtr)  
00751 {
00752   trx_sysf_t* sys_header;
00753   ulint   slot_no;
00754   buf_block_t*  block;
00755   page_t*   page;
00756   ulint   page_no;
00757   byte*   ptr;
00758   ulint   len;
00759 
00760   ut_ad(mtr);
00761 
00762   /* Note that below we first reserve the file space x-latch, and
00763   then enter the kernel: we must do it in this order to conform
00764   to the latching order rules. */
00765 
00766   mtr_x_lock(fil_space_get_latch(TRX_SYS_SPACE, NULL), mtr);
00767   mutex_enter(&kernel_mutex);
00768 
00769   /* Create the trx sys file block in a new allocated file segment */
00770   block = fseg_create(TRX_SYS_SPACE, 0, TRX_SYS + TRX_SYS_FSEG_HEADER,
00771           mtr);
00772   buf_block_dbg_add_level(block, SYNC_TRX_SYS_HEADER);
00773 
00774   ut_a(buf_block_get_page_no(block) == TRX_SYS_PAGE_NO);
00775 
00776   page = buf_block_get_frame(block);
00777 
00778   mlog_write_ulint(page + FIL_PAGE_TYPE, FIL_PAGE_TYPE_TRX_SYS,
00779        MLOG_2BYTES, mtr);
00780 
00781   /* Reset the doublewrite buffer magic number to zero so that we
00782   know that the doublewrite buffer has not yet been created (this
00783   suppresses a Valgrind warning) */
00784 
00785   mlog_write_ulint(page + TRX_SYS_DOUBLEWRITE
00786        + TRX_SYS_DOUBLEWRITE_MAGIC, 0, MLOG_4BYTES, mtr);
00787 
00788   sys_header = trx_sysf_get(mtr);
00789 
00790   /* Start counting transaction ids from number 1 up */
00791   mach_write_to_8(sys_header + TRX_SYS_TRX_ID_STORE, 1);
00792 
00793   /* Reset the rollback segment slots.  Old versions of InnoDB
00794   define TRX_SYS_N_RSEGS as 256 (TRX_SYS_OLD_N_RSEGS) and expect
00795   that the whole array is initialized. */
00796   ptr = TRX_SYS_RSEGS + sys_header;
00797   len = ut_max(TRX_SYS_OLD_N_RSEGS, TRX_SYS_N_RSEGS)
00798     * TRX_SYS_RSEG_SLOT_SIZE;
00799   memset(ptr, 0xff, len);
00800   ptr += len;
00801   ut_a(ptr <= page + (UNIV_PAGE_SIZE - FIL_PAGE_DATA_END));
00802 
00803   /* Initialize all of the page.  This part used to be uninitialized. */
00804   memset(ptr, 0, UNIV_PAGE_SIZE - FIL_PAGE_DATA_END + page - ptr);
00805 
00806   mlog_log_string(sys_header, UNIV_PAGE_SIZE - FIL_PAGE_DATA_END
00807       + page - sys_header, mtr);
00808 
00809   /* Create the first rollback segment in the SYSTEM tablespace */
00810   slot_no = trx_sysf_rseg_find_free(mtr);
00811   page_no = trx_rseg_header_create(TRX_SYS_SPACE, 0, ULINT_MAX, slot_no,
00812            mtr);
00813   ut_a(slot_no == TRX_SYS_SYSTEM_RSEG_ID);
00814   ut_a(page_no == FSP_FIRST_RSEG_PAGE_NO);
00815 
00816   mutex_exit(&kernel_mutex);
00817 }
00818 
00819 /*****************************************************************/
00822 UNIV_INTERN
00823 void
00824 trx_sys_init_at_db_start(void)
00825 /*==========================*/
00826 {
00827   trx_sysf_t* sys_header;
00828   ib_uint64_t rows_to_undo  = 0;
00829   const char* unit    = "";
00830   trx_t*    trx;
00831   mtr_t   mtr;
00832 
00833   mtr_start(&mtr);
00834 
00835   ut_ad(trx_sys == NULL);
00836 
00837   mutex_enter(&kernel_mutex);
00838 
00839         trx_sys = static_cast<trx_sys_t *>(mem_alloc(sizeof(trx_sys_t)));
00840 
00841   sys_header = trx_sysf_get(&mtr);
00842 
00843   trx_rseg_list_and_array_init(sys_header, &mtr);
00844 
00845   trx_sys->latest_rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
00846 
00847   /* VERY important: after the database is started, max_trx_id value is
00848   divisible by TRX_SYS_TRX_ID_WRITE_MARGIN, and the 'if' in
00849   trx_sys_get_new_trx_id will evaluate to TRUE when the function
00850   is first time called, and the value for trx id will be written
00851   to the disk-based header! Thus trx id values will not overlap when
00852   the database is repeatedly started! */
00853 
00854   trx_sys->max_trx_id = 2 * TRX_SYS_TRX_ID_WRITE_MARGIN
00855     + ut_uint64_align_up(mach_read_from_8(sys_header
00856                + TRX_SYS_TRX_ID_STORE),
00857              TRX_SYS_TRX_ID_WRITE_MARGIN);
00858 
00859   UT_LIST_INIT(trx_sys->mysql_trx_list);
00860   trx_dummy_sess = sess_open();
00861   trx_lists_init_at_db_start();
00862 
00863   if (UT_LIST_GET_LEN(trx_sys->trx_list) > 0) {
00864     trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
00865 
00866     for (;;) {
00867 
00868       if (trx->conc_state != TRX_PREPARED) {
00869         rows_to_undo += trx->undo_no;
00870       }
00871 
00872       trx = UT_LIST_GET_NEXT(trx_list, trx);
00873 
00874       if (!trx) {
00875         break;
00876       }
00877     }
00878 
00879     if (rows_to_undo > 1000000000) {
00880       unit = "M";
00881       rows_to_undo = rows_to_undo / 1000000;
00882     }
00883 
00884     fprintf(stderr,
00885       "InnoDB: %lu transaction(s) which must be"
00886       " rolled back or cleaned up\n"
00887       "InnoDB: in total %lu%s row operations to undo\n",
00888       (ulong) UT_LIST_GET_LEN(trx_sys->trx_list),
00889       (ulong) rows_to_undo, unit);
00890 
00891     fprintf(stderr, "InnoDB: Trx id counter is " TRX_ID_FMT "\n",
00892       trx_sys->max_trx_id);
00893   }
00894 
00895   UT_LIST_INIT(trx_sys->view_list);
00896 
00897   trx_purge_sys_create();
00898 
00899   mutex_exit(&kernel_mutex);
00900 
00901   mtr_commit(&mtr);
00902 }
00903 
00904 /*****************************************************************/
00906 UNIV_INTERN
00907 void
00908 trx_sys_create(void)
00909 /*================*/
00910 {
00911   mtr_t mtr;
00912 
00913   mtr_start(&mtr);
00914 
00915   trx_sysf_create(&mtr);
00916 
00917   mtr_commit(&mtr);
00918 
00919   trx_sys_init_at_db_start();
00920 }
00921 
00922 /*****************************************************************/
00925 static
00926 ibool
00927 trx_sys_file_format_max_write(
00928 /*==========================*/
00929   ulint   format_id,  
00930   const char**  name)   
00932 {
00933   mtr_t   mtr;
00934   byte*   ptr;
00935   buf_block_t*  block;
00936   ib_uint64_t tag_value;
00937 
00938   mtr_start(&mtr);
00939 
00940   block = buf_page_get(
00941     TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO, RW_X_LATCH, &mtr);
00942 
00943   file_format_max.id = format_id;
00944   file_format_max.name = trx_sys_file_format_id_to_name(format_id);
00945 
00946   ptr = buf_block_get_frame(block) + TRX_SYS_FILE_FORMAT_TAG;
00947   tag_value = format_id + TRX_SYS_FILE_FORMAT_TAG_MAGIC_N;
00948 
00949   if (name) {
00950     *name = file_format_max.name;
00951   }
00952 
00953   mlog_write_ull(ptr, tag_value, &mtr);
00954 
00955   mtr_commit(&mtr);
00956 
00957   return(TRUE);
00958 }
00959 
00960 /*****************************************************************/
00963 static
00964 ulint
00965 trx_sys_file_format_max_read(void)
00966 /*==============================*/
00967 {
00968   mtr_t     mtr;
00969   const byte*   ptr;
00970   const buf_block_t*  block;
00971   ib_id_t     file_format_id;
00972 
00973   /* Since this is called during the startup phase it's safe to
00974   read the value without a covering mutex. */
00975   mtr_start(&mtr);
00976 
00977   block = buf_page_get(
00978     TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO, RW_X_LATCH, &mtr);
00979 
00980   ptr = buf_block_get_frame(block) + TRX_SYS_FILE_FORMAT_TAG;
00981   file_format_id = mach_read_from_8(ptr);
00982 
00983   mtr_commit(&mtr);
00984 
00985   file_format_id -= TRX_SYS_FILE_FORMAT_TAG_MAGIC_N;
00986 
00987   if (file_format_id >= FILE_FORMAT_NAME_N) {
00988 
00989     /* Either it has never been tagged, or garbage in it. */
00990     return(ULINT_UNDEFINED);
00991   }
00992 
00993   return((ulint) file_format_id);
00994 }
00995 
00996 /*****************************************************************/
00999 UNIV_INTERN
01000 const char*
01001 trx_sys_file_format_id_to_name(
01002 /*===========================*/
01003   const ulint id) 
01004 {
01005   ut_a(id < FILE_FORMAT_NAME_N);
01006 
01007   return(file_format_name_map[id]);
01008 }
01009 
01010 /*****************************************************************/
01014 UNIV_INTERN
01015 ulint
01016 trx_sys_file_format_max_check(
01017 /*==========================*/
01018   ulint max_format_id)  
01019 {
01020   ulint format_id;
01021 
01022   /* Check the file format in the tablespace. Do not try to
01023   recover if the file format is not supported by the engine
01024   unless forced by the user. */
01025   format_id = trx_sys_file_format_max_read();
01026   if (format_id == ULINT_UNDEFINED) {
01027     /* Format ID was not set. Set it to minimum possible
01028     value. */
01029     format_id = DICT_TF_FORMAT_MIN;
01030   }
01031 
01032         drizzled::errmsg_printf(drizzled::error::INFO, "InnoDB: highest supported file format is %s",
01033                                 trx_sys_file_format_id_to_name(DICT_TF_FORMAT_MAX));
01034 
01035   if (format_id > DICT_TF_FORMAT_MAX) {
01036 
01037     ut_a(format_id < FILE_FORMAT_NAME_N);
01038 
01039                 drizzled::errmsg_printf(drizzled::error::ERROR,
01040       "InnoDB: %s: the system tablespace is in a file "
01041       "format that this version doesn't support - %s",
01042       ((max_format_id <= DICT_TF_FORMAT_MAX)
01043         ? "Error" : "Warning"),
01044       trx_sys_file_format_id_to_name(format_id));
01045 
01046     if (max_format_id <= DICT_TF_FORMAT_MAX) {
01047       return(DB_ERROR);
01048     }
01049   }
01050 
01051   format_id = (format_id > max_format_id) ? format_id : max_format_id;
01052 
01053   /* We don't need a mutex here, as this function should only
01054   be called once at start up. */
01055   file_format_max.id = format_id;
01056   file_format_max.name = trx_sys_file_format_id_to_name(format_id);
01057 
01058   return(DB_SUCCESS);
01059 }
01060 
01061 /*****************************************************************/
01065 UNIV_INTERN
01066 ibool
01067 trx_sys_file_format_max_set(
01068 /*========================*/
01069   ulint   format_id,  
01070   const char**  name)   
01072 {
01073   ibool   ret = FALSE;
01074 
01075   ut_a(format_id <= DICT_TF_FORMAT_MAX);
01076 
01077   mutex_enter(&file_format_max.mutex);
01078 
01079   /* Only update if not already same value. */
01080   if (format_id != file_format_max.id) {
01081 
01082     ret = trx_sys_file_format_max_write(format_id, name);
01083   }
01084 
01085   mutex_exit(&file_format_max.mutex);
01086 
01087   return(ret);
01088 }
01089 
01090 /********************************************************************/
01095 UNIV_INTERN
01096 void
01097 trx_sys_file_format_tag_init(void)
01098 /*==============================*/
01099 {
01100   ulint format_id;
01101 
01102   format_id = trx_sys_file_format_max_read();
01103 
01104   /* If format_id is not set then set it to the minimum. */
01105   if (format_id == ULINT_UNDEFINED) {
01106     trx_sys_file_format_max_set(DICT_TF_FORMAT_MIN, NULL);
01107   }
01108 }
01109 
01110 /********************************************************************/
01114 UNIV_INTERN
01115 ibool
01116 trx_sys_file_format_max_upgrade(
01117 /*============================*/
01118   const char**  name,   
01119   ulint   format_id)  
01120 {
01121   ibool   ret = FALSE;
01122 
01123   ut_a(name);
01124   ut_a(file_format_max.name != NULL);
01125   ut_a(format_id <= DICT_TF_FORMAT_MAX);
01126 
01127   mutex_enter(&file_format_max.mutex);
01128 
01129   if (format_id > file_format_max.id) {
01130 
01131     ret = trx_sys_file_format_max_write(format_id, name);
01132   }
01133 
01134   mutex_exit(&file_format_max.mutex);
01135 
01136   return(ret);
01137 }
01138 
01139 /*****************************************************************/
01142 UNIV_INTERN
01143 const char*
01144 trx_sys_file_format_max_get(void)
01145 /*=============================*/
01146 {
01147   return(file_format_max.name);
01148 }
01149 
01150 /*****************************************************************/
01152 UNIV_INTERN
01153 void
01154 trx_sys_file_format_init(void)
01155 /*==========================*/
01156 {
01157   mutex_create(file_format_max_mutex_key,
01158          &file_format_max.mutex, SYNC_FILE_FORMAT_TAG);
01159 
01160   /* We don't need a mutex here, as this function should only
01161   be called once at start up. */
01162   file_format_max.id = DICT_TF_FORMAT_MIN;
01163 
01164   file_format_max.name = trx_sys_file_format_id_to_name(
01165     file_format_max.id);
01166 }
01167 
01168 /*****************************************************************/
01170 UNIV_INTERN
01171 void
01172 trx_sys_file_format_close(void)
01173 /*===========================*/
01174 {
01175   /* Does nothing at the moment */
01176 }
01177 
01178 /*********************************************************************
01179 Creates the rollback segments */
01180 UNIV_INTERN
01181 void
01182 trx_sys_create_rsegs(
01183 /*=================*/
01184   ulint n_rsegs)  
01185 {
01186   ulint new_rsegs = 0;
01187 
01188   /* Do not create additional rollback segments if
01189   innodb_force_recovery has been set and the database
01190   was not shutdown cleanly. */
01191   if (!srv_force_recovery && !recv_needed_recovery) {
01192     ulint i;
01193 
01194     for (i = 0;  i < n_rsegs; ++i) {
01195 
01196       if (trx_rseg_create() != NULL) {
01197         ++new_rsegs;
01198       } else {
01199         break;
01200       }
01201     }
01202   }
01203 
01204   if (new_rsegs > 0) {
01205     fprintf(stderr,
01206       "InnoDB: %lu rollback segment(s) active.\n",
01207             new_rsegs);
01208   }
01209 }
01210 
01211 #else /* !UNIV_HOTBACKUP */
01212 
01213 /* THESE ARE COPIED FROM NON-HOTBACKUP PART OF THE INNODB SOURCE TREE
01214    (This code duplicaton should be fixed at some point!)
01215 */
01216 
01217 #define TRX_SYS_SPACE 0 /* the SYSTEM tablespace */
01218 /* The offset of the file format tag on the trx system header page */
01219 #define TRX_SYS_FILE_FORMAT_TAG   (UNIV_PAGE_SIZE - 16)
01220 /* We use these random constants to reduce the probability of reading
01221 garbage (from previous versions) that maps to an actual format id. We
01222 use these as bit masks at the time of  reading and writing from/to disk. */
01223 #define TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_LOW 3645922177UL
01224 #define TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_HIGH  2745987765UL
01225 
01226 /* END OF COPIED DEFINITIONS */
01227 
01228 
01229 /*****************************************************************/
01235 UNIV_INTERN
01236 ibool
01237 trx_sys_read_file_format_id(
01238 /*========================*/
01239   const char *pathname,  
01241   ulint *format_id)      
01243 {
01244   os_file_t file;
01245   ibool   success;
01246   byte    buf[UNIV_PAGE_SIZE * 2];
01247   page_t*   page = ut_align(buf, UNIV_PAGE_SIZE);
01248   const byte* ptr;
01249   ib_id_t   file_format_id;
01250 
01251   *format_id = ULINT_UNDEFINED;
01252 
01253   file = os_file_create_simple_no_error_handling(
01254     innodb_file_data_key,
01255     pathname,
01256     OS_FILE_OPEN,
01257     OS_FILE_READ_ONLY,
01258     &success
01259   );
01260   if (!success) {
01261     /* The following call prints an error message */
01262     os_file_get_last_error(TRUE);
01263 
01264     ut_print_timestamp(stderr);
01265 
01266     fprintf(stderr,
01267 "  ibbackup: Error: trying to read system tablespace file format,\n"
01268 "  ibbackup: but could not open the tablespace file %s!\n",
01269       pathname
01270     );
01271     return(FALSE);
01272   }
01273 
01274   /* Read the page on which file format is stored */
01275 
01276   success = os_file_read_no_error_handling(
01277     file, page, TRX_SYS_PAGE_NO * UNIV_PAGE_SIZE, 0, UNIV_PAGE_SIZE
01278   );
01279   if (!success) {
01280     /* The following call prints an error message */
01281     os_file_get_last_error(TRUE);
01282 
01283     ut_print_timestamp(stderr);
01284 
01285     fprintf(stderr,
01286 "  ibbackup: Error: trying to read system table space file format,\n"
01287 "  ibbackup: but failed to read the tablespace file %s!\n",
01288       pathname
01289     );
01290     os_file_close(file);
01291     return(FALSE);
01292   }
01293   os_file_close(file);
01294 
01295   /* get the file format from the page */
01296   ptr = page + TRX_SYS_FILE_FORMAT_TAG;
01297   file_format_id = mach_read_from_8(ptr);
01298   file_format_id -= TRX_SYS_FILE_FORMAT_TAG_MAGIC_N;
01299 
01300   if (file_format_id >= FILE_FORMAT_NAME_N) {
01301 
01302     /* Either it has never been tagged, or garbage in it. */
01303     return(TRUE);
01304   }
01305 
01306   *format_id = (ulint) file_format_id;
01307 
01308   return(TRUE);
01309 }
01310 
01311 
01312 /*****************************************************************/
01315 UNIV_INTERN
01316 ibool
01317 trx_sys_read_pertable_file_format_id(
01318 /*=================================*/
01319   const char *pathname,  
01321   ulint *format_id)      
01323 {
01324   os_file_t file;
01325   ibool   success;
01326   byte    buf[UNIV_PAGE_SIZE * 2];
01327   page_t*   page = ut_align(buf, UNIV_PAGE_SIZE);
01328   const byte* ptr;
01329   ib_uint32_t flags;
01330 
01331   *format_id = ULINT_UNDEFINED;
01332 
01333   file = os_file_create_simple_no_error_handling(
01334     innodb_file_data_key,
01335     pathname,
01336     OS_FILE_OPEN,
01337     OS_FILE_READ_ONLY,
01338     &success
01339   );
01340   if (!success) {
01341     /* The following call prints an error message */
01342     os_file_get_last_error(TRUE);
01343         
01344     ut_print_timestamp(stderr);
01345         
01346     fprintf(stderr,
01347 "  ibbackup: Error: trying to read per-table tablespace format,\n"
01348 "  ibbackup: but could not open the tablespace file %s!\n",
01349       pathname
01350     );
01351     return(FALSE);
01352   }
01353 
01354   /* Read the first page of the per-table datafile */
01355 
01356   success = os_file_read_no_error_handling(
01357     file, page, 0, 0, UNIV_PAGE_SIZE
01358   );
01359   if (!success) {
01360     /* The following call prints an error message */
01361     os_file_get_last_error(TRUE);
01362         
01363     ut_print_timestamp(stderr);
01364         
01365     fprintf(stderr,
01366 "  ibbackup: Error: trying to per-table data file format,\n"
01367 "  ibbackup: but failed to read the tablespace file %s!\n",
01368       pathname
01369     );
01370     os_file_close(file);
01371     return(FALSE);
01372   }
01373   os_file_close(file);
01374 
01375   /* get the file format from the page */
01376   ptr = page + 54;
01377   flags = mach_read_from_4(ptr);
01378   if (flags == 0) {
01379     /* file format is Antelope */
01380     *format_id = 0;
01381     return (TRUE);
01382   } else if (flags & 1) {
01383     /* tablespace flags are ok */
01384     *format_id = (flags / 32) % 128;
01385     return (TRUE);
01386   } else {
01387     /* bad tablespace flags */
01388     return(FALSE);
01389   }
01390 }
01391 
01392 
01393 /*****************************************************************/
01396 UNIV_INTERN
01397 const char*
01398 trx_sys_file_format_id_to_name(
01399 /*===========================*/
01400   const ulint id) 
01401 {
01402   if (!(id < FILE_FORMAT_NAME_N)) {
01403     /* unknown id */
01404     return ("Unknown");
01405   }
01406 
01407   return(file_format_name_map[id]);
01408 }
01409 
01410 #endif /* !UNIV_HOTBACKUP */
01411 
01412 #ifndef UNIV_HOTBACKUP
01413 /*********************************************************************
01414 Shutdown/Close the transaction system. */
01415 UNIV_INTERN
01416 void
01417 trx_sys_close(void)
01418 /*===============*/
01419 {
01420   trx_rseg_t* rseg;
01421   read_view_t*  view;
01422 
01423   ut_ad(trx_sys != NULL);
01424 
01425   /* Check that all read views are closed except read view owned
01426   by a purge. */
01427 
01428   if (UT_LIST_GET_LEN(trx_sys->view_list) > 1) {
01429     fprintf(stderr,
01430       "InnoDB: Error: all read views were not closed"
01431       " before shutdown:\n"
01432       "InnoDB: %lu read views open \n",
01433       static_cast<ulint>(UT_LIST_GET_LEN(trx_sys->view_list)) - 1);
01434   }
01435 
01436   sess_close(trx_dummy_sess);
01437   trx_dummy_sess = NULL;
01438 
01439   trx_purge_sys_close();
01440 
01441   mutex_enter(&kernel_mutex);
01442 
01443   /* Free the double write data structures. */
01444   ut_a(trx_doublewrite != NULL);
01445   ut_free(trx_doublewrite->write_buf_unaligned);
01446   trx_doublewrite->write_buf_unaligned = NULL;
01447 
01448   mem_free(trx_doublewrite->buf_block_arr);
01449   trx_doublewrite->buf_block_arr = NULL;
01450 
01451   mutex_free(&trx_doublewrite->mutex);
01452   mem_free(trx_doublewrite);
01453   trx_doublewrite = NULL;
01454 
01455   /* There can't be any active transactions. */
01456   rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
01457 
01458   while (rseg != NULL) {
01459     trx_rseg_t* prev_rseg = rseg;
01460 
01461     rseg = UT_LIST_GET_NEXT(rseg_list, prev_rseg);
01462     UT_LIST_REMOVE(rseg_list, trx_sys->rseg_list, prev_rseg);
01463 
01464     trx_rseg_mem_free(prev_rseg);
01465   }
01466 
01467   view = UT_LIST_GET_FIRST(trx_sys->view_list);
01468 
01469   while (view != NULL) {
01470     read_view_t*  prev_view = view;
01471 
01472     view = UT_LIST_GET_NEXT(view_list, prev_view);
01473 
01474     /* Views are allocated from the trx_sys->global_read_view_heap.
01475     So, we simply remove the element here. */
01476     UT_LIST_REMOVE(view_list, trx_sys->view_list, prev_view);
01477   }
01478 
01479   ut_a(UT_LIST_GET_LEN(trx_sys->trx_list) == 0);
01480   ut_a(UT_LIST_GET_LEN(trx_sys->rseg_list) == 0);
01481   ut_a(UT_LIST_GET_LEN(trx_sys->view_list) == 0);
01482   ut_a(UT_LIST_GET_LEN(trx_sys->mysql_trx_list) == 0);
01483 
01484   mem_free(trx_sys);
01485 
01486   trx_sys = NULL;
01487   mutex_exit(&kernel_mutex);
01488 }
01489 #endif /* !UNIV_HOTBACKUP */