Drizzled Public API Documentation

fil0fil.cc
00001 /*****************************************************************************
00002 
00003 Copyright (C) 1995, 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 "fil0fil.h"
00027 
00028 #include "mem0mem.h"
00029 #include "hash0hash.h"
00030 #include "os0file.h"
00031 #include "mach0data.h"
00032 #include "buf0buf.h"
00033 #include "buf0flu.h"
00034 #include "log0recv.h"
00035 #include "fsp0fsp.h"
00036 #include "srv0srv.h"
00037 #include "srv0start.h"
00038 #include "mtr0mtr.h"
00039 #include "mtr0log.h"
00040 #include "dict0dict.h"
00041 #include "page0page.h"
00042 #include "page0zip.h"
00043 #include "xtrabackup_api.h"
00044 #ifndef UNIV_HOTBACKUP
00045 # include "buf0lru.h"
00046 # include "ibuf0ibuf.h"
00047 # include "sync0sync.h"
00048 # include "os0sync.h"
00049 #else /* !UNIV_HOTBACKUP */
00050 static ulint srv_data_read, srv_data_written;
00051 #endif /* !UNIV_HOTBACKUP */
00052 
00053 /*
00054     IMPLEMENTATION OF THE TABLESPACE MEMORY CACHE
00055     =============================================
00056 
00057 The tablespace cache is responsible for providing fast read/write access to
00058 tablespaces and logs of the database. File creation and deletion is done
00059 in other modules which know more of the logic of the operation, however.
00060 
00061 A tablespace consists of a chain of files. The size of the files does not
00062 have to be divisible by the database block size, because we may just leave
00063 the last incomplete block unused. When a new file is appended to the
00064 tablespace, the maximum size of the file is also specified. At the moment,
00065 we think that it is best to extend the file to its maximum size already at
00066 the creation of the file, because then we can avoid dynamically extending
00067 the file when more space is needed for the tablespace.
00068 
00069 A block's position in the tablespace is specified with a 32-bit unsigned
00070 integer. The files in the chain are thought to be catenated, and the block
00071 corresponding to an address n is the nth block in the catenated file (where
00072 the first block is named the 0th block, and the incomplete block fragments
00073 at the end of files are not taken into account). A tablespace can be extended
00074 by appending a new file at the end of the chain.
00075 
00076 Our tablespace concept is similar to the one of Oracle.
00077 
00078 To acquire more speed in disk transfers, a technique called disk striping is
00079 sometimes used. This means that logical block addresses are divided in a
00080 round-robin fashion across several disks. Windows NT supports disk striping,
00081 so there we do not need to support it in the database. Disk striping is
00082 implemented in hardware in RAID disks. We conclude that it is not necessary
00083 to implement it in the database. Oracle 7 does not support disk striping,
00084 either.
00085 
00086 Another trick used at some database sites is replacing tablespace files by
00087 raw disks, that is, the whole physical disk drive, or a partition of it, is
00088 opened as a single file, and it is accessed through byte offsets calculated
00089 from the start of the disk or the partition. This is recommended in some
00090 books on database tuning to achieve more speed in i/o. Using raw disk
00091 certainly prevents the OS from fragmenting disk space, but it is not clear
00092 if it really adds speed. We measured on the Pentium 100 MHz + NT + NTFS file
00093 system + EIDE Conner disk only a negligible difference in speed when reading
00094 from a file, versus reading from a raw disk.
00095 
00096 To have fast access to a tablespace or a log file, we put the data structures
00097 to a hash table. Each tablespace and log file is given an unique 32-bit
00098 identifier.
00099 
00100 Some operating systems do not support many open files at the same time,
00101 though NT seems to tolerate at least 900 open files. Therefore, we put the
00102 open files in an LRU-list. If we need to open another file, we may close the
00103 file at the end of the LRU-list. When an i/o-operation is pending on a file,
00104 the file cannot be closed. We take the file nodes with pending i/o-operations
00105 out of the LRU-list and keep a count of pending operations. When an operation
00106 completes, we decrement the count and return the file node to the LRU-list if
00107 the count drops to zero. */
00108 
00112 UNIV_INTERN const char* fil_path_to_mysql_datadir = ".";
00113 
00115 UNIV_INTERN ulint fil_n_log_flushes     = 0;
00116 
00118 UNIV_INTERN ulint fil_n_pending_log_flushes   = 0;
00120 UNIV_INTERN ulint fil_n_pending_tablespace_flushes  = 0;
00121 
00123 UNIV_INTERN fil_addr_t  fil_addr_null = {FIL_NULL, 0};
00124 
00125 #ifdef UNIV_PFS_MUTEX
00126 /* Key to register fil_system_mutex with performance schema */
00127 UNIV_INTERN mysql_pfs_key_t fil_system_mutex_key;
00128 #endif /* UNIV_PFS_MUTEX */
00129 
00130 #ifdef UNIV_PFS_RWLOCK
00131 /* Key to register file space latch with performance schema */
00132 UNIV_INTERN mysql_pfs_key_t fil_space_latch_key;
00133 #endif /* UNIV_PFS_RWLOCK */
00134 
00136 struct fil_node_struct {
00137   fil_space_t*  space;  
00139   char*   name; 
00140   ibool   open; 
00141   os_file_t handle; 
00142   ibool   is_raw_disk;
00144   ulint   size; 
00147   ulint   n_pending;
00151   ulint   n_pending_flushes;
00155   ib_int64_t  modification_counter;
00157   ib_int64_t  flush_counter;
00160   UT_LIST_NODE_T(fil_node_t) chain;
00162   UT_LIST_NODE_T(fil_node_t) LRU;
00164   ulint   magic_n;
00165 };
00166 
00168 #define FIL_NODE_MAGIC_N  89389
00169 
00171 struct fil_space_struct {
00172   char*   name; 
00174   ulint   id; 
00175   ib_int64_t  tablespace_version;
00181   ibool   mark; 
00185   ibool   stop_ios;
00189   ibool   stop_ibuf_merges;
00192   ibool   is_being_deleted;
00199   ulint   purpose;
00201   UT_LIST_BASE_NODE_T(fil_node_t) chain;
00203   ulint   size; 
00207   ulint   flags;  
00208   ulint   n_reserved_extents;
00211   ulint   n_pending_flushes; 
00214   ulint   n_pending_ibuf_merges;
00220   hash_node_t hash; 
00221   hash_node_t name_hash;
00222 #ifndef UNIV_HOTBACKUP
00223   rw_lock_t latch;  
00225 #endif /* !UNIV_HOTBACKUP */
00226   UT_LIST_NODE_T(fil_space_t) unflushed_spaces;
00229   ibool   is_in_unflushed_spaces; 
00231   UT_LIST_NODE_T(fil_space_t) space_list;
00233   ulint   magic_n;
00234 };
00235 
00237 #define FIL_SPACE_MAGIC_N 89472
00238 
00240 typedef struct fil_system_struct  fil_system_t;
00241 
00246 struct fil_system_struct {
00247 #ifndef UNIV_HOTBACKUP
00248   mutex_t   mutex;    
00249 #endif /* !UNIV_HOTBACKUP */
00250   hash_table_t* spaces;   
00253   hash_table_t* name_hash;  
00255   UT_LIST_BASE_NODE_T(fil_node_t) LRU;
00266   UT_LIST_BASE_NODE_T(fil_space_t) unflushed_spaces;
00272   ulint   n_open;   
00273   ulint   max_n_open; 
00275   ib_int64_t  modification_counter;
00277   ulint   max_assigned_id;
00283   ib_int64_t  tablespace_version;
00291   UT_LIST_BASE_NODE_T(fil_space_t) space_list;
00293   ibool   space_id_reuse_warned;
00294           /* !< TRUE if fil_space_create()
00295           has issued a warning about
00296           potential space_id reuse */
00297 };
00298 
00301 fil_system_t* fil_system  = NULL;
00302 
00303 
00304 /********************************************************************/
00311 static
00312 void
00313 fil_node_prepare_for_io(
00314 /*====================*/
00315   fil_node_t* node, 
00316   fil_system_t* system, 
00317   fil_space_t*  space); 
00318 /********************************************************************/
00321 static
00322 void
00323 fil_node_complete_io(
00324 /*=================*/
00325   fil_node_t* node, 
00326   fil_system_t* system, 
00327   ulint   type);  
00330 /*******************************************************************/
00334 static
00335 ulint
00336 fil_get_space_id_for_table(
00337 /*=======================*/
00338   const char* name);  
00340 /*******************************************************************/
00345 static
00346 ibool
00347 fil_space_free(
00348 /*===========*/
00349   ulint   id,   /* in: space id */
00350   ibool   x_latched); /* in: TRUE if caller has space->latch
00351           in X mode */
00352 /********************************************************************/
00358 UNIV_INLINE
00359 ulint
00360 fil_read(
00361 /*=====*/
00362   ibool sync,   
00363   ulint space_id, 
00364   ulint zip_size, 
00366   ulint block_offset, 
00367   ulint byte_offset,  
00369   ulint len,    
00372   void* buf,    
00374   void* message)  
00376 {
00377   return(fil_io(OS_FILE_READ, sync, space_id, zip_size, block_offset,
00378             byte_offset, len, buf, message));
00379 }
00380 
00381 /********************************************************************/
00387 UNIV_INLINE
00388 ulint
00389 fil_write(
00390 /*======*/
00391   ibool sync,   
00392   ulint space_id, 
00393   ulint zip_size, 
00395   ulint block_offset, 
00396   ulint byte_offset,  
00398   ulint len,    
00401   void* buf,    
00403   void* message)  
00405 {
00406   return(fil_io(OS_FILE_WRITE, sync, space_id, zip_size, block_offset,
00407              byte_offset, len, buf, message));
00408 }
00409 
00410 /*******************************************************************/
00412 UNIV_INLINE
00413 fil_space_t*
00414 fil_space_get_by_id(
00415 /*================*/
00416   ulint id) 
00417 {
00418   fil_space_t*  space;
00419 
00420   ut_ad(mutex_own(&fil_system->mutex));
00421 
00422   HASH_SEARCH(hash, fil_system->spaces, id,
00423         fil_space_t*, space,
00424         ut_ad(space->magic_n == FIL_SPACE_MAGIC_N),
00425         space->id == id);
00426 
00427   return(space);
00428 }
00429 
00430 /*******************************************************************/
00432 UNIV_INLINE
00433 fil_space_t*
00434 fil_space_get_by_name(
00435 /*==================*/
00436   const char* name) 
00437 {
00438   fil_space_t*  space;
00439   ulint   fold;
00440 
00441   ut_ad(mutex_own(&fil_system->mutex));
00442 
00443   fold = ut_fold_string(name);
00444 
00445   HASH_SEARCH(name_hash, fil_system->name_hash, fold,
00446         fil_space_t*, space,
00447         ut_ad(space->magic_n == FIL_SPACE_MAGIC_N),
00448         !strcmp(name, space->name));
00449 
00450   return(space);
00451 }
00452 
00453 #ifndef UNIV_HOTBACKUP
00454 /*******************************************************************/
00458 UNIV_INTERN
00459 ib_int64_t
00460 fil_space_get_version(
00461 /*==================*/
00462   ulint id) 
00463 {
00464   fil_space_t*  space;
00465   ib_int64_t  version   = -1;
00466 
00467   ut_ad(fil_system);
00468 
00469   mutex_enter(&fil_system->mutex);
00470 
00471   space = fil_space_get_by_id(id);
00472 
00473   if (space) {
00474     version = space->tablespace_version;
00475   }
00476 
00477   mutex_exit(&fil_system->mutex);
00478 
00479   return(version);
00480 }
00481 
00482 /*******************************************************************/
00485 UNIV_INTERN
00486 rw_lock_t*
00487 fil_space_get_latch(
00488 /*================*/
00489   ulint id, 
00490   ulint*  flags)  
00491 {
00492   fil_space_t*  space;
00493 
00494   ut_ad(fil_system);
00495 
00496   mutex_enter(&fil_system->mutex);
00497 
00498   space = fil_space_get_by_id(id);
00499 
00500   ut_a(space);
00501 
00502   if (flags) {
00503     *flags = space->flags;
00504   }
00505 
00506   mutex_exit(&fil_system->mutex);
00507 
00508   return(&(space->latch));
00509 }
00510 
00511 /*******************************************************************/
00514 UNIV_INTERN
00515 ulint
00516 fil_space_get_type(
00517 /*===============*/
00518   ulint id) 
00519 {
00520   fil_space_t*  space;
00521 
00522   ut_ad(fil_system);
00523 
00524   mutex_enter(&fil_system->mutex);
00525 
00526   space = fil_space_get_by_id(id);
00527 
00528   ut_a(space);
00529 
00530   mutex_exit(&fil_system->mutex);
00531 
00532   return(space->purpose);
00533 }
00534 #endif /* !UNIV_HOTBACKUP */
00535 
00536 /**********************************************************************/
00540 static
00541 ibool
00542 fil_space_is_flushed(
00543 /*=================*/
00544   fil_space_t*  space)  
00545 {
00546   fil_node_t* node;
00547 
00548   ut_ad(mutex_own(&fil_system->mutex));
00549 
00550   node = UT_LIST_GET_FIRST(space->chain);
00551 
00552   while (node) {
00553     if (node->modification_counter > node->flush_counter) {
00554 
00555       return(FALSE);
00556     }
00557 
00558     node = UT_LIST_GET_NEXT(chain, node);
00559   }
00560 
00561   return(TRUE);
00562 }
00563 
00564 /*******************************************************************/
00566 UNIV_INTERN
00567 void
00568 fil_node_create(
00569 /*============*/
00570   const char* name, 
00571   ulint   size, 
00573   ulint   id, 
00574   ibool   is_raw) 
00576 {
00577   fil_node_t* node;
00578   fil_space_t*  space;
00579 
00580   ut_a(fil_system);
00581   ut_a(name);
00582 
00583   mutex_enter(&fil_system->mutex);
00584 
00585   node = static_cast<fil_node_t *>(mem_alloc(sizeof(fil_node_t)));
00586 
00587   node->name = mem_strdup(name);
00588   node->open = FALSE;
00589 
00590   ut_a(!is_raw || srv_start_raw_disk_in_use);
00591 
00592   node->is_raw_disk = is_raw;
00593   node->size = size;
00594   node->magic_n = FIL_NODE_MAGIC_N;
00595   node->n_pending = 0;
00596   node->n_pending_flushes = 0;
00597 
00598   node->modification_counter = 0;
00599   node->flush_counter = 0;
00600 
00601   space = fil_space_get_by_id(id);
00602 
00603   if (!space) {
00604     ut_print_timestamp(stderr);
00605     fprintf(stderr,
00606       "  InnoDB: Error: Could not find tablespace %lu for\n"
00607       "InnoDB: file ", (ulong) id);
00608     ut_print_filename(stderr, name);
00609     fputs(" in the tablespace memory cache.\n", stderr);
00610     mem_free(node->name);
00611 
00612     mem_free(node);
00613 
00614     mutex_exit(&fil_system->mutex);
00615 
00616     return;
00617   }
00618 
00619   space->size += size;
00620 
00621   node->space = space;
00622 
00623   UT_LIST_ADD_LAST(chain, space->chain, node);
00624 
00625   if (id < SRV_LOG_SPACE_FIRST_ID && fil_system->max_assigned_id < id) {
00626 
00627     fil_system->max_assigned_id = id;
00628   }
00629 
00630   mutex_exit(&fil_system->mutex);
00631 }
00632 
00633 /********************************************************************/
00636 static
00637 void
00638 fil_node_open_file(
00639 /*===============*/
00640   fil_node_t* node, 
00641   fil_system_t* system, 
00642   fil_space_t*  space)  
00643 {
00644   uint64_t  size_bytes;
00645   ulint   size_low;
00646   ulint   size_high;
00647   ibool   ret;
00648   ibool   success;
00649   byte*   buf2;
00650   byte*   page;
00651   ulint   space_id;
00652   ulint   flags;
00653 
00654   ut_ad(mutex_own(&(system->mutex)));
00655   ut_a(node->n_pending == 0);
00656   ut_a(node->open == FALSE);
00657 
00658   if (node->size == 0) {
00659     /* It must be a single-table tablespace and we do not know the
00660     size of the file yet. First we open the file in the normal
00661     mode, no async I/O here, for simplicity. Then do some checks,
00662     and close the file again.
00663     NOTE that we could not use the simple file read function
00664     os_file_read() in Windows to read from a file opened for
00665     async I/O! */
00666 
00667     node->handle = os_file_create_simple_no_error_handling(
00668       innodb_file_data_key, node->name, OS_FILE_OPEN,
00669       OS_FILE_READ_ONLY, &success);
00670     if (!success) {
00671       /* The following call prints an error message */
00672       os_file_get_last_error(TRUE);
00673 
00674       ut_print_timestamp(stderr);
00675 
00676       fprintf(stderr,
00677         "  InnoDB: Fatal error: cannot open %s\n."
00678         "InnoDB: Have you deleted .ibd files"
00679         " under a running mysqld server?\n",
00680         node->name);
00681       ut_a(0);
00682     }
00683 
00684     os_file_get_size(node->handle, &size_low, &size_high);
00685 
00686     size_bytes = (((uint64_t)size_high) << 32) + size_low;
00687 #ifdef UNIV_HOTBACKUP
00688     if (space->id == 0) {
00689       node->size = size_bytes / UNIV_PAGE_SIZE;
00690       os_file_close(node->handle);
00691       goto add_size;
00692     }
00693 #endif /* UNIV_HOTBACKUP */
00694     ut_a(space->purpose != FIL_LOG);
00695     ut_a(space->id != 0);
00696 
00697     if (size_bytes < FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE) {
00698       fprintf(stderr,
00699         "InnoDB: Error: the size of single-table"
00700         " tablespace file %s\n"
00701         "InnoDB: is only %lu %lu,"
00702         " should be at least %lu!\n",
00703         node->name,
00704         (ulong) size_high,
00705         (ulong) size_low,
00706         (ulong) (FIL_IBD_FILE_INITIAL_SIZE
00707            * UNIV_PAGE_SIZE));
00708 
00709       ut_a(0);
00710     }
00711 
00712     /* Read the first page of the tablespace */
00713 
00714     buf2 = static_cast<unsigned char *>(ut_malloc(2 * UNIV_PAGE_SIZE));
00715     /* Align the memory for file i/o if we might have O_DIRECT
00716     set */
00717     page = static_cast<unsigned char *>(ut_align(buf2, UNIV_PAGE_SIZE));
00718 
00719     success = os_file_read(node->handle, page, 0, 0,
00720                UNIV_PAGE_SIZE);
00721     space_id = fsp_header_get_space_id(page);
00722     flags = fsp_header_get_flags(page);
00723 
00724     ut_free(buf2);
00725 
00726     /* Close the file now that we have read the space id from it */
00727 
00728     os_file_close(node->handle);
00729 
00730     if (UNIV_UNLIKELY(space_id != space->id)) {
00731       fprintf(stderr,
00732         "InnoDB: Error: tablespace id is %lu"
00733         " in the data dictionary\n"
00734         "InnoDB: but in file %s it is %lu!\n",
00735         space->id, node->name, space_id);
00736 
00737       ut_error;
00738     }
00739 
00740     if (UNIV_UNLIKELY(space_id == ULINT_UNDEFINED
00741           || space_id == 0)) {
00742       fprintf(stderr,
00743         "InnoDB: Error: tablespace id %lu"
00744         " in file %s is not sensible\n",
00745         (ulong) space_id, node->name);
00746 
00747       ut_error;
00748     }
00749 
00750     if (UNIV_UNLIKELY(space->flags != flags)) {
00751       fprintf(stderr,
00752         "InnoDB: Error: table flags are %lx"
00753         " in the data dictionary\n"
00754         "InnoDB: but the flags in file %s are %lx!\n",
00755         space->flags, node->name, flags);
00756 
00757       ut_error;
00758     }
00759 
00760     if (size_bytes >= 1024 * 1024) {
00761       /* Truncate the size to whole megabytes. */
00762       size_bytes = ut_2pow_round(size_bytes, 1024 * 1024);
00763     }
00764 
00765     if (!(flags & DICT_TF_ZSSIZE_MASK)) {
00766       node->size = (ulint)size_bytes / UNIV_PAGE_SIZE;
00767     } else {
00768       node->size = (ulint)
00769         (size_bytes
00770          / dict_table_flags_to_zip_size(flags));
00771     }
00772 
00773 #ifdef UNIV_HOTBACKUP
00774 add_size:
00775 #endif /* UNIV_HOTBACKUP */
00776     space->size += node->size;
00777   }
00778 
00779   /* printf("Opening file %s\n", node->name); */
00780 
00781   /* Open the file for reading and writing, in Windows normally in the
00782   unbuffered async I/O mode, though global variables may make
00783   os_file_create() to fall back to the normal file I/O mode. */
00784 
00785   if (space->purpose == FIL_LOG) {
00786     node->handle = os_file_create(innodb_file_log_key,
00787                 node->name, OS_FILE_OPEN,
00788                 OS_FILE_AIO, OS_LOG_FILE,
00789                 &ret);
00790   } else if (node->is_raw_disk) {
00791     node->handle = os_file_create(innodb_file_data_key,
00792                 node->name,
00793                 OS_FILE_OPEN_RAW,
00794                 OS_FILE_AIO, OS_DATA_FILE,
00795                  &ret);
00796   } else {
00797     node->handle = os_file_create(innodb_file_data_key,
00798                 node->name, OS_FILE_OPEN,
00799                 OS_FILE_AIO, OS_DATA_FILE,
00800                 &ret);
00801   }
00802 
00803   ut_a(ret);
00804 
00805   node->open = TRUE;
00806 
00807   system->n_open++;
00808 
00809   if (space->purpose == FIL_TABLESPACE && space->id != 0) {
00810     /* Put the node to the LRU list */
00811     UT_LIST_ADD_FIRST(LRU, system->LRU, node);
00812   }
00813 }
00814 
00815 /**********************************************************************/
00817 static
00818 void
00819 fil_node_close_file(
00820 /*================*/
00821   fil_node_t* node, 
00822   fil_system_t* system) 
00823 {
00824   ibool ret;
00825 
00826   ut_ad(node && system);
00827   ut_ad(mutex_own(&(system->mutex)));
00828   ut_a(node->open);
00829   ut_a(node->n_pending == 0);
00830   ut_a(node->n_pending_flushes == 0);
00831   ut_a(node->modification_counter == node->flush_counter);
00832 
00833   ret = os_file_close(node->handle);
00834   ut_a(ret);
00835 
00836   /* printf("Closing file %s\n", node->name); */
00837 
00838   node->open = FALSE;
00839   ut_a(system->n_open > 0);
00840   system->n_open--;
00841 
00842   if (node->space->purpose == FIL_TABLESPACE && node->space->id != 0) {
00843     ut_a(UT_LIST_GET_LEN(system->LRU) > 0);
00844 
00845     /* The node is in the LRU list, remove it */
00846     UT_LIST_REMOVE(LRU, system->LRU, node);
00847   }
00848 }
00849 
00850 /********************************************************************/
00858 static
00859 ibool
00860 fil_try_to_close_file_in_LRU(
00861 /*=========================*/
00862   ibool print_info) 
00864 {
00865   fil_node_t* node;
00866 
00867   ut_ad(mutex_own(&fil_system->mutex));
00868 
00869   node = UT_LIST_GET_LAST(fil_system->LRU);
00870 
00871   if (print_info) {
00872     fprintf(stderr,
00873       "InnoDB: fil_sys open file LRU len %lu\n",
00874       (ulong) UT_LIST_GET_LEN(fil_system->LRU));
00875   }
00876 
00877   while (node != NULL) {
00878     if (node->modification_counter == node->flush_counter
00879         && node->n_pending_flushes == 0) {
00880 
00881       fil_node_close_file(node, fil_system);
00882 
00883       return(TRUE);
00884     }
00885 
00886     if (print_info && node->n_pending_flushes > 0) {
00887       fputs("InnoDB: cannot close file ", stderr);
00888       ut_print_filename(stderr, node->name);
00889       fprintf(stderr, ", because n_pending_flushes %lu\n",
00890         (ulong) node->n_pending_flushes);
00891     }
00892 
00893     if (print_info
00894         && node->modification_counter != node->flush_counter) {
00895       fputs("InnoDB: cannot close file ", stderr);
00896       ut_print_filename(stderr, node->name);
00897       fprintf(stderr,
00898         ", because mod_count %ld != fl_count %ld\n",
00899         (long) node->modification_counter,
00900         (long) node->flush_counter);
00901     }
00902 
00903     node = UT_LIST_GET_PREV(LRU, node);
00904   }
00905 
00906   return(FALSE);
00907 }
00908 
00909 /*******************************************************************/
00913 static
00914 void
00915 fil_mutex_enter_and_prepare_for_io(
00916 /*===============================*/
00917   ulint space_id) 
00918 {
00919   fil_space_t*  space;
00920   ibool   success;
00921   ibool   print_info  = FALSE;
00922   ulint   count   = 0;
00923   ulint   count2    = 0;
00924 
00925 retry:
00926   mutex_enter(&fil_system->mutex);
00927 
00928   if (space_id == 0 || space_id >= SRV_LOG_SPACE_FIRST_ID) {
00929     /* We keep log files and system tablespace files always open;
00930     this is important in preventing deadlocks in this module, as
00931     a page read completion often performs another read from the
00932     insert buffer. The insert buffer is in tablespace 0, and we
00933     cannot end up waiting in this function. */
00934 
00935     return;
00936   }
00937 
00938   if (fil_system->n_open < fil_system->max_n_open) {
00939 
00940     return;
00941   }
00942 
00943   space = fil_space_get_by_id(space_id);
00944 
00945   if (space != NULL && space->stop_ios) {
00946     /* We are going to do a rename file and want to stop new i/o's
00947     for a while */
00948 
00949     if (count2 > 20000) {
00950       fputs("InnoDB: Warning: tablespace ", stderr);
00951       ut_print_filename(stderr, space->name);
00952       fprintf(stderr,
00953         " has i/o ops stopped for a long time %lu\n",
00954         (ulong) count2);
00955     }
00956 
00957     mutex_exit(&fil_system->mutex);
00958 
00959     os_thread_sleep(20000);
00960 
00961     count2++;
00962 
00963     goto retry;
00964   }
00965 
00966   /* If the file is already open, no need to do anything; if the space
00967   does not exist, we handle the situation in the function which called
00968   this function */
00969 
00970   if (!space || UT_LIST_GET_FIRST(space->chain)->open) {
00971 
00972     return;
00973   }
00974 
00975   if (count > 1) {
00976     print_info = TRUE;
00977   }
00978 
00979   /* Too many files are open, try to close some */
00980 close_more:
00981   success = fil_try_to_close_file_in_LRU(print_info);
00982 
00983   if (success && fil_system->n_open >= fil_system->max_n_open) {
00984 
00985     goto close_more;
00986   }
00987 
00988   if (fil_system->n_open < fil_system->max_n_open) {
00989     /* Ok */
00990 
00991     return;
00992   }
00993 
00994   if (count >= 2) {
00995     ut_print_timestamp(stderr);
00996     fprintf(stderr,
00997       "  InnoDB: Warning: too many (%lu) files stay open"
00998       " while the maximum\n"
00999       "InnoDB: allowed value would be %lu.\n"
01000       "InnoDB: You may need to raise the value of"
01001       " innodb_open_files in\n"
01002       "InnoDB: my.cnf.\n",
01003       (ulong) fil_system->n_open,
01004       (ulong) fil_system->max_n_open);
01005 
01006     return;
01007   }
01008 
01009   mutex_exit(&fil_system->mutex);
01010 
01011 #ifndef UNIV_HOTBACKUP
01012   /* Wake the i/o-handler threads to make sure pending i/o's are
01013   performed */
01014   os_aio_simulated_wake_handler_threads();
01015 
01016   os_thread_sleep(20000);
01017 #endif
01018   /* Flush tablespaces so that we can close modified files in the LRU
01019   list */
01020 
01021   fil_flush_file_spaces(FIL_TABLESPACE);
01022 
01023   count++;
01024 
01025   goto retry;
01026 }
01027 
01028 /*******************************************************************/
01030 static
01031 void
01032 fil_node_free(
01033 /*==========*/
01034   fil_node_t* node, 
01035   fil_system_t* system, 
01036   fil_space_t*  space)  
01037 {
01038   ut_ad(node && system && space);
01039   ut_ad(mutex_own(&(system->mutex)));
01040   ut_a(node->magic_n == FIL_NODE_MAGIC_N);
01041   ut_a(node->n_pending == 0);
01042 
01043   if (node->open) {
01044     /* We fool the assertion in fil_node_close_file() to think
01045     there are no unflushed modifications in the file */
01046 
01047     node->modification_counter = node->flush_counter;
01048 
01049     if (space->is_in_unflushed_spaces
01050         && fil_space_is_flushed(space)) {
01051 
01052       space->is_in_unflushed_spaces = FALSE;
01053 
01054       UT_LIST_REMOVE(unflushed_spaces,
01055                system->unflushed_spaces,
01056                space);
01057     }
01058 
01059     fil_node_close_file(node, system);
01060   }
01061 
01062   space->size -= node->size;
01063 
01064   UT_LIST_REMOVE(chain, space->chain, node);
01065 
01066   mem_free(node->name);
01067   mem_free(node);
01068 }
01069 
01070 #ifdef UNIV_LOG_ARCHIVE
01071 /****************************************************************/
01074 UNIV_INTERN
01075 void
01076 fil_space_truncate_start(
01077 /*=====================*/
01078   ulint id,   
01079   ulint trunc_len)  
01082 {
01083   fil_node_t* node;
01084   fil_space_t*  space;
01085 
01086   mutex_enter(&fil_system->mutex);
01087 
01088   space = fil_space_get_by_id(id);
01089 
01090   ut_a(space);
01091 
01092   while (trunc_len > 0) {
01093     node = UT_LIST_GET_FIRST(space->chain);
01094 
01095     ut_a(node->size * UNIV_PAGE_SIZE <= trunc_len);
01096 
01097     trunc_len -= node->size * UNIV_PAGE_SIZE;
01098 
01099     fil_node_free(node, fil_system, space);
01100   }
01101 
01102   mutex_exit(&fil_system->mutex);
01103 }
01104 #endif /* UNIV_LOG_ARCHIVE */
01105 
01106 /*******************************************************************/
01110 UNIV_INTERN
01111 ibool
01112 fil_space_create(
01113 /*=============*/
01114   const char* name, 
01115   ulint   id, 
01116   ulint   flags,  
01118   ulint   purpose)
01119 {
01120   fil_space_t*  space;
01121 
01122   /* The tablespace flags (FSP_SPACE_FLAGS) should be 0 for
01123   ROW_FORMAT=COMPACT
01124   ((table->flags & ~(~0 << DICT_TF_BITS)) == DICT_TF_COMPACT) and
01125   ROW_FORMAT=REDUNDANT (table->flags == 0).  For any other
01126   format, the tablespace flags should equal
01127   (table->flags & ~(~0 << DICT_TF_BITS)). */
01128   ut_a(flags != DICT_TF_COMPACT);
01129   ut_a(!(flags & (~0UL << DICT_TF_BITS)));
01130 
01131 try_again:
01132   /*printf(
01133   "InnoDB: Adding tablespace %lu of name %s, purpose %lu\n", id, name,
01134   purpose);*/
01135 
01136   ut_a(fil_system);
01137   ut_a(name);
01138 
01139   mutex_enter(&fil_system->mutex);
01140 
01141   space = fil_space_get_by_name(name);
01142 
01143   if (UNIV_LIKELY_NULL(space)) {
01144     ibool success;
01145     ulint namesake_id;
01146 
01147     ut_print_timestamp(stderr);
01148     fprintf(stderr,
01149       "  InnoDB: Warning: trying to init to the"
01150       " tablespace memory cache\n"
01151       "InnoDB: a tablespace %lu of name ", (ulong) id);
01152     ut_print_filename(stderr, name);
01153     fprintf(stderr, ",\n"
01154       "InnoDB: but a tablespace %lu of the same name\n"
01155       "InnoDB: already exists in the"
01156       " tablespace memory cache!\n",
01157       (ulong) space->id);
01158 
01159     if (id == 0 || purpose != FIL_TABLESPACE) {
01160 
01161       mutex_exit(&fil_system->mutex);
01162 
01163       return(FALSE);
01164     }
01165 
01166     fprintf(stderr,
01167       "InnoDB: We assume that InnoDB did a crash recovery,"
01168       " and you had\n"
01169       "InnoDB: an .ibd file for which the table"
01170       " did not exist in the\n"
01171       "InnoDB: InnoDB internal data dictionary in the"
01172       " ibdata files.\n"
01173       "InnoDB: We assume that you later removed the"
01174       " .ibd and .frm files,\n"
01175       "InnoDB: and are now trying to recreate the table."
01176       " We now remove the\n"
01177       "InnoDB: conflicting tablespace object"
01178       " from the memory cache and try\n"
01179       "InnoDB: the init again.\n");
01180 
01181     namesake_id = space->id;
01182 
01183     success = fil_space_free(namesake_id, FALSE);
01184     ut_a(success);
01185 
01186     mutex_exit(&fil_system->mutex);
01187 
01188     goto try_again;
01189   }
01190 
01191   space = fil_space_get_by_id(id);
01192 
01193   if (UNIV_LIKELY_NULL(space)) {
01194     fprintf(stderr,
01195       "InnoDB: Error: trying to add tablespace %lu"
01196       " of name ", (ulong) id);
01197     ut_print_filename(stderr, name);
01198     fprintf(stderr, "\n"
01199       "InnoDB: to the tablespace memory cache,"
01200       " but tablespace\n"
01201       "InnoDB: %lu of name ", (ulong) space->id);
01202     ut_print_filename(stderr, space->name);
01203     fputs(" already exists in the tablespace\n"
01204           "InnoDB: memory cache!\n", stderr);
01205 
01206     mutex_exit(&fil_system->mutex);
01207 
01208     return(FALSE);
01209   }
01210 
01211   space = static_cast<fil_space_t *>(mem_alloc(sizeof(fil_space_t)));
01212 
01213   space->name = mem_strdup(name);
01214   space->id = id;
01215 
01216   fil_system->tablespace_version++;
01217   space->tablespace_version = fil_system->tablespace_version;
01218   space->mark = FALSE;
01219 
01220   if (UNIV_LIKELY(purpose == FIL_TABLESPACE && !recv_recovery_on)
01221       && UNIV_UNLIKELY(id > fil_system->max_assigned_id)) {
01222     if (!fil_system->space_id_reuse_warned) {
01223       fil_system->space_id_reuse_warned = TRUE;
01224 
01225       ut_print_timestamp(stderr);
01226       fprintf(stderr,
01227         "  InnoDB: Warning: allocated tablespace %lu,"
01228         " old maximum was %lu\n",
01229         (ulong) id,
01230         (ulong) fil_system->max_assigned_id);
01231     }
01232 
01233     fil_system->max_assigned_id = id;
01234   }
01235 
01236   space->stop_ios = FALSE;
01237   space->stop_ibuf_merges = FALSE;
01238   space->is_being_deleted = FALSE;
01239   space->purpose = purpose;
01240   space->size = 0;
01241   space->flags = flags;
01242 
01243   space->n_reserved_extents = 0;
01244 
01245   space->n_pending_flushes = 0;
01246   space->n_pending_ibuf_merges = 0;
01247 
01248   UT_LIST_INIT(space->chain);
01249   space->magic_n = FIL_SPACE_MAGIC_N;
01250 
01251   rw_lock_create(fil_space_latch_key, &space->latch, SYNC_FSP);
01252 
01253   HASH_INSERT(fil_space_t, hash, fil_system->spaces, id, space);
01254 
01255   HASH_INSERT(fil_space_t, name_hash, fil_system->name_hash,
01256         ut_fold_string(name), space);
01257   space->is_in_unflushed_spaces = FALSE;
01258 
01259   UT_LIST_ADD_LAST(space_list, fil_system->space_list, space);
01260 
01261   mutex_exit(&fil_system->mutex);
01262 
01263   return(TRUE);
01264 }
01265 
01266 /*******************************************************************/
01271 UNIV_INTERN
01272 ibool
01273 fil_assign_new_space_id(
01274 /*====================*/
01275   ulint*  space_id) 
01276 {
01277   ulint id;
01278   ibool success;
01279 
01280   mutex_enter(&fil_system->mutex);
01281 
01282   id = *space_id;
01283 
01284   if (id < fil_system->max_assigned_id) {
01285     id = fil_system->max_assigned_id;
01286   }
01287 
01288   id++;
01289 
01290   if (id > (SRV_LOG_SPACE_FIRST_ID / 2) && (id % 1000000UL == 0)) {
01291     ut_print_timestamp(stderr);
01292     fprintf(stderr,
01293       "InnoDB: Warning: you are running out of new"
01294       " single-table tablespace id's.\n"
01295       "InnoDB: Current counter is %lu and it"
01296       " must not exceed %lu!\n"
01297       "InnoDB: To reset the counter to zero"
01298       " you have to dump all your tables and\n"
01299       "InnoDB: recreate the whole InnoDB installation.\n",
01300       (ulong) id,
01301       (ulong) SRV_LOG_SPACE_FIRST_ID);
01302   }
01303 
01304   success = (id < SRV_LOG_SPACE_FIRST_ID);
01305 
01306   if (success) {
01307     *space_id = fil_system->max_assigned_id = id;
01308   } else {
01309     ut_print_timestamp(stderr);
01310     fprintf(stderr,
01311       "InnoDB: You have run out of single-table"
01312       " tablespace id's!\n"
01313       "InnoDB: Current counter is %lu.\n"
01314       "InnoDB: To reset the counter to zero you"
01315       " have to dump all your tables and\n"
01316       "InnoDB: recreate the whole InnoDB installation.\n",
01317       (ulong) id);
01318     *space_id = ULINT_UNDEFINED;
01319   }
01320 
01321   mutex_exit(&fil_system->mutex);
01322 
01323   return(success);
01324 }
01325 
01326 /*******************************************************************/
01331 static
01332 ibool
01333 fil_space_free(
01334 /*===========*/
01335           /* out: TRUE if success */
01336   ulint   id,   /* in: space id */
01337   ibool   x_latched)  /* in: TRUE if caller has space->latch
01338           in X mode */
01339 {
01340   fil_space_t*  space;
01341   fil_space_t*  tablespace;
01342   fil_node_t* fil_node;
01343 
01344   ut_ad(mutex_own(&fil_system->mutex));
01345 
01346   space = fil_space_get_by_id(id);
01347 
01348   if (!space) {
01349     ut_print_timestamp(stderr);
01350     fprintf(stderr,
01351       "  InnoDB: Error: trying to remove tablespace %lu"
01352       " from the cache but\n"
01353       "InnoDB: it is not there.\n", (ulong) id);
01354 
01355     return(FALSE);
01356   }
01357 
01358   HASH_DELETE(fil_space_t, hash, fil_system->spaces, id, space);
01359 
01360   tablespace = fil_space_get_by_name(space->name);
01361   ut_a(tablespace);
01362   ut_a(space == tablespace);
01363 
01364   HASH_DELETE(fil_space_t, name_hash, fil_system->name_hash,
01365         ut_fold_string(space->name), space);
01366 
01367   if (space->is_in_unflushed_spaces) {
01368     space->is_in_unflushed_spaces = FALSE;
01369 
01370     UT_LIST_REMOVE(unflushed_spaces, fil_system->unflushed_spaces,
01371              space);
01372   }
01373 
01374   UT_LIST_REMOVE(space_list, fil_system->space_list, space);
01375 
01376   ut_a(space->magic_n == FIL_SPACE_MAGIC_N);
01377   ut_a(0 == space->n_pending_flushes);
01378 
01379   fil_node = UT_LIST_GET_FIRST(space->chain);
01380 
01381   while (fil_node != NULL) {
01382     fil_node_free(fil_node, fil_system, space);
01383 
01384     fil_node = UT_LIST_GET_FIRST(space->chain);
01385   }
01386 
01387   ut_a(0 == UT_LIST_GET_LEN(space->chain));
01388 
01389   if (x_latched) {
01390     rw_lock_x_unlock(&space->latch);
01391   }
01392 
01393   rw_lock_free(&(space->latch));
01394 
01395   mem_free(space->name);
01396   mem_free(space);
01397 
01398   return(TRUE);
01399 }
01400 
01401 /*******************************************************************/
01405 UNIV_INTERN
01406 ulint
01407 fil_space_get_size(
01408 /*===============*/
01409   ulint id) 
01410 {
01411   fil_node_t* node;
01412   fil_space_t*  space;
01413   ulint   size;
01414 
01415   ut_ad(fil_system);
01416 
01417   fil_mutex_enter_and_prepare_for_io(id);
01418 
01419   space = fil_space_get_by_id(id);
01420 
01421   if (space == NULL) {
01422     mutex_exit(&fil_system->mutex);
01423 
01424     return(0);
01425   }
01426 
01427   if (space->size == 0 && space->purpose == FIL_TABLESPACE) {
01428     ut_a(id != 0);
01429 
01430     ut_a(1 == UT_LIST_GET_LEN(space->chain));
01431 
01432     node = UT_LIST_GET_FIRST(space->chain);
01433 
01434     /* It must be a single-table tablespace and we have not opened
01435     the file yet; the following calls will open it and update the
01436     size fields */
01437 
01438     fil_node_prepare_for_io(node, fil_system, space);
01439     fil_node_complete_io(node, fil_system, OS_FILE_READ);
01440   }
01441 
01442   size = space->size;
01443 
01444   mutex_exit(&fil_system->mutex);
01445 
01446   return(size);
01447 }
01448 
01449 /*******************************************************************/
01453 UNIV_INTERN
01454 ulint
01455 fil_space_get_flags(
01456 /*================*/
01457   ulint id) 
01458 {
01459   fil_node_t* node;
01460   fil_space_t*  space;
01461   ulint   flags;
01462 
01463   ut_ad(fil_system);
01464 
01465   if (UNIV_UNLIKELY(!id)) {
01466     return(0);
01467   }
01468 
01469   fil_mutex_enter_and_prepare_for_io(id);
01470 
01471   space = fil_space_get_by_id(id);
01472 
01473   if (space == NULL) {
01474     mutex_exit(&fil_system->mutex);
01475 
01476     return(ULINT_UNDEFINED);
01477   }
01478 
01479   if (space->size == 0 && space->purpose == FIL_TABLESPACE) {
01480     ut_a(id != 0);
01481 
01482     ut_a(1 == UT_LIST_GET_LEN(space->chain));
01483 
01484     node = UT_LIST_GET_FIRST(space->chain);
01485 
01486     /* It must be a single-table tablespace and we have not opened
01487     the file yet; the following calls will open it and update the
01488     size fields */
01489 
01490     fil_node_prepare_for_io(node, fil_system, space);
01491     fil_node_complete_io(node, fil_system, OS_FILE_READ);
01492   }
01493 
01494   flags = space->flags;
01495 
01496   mutex_exit(&fil_system->mutex);
01497 
01498   return(flags);
01499 }
01500 
01501 /*******************************************************************/
01505 UNIV_INTERN
01506 ulint
01507 fil_space_get_zip_size(
01508 /*===================*/
01509   ulint id) 
01510 {
01511   ulint flags;
01512 
01513   flags = fil_space_get_flags(id);
01514 
01515   if (flags && flags != ULINT_UNDEFINED) {
01516 
01517     return(dict_table_flags_to_zip_size(flags));
01518   }
01519 
01520   return(flags);
01521 }
01522 
01523 /*******************************************************************/
01527 UNIV_INTERN
01528 ibool
01529 fil_check_adress_in_tablespace(
01530 /*===========================*/
01531   ulint id, 
01532   ulint page_no)
01533 {
01534   if (fil_space_get_size(id) > page_no) {
01535 
01536     return(TRUE);
01537   }
01538 
01539   return(FALSE);
01540 }
01541 
01542 /****************************************************************/
01544 UNIV_INTERN
01545 void
01546 fil_init(
01547 /*=====*/
01548   ulint hash_size,  
01549   ulint max_n_open) 
01550 {
01551   ut_a(fil_system == NULL);
01552 
01553   ut_a(hash_size > 0);
01554   ut_a(max_n_open > 0);
01555 
01556         void *fil_system_ptr= mem_zalloc(sizeof(fil_system_t));
01557   fil_system = static_cast<fil_system_t *>(fil_system_ptr);
01558 
01559   mutex_create(fil_system_mutex_key,
01560          &fil_system->mutex, SYNC_ANY_LATCH);
01561 
01562   fil_system->spaces = hash_create(hash_size);
01563   fil_system->name_hash = hash_create(hash_size);
01564 
01565   UT_LIST_INIT(fil_system->LRU);
01566 
01567   fil_system->max_n_open = max_n_open;
01568 }
01569 
01570 /*******************************************************************/
01576 UNIV_INTERN
01577 void
01578 fil_open_log_and_system_tablespace_files(void)
01579 /*==========================================*/
01580 {
01581   fil_space_t*  space;
01582   fil_node_t* node;
01583 
01584   mutex_enter(&fil_system->mutex);
01585 
01586   space = UT_LIST_GET_FIRST(fil_system->space_list);
01587 
01588   while (space != NULL) {
01589     if (space->purpose != FIL_TABLESPACE || space->id == 0) {
01590       node = UT_LIST_GET_FIRST(space->chain);
01591 
01592       while (node != NULL) {
01593         if (!node->open) {
01594           fil_node_open_file(node, fil_system,
01595                  space);
01596         }
01597         if (fil_system->max_n_open
01598             < 10 + fil_system->n_open) {
01599           fprintf(stderr,
01600             "InnoDB: Warning: you must"
01601             " raise the value of"
01602             " innodb_open_files in\n"
01603             "InnoDB: my.cnf! Remember that"
01604             " InnoDB keeps all log files"
01605             " and all system\n"
01606             "InnoDB: tablespace files open"
01607             " for the whole time mysqld is"
01608             " running, and\n"
01609             "InnoDB: needs to open also"
01610             " some .ibd files if the"
01611             " file-per-table storage\n"
01612             "InnoDB: model is used."
01613             " Current open files %lu,"
01614             " max allowed"
01615             " open files %lu.\n",
01616             (ulong) fil_system->n_open,
01617             (ulong) fil_system->max_n_open);
01618         }
01619         node = UT_LIST_GET_NEXT(chain, node);
01620       }
01621     }
01622     space = UT_LIST_GET_NEXT(space_list, space);
01623   }
01624 
01625   mutex_exit(&fil_system->mutex);
01626 }
01627 
01628 /*******************************************************************/
01631 UNIV_INTERN
01632 void
01633 fil_close_all_files(void)
01634 /*=====================*/
01635 {
01636   fil_space_t*  space;
01637 
01638   mutex_enter(&fil_system->mutex);
01639 
01640   space = UT_LIST_GET_FIRST(fil_system->space_list);
01641 
01642   while (space != NULL) {
01643     fil_node_t* node;
01644     fil_space_t*  prev_space = space;
01645 
01646     for (node = UT_LIST_GET_FIRST(space->chain);
01647          node != NULL;
01648          node = UT_LIST_GET_NEXT(chain, node)) {
01649 
01650       if (node->open) {
01651         fil_node_close_file(node, fil_system);
01652       }
01653     }
01654 
01655     space = UT_LIST_GET_NEXT(space_list, space);
01656 
01657     fil_space_free(prev_space->id, FALSE);
01658   }
01659 
01660   mutex_exit(&fil_system->mutex);
01661 }
01662 
01663 /*******************************************************************/
01666 UNIV_INTERN
01667 void
01668 fil_set_max_space_id_if_bigger(
01669 /*===========================*/
01670   ulint max_id) 
01671 {
01672   if (max_id >= SRV_LOG_SPACE_FIRST_ID) {
01673     fprintf(stderr,
01674       "InnoDB: Fatal error: max tablespace id"
01675       " is too high, %lu\n", (ulong) max_id);
01676     ut_error;
01677   }
01678 
01679   mutex_enter(&fil_system->mutex);
01680 
01681   if (fil_system->max_assigned_id < max_id) {
01682 
01683     fil_system->max_assigned_id = max_id;
01684   }
01685 
01686   mutex_exit(&fil_system->mutex);
01687 }
01688 
01689 /****************************************************************/
01693 static
01694 ulint
01695 fil_write_lsn_and_arch_no_to_file(
01696 /*==============================*/
01697   ulint   sum_of_sizes, 
01699   ib_uint64_t lsn,    
01700   ulint   /*arch_log_no __attribute__((unused))*/)
01702 {
01703   byte* buf1;
01704   byte* buf;
01705 
01706   buf1 = static_cast<byte *>(mem_alloc(2 * UNIV_PAGE_SIZE));
01707   buf = static_cast<byte *>(ut_align(buf1, UNIV_PAGE_SIZE));
01708 
01709   fil_read(TRUE, 0, 0, sum_of_sizes, 0, UNIV_PAGE_SIZE, buf, NULL);
01710 
01711   mach_write_to_8(buf + FIL_PAGE_FILE_FLUSH_LSN, lsn);
01712 
01713   fil_write(TRUE, 0, 0, sum_of_sizes, 0, UNIV_PAGE_SIZE, buf, NULL);
01714 
01715   mem_free(buf1);
01716 
01717   return(DB_SUCCESS);
01718 }
01719 
01720 /****************************************************************/
01724 UNIV_INTERN
01725 ulint
01726 fil_write_flushed_lsn_to_data_files(
01727 /*================================*/
01728   ib_uint64_t lsn,    
01729   ulint   arch_log_no)  
01731 {
01732   fil_space_t*  space;
01733   fil_node_t* node;
01734   ulint   sum_of_sizes;
01735   ulint   err;
01736 
01737   mutex_enter(&fil_system->mutex);
01738 
01739   space = UT_LIST_GET_FIRST(fil_system->space_list);
01740 
01741   while (space) {
01742     /* We only write the lsn to all existing data files which have
01743     been open during the lifetime of the mysqld process; they are
01744     represented by the space objects in the tablespace memory
01745     cache. Note that all data files in the system tablespace 0 are
01746     always open. */
01747 
01748     if (space->purpose == FIL_TABLESPACE
01749         && space->id == 0) {
01750       sum_of_sizes = 0;
01751 
01752       node = UT_LIST_GET_FIRST(space->chain);
01753       while (node) {
01754         mutex_exit(&fil_system->mutex);
01755 
01756         err = fil_write_lsn_and_arch_no_to_file(
01757           sum_of_sizes, lsn, arch_log_no);
01758         if (err != DB_SUCCESS) {
01759 
01760           return(err);
01761         }
01762 
01763         mutex_enter(&fil_system->mutex);
01764 
01765         sum_of_sizes += node->size;
01766         node = UT_LIST_GET_NEXT(chain, node);
01767       }
01768     }
01769     space = UT_LIST_GET_NEXT(space_list, space);
01770   }
01771 
01772   mutex_exit(&fil_system->mutex);
01773 
01774   return(DB_SUCCESS);
01775 }
01776 
01777 /*******************************************************************/
01780 UNIV_INTERN
01781 void
01782 fil_read_flushed_lsn_and_arch_log_no(
01783 /*=================================*/
01784   os_file_t data_file,    
01785   ibool   one_read_already, 
01788 #ifdef UNIV_LOG_ARCHIVE
01789   ulint*    min_arch_log_no,  
01790   ulint*    max_arch_log_no,  
01791 #endif /* UNIV_LOG_ARCHIVE */
01792   ib_uint64_t*  min_flushed_lsn,  
01793   ib_uint64_t*  max_flushed_lsn)  
01794 {
01795   byte*   buf;
01796   byte*   buf2;
01797   ib_uint64_t flushed_lsn;
01798 
01799   buf2 = static_cast<byte *>(ut_malloc(2 * UNIV_PAGE_SIZE));
01800   /* Align the memory for a possible read from a raw device */
01801   buf = static_cast<byte *>(ut_align(buf2, UNIV_PAGE_SIZE));
01802 
01803   os_file_read(data_file, buf, 0, 0, UNIV_PAGE_SIZE);
01804 
01805   flushed_lsn = mach_read_from_8(buf + FIL_PAGE_FILE_FLUSH_LSN);
01806 
01807   ut_free(buf2);
01808 
01809   if (!one_read_already) {
01810     *min_flushed_lsn = flushed_lsn;
01811     *max_flushed_lsn = flushed_lsn;
01812 #ifdef UNIV_LOG_ARCHIVE
01813     *min_arch_log_no = arch_log_no;
01814     *max_arch_log_no = arch_log_no;
01815 #endif /* UNIV_LOG_ARCHIVE */
01816     return;
01817   }
01818 
01819   if (*min_flushed_lsn > flushed_lsn) {
01820     *min_flushed_lsn = flushed_lsn;
01821   }
01822   if (*max_flushed_lsn < flushed_lsn) {
01823     *max_flushed_lsn = flushed_lsn;
01824   }
01825 #ifdef UNIV_LOG_ARCHIVE
01826   if (*min_arch_log_no > arch_log_no) {
01827     *min_arch_log_no = arch_log_no;
01828   }
01829   if (*max_arch_log_no < arch_log_no) {
01830     *max_arch_log_no = arch_log_no;
01831   }
01832 #endif /* UNIV_LOG_ARCHIVE */
01833 }
01834 
01835 /*================ SINGLE-TABLE TABLESPACES ==========================*/
01836 
01837 #ifndef UNIV_HOTBACKUP
01838 /*******************************************************************/
01842 UNIV_INTERN
01843 ibool
01844 fil_inc_pending_ibuf_merges(
01845 /*========================*/
01846   ulint id) 
01847 {
01848   fil_space_t*  space;
01849 
01850   mutex_enter(&fil_system->mutex);
01851 
01852   space = fil_space_get_by_id(id);
01853 
01854   if (space == NULL) {
01855     fprintf(stderr,
01856       "InnoDB: Error: trying to do ibuf merge to a"
01857       " dropped tablespace %lu\n",
01858       (ulong) id);
01859   }
01860 
01861   if (space == NULL || space->stop_ibuf_merges) {
01862     mutex_exit(&fil_system->mutex);
01863 
01864     return(TRUE);
01865   }
01866 
01867   space->n_pending_ibuf_merges++;
01868 
01869   mutex_exit(&fil_system->mutex);
01870 
01871   return(FALSE);
01872 }
01873 
01874 /*******************************************************************/
01876 UNIV_INTERN
01877 void
01878 fil_decr_pending_ibuf_merges(
01879 /*=========================*/
01880   ulint id) 
01881 {
01882   fil_space_t*  space;
01883 
01884   mutex_enter(&fil_system->mutex);
01885 
01886   space = fil_space_get_by_id(id);
01887 
01888   if (space == NULL) {
01889     fprintf(stderr,
01890       "InnoDB: Error: decrementing ibuf merge of a"
01891       " dropped tablespace %lu\n",
01892       (ulong) id);
01893   }
01894 
01895   if (space != NULL) {
01896     space->n_pending_ibuf_merges--;
01897   }
01898 
01899   mutex_exit(&fil_system->mutex);
01900 }
01901 #endif /* !UNIV_HOTBACKUP */
01902 
01903 /********************************************************/
01905 static
01906 void
01907 fil_create_directory_for_tablename(
01908 /*===============================*/
01909   const char* name) 
01911 {
01912   const char* namend;
01913   char*   path;
01914   ulint   len;
01915 
01916   len = strlen(fil_path_to_mysql_datadir);
01917   namend = strchr(name, '/');
01918   ut_a(namend);
01919   path = static_cast<char *>(mem_alloc(len + (namend - name) + 2));
01920 
01921   memcpy(path, fil_path_to_mysql_datadir, len);
01922   path[len] = '/';
01923   memcpy(path + len + 1, name, namend - name);
01924   path[len + (namend - name) + 1] = 0;
01925 
01926   srv_normalize_path_for_win(path);
01927 
01928   ut_a(os_file_create_directory(path, FALSE));
01929   mem_free(path);
01930 }
01931 
01932 #ifndef UNIV_HOTBACKUP
01933 /********************************************************/
01935 static
01936 void
01937 fil_op_write_log(
01938 /*=============*/
01939   ulint   type,   
01943   ulint   space_id, 
01944   ulint   log_flags,  
01946   ulint   flags,    
01949   const char* name,   
01953   const char* new_name, 
01956   mtr_t*    mtr)    
01957 {
01958   byte* log_ptr;
01959   ulint len;
01960 
01961   log_ptr = mlog_open(mtr, 11 + 2 + 1);
01962 
01963   if (!log_ptr) {
01964     /* Logging in mtr is switched off during crash recovery:
01965     in that case mlog_open returns NULL */
01966     return;
01967   }
01968 
01969   log_ptr = mlog_write_initial_log_record_for_file_op(
01970     type, space_id, log_flags, log_ptr, mtr);
01971   if (type == MLOG_FILE_CREATE2) {
01972     mach_write_to_4(log_ptr, flags);
01973     log_ptr += 4;
01974   }
01975   /* Let us store the strings as null-terminated for easier readability
01976   and handling */
01977 
01978   len = strlen(name) + 1;
01979 
01980   mach_write_to_2(log_ptr, len);
01981   log_ptr += 2;
01982   mlog_close(mtr, log_ptr);
01983 
01984   mlog_catenate_string(mtr, (byte*) name, len);
01985 
01986   if (type == MLOG_FILE_RENAME) {
01987     len = strlen(new_name) + 1;
01988     log_ptr = mlog_open(mtr, 2 + len);
01989     ut_a(log_ptr);
01990     mach_write_to_2(log_ptr, len);
01991     log_ptr += 2;
01992     mlog_close(mtr, log_ptr);
01993 
01994     mlog_catenate_string(mtr, (byte*) new_name, len);
01995   }
01996 }
01997 #endif
01998 
01999 /*******************************************************************/
02013 UNIV_INTERN
02014 byte*
02015 fil_op_log_parse_or_replay(
02016 /*=======================*/
02017   byte* ptr,    
02020   byte* end_ptr,  
02021   ulint type,   
02022   ulint space_id, 
02025   ulint log_flags)  
02027 {
02028   ulint   name_len;
02029   ulint   new_name_len;
02030   const char* name;
02031   const char* new_name  = NULL;
02032   ulint   flags   = 0;
02033 
02034   if (type == MLOG_FILE_CREATE2) {
02035     if (end_ptr < ptr + 4) {
02036 
02037       return(NULL);
02038     }
02039 
02040     flags = mach_read_from_4(ptr);
02041     ptr += 4;
02042   }
02043 
02044   if (end_ptr < ptr + 2) {
02045 
02046     return(NULL);
02047   }
02048 
02049   name_len = mach_read_from_2(ptr);
02050 
02051   ptr += 2;
02052 
02053   if (end_ptr < ptr + name_len) {
02054 
02055     return(NULL);
02056   }
02057 
02058   name = (const char*) ptr;
02059 
02060   ptr += name_len;
02061 
02062   if (type == MLOG_FILE_RENAME) {
02063     if (end_ptr < ptr + 2) {
02064 
02065       return(NULL);
02066     }
02067 
02068     new_name_len = mach_read_from_2(ptr);
02069 
02070     ptr += 2;
02071 
02072     if (end_ptr < ptr + new_name_len) {
02073 
02074       return(NULL);
02075     }
02076 
02077     new_name = (const char*) ptr;
02078 
02079     ptr += new_name_len;
02080   }
02081 
02082   /* We managed to parse a full log record body */
02083   /*
02084   printf("Parsed log rec of type %lu space %lu\n"
02085   "name %s\n", type, space_id, name);
02086 
02087   if (type == MLOG_FILE_RENAME) {
02088   printf("new name %s\n", new_name);
02089   }
02090   */
02091   if (!space_id) {
02092 
02093     return(ptr);
02094   }
02095 
02096   /* Let us try to perform the file operation, if sensible. Note that
02097   ibbackup has at this stage already read in all space id info to the
02098   fil0fil.c data structures.
02099 
02100   NOTE that our algorithm is not guaranteed to work correctly if there
02101   were renames of tables during the backup. See ibbackup code for more
02102   on the problem. */
02103 
02104   switch (type) {
02105   case MLOG_FILE_DELETE:
02106     if (fil_tablespace_exists_in_mem(space_id)) {
02107       ut_a(fil_delete_tablespace(space_id));
02108     }
02109 
02110     break;
02111 
02112   case MLOG_FILE_RENAME:
02113     /* We do the rename based on space id, not old file name;
02114     this should guarantee that after the log replay each .ibd file
02115     has the correct name for the latest log sequence number; the
02116     proof is left as an exercise :) */
02117 
02118     if (fil_tablespace_exists_in_mem(space_id)) {
02119       /* Create the database directory for the new name, if
02120       it does not exist yet */
02121       fil_create_directory_for_tablename(new_name);
02122 
02123       /* Rename the table if there is not yet a tablespace
02124       with the same name */
02125 
02126       if (fil_get_space_id_for_table(new_name)
02127           == ULINT_UNDEFINED) {
02128         /* We do not care of the old name, that is
02129         why we pass NULL as the first argument */
02130         if (!fil_rename_tablespace(NULL, space_id,
02131                  new_name)) {
02132           ut_error;
02133         }
02134       }
02135     }
02136 
02137     break;
02138 
02139   case MLOG_FILE_CREATE:
02140   case MLOG_FILE_CREATE2:
02141     if (fil_tablespace_exists_in_mem(space_id)) {
02142       /* Do nothing */
02143     } else if (fil_get_space_id_for_table(name)
02144          != ULINT_UNDEFINED) {
02145       /* Do nothing */
02146     } else if (log_flags & MLOG_FILE_FLAG_TEMP) {
02147       /* Temporary table, do nothing */
02148     } else {
02149       /* Create the database directory for name, if it does
02150       not exist yet */
02151       fil_create_directory_for_tablename(name);
02152 
02153       if (fil_create_new_single_table_tablespace(
02154             space_id, name, FALSE, flags,
02155             FIL_IBD_FILE_INITIAL_SIZE) != DB_SUCCESS) {
02156         ut_error;
02157       }
02158     }
02159 
02160     break;
02161 
02162   default:
02163     ut_error;
02164   }
02165 
02166   return(ptr);
02167 }
02168 
02169 /*******************************************************************/
02173 UNIV_INTERN
02174 ibool
02175 fil_delete_tablespace(
02176 /*==================*/
02177   ulint id) 
02178 {
02179   ibool   success;
02180   fil_space_t*  space;
02181   fil_node_t* node;
02182   ulint   count   = 0;
02183   char*   path;
02184 
02185   ut_a(id != 0);
02186 stop_ibuf_merges:
02187   mutex_enter(&fil_system->mutex);
02188 
02189   space = fil_space_get_by_id(id);
02190 
02191   if (space != NULL) {
02192     space->stop_ibuf_merges = TRUE;
02193 
02194     if (space->n_pending_ibuf_merges == 0) {
02195       mutex_exit(&fil_system->mutex);
02196 
02197       count = 0;
02198 
02199       goto try_again;
02200     } else {
02201       if (count > 5000) {
02202         ut_print_timestamp(stderr);
02203         fputs("  InnoDB: Warning: trying to"
02204               " delete tablespace ", stderr);
02205         ut_print_filename(stderr, space->name);
02206         fprintf(stderr, ",\n"
02207           "InnoDB: but there are %lu pending"
02208           " ibuf merges on it.\n"
02209           "InnoDB: Loop %lu.\n",
02210           (ulong) space->n_pending_ibuf_merges,
02211           (ulong) count);
02212       }
02213 
02214       mutex_exit(&fil_system->mutex);
02215 
02216       os_thread_sleep(20000);
02217       count++;
02218 
02219       goto stop_ibuf_merges;
02220     }
02221   }
02222 
02223   mutex_exit(&fil_system->mutex);
02224   count = 0;
02225 
02226 try_again:
02227   mutex_enter(&fil_system->mutex);
02228 
02229   space = fil_space_get_by_id(id);
02230 
02231   if (space == NULL) {
02232     ut_print_timestamp(stderr);
02233     fprintf(stderr,
02234       "  InnoDB: Error: cannot delete tablespace %lu\n"
02235       "InnoDB: because it is not found in the"
02236       " tablespace memory cache.\n",
02237       (ulong) id);
02238 
02239     mutex_exit(&fil_system->mutex);
02240 
02241     return(FALSE);
02242   }
02243 
02244   ut_a(space);
02245   ut_a(space->n_pending_ibuf_merges == 0);
02246 
02247   space->is_being_deleted = TRUE;
02248 
02249   ut_a(UT_LIST_GET_LEN(space->chain) == 1);
02250   node = UT_LIST_GET_FIRST(space->chain);
02251 
02252   if (space->n_pending_flushes > 0 || node->n_pending > 0) {
02253     if (count > 1000) {
02254       ut_print_timestamp(stderr);
02255       fputs("  InnoDB: Warning: trying to"
02256             " delete tablespace ", stderr);
02257       ut_print_filename(stderr, space->name);
02258       fprintf(stderr, ",\n"
02259         "InnoDB: but there are %lu flushes"
02260         " and %lu pending i/o's on it\n"
02261         "InnoDB: Loop %lu.\n",
02262         (ulong) space->n_pending_flushes,
02263         (ulong) node->n_pending,
02264         (ulong) count);
02265     }
02266     mutex_exit(&fil_system->mutex);
02267     os_thread_sleep(20000);
02268 
02269     count++;
02270 
02271     goto try_again;
02272   }
02273 
02274   path = mem_strdup(space->name);
02275 
02276   mutex_exit(&fil_system->mutex);
02277 
02278   /* Important: We rely on the data dictionary mutex to ensure
02279   that a race is not possible here. It should serialize the tablespace
02280   drop/free. We acquire an X latch only to avoid a race condition
02281   when accessing the tablespace instance via:
02282 
02283     fsp_get_available_space_in_free_extents().
02284 
02285   There our main motivation is to reduce the contention on the
02286   dictionary mutex. */
02287 
02288   rw_lock_x_lock(&space->latch);
02289 
02290 #ifndef UNIV_HOTBACKUP
02291   /* Invalidate in the buffer pool all pages belonging to the
02292   tablespace. Since we have set space->is_being_deleted = TRUE, readahead
02293   or ibuf merge can no longer read more pages of this tablespace to the
02294   buffer pool. Thus we can clean the tablespace out of the buffer pool
02295   completely and permanently. The flag is_being_deleted also prevents
02296   fil_flush() from being applied to this tablespace. */
02297 
02298   buf_LRU_invalidate_tablespace(id);
02299 #endif
02300   /* printf("Deleting tablespace %s id %lu\n", space->name, id); */
02301 
02302   mutex_enter(&fil_system->mutex);
02303 
02304   success = fil_space_free(id, TRUE);
02305 
02306   mutex_exit(&fil_system->mutex);
02307 
02308   if (success) {
02309     success = os_file_delete(path);
02310 
02311     if (!success) {
02312       success = os_file_delete_if_exists(path);
02313     }
02314   } else {
02315     rw_lock_x_unlock(&space->latch);
02316   }
02317 
02318   if (success) {
02319 #ifndef UNIV_HOTBACKUP
02320     /* Write a log record about the deletion of the .ibd
02321     file, so that ibbackup can replay it in the
02322     --apply-log phase. We use a dummy mtr and the familiar
02323     log write mechanism. */
02324     mtr_t   mtr;
02325 
02326     /* When replaying the operation in ibbackup, do not try
02327     to write any log record */
02328     mtr_start(&mtr);
02329 
02330     fil_op_write_log(MLOG_FILE_DELETE, id, 0, 0, path, NULL, &mtr);
02331     mtr_commit(&mtr);
02332 #endif
02333     mem_free(path);
02334 
02335     return(TRUE);
02336   }
02337 
02338   mem_free(path);
02339 
02340   return(FALSE);
02341 }
02342 
02343 /*******************************************************************/
02346 UNIV_INTERN
02347 ibool
02348 fil_tablespace_is_being_deleted(
02349 /*============================*/
02350   ulint   id) 
02351 {
02352   fil_space_t*  space;
02353   ibool   is_being_deleted;
02354 
02355   mutex_enter(&fil_system->mutex);
02356 
02357   space = fil_space_get_by_id(id);
02358 
02359   ut_a(space != NULL);
02360 
02361   is_being_deleted = space->is_being_deleted;
02362 
02363   mutex_exit(&fil_system->mutex);
02364 
02365   return(is_being_deleted);
02366 }
02367 
02368 #ifndef UNIV_HOTBACKUP
02369 /*******************************************************************/
02378 UNIV_INTERN
02379 ibool
02380 fil_discard_tablespace(
02381 /*===================*/
02382   ulint id) 
02383 {
02384   ibool success;
02385 
02386   success = fil_delete_tablespace(id);
02387 
02388   if (!success) {
02389     fprintf(stderr,
02390       "InnoDB: Warning: cannot delete tablespace %lu"
02391       " in DISCARD TABLESPACE.\n"
02392       "InnoDB: But let us remove the"
02393       " insert buffer entries for this tablespace.\n",
02394       (ulong) id);
02395   }
02396 
02397   /* Remove all insert buffer entries for the tablespace */
02398 
02399   ibuf_delete_for_discarded_space(id);
02400 
02401   return(success);
02402 }
02403 #endif /* !UNIV_HOTBACKUP */
02404 
02405 /*******************************************************************/
02408 static
02409 ibool
02410 fil_rename_tablespace_in_mem(
02411 /*=========================*/
02412   fil_space_t*  space,  
02413   fil_node_t* node, 
02414   const char* path) 
02415 {
02416   fil_space_t*  space2;
02417   const char* old_name  = space->name;
02418 
02419   ut_ad(mutex_own(&fil_system->mutex));
02420 
02421   space2 = fil_space_get_by_name(old_name);
02422   if (space != space2) {
02423     fputs("InnoDB: Error: cannot find ", stderr);
02424     ut_print_filename(stderr, old_name);
02425     fputs(" in tablespace memory cache\n", stderr);
02426 
02427     return(FALSE);
02428   }
02429 
02430   space2 = fil_space_get_by_name(path);
02431   if (space2 != NULL) {
02432     fputs("InnoDB: Error: ", stderr);
02433     ut_print_filename(stderr, path);
02434     fputs(" is already in tablespace memory cache\n", stderr);
02435 
02436     return(FALSE);
02437   }
02438 
02439   HASH_DELETE(fil_space_t, name_hash, fil_system->name_hash,
02440         ut_fold_string(space->name), space);
02441   mem_free(space->name);
02442   mem_free(node->name);
02443 
02444   space->name = mem_strdup(path);
02445   node->name = mem_strdup(path);
02446 
02447   HASH_INSERT(fil_space_t, name_hash, fil_system->name_hash,
02448         ut_fold_string(path), space);
02449   return(TRUE);
02450 }
02451 
02452 /*******************************************************************/
02456 static
02457 char*
02458 fil_make_ibd_name(
02459 /*==============*/
02460   const char* name,   
02462   ibool   is_temp)  
02463 {
02464   ulint namelen   = strlen(name);
02465   ulint dirlen    = strlen(fil_path_to_mysql_datadir);
02466   char* filename  = static_cast<char *>(mem_alloc(namelen + dirlen + sizeof "/.ibd"));
02467 
02468   if (is_temp) {
02469     memcpy(filename, name, namelen);
02470     memcpy(filename + namelen, ".ibd", sizeof ".ibd");
02471   } else {
02472     memcpy(filename, fil_path_to_mysql_datadir, dirlen);
02473     filename[dirlen] = '/';
02474 
02475     memcpy(filename + dirlen + 1, name, namelen);
02476     memcpy(filename + dirlen + namelen + 1, ".ibd", sizeof ".ibd");
02477   }
02478 
02479   srv_normalize_path_for_win(filename);
02480 
02481   return(filename);
02482 }
02483 
02484 /*******************************************************************/
02488 UNIV_INTERN
02489 ibool
02490 fil_rename_tablespace(
02491 /*==================*/
02492   const char* old_name, 
02496   ulint   id,   
02497   const char* new_name) 
02500 {
02501   ibool   success;
02502   fil_space_t*  space;
02503   fil_node_t* node;
02504   ulint   count   = 0;
02505   char*   path;
02506   ibool   old_name_was_specified    = TRUE;
02507   char*   old_path;
02508 
02509   ut_a(id != 0);
02510 
02511   if (old_name == NULL) {
02512     old_name = "(name not specified)";
02513     old_name_was_specified = FALSE;
02514   }
02515 retry:
02516   count++;
02517 
02518   if (count > 1000) {
02519     ut_print_timestamp(stderr);
02520     fputs("  InnoDB: Warning: problems renaming ", stderr);
02521     ut_print_filename(stderr, old_name);
02522     fputs(" to ", stderr);
02523     ut_print_filename(stderr, new_name);
02524     fprintf(stderr, ", %lu iterations\n", (ulong) count);
02525   }
02526 
02527   mutex_enter(&fil_system->mutex);
02528 
02529   space = fil_space_get_by_id(id);
02530 
02531   if (space == NULL) {
02532     fprintf(stderr,
02533       "InnoDB: Error: cannot find space id %lu"
02534       " in the tablespace memory cache\n"
02535       "InnoDB: though the table ", (ulong) id);
02536     ut_print_filename(stderr, old_name);
02537     fputs(" in a rename operation should have that id\n", stderr);
02538     mutex_exit(&fil_system->mutex);
02539 
02540     return(FALSE);
02541   }
02542 
02543   if (count > 25000) {
02544     space->stop_ios = FALSE;
02545     mutex_exit(&fil_system->mutex);
02546 
02547     return(FALSE);
02548   }
02549 
02550   /* We temporarily close the .ibd file because we do not trust that
02551   operating systems can rename an open file. For the closing we have to
02552   wait until there are no pending i/o's or flushes on the file. */
02553 
02554   space->stop_ios = TRUE;
02555 
02556   ut_a(UT_LIST_GET_LEN(space->chain) == 1);
02557   node = UT_LIST_GET_FIRST(space->chain);
02558 
02559   if (node->n_pending > 0 || node->n_pending_flushes > 0) {
02560     /* There are pending i/o's or flushes, sleep for a while and
02561     retry */
02562 
02563     mutex_exit(&fil_system->mutex);
02564 
02565     os_thread_sleep(20000);
02566 
02567     goto retry;
02568 
02569   } else if (node->modification_counter > node->flush_counter) {
02570     /* Flush the space */
02571 
02572     mutex_exit(&fil_system->mutex);
02573 
02574     os_thread_sleep(20000);
02575 
02576     fil_flush(id);
02577 
02578     goto retry;
02579 
02580   } else if (node->open) {
02581     /* Close the file */
02582 
02583     fil_node_close_file(node, fil_system);
02584   }
02585 
02586   /* Check that the old name in the space is right */
02587 
02588   if (old_name_was_specified) {
02589     old_path = fil_make_ibd_name(old_name, FALSE);
02590 
02591     ut_a(strcmp(space->name, old_path) == 0);
02592     ut_a(strcmp(node->name, old_path) == 0);
02593   } else {
02594     old_path = mem_strdup(space->name);
02595   }
02596 
02597   /* Rename the tablespace and the node in the memory cache */
02598   path = fil_make_ibd_name(new_name, FALSE);
02599   success = fil_rename_tablespace_in_mem(space, node, path);
02600 
02601   if (success) {
02602     success = os_file_rename(innodb_file_data_key, old_path, path);
02603 
02604     if (!success) {
02605       /* We have to revert the changes we made
02606       to the tablespace memory cache */
02607 
02608       ut_a(fil_rename_tablespace_in_mem(space, node,
02609                 old_path));
02610     }
02611   }
02612 
02613   mem_free(path);
02614   mem_free(old_path);
02615 
02616   space->stop_ios = FALSE;
02617 
02618   mutex_exit(&fil_system->mutex);
02619 
02620 #ifndef UNIV_HOTBACKUP
02621   if (success) {
02622     mtr_t   mtr;
02623 
02624     mtr_start(&mtr);
02625 
02626     fil_op_write_log(MLOG_FILE_RENAME, id, 0, 0, old_name, new_name,
02627          &mtr);
02628     mtr_commit(&mtr);
02629   }
02630 #endif
02631   return(success);
02632 }
02633 
02634 /*******************************************************************/
02641 UNIV_INTERN
02642 ulint
02643 fil_create_new_single_table_tablespace(
02644 /*===================================*/
02645   ulint   space_id, 
02646   const char* tablename,  
02650   ibool   is_temp,  
02652   ulint   flags,    
02653   ulint   size)   
02656 {
02657   os_file_t file;
02658   ibool   ret;
02659   ulint   err;
02660   byte*   buf2;
02661   byte*   page;
02662   ibool   success;
02663   char*   path;
02664 
02665   ut_a(space_id > 0);
02666   ut_a(space_id < SRV_LOG_SPACE_FIRST_ID);
02667   ut_a(size >= FIL_IBD_FILE_INITIAL_SIZE);
02668   /* The tablespace flags (FSP_SPACE_FLAGS) should be 0 for
02669   ROW_FORMAT=COMPACT
02670   ((table->flags & ~(~0 << DICT_TF_BITS)) == DICT_TF_COMPACT) and
02671   ROW_FORMAT=REDUNDANT (table->flags == 0).  For any other
02672   format, the tablespace flags should equal
02673   (table->flags & ~(~0 << DICT_TF_BITS)). */
02674   ut_a(flags != DICT_TF_COMPACT);
02675   ut_a(!(flags & (~0UL << DICT_TF_BITS)));
02676 
02677   path = fil_make_ibd_name(tablename, is_temp);
02678 
02679   file = os_file_create(innodb_file_data_key, path,
02680             OS_FILE_CREATE, OS_FILE_NORMAL,
02681             OS_DATA_FILE, &ret);
02682   if (ret == FALSE) {
02683     ut_print_timestamp(stderr);
02684     fputs("  InnoDB: Error creating file ", stderr);
02685     ut_print_filename(stderr, path);
02686     fputs(".\n", stderr);
02687 
02688     /* The following call will print an error message */
02689 
02690     err = os_file_get_last_error(TRUE);
02691 
02692     if (err == OS_FILE_ALREADY_EXISTS) {
02693       fputs("InnoDB: The file already exists though"
02694             " the corresponding table did not\n"
02695             "InnoDB: exist in the InnoDB data dictionary."
02696             " Have you moved InnoDB\n"
02697             "InnoDB: .ibd files around without using the"
02698             " SQL commands\n"
02699             "InnoDB: DISCARD TABLESPACE and"
02700             " IMPORT TABLESPACE, or did\n"
02701             "InnoDB: mysqld crash in the middle of"
02702             " CREATE TABLE? You can\n"
02703             "InnoDB: resolve the problem by"
02704             " removing the file ", stderr);
02705       ut_print_filename(stderr, path);
02706       fputs("\n"
02707             "InnoDB: under the 'datadir' of MySQL.\n",
02708             stderr);
02709 
02710       mem_free(path);
02711       return(DB_TABLESPACE_ALREADY_EXISTS);
02712     }
02713 
02714     if (err == OS_FILE_DISK_FULL) {
02715 
02716       mem_free(path);
02717       return(DB_OUT_OF_FILE_SPACE);
02718     }
02719 
02720     mem_free(path);
02721     return(DB_ERROR);
02722   }
02723 
02724   ret = os_file_set_size(path, file, size * UNIV_PAGE_SIZE, 0);
02725 
02726   if (!ret) {
02727     err = DB_OUT_OF_FILE_SPACE;
02728 error_exit:
02729     os_file_close(file);
02730 error_exit2:
02731     os_file_delete(path);
02732 
02733     mem_free(path);
02734     return(err);
02735   }
02736 
02737   /* printf("Creating tablespace %s id %lu\n", path, space_id); */
02738 
02739   /* We have to write the space id to the file immediately and flush the
02740   file to disk. This is because in crash recovery we must be aware what
02741   tablespaces exist and what are their space id's, so that we can apply
02742   the log records to the right file. It may take quite a while until
02743   buffer pool flush algorithms write anything to the file and flush it to
02744   disk. If we would not write here anything, the file would be filled
02745   with zeros from the call of os_file_set_size(), until a buffer pool
02746   flush would write to it. */
02747 
02748   buf2 = static_cast<byte *>(ut_malloc(3 * UNIV_PAGE_SIZE));
02749   /* Align the memory for file i/o if we might have O_DIRECT set */
02750   page = static_cast<byte *>(ut_align(buf2, UNIV_PAGE_SIZE));
02751 
02752   memset(page, '\0', UNIV_PAGE_SIZE);
02753 
02754   fsp_header_init_fields(page, space_id, flags);
02755   mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, space_id);
02756 
02757   if (!(flags & DICT_TF_ZSSIZE_MASK)) {
02758     buf_flush_init_for_writing(page, NULL, 0);
02759     ret = os_file_write(path, file, page, 0, 0, UNIV_PAGE_SIZE);
02760   } else {
02761     page_zip_des_t  page_zip;
02762     ulint   zip_size;
02763 
02764     zip_size = ((PAGE_ZIP_MIN_SIZE >> 1)
02765           << ((flags & DICT_TF_ZSSIZE_MASK)
02766         >> DICT_TF_ZSSIZE_SHIFT));
02767 
02768     page_zip_set_size(&page_zip, zip_size);
02769     page_zip.data = page + UNIV_PAGE_SIZE;
02770 #ifdef UNIV_DEBUG
02771     page_zip.m_start =
02772 #endif /* UNIV_DEBUG */
02773       page_zip.m_end = page_zip.m_nonempty =
02774       page_zip.n_blobs = 0;
02775     buf_flush_init_for_writing(page, &page_zip, 0);
02776     ret = os_file_write(path, file, page_zip.data, 0, 0, zip_size);
02777   }
02778 
02779   ut_free(buf2);
02780 
02781   if (!ret) {
02782     fputs("InnoDB: Error: could not write the first page"
02783           " to tablespace ", stderr);
02784     ut_print_filename(stderr, path);
02785     putc('\n', stderr);
02786     err = DB_ERROR;
02787     goto error_exit;
02788   }
02789 
02790   ret = os_file_flush(file);
02791 
02792   if (!ret) {
02793     fputs("InnoDB: Error: file flush of tablespace ", stderr);
02794     ut_print_filename(stderr, path);
02795     fputs(" failed\n", stderr);
02796     err = DB_ERROR;
02797     goto error_exit;
02798   }
02799 
02800   os_file_close(file);
02801 
02802   success = fil_space_create(path, space_id, flags, FIL_TABLESPACE);
02803 
02804   if (!success) {
02805     err = DB_ERROR;
02806     goto error_exit2;
02807   }
02808 
02809   fil_node_create(path, size, space_id, FALSE);
02810 
02811 #ifndef UNIV_HOTBACKUP
02812   {
02813     mtr_t   mtr;
02814 
02815     mtr_start(&mtr);
02816 
02817     fil_op_write_log(flags
02818          ? MLOG_FILE_CREATE2
02819          : MLOG_FILE_CREATE,
02820          space_id,
02821          is_temp ? MLOG_FILE_FLAG_TEMP : 0,
02822          flags,
02823          tablename, NULL, &mtr);
02824 
02825     mtr_commit(&mtr);
02826   }
02827 #endif
02828   mem_free(path);
02829   return(DB_SUCCESS);
02830 }
02831 
02832 #ifndef UNIV_HOTBACKUP
02833 /********************************************************************/
02843 UNIV_INTERN
02844 ibool
02845 fil_reset_too_high_lsns(
02846 /*====================*/
02847   const char* name,   
02849   ib_uint64_t current_lsn)  
02852 {
02853   os_file_t file;
02854   char*   filepath;
02855   byte*   page;
02856   byte*   buf2;
02857   ib_uint64_t flush_lsn;
02858   ulint   space_id;
02859   ib_int64_t  file_size;
02860   ib_int64_t  offset;
02861   ulint   zip_size;
02862   ibool   success;
02863   page_zip_des_t  page_zip;
02864 
02865   filepath = fil_make_ibd_name(name, FALSE);
02866 
02867   file = os_file_create_simple_no_error_handling(
02868     innodb_file_data_key, filepath, OS_FILE_OPEN,
02869     OS_FILE_READ_WRITE, &success);
02870   if (!success) {
02871     /* The following call prints an error message */
02872     os_file_get_last_error(TRUE);
02873 
02874     ut_print_timestamp(stderr);
02875 
02876     fputs("  InnoDB: Error: trying to open a table,"
02877           " but could not\n"
02878           "InnoDB: open the tablespace file ", stderr);
02879     ut_print_filename(stderr, filepath);
02880     fputs("!\n", stderr);
02881     mem_free(filepath);
02882 
02883     return(FALSE);
02884   }
02885 
02886   /* Read the first page of the tablespace */
02887 
02888   buf2 = static_cast<byte *>(ut_malloc(3 * UNIV_PAGE_SIZE));
02889   /* Align the memory for file i/o if we might have O_DIRECT set */
02890   page = static_cast<byte *>(ut_align(buf2, UNIV_PAGE_SIZE));
02891 
02892   success = os_file_read(file, page, 0, 0, UNIV_PAGE_SIZE);
02893   if (!success) {
02894 
02895     goto func_exit;
02896   }
02897 
02898   /* We have to read the file flush lsn from the header of the file */
02899 
02900   flush_lsn = mach_read_from_8(page + FIL_PAGE_FILE_FLUSH_LSN);
02901 
02902   if (current_lsn >= flush_lsn) {
02903     /* Ok */
02904     success = TRUE;
02905 
02906     goto func_exit;
02907   }
02908 
02909   space_id = fsp_header_get_space_id(page);
02910   zip_size = fsp_header_get_zip_size(page);
02911 
02912   page_zip_des_init(&page_zip);
02913   page_zip_set_size(&page_zip, zip_size);
02914   if (zip_size) {
02915     page_zip.data = page + UNIV_PAGE_SIZE;
02916   }
02917 
02918   ut_print_timestamp(stderr);
02919   fprintf(stderr,
02920     "  InnoDB: Flush lsn in the tablespace file %lu"
02921     " to be imported\n"
02922     "InnoDB: is %"PRIu64", which exceeds current"
02923     " system lsn %"PRIu64".\n"
02924     "InnoDB: We reset the lsn's in the file ",
02925     (ulong) space_id,
02926     flush_lsn, current_lsn);
02927   ut_print_filename(stderr, filepath);
02928   fputs(".\n", stderr);
02929 
02930   ut_a(ut_is_2pow(zip_size));
02931   ut_a(zip_size <= UNIV_PAGE_SIZE);
02932 
02933   /* Loop through all the pages in the tablespace and reset the lsn and
02934   the page checksum if necessary */
02935 
02936   file_size = os_file_get_size_as_iblonglong(file);
02937 
02938   for (offset = 0; offset < file_size;
02939        offset += zip_size ? zip_size : UNIV_PAGE_SIZE) {
02940     success = os_file_read(file, page,
02941                (ulint)(offset & 0xFFFFFFFFUL),
02942                (ulint)(offset >> 32),
02943                zip_size ? zip_size : UNIV_PAGE_SIZE);
02944     if (!success) {
02945 
02946       goto func_exit;
02947     }
02948     if (mach_read_from_8(page + FIL_PAGE_LSN) > current_lsn) {
02949       /* We have to reset the lsn */
02950 
02951       if (zip_size) {
02952         memcpy(page_zip.data, page, zip_size);
02953         buf_flush_init_for_writing(
02954           page, &page_zip, current_lsn);
02955         success = os_file_write(
02956           filepath, file, page_zip.data,
02957           (ulint) offset & 0xFFFFFFFFUL,
02958           (ulint) (offset >> 32), zip_size);
02959       } else {
02960         buf_flush_init_for_writing(
02961           page, NULL, current_lsn);
02962         success = os_file_write(
02963           filepath, file, page,
02964           (ulint)(offset & 0xFFFFFFFFUL),
02965           (ulint)(offset >> 32),
02966           UNIV_PAGE_SIZE);
02967       }
02968 
02969       if (!success) {
02970 
02971         goto func_exit;
02972       }
02973     }
02974   }
02975 
02976   success = os_file_flush(file);
02977   if (!success) {
02978 
02979     goto func_exit;
02980   }
02981 
02982   /* We now update the flush_lsn stamp at the start of the file */
02983   success = os_file_read(file, page, 0, 0,
02984              zip_size ? zip_size : UNIV_PAGE_SIZE);
02985   if (!success) {
02986 
02987     goto func_exit;
02988   }
02989 
02990   mach_write_to_8(page + FIL_PAGE_FILE_FLUSH_LSN, current_lsn);
02991 
02992   success = os_file_write(filepath, file, page, 0, 0,
02993         zip_size ? zip_size : UNIV_PAGE_SIZE);
02994   if (!success) {
02995 
02996     goto func_exit;
02997   }
02998   success = os_file_flush(file);
02999 func_exit:
03000   os_file_close(file);
03001   ut_free(buf2);
03002   mem_free(filepath);
03003 
03004   return(success);
03005 }
03006 
03007 /********************************************************************/
03017 UNIV_INTERN
03018 ibool
03019 fil_open_single_table_tablespace(
03020 /*=============================*/
03021   ibool   check_space_id, 
03028   ulint   id,   
03029   ulint   flags,    
03030   const char* name)   
03032 {
03033   os_file_t file;
03034   char*   filepath;
03035   ibool   success;
03036   byte*   buf2;
03037   byte*   page;
03038   ulint   space_id;
03039   ulint   space_flags;
03040 
03041   filepath = fil_make_ibd_name(name, FALSE);
03042 
03043   /* The tablespace flags (FSP_SPACE_FLAGS) should be 0 for
03044   ROW_FORMAT=COMPACT
03045   ((table->flags & ~(~0 << DICT_TF_BITS)) == DICT_TF_COMPACT) and
03046   ROW_FORMAT=REDUNDANT (table->flags == 0).  For any other
03047   format, the tablespace flags should equal
03048   (table->flags & ~(~0 << DICT_TF_BITS)). */
03049   ut_a(flags != DICT_TF_COMPACT);
03050   ut_a(!(flags & (~0UL << DICT_TF_BITS)));
03051 
03052   file = os_file_create_simple_no_error_handling(
03053     innodb_file_data_key, filepath, OS_FILE_OPEN,
03054     OS_FILE_READ_ONLY, &success);
03055   if (!success) {
03056     /* The following call prints an error message */
03057     os_file_get_last_error(TRUE);
03058 
03059     ut_print_timestamp(stderr);
03060 
03061     fputs("  InnoDB: Error: trying to open a table,"
03062           " but could not\n"
03063           "InnoDB: open the tablespace file ", stderr);
03064     ut_print_filename(stderr, filepath);
03065     fputs("!\n"
03066           "InnoDB: Have you moved InnoDB .ibd files around"
03067           " without using the\n"
03068           "InnoDB: commands DISCARD TABLESPACE and"
03069           " IMPORT TABLESPACE?\n"
03070           "InnoDB: It is also possible that this is"
03071           " a temporary table #sql...,\n"
03072           "InnoDB: and MySQL removed the .ibd file for this.\n"
03073           "InnoDB: Please refer to\n"
03074           "InnoDB: " REFMAN "innodb-troubleshooting-datadict.html\n"
03075           "InnoDB: for how to resolve the issue.\n", stderr);
03076 
03077     mem_free(filepath);
03078 
03079     return(FALSE);
03080   }
03081 
03082   if (!check_space_id) {
03083     space_id = id;
03084 
03085     goto skip_check;
03086   }
03087 
03088   /* Read the first page of the tablespace */
03089 
03090   buf2 = static_cast<byte *>(ut_malloc(2 * UNIV_PAGE_SIZE));
03091   /* Align the memory for file i/o if we might have O_DIRECT set */
03092   page = static_cast<byte *>(ut_align(buf2, UNIV_PAGE_SIZE));
03093 
03094   success = os_file_read(file, page, 0, 0, UNIV_PAGE_SIZE);
03095 
03096   /* We have to read the tablespace id and flags from the file. */
03097 
03098   space_id = fsp_header_get_space_id(page);
03099   space_flags = fsp_header_get_flags(page);
03100 
03101   ut_free(buf2);
03102 
03103   if (UNIV_UNLIKELY(space_id != id
03104         || space_flags != (flags & ~(~0 << DICT_TF_BITS)))) {
03105     ut_print_timestamp(stderr);
03106 
03107     fputs("  InnoDB: Error: tablespace id and flags in file ",
03108           stderr);
03109     ut_print_filename(stderr, filepath);
03110     fprintf(stderr, " are %lu and %lu, but in the InnoDB\n"
03111       "InnoDB: data dictionary they are %lu and %lu.\n"
03112       "InnoDB: Have you moved InnoDB .ibd files"
03113       " around without using the\n"
03114       "InnoDB: commands DISCARD TABLESPACE and"
03115       " IMPORT TABLESPACE?\n"
03116       "InnoDB: Please refer to\n"
03117       "InnoDB: " REFMAN "innodb-troubleshooting-datadict.html\n"
03118       "InnoDB: for how to resolve the issue.\n",
03119       (ulong) space_id, (ulong) space_flags,
03120       (ulong) id, (ulong) flags);
03121 
03122     success = FALSE;
03123 
03124     goto func_exit;
03125   }
03126 
03127 skip_check:
03128   success = fil_space_create(filepath, space_id, flags, FIL_TABLESPACE);
03129 
03130   if (!success) {
03131     goto func_exit;
03132   }
03133 
03134   /* We do not measure the size of the file, that is why we pass the 0
03135   below */
03136 
03137   fil_node_create(filepath, 0, space_id, FALSE);
03138 func_exit:
03139   os_file_close(file);
03140   mem_free(filepath);
03141 
03142   return(success);
03143 }
03144 #endif /* !UNIV_HOTBACKUP */
03145 
03146 #ifdef UNIV_HOTBACKUP
03147 /*******************************************************************/
03151 static
03152 char*
03153 fil_make_ibbackup_old_name(
03154 /*=======================*/
03155   const char* name)   
03156 {
03157   static const char suffix[] = "_ibbackup_old_vers_";
03158   ulint len = strlen(name);
03159   char* path  = mem_alloc(len + (15 + sizeof suffix));
03160 
03161   memcpy(path, name, len);
03162   memcpy(path + len, suffix, (sizeof suffix) - 1);
03163   ut_sprintf_timestamp_without_extra_chars(path + len + sizeof suffix);
03164   return(path);
03165 }
03166 #endif /* UNIV_HOTBACKUP */
03167 
03168 /********************************************************************/
03171 static
03172 void
03173 fil_load_single_table_tablespace(
03174 /*=============================*/
03175   const char* dbname,   
03176   const char* filename) 
03178 {
03179   os_file_t file;
03180   char*   filepath;
03181   ibool   success;
03182   byte*   buf2;
03183   byte*   page;
03184   ulint   space_id;
03185   ulint   flags;
03186   ulint   size_low;
03187   ulint   size_high;
03188   uint64_t  size;
03189 #ifdef UNIV_HOTBACKUP
03190   fil_space_t*  space;
03191 #endif
03192   filepath = static_cast<char *>(mem_alloc(strlen(dbname) + strlen(filename)
03193            + strlen(fil_path_to_mysql_datadir) + 3));
03194 
03195   sprintf(filepath, "%s/%s/%s", fil_path_to_mysql_datadir, dbname,
03196     filename);
03197   srv_normalize_path_for_win(filepath);
03198 #ifdef __WIN__
03199 # ifndef UNIV_HOTBACKUP
03200   /* If lower_case_table_names is 0 or 2, then MySQL allows database
03201   directory names with upper case letters. On Windows, all table and
03202   database names in InnoDB are internally always in lower case. Put the
03203   file path to lower case, so that we are consistent with InnoDB's
03204   internal data dictionary. */
03205 
03206   dict_casedn_str(filepath);
03207 # endif /* !UNIV_HOTBACKUP */
03208 #endif
03209   file = os_file_create_simple_no_error_handling(
03210     innodb_file_data_key, filepath, OS_FILE_OPEN,
03211     OS_FILE_READ_ONLY, &success);
03212   if (!success) {
03213     /* The following call prints an error message */
03214     os_file_get_last_error(TRUE);
03215 
03216     fprintf(stderr,
03217       "InnoDB: Error: could not open single-table tablespace"
03218       " file\n"
03219       "InnoDB: %s!\n"
03220       "InnoDB: We do not continue the crash recovery,"
03221       " because the table may become\n"
03222       "InnoDB: corrupt if we cannot apply the log records"
03223       " in the InnoDB log to it.\n"
03224       "InnoDB: To fix the problem and start mysqld:\n"
03225       "InnoDB: 1) If there is a permission problem"
03226       " in the file and mysqld cannot\n"
03227       "InnoDB: open the file, you should"
03228       " modify the permissions.\n"
03229       "InnoDB: 2) If the table is not needed, or you can"
03230       " restore it from a backup,\n"
03231       "InnoDB: then you can remove the .ibd file,"
03232       " and InnoDB will do a normal\n"
03233       "InnoDB: crash recovery and ignore that table.\n"
03234       "InnoDB: 3) If the file system or the"
03235       " disk is broken, and you cannot remove\n"
03236       "InnoDB: the .ibd file, you can set"
03237       " innodb_force_recovery > 0 in my.cnf\n"
03238       "InnoDB: and force InnoDB to continue crash"
03239       " recovery here.\n", filepath);
03240 
03241     mem_free(filepath);
03242 
03243     if (srv_force_recovery > 0) {
03244       fprintf(stderr,
03245         "InnoDB: innodb_force_recovery"
03246         " was set to %lu. Continuing crash recovery\n"
03247         "InnoDB: even though we cannot access"
03248         " the .ibd file of this table.\n",
03249         srv_force_recovery);
03250       return;
03251     }
03252 
03253     exit(1);
03254   }
03255 
03256   success = os_file_get_size(file, &size_low, &size_high);
03257 
03258   if (!success) {
03259     /* The following call prints an error message */
03260     os_file_get_last_error(TRUE);
03261 
03262     fprintf(stderr,
03263       "InnoDB: Error: could not measure the size"
03264       " of single-table tablespace file\n"
03265       "InnoDB: %s!\n"
03266       "InnoDB: We do not continue crash recovery,"
03267       " because the table will become\n"
03268       "InnoDB: corrupt if we cannot apply the log records"
03269       " in the InnoDB log to it.\n"
03270       "InnoDB: To fix the problem and start mysqld:\n"
03271       "InnoDB: 1) If there is a permission problem"
03272       " in the file and mysqld cannot\n"
03273       "InnoDB: access the file, you should"
03274       " modify the permissions.\n"
03275       "InnoDB: 2) If the table is not needed,"
03276       " or you can restore it from a backup,\n"
03277       "InnoDB: then you can remove the .ibd file,"
03278       " and InnoDB will do a normal\n"
03279       "InnoDB: crash recovery and ignore that table.\n"
03280       "InnoDB: 3) If the file system or the disk is broken,"
03281       " and you cannot remove\n"
03282       "InnoDB: the .ibd file, you can set"
03283       " innodb_force_recovery > 0 in my.cnf\n"
03284       "InnoDB: and force InnoDB to continue"
03285       " crash recovery here.\n", filepath);
03286 
03287     os_file_close(file);
03288     mem_free(filepath);
03289 
03290     if (srv_force_recovery > 0) {
03291       fprintf(stderr,
03292         "InnoDB: innodb_force_recovery"
03293         " was set to %lu. Continuing crash recovery\n"
03294         "InnoDB: even though we cannot access"
03295         " the .ibd file of this table.\n",
03296         srv_force_recovery);
03297       return;
03298     }
03299 
03300     exit(1);
03301   }
03302 
03303   /* TODO: What to do in other cases where we cannot access an .ibd
03304   file during a crash recovery? */
03305 
03306   /* Every .ibd file is created >= 4 pages in size. Smaller files
03307   cannot be ok. */
03308 
03309   size = (((ib_int64_t)size_high) << 32) + (ib_int64_t)size_low;
03310 #ifndef UNIV_HOTBACKUP
03311   if (size < FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE) {
03312     fprintf(stderr,
03313       "InnoDB: Error: the size of single-table tablespace"
03314       " file %s\n"
03315       "InnoDB: is only %lu %lu, should be at least %lu!",
03316       filepath,
03317       (ulong) size_high,
03318       (ulong) size_low, (ulong) (4 * UNIV_PAGE_SIZE));
03319     os_file_close(file);
03320     mem_free(filepath);
03321 
03322     return;
03323   }
03324 #endif
03325   /* Read the first page of the tablespace if the size big enough */
03326 
03327   buf2 = static_cast<byte *>(ut_malloc(2 * UNIV_PAGE_SIZE));
03328   /* Align the memory for file i/o if we might have O_DIRECT set */
03329   page = static_cast<byte *>(ut_align(buf2, UNIV_PAGE_SIZE));
03330 
03331   if (size >= FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE) {
03332     success = os_file_read(file, page, 0, 0, UNIV_PAGE_SIZE);
03333 
03334     /* We have to read the tablespace id from the file */
03335 
03336     space_id = fsp_header_get_space_id(page);
03337     flags = fsp_header_get_flags(page);
03338   } else {
03339     space_id = ULINT_UNDEFINED;
03340     flags = 0;
03341   }
03342 
03343 #ifndef UNIV_HOTBACKUP
03344   if (space_id == ULINT_UNDEFINED || space_id == 0) {
03345     fprintf(stderr,
03346       "InnoDB: Error: tablespace id %lu in file %s"
03347       " is not sensible\n",
03348       (ulong) space_id,
03349       filepath);
03350     goto func_exit;
03351   }
03352 #else
03353   if (space_id == ULINT_UNDEFINED || space_id == 0) {
03354     char* new_path;
03355 
03356     fprintf(stderr,
03357       "InnoDB: Renaming tablespace %s of id %lu,\n"
03358       "InnoDB: to %s_ibbackup_old_vers_<timestamp>\n"
03359       "InnoDB: because its size %" PRId64 " is too small"
03360       " (< 4 pages 16 kB each),\n"
03361       "InnoDB: or the space id in the file header"
03362       " is not sensible.\n"
03363       "InnoDB: This can happen in an ibbackup run,"
03364       " and is not dangerous.\n",
03365       filepath, space_id, filepath, size);
03366     os_file_close(file);
03367 
03368     new_path = fil_make_ibbackup_old_name(filepath);
03369     ut_a(os_file_rename(innodb_file_data_key, filepath, new_path));
03370 
03371     ut_free(buf2);
03372     mem_free(filepath);
03373     mem_free(new_path);
03374 
03375     return;
03376   }
03377 
03378   /* A backup may contain the same space several times, if the space got
03379   renamed at a sensitive time. Since it is enough to have one version of
03380   the space, we rename the file if a space with the same space id
03381   already exists in the tablespace memory cache. We rather rename the
03382   file than delete it, because if there is a bug, we do not want to
03383   destroy valuable data. */
03384 
03385   mutex_enter(&fil_system->mutex);
03386 
03387   space = fil_space_get_by_id(space_id);
03388 
03389   if (space) {
03390     char* new_path;
03391 
03392     fprintf(stderr,
03393       "InnoDB: Renaming tablespace %s of id %lu,\n"
03394       "InnoDB: to %s_ibbackup_old_vers_<timestamp>\n"
03395       "InnoDB: because space %s with the same id\n"
03396       "InnoDB: was scanned earlier. This can happen"
03397       " if you have renamed tables\n"
03398       "InnoDB: during an ibbackup run.\n",
03399       filepath, space_id, filepath,
03400       space->name);
03401     os_file_close(file);
03402 
03403     new_path = fil_make_ibbackup_old_name(filepath);
03404 
03405     mutex_exit(&fil_system->mutex);
03406 
03407     ut_a(os_file_rename(innodb_file_data_key, filepath, new_path));
03408 
03409     ut_free(buf2);
03410     mem_free(filepath);
03411     mem_free(new_path);
03412 
03413     return;
03414   }
03415   mutex_exit(&fil_system->mutex);
03416 #endif
03417   success = fil_space_create(filepath, space_id, flags, FIL_TABLESPACE);
03418 
03419   if (!success) {
03420 
03421     if (srv_force_recovery > 0) {
03422       fprintf(stderr,
03423         "InnoDB: innodb_force_recovery"
03424         " was set to %lu. Continuing crash recovery\n"
03425         "InnoDB: even though the tablespace creation"
03426         " of this table failed.\n",
03427         srv_force_recovery);
03428       goto func_exit;
03429     }
03430 
03431     exit(1);
03432   }
03433 
03434   /* We do not use the size information we have about the file, because
03435   the rounding formula for extents and pages is somewhat complex; we
03436   let fil_node_open() do that task. */
03437 
03438   fil_node_create(filepath, 0, space_id, FALSE);
03439 func_exit:
03440   os_file_close(file);
03441   ut_free(buf2);
03442   mem_free(filepath);
03443 }
03444 
03445 /***********************************************************************/
03451 int
03452 fil_file_readdir_next_file(
03453 /*=======================*/
03454   ulint*    err,  
03456   const char* dirname,
03457   os_file_dir_t dir,  
03458   os_file_stat_t* info) 
03459 {
03460   ulint i;
03461   int ret;
03462 
03463   for (i = 0; i < 100; i++) {
03464     ret = os_file_readdir_next_file(dirname, dir, info);
03465 
03466     if (ret != -1) {
03467 
03468       return(ret);
03469     }
03470 
03471     fprintf(stderr,
03472       "InnoDB: Error: os_file_readdir_next_file()"
03473       " returned -1 in\n"
03474       "InnoDB: directory %s\n"
03475       "InnoDB: Crash recovery may have failed"
03476       " for some .ibd files!\n", dirname);
03477 
03478     *err = DB_ERROR;
03479   }
03480 
03481   return(-1);
03482 }
03483 
03484 /********************************************************************/
03492 UNIV_INTERN
03493 ulint
03494 fil_load_single_table_tablespaces(void)
03495 /*===================================*/
03496 {
03497   int   ret;
03498   char*   dbpath    = NULL;
03499   ulint   dbpath_len  = 100;
03500   os_file_dir_t dir;
03501   os_file_dir_t dbdir;
03502   os_file_stat_t  dbinfo;
03503   os_file_stat_t  fileinfo;
03504   ulint   err   = DB_SUCCESS;
03505 
03506   /* The datadir of MySQL is always the default directory of mysqld */
03507 
03508   dir = os_file_opendir(fil_path_to_mysql_datadir, TRUE);
03509 
03510   if (dir == NULL) {
03511 
03512     return(DB_ERROR);
03513   }
03514 
03515   dbpath = static_cast<char *>(mem_alloc(dbpath_len));
03516 
03517   /* Scan all directories under the datadir. They are the database
03518   directories of MySQL. */
03519 
03520   ret = fil_file_readdir_next_file(&err, fil_path_to_mysql_datadir, dir,
03521            &dbinfo);
03522   while (ret == 0) {
03523     ulint len;
03524     /* printf("Looking at %s in datadir\n", dbinfo.name); */
03525 
03526     if (dbinfo.type == OS_FILE_TYPE_FILE
03527         || dbinfo.type == OS_FILE_TYPE_UNKNOWN) {
03528 
03529       goto next_datadir_item;
03530     }
03531 
03532     /* We found a symlink or a directory; try opening it to see
03533     if a symlink is a directory */
03534 
03535     len = strlen(fil_path_to_mysql_datadir)
03536       + strlen (dbinfo.name) + 2;
03537     if (len > dbpath_len) {
03538       dbpath_len = len;
03539 
03540       if (dbpath) {
03541         mem_free(dbpath);
03542       }
03543 
03544       dbpath = static_cast<char *>(mem_alloc(dbpath_len));
03545     }
03546     sprintf(dbpath, "%s/%s", fil_path_to_mysql_datadir,
03547       dbinfo.name);
03548     srv_normalize_path_for_win(dbpath);
03549 
03550     dbdir = os_file_opendir(dbpath, FALSE);
03551 
03552     if (dbdir != NULL) {
03553       /* printf("Opened dir %s\n", dbinfo.name); */
03554 
03555       /* We found a database directory; loop through it,
03556       looking for possible .ibd files in it */
03557 
03558       ret = fil_file_readdir_next_file(&err, dbpath, dbdir,
03559                &fileinfo);
03560       while (ret == 0) {
03561         /* printf(
03562         "     Looking at file %s\n", fileinfo.name); */
03563 
03564         if (fileinfo.type == OS_FILE_TYPE_DIR) {
03565 
03566           goto next_file_item;
03567         }
03568 
03569         /* We found a symlink or a file */
03570         if (strlen(fileinfo.name) > 4
03571             && 0 == strcmp(fileinfo.name
03572                + strlen(fileinfo.name) - 4,
03573                ".ibd")) {
03574           /* The name ends in .ibd; try opening
03575           the file */
03576           fil_load_single_table_tablespace(
03577             dbinfo.name, fileinfo.name);
03578         }
03579 next_file_item:
03580         ret = fil_file_readdir_next_file(&err,
03581                  dbpath, dbdir,
03582                  &fileinfo);
03583       }
03584 
03585       if (0 != os_file_closedir(dbdir)) {
03586         fputs("InnoDB: Warning: could not"
03587               " close database directory ", stderr);
03588         ut_print_filename(stderr, dbpath);
03589         putc('\n', stderr);
03590 
03591         err = DB_ERROR;
03592       }
03593     }
03594 
03595 next_datadir_item:
03596     ret = fil_file_readdir_next_file(&err,
03597              fil_path_to_mysql_datadir,
03598              dir, &dbinfo);
03599   }
03600 
03601   mem_free(dbpath);
03602 
03603   if (0 != os_file_closedir(dir)) {
03604     fprintf(stderr,
03605       "InnoDB: Error: could not close MySQL datadir\n");
03606 
03607     return(DB_ERROR);
03608   }
03609 
03610   return(err);
03611 }
03612 
03613 /*******************************************************************/
03617 UNIV_INTERN
03618 ibool
03619 fil_tablespace_deleted_or_being_deleted_in_mem(
03620 /*===========================================*/
03621   ulint   id, 
03622   ib_int64_t  version)
03625 {
03626   fil_space_t*  space;
03627 
03628   ut_ad(fil_system);
03629 
03630   mutex_enter(&fil_system->mutex);
03631 
03632   space = fil_space_get_by_id(id);
03633 
03634   if (space == NULL || space->is_being_deleted) {
03635     mutex_exit(&fil_system->mutex);
03636 
03637     return(TRUE);
03638   }
03639 
03640   if (version != ((ib_int64_t)-1)
03641       && space->tablespace_version != version) {
03642     mutex_exit(&fil_system->mutex);
03643 
03644     return(TRUE);
03645   }
03646 
03647   mutex_exit(&fil_system->mutex);
03648 
03649   return(FALSE);
03650 }
03651 
03652 /*******************************************************************/
03655 UNIV_INTERN
03656 ibool
03657 fil_tablespace_exists_in_mem(
03658 /*=========================*/
03659   ulint id) 
03660 {
03661   fil_space_t*  space;
03662 
03663   ut_ad(fil_system);
03664 
03665   mutex_enter(&fil_system->mutex);
03666 
03667   space = fil_space_get_by_id(id);
03668 
03669   mutex_exit(&fil_system->mutex);
03670 
03671   return(space != NULL);
03672 }
03673 
03674 /*******************************************************************/
03679 UNIV_INTERN
03680 ibool
03681 fil_space_for_table_exists_in_mem(
03682 /*==============================*/
03683   ulint   id,   
03684   const char* name,   
03687   ibool   is_temp,  
03689   ibool   mark_space, 
03695   ibool   print_error_if_does_not_exist)
03700 {
03701   fil_space_t*  tablespace;
03702   fil_space_t*  space;
03703   char*   path;
03704 
03705   ut_ad(fil_system);
03706 
03707   mutex_enter(&fil_system->mutex);
03708 
03709   path = fil_make_ibd_name(name, is_temp);
03710 
03711   /* Look if there is a space with the same id */
03712 
03713   space = fil_space_get_by_id(id);
03714 
03715   /* Look if there is a space with the same name; the name is the
03716   directory path from the datadir to the file */
03717 
03718   tablespace = fil_space_get_by_name(path);
03719   if (space && space == tablespace) {
03720     /* Found */
03721 
03722     if (mark_space) {
03723       space->mark = TRUE;
03724     }
03725 
03726     mem_free(path);
03727     mutex_exit(&fil_system->mutex);
03728 
03729     return(TRUE);
03730   }
03731 
03732   if (!print_error_if_does_not_exist) {
03733 
03734     mem_free(path);
03735     mutex_exit(&fil_system->mutex);
03736 
03737     return(FALSE);
03738   }
03739 
03740   if (space == NULL) {
03741     if (tablespace == NULL) {
03742       ut_print_timestamp(stderr);
03743       fputs("  InnoDB: Error: table ", stderr);
03744       ut_print_filename(stderr, name);
03745       fprintf(stderr, "\n"
03746         "InnoDB: in InnoDB data dictionary"
03747         " has tablespace id %lu,\n"
03748         "InnoDB: but tablespace with that id"
03749         " or name does not exist. Have\n"
03750         "InnoDB: you deleted or moved .ibd files?\n"
03751         "InnoDB: This may also be a table created with"
03752         " CREATE TEMPORARY TABLE\n"
03753         "InnoDB: whose .ibd and .frm files"
03754         " MySQL automatically removed, but the\n"
03755         "InnoDB: table still exists in the"
03756         " InnoDB internal data dictionary.\n",
03757         (ulong) id);
03758     } else {
03759       ut_print_timestamp(stderr);
03760       fputs("  InnoDB: Error: table ", stderr);
03761       ut_print_filename(stderr, name);
03762       fprintf(stderr, "\n"
03763         "InnoDB: in InnoDB data dictionary has"
03764         " tablespace id %lu,\n"
03765         "InnoDB: but a tablespace with that id"
03766         " does not exist. There is\n"
03767         "InnoDB: a tablespace of name %s and id %lu,"
03768         " though. Have\n"
03769         "InnoDB: you deleted or moved .ibd files?\n",
03770         (ulong) id, tablespace->name,
03771         (ulong) tablespace->id);
03772     }
03773 error_exit:
03774     fputs("InnoDB: Please refer to\n"
03775           "InnoDB: " REFMAN "innodb-troubleshooting-datadict.html\n"
03776           "InnoDB: for how to resolve the issue.\n", stderr);
03777 
03778     mem_free(path);
03779     mutex_exit(&fil_system->mutex);
03780 
03781     return(FALSE);
03782   }
03783 
03784   if (0 != strcmp(space->name, path)) {
03785     ut_print_timestamp(stderr);
03786     fputs("  InnoDB: Error: table ", stderr);
03787     ut_print_filename(stderr, name);
03788     fprintf(stderr, "\n"
03789       "InnoDB: in InnoDB data dictionary has"
03790       " tablespace id %lu,\n"
03791       "InnoDB: but the tablespace with that id"
03792       " has name %s.\n"
03793       "InnoDB: Have you deleted or moved .ibd files?\n",
03794       (ulong) id, space->name);
03795 
03796     if (tablespace != NULL) {
03797       fputs("InnoDB: There is a tablespace"
03798             " with the right name\n"
03799             "InnoDB: ", stderr);
03800       ut_print_filename(stderr, tablespace->name);
03801       fprintf(stderr, ", but its id is %lu.\n",
03802         (ulong) tablespace->id);
03803     }
03804 
03805     goto error_exit;
03806   }
03807 
03808   mem_free(path);
03809   mutex_exit(&fil_system->mutex);
03810 
03811   return(FALSE);
03812 }
03813 
03814 /*******************************************************************/
03818 static
03819 ulint
03820 fil_get_space_id_for_table(
03821 /*=======================*/
03822   const char* name) 
03824 {
03825   fil_space_t*  tablespace;
03826   ulint   id    = ULINT_UNDEFINED;
03827   char*   path;
03828 
03829   ut_ad(fil_system);
03830 
03831   mutex_enter(&fil_system->mutex);
03832 
03833   path = fil_make_ibd_name(name, FALSE);
03834 
03835   /* Look if there is a space with the same name; the name is the
03836   directory path to the file */
03837 
03838   tablespace = fil_space_get_by_name(path);
03839 
03840   if (tablespace) {
03841     id = tablespace->id;
03842   }
03843 
03844   mem_free(path);
03845 
03846   mutex_exit(&fil_system->mutex);
03847 
03848   return(id);
03849 }
03850 
03851 /**********************************************************************/
03856 UNIV_INTERN
03857 ibool
03858 fil_extend_space_to_desired_size(
03859 /*=============================*/
03860   ulint*  actual_size,  
03863   ulint space_id, 
03864   ulint size_after_extend)
03867 {
03868   fil_node_t* node;
03869   fil_space_t*  space;
03870   byte*   buf2;
03871   byte*   buf;
03872   ulint   buf_size;
03873   ulint   start_page_no;
03874   ulint   file_start_page_no;
03875   ulint   offset_high;
03876   ulint   offset_low;
03877   ulint   page_size;
03878   ibool   success   = TRUE;
03879 
03880   fil_mutex_enter_and_prepare_for_io(space_id);
03881 
03882   space = fil_space_get_by_id(space_id);
03883   ut_a(space);
03884 
03885   if (space->size >= size_after_extend) {
03886     /* Space already big enough */
03887 
03888     *actual_size = space->size;
03889 
03890     mutex_exit(&fil_system->mutex);
03891 
03892     return(TRUE);
03893   }
03894 
03895   page_size = dict_table_flags_to_zip_size(space->flags);
03896   if (!page_size) {
03897     page_size = UNIV_PAGE_SIZE;
03898   }
03899 
03900   node = UT_LIST_GET_LAST(space->chain);
03901 
03902   fil_node_prepare_for_io(node, fil_system, space);
03903 
03904   start_page_no = space->size;
03905   file_start_page_no = space->size - node->size;
03906 
03907   /* Extend at most 64 pages at a time */
03908   buf_size = ut_min(64, size_after_extend - start_page_no) * page_size;
03909   buf2 = static_cast<byte *>(mem_alloc(buf_size + page_size));
03910   buf = static_cast<byte *>(ut_align(buf2, page_size));
03911 
03912   memset(buf, 0, buf_size);
03913 
03914   while (start_page_no < size_after_extend) {
03915     ulint n_pages = ut_min(buf_size / page_size,
03916            size_after_extend - start_page_no);
03917 
03918     offset_high = (start_page_no - file_start_page_no)
03919       / (4096 * ((1024 * 1024) / page_size));
03920     offset_low  = ((start_page_no - file_start_page_no)
03921              % (4096 * ((1024 * 1024) / page_size)))
03922       * page_size;
03923 #ifdef UNIV_HOTBACKUP
03924     success = os_file_write(node->name, node->handle, buf,
03925           offset_low, offset_high,
03926           page_size * n_pages);
03927 #else
03928     success = os_aio(OS_FILE_WRITE, OS_AIO_SYNC,
03929          node->name, node->handle, buf,
03930          offset_low, offset_high,
03931          page_size * n_pages,
03932          NULL, NULL);
03933 #endif
03934     if (success) {
03935       node->size += n_pages;
03936       space->size += n_pages;
03937 
03938       os_has_said_disk_full = FALSE;
03939     } else {
03940       /* Let us measure the size of the file to determine
03941       how much we were able to extend it */
03942 
03943       n_pages = ((ulint)
03944            (os_file_get_size_as_iblonglong(
03945              node->handle)
03946             / page_size)) - node->size;
03947 
03948       node->size += n_pages;
03949       space->size += n_pages;
03950 
03951       break;
03952     }
03953 
03954     start_page_no += n_pages;
03955   }
03956 
03957   mem_free(buf2);
03958 
03959   fil_node_complete_io(node, fil_system, OS_FILE_WRITE);
03960 
03961   *actual_size = space->size;
03962 
03963 #ifndef UNIV_HOTBACKUP
03964   if (space_id == 0) {
03965     ulint pages_per_mb = (1024 * 1024) / page_size;
03966 
03967     /* Keep the last data file size info up to date, rounded to
03968     full megabytes */
03969 
03970     srv_data_file_sizes[srv_n_data_files - 1]
03971       = (node->size / pages_per_mb) * pages_per_mb;
03972   }
03973 #endif /* !UNIV_HOTBACKUP */
03974 
03975   /*
03976   printf("Extended %s to %lu, actual size %lu pages\n", space->name,
03977   size_after_extend, *actual_size); */
03978   mutex_exit(&fil_system->mutex);
03979 
03980   fil_flush(space_id);
03981 
03982   return(success);
03983 }
03984 
03985 #ifdef UNIV_HOTBACKUP
03986 /********************************************************************/
03991 UNIV_INTERN
03992 void
03993 fil_extend_tablespaces_to_stored_len(void)
03994 /*======================================*/
03995 {
03996   fil_space_t*  space;
03997   byte*   buf;
03998   ulint   actual_size;
03999   ulint   size_in_header;
04000   ulint   error;
04001   ibool   success;
04002 
04003   buf = mem_alloc(UNIV_PAGE_SIZE);
04004 
04005   mutex_enter(&fil_system->mutex);
04006 
04007   space = UT_LIST_GET_FIRST(fil_system->space_list);
04008 
04009   while (space) {
04010     ut_a(space->purpose == FIL_TABLESPACE);
04011 
04012     mutex_exit(&fil_system->mutex); /* no need to protect with a
04013                 mutex, because this is a
04014                 single-threaded operation */
04015     error = fil_read(TRUE, space->id,
04016          dict_table_flags_to_zip_size(space->flags),
04017          0, 0, UNIV_PAGE_SIZE, buf, NULL);
04018     ut_a(error == DB_SUCCESS);
04019 
04020     size_in_header = fsp_get_size_low(buf);
04021 
04022     success = fil_extend_space_to_desired_size(
04023       &actual_size, space->id, size_in_header);
04024     if (!success) {
04025       fprintf(stderr,
04026         "InnoDB: Error: could not extend the"
04027         " tablespace of %s\n"
04028         "InnoDB: to the size stored in header,"
04029         " %lu pages;\n"
04030         "InnoDB: size after extension %lu pages\n"
04031         "InnoDB: Check that you have free disk space"
04032         " and retry!\n",
04033         space->name, size_in_header, actual_size);
04034       exit(1);
04035     }
04036 
04037     mutex_enter(&fil_system->mutex);
04038 
04039     space = UT_LIST_GET_NEXT(space_list, space);
04040   }
04041 
04042   mutex_exit(&fil_system->mutex);
04043 
04044   mem_free(buf);
04045 }
04046 #endif
04047 
04048 /*========== RESERVE FREE EXTENTS (for a B-tree split, for example) ===*/
04049 
04050 /*******************************************************************/
04053 UNIV_INTERN
04054 ibool
04055 fil_space_reserve_free_extents(
04056 /*===========================*/
04057   ulint id,   
04058   ulint n_free_now, 
04059   ulint n_to_reserve) 
04060 {
04061   fil_space_t*  space;
04062   ibool   success;
04063 
04064   ut_ad(fil_system);
04065 
04066   mutex_enter(&fil_system->mutex);
04067 
04068   space = fil_space_get_by_id(id);
04069 
04070   ut_a(space);
04071 
04072   if (space->n_reserved_extents + n_to_reserve > n_free_now) {
04073     success = FALSE;
04074   } else {
04075     space->n_reserved_extents += n_to_reserve;
04076     success = TRUE;
04077   }
04078 
04079   mutex_exit(&fil_system->mutex);
04080 
04081   return(success);
04082 }
04083 
04084 /*******************************************************************/
04086 UNIV_INTERN
04087 void
04088 fil_space_release_free_extents(
04089 /*===========================*/
04090   ulint id,   
04091   ulint n_reserved) 
04092 {
04093   fil_space_t*  space;
04094 
04095   ut_ad(fil_system);
04096 
04097   mutex_enter(&fil_system->mutex);
04098 
04099   space = fil_space_get_by_id(id);
04100 
04101   ut_a(space);
04102   ut_a(space->n_reserved_extents >= n_reserved);
04103 
04104   space->n_reserved_extents -= n_reserved;
04105 
04106   mutex_exit(&fil_system->mutex);
04107 }
04108 
04109 /*******************************************************************/
04112 UNIV_INTERN
04113 ulint
04114 fil_space_get_n_reserved_extents(
04115 /*=============================*/
04116   ulint id)   
04117 {
04118   fil_space_t*  space;
04119   ulint   n;
04120 
04121   ut_ad(fil_system);
04122 
04123   mutex_enter(&fil_system->mutex);
04124 
04125   space = fil_space_get_by_id(id);
04126 
04127   ut_a(space);
04128 
04129   n = space->n_reserved_extents;
04130 
04131   mutex_exit(&fil_system->mutex);
04132 
04133   return(n);
04134 }
04135 
04136 /*============================ FILE I/O ================================*/
04137 
04138 /********************************************************************/
04145 static
04146 void
04147 fil_node_prepare_for_io(
04148 /*====================*/
04149   fil_node_t* node, 
04150   fil_system_t* system, 
04151   fil_space_t*  space)  
04152 {
04153   ut_ad(node && system && space);
04154   ut_ad(mutex_own(&(system->mutex)));
04155 
04156   if (system->n_open > system->max_n_open + 5) {
04157     ut_print_timestamp(stderr);
04158     fprintf(stderr,
04159       "  InnoDB: Warning: open files %lu"
04160       " exceeds the limit %lu\n",
04161       (ulong) system->n_open,
04162       (ulong) system->max_n_open);
04163   }
04164 
04165   if (node->open == FALSE) {
04166     /* File is closed: open it */
04167     ut_a(node->n_pending == 0);
04168 
04169     fil_node_open_file(node, system, space);
04170   }
04171 
04172   if (node->n_pending == 0 && space->purpose == FIL_TABLESPACE
04173       && space->id != 0) {
04174     /* The node is in the LRU list, remove it */
04175 
04176     ut_a(UT_LIST_GET_LEN(system->LRU) > 0);
04177 
04178     UT_LIST_REMOVE(LRU, system->LRU, node);
04179   }
04180 
04181   node->n_pending++;
04182 }
04183 
04184 /********************************************************************/
04187 static
04188 void
04189 fil_node_complete_io(
04190 /*=================*/
04191   fil_node_t* node, 
04192   fil_system_t* system, 
04193   ulint   type) 
04196 {
04197   ut_ad(node);
04198   ut_ad(system);
04199   ut_ad(mutex_own(&(system->mutex)));
04200 
04201   ut_a(node->n_pending > 0);
04202 
04203   node->n_pending--;
04204 
04205   if (type == OS_FILE_WRITE) {
04206     system->modification_counter++;
04207     node->modification_counter = system->modification_counter;
04208 
04209     if (!node->space->is_in_unflushed_spaces) {
04210 
04211       node->space->is_in_unflushed_spaces = TRUE;
04212       UT_LIST_ADD_FIRST(unflushed_spaces,
04213             system->unflushed_spaces,
04214             node->space);
04215     }
04216   }
04217 
04218   if (node->n_pending == 0 && node->space->purpose == FIL_TABLESPACE
04219       && node->space->id != 0) {
04220     /* The node must be put back to the LRU list */
04221     UT_LIST_ADD_FIRST(LRU, system->LRU, node);
04222   }
04223 }
04224 
04225 /********************************************************************/
04227 static
04228 void
04229 fil_report_invalid_page_access(
04230 /*===========================*/
04231   ulint   block_offset, 
04232   ulint   space_id, 
04233   const char* space_name, 
04234   ulint   byte_offset,  
04235   ulint   len,    
04236   ulint   type)   
04237 {
04238   fprintf(stderr,
04239     "InnoDB: Error: trying to access page number %lu"
04240     " in space %lu,\n"
04241     "InnoDB: space name %s,\n"
04242     "InnoDB: which is outside the tablespace bounds.\n"
04243     "InnoDB: Byte offset %lu, len %lu, i/o type %lu.\n"
04244     "InnoDB: If you get this error at mysqld startup,"
04245     " please check that\n"
04246     "InnoDB: your my.cnf matches the ibdata files"
04247     " that you have in the\n"
04248     "InnoDB: MySQL server.\n",
04249     (ulong) block_offset, (ulong) space_id, space_name,
04250     (ulong) byte_offset, (ulong) len, (ulong) type);
04251 }
04252 
04253 /********************************************************************/
04257 UNIV_INTERN
04258 ulint
04259 fil_io(
04260 /*===*/
04261   ulint type,   
04270   ibool sync,   
04271   ulint space_id, 
04272   ulint zip_size, 
04274   ulint block_offset, 
04275   ulint byte_offset,  
04278   ulint len,    
04281   void* buf,    
04284   void* message)  
04286 {
04287   ulint   mode;
04288   fil_space_t*  space;
04289   fil_node_t* node;
04290   ulint   offset_high;
04291   ulint   offset_low;
04292   ibool   ret;
04293   ulint   is_log;
04294   ulint   wake_later;
04295 
04296   is_log = type & OS_FILE_LOG;
04297   type = type & ~OS_FILE_LOG;
04298 
04299   wake_later = type & OS_AIO_SIMULATED_WAKE_LATER;
04300   type = type & ~OS_AIO_SIMULATED_WAKE_LATER;
04301 
04302   ut_ad(byte_offset < UNIV_PAGE_SIZE);
04303   ut_ad(!zip_size || !byte_offset);
04304   ut_ad(ut_is_2pow(zip_size));
04305   ut_ad(buf);
04306   ut_ad(len > 0);
04307   ut_ad(fil_validate());
04308 #ifndef UNIV_HOTBACKUP
04309 # ifndef UNIV_LOG_DEBUG
04310   /* ibuf bitmap pages must be read in the sync aio mode: */
04311   ut_ad(recv_no_ibuf_operations || (type == OS_FILE_WRITE)
04312         || !ibuf_bitmap_page(zip_size, block_offset)
04313         || sync || is_log);
04314   ut_ad(!ibuf_inside() || is_log || (type == OS_FILE_WRITE)
04315         || ibuf_page(space_id, zip_size, block_offset, NULL));
04316 # endif /* UNIV_LOG_DEBUG */
04317   if (sync) {
04318     mode = OS_AIO_SYNC;
04319   } else if (is_log) {
04320     mode = OS_AIO_LOG;
04321   } else if (type == OS_FILE_READ
04322        && !recv_no_ibuf_operations
04323        && ibuf_page(space_id, zip_size, block_offset, NULL)) {
04324     mode = OS_AIO_IBUF;
04325   } else {
04326     mode = OS_AIO_NORMAL;
04327   }
04328 #else /* !UNIV_HOTBACKUP */
04329   ut_a(sync);
04330   mode = OS_AIO_SYNC;
04331 #endif /* !UNIV_HOTBACKUP */
04332 
04333   if (type == OS_FILE_READ) {
04334     srv_data_read+= len;
04335   } else if (type == OS_FILE_WRITE) {
04336     srv_data_written+= len;
04337   }
04338 
04339   /* Reserve the fil_system mutex and make sure that we can open at
04340   least one file while holding it, if the file is not already open */
04341 
04342   fil_mutex_enter_and_prepare_for_io(space_id);
04343 
04344   space = fil_space_get_by_id(space_id);
04345 
04346   if (!space) {
04347     mutex_exit(&fil_system->mutex);
04348 
04349     ut_print_timestamp(stderr);
04350     fprintf(stderr,
04351       "  InnoDB: Error: trying to do i/o"
04352       " to a tablespace which does not exist.\n"
04353       "InnoDB: i/o type %lu, space id %lu,"
04354       " page no. %lu, i/o length %lu bytes\n",
04355       (ulong) type, (ulong) space_id, (ulong) block_offset,
04356       (ulong) len);
04357 
04358     return(DB_TABLESPACE_DELETED);
04359   }
04360 
04361   ut_ad((mode != OS_AIO_IBUF) || (space->purpose == FIL_TABLESPACE));
04362 
04363   node = UT_LIST_GET_FIRST(space->chain);
04364 
04365   for (;;) {
04366     if (UNIV_UNLIKELY(node == NULL)) {
04367       fil_report_invalid_page_access(
04368         block_offset, space_id, space->name,
04369         byte_offset, len, type);
04370 
04371       ut_error;
04372     }
04373 
04374     if (space->id != 0 && node->size == 0) {
04375       /* We do not know the size of a single-table tablespace
04376       before we open the file */
04377 
04378       break;
04379     }
04380 
04381     if (node->size > block_offset) {
04382       /* Found! */
04383       break;
04384     } else {
04385       block_offset -= node->size;
04386       node = UT_LIST_GET_NEXT(chain, node);
04387     }
04388   }
04389 
04390   /* Open file if closed */
04391   fil_node_prepare_for_io(node, fil_system, space);
04392 
04393   /* Check that at least the start offset is within the bounds of a
04394   single-table tablespace */
04395   if (UNIV_UNLIKELY(node->size <= block_offset)
04396       && space->id != 0 && space->purpose == FIL_TABLESPACE) {
04397 
04398     fil_report_invalid_page_access(
04399       block_offset, space_id, space->name, byte_offset,
04400       len, type);
04401 
04402     ut_error;
04403   }
04404 
04405   /* Now we have made the changes in the data structures of fil_system */
04406   mutex_exit(&fil_system->mutex);
04407 
04408   /* Calculate the low 32 bits and the high 32 bits of the file offset */
04409 
04410   if (!zip_size) {
04411     offset_high = (block_offset >> (32 - UNIV_PAGE_SIZE_SHIFT));
04412     offset_low  = ((block_offset << UNIV_PAGE_SIZE_SHIFT)
04413              & 0xFFFFFFFFUL) + byte_offset;
04414 
04415     ut_a(node->size - block_offset
04416          >= ((byte_offset + len + (UNIV_PAGE_SIZE - 1))
04417        / UNIV_PAGE_SIZE));
04418   } else {
04419     ulint zip_size_shift;
04420     switch (zip_size) {
04421     case 1024: zip_size_shift = 10; break;
04422     case 2048: zip_size_shift = 11; break;
04423     case 4096: zip_size_shift = 12; break;
04424     case 8192: zip_size_shift = 13; break;
04425     case 16384: zip_size_shift = 14; break;
04426     default: ut_error;
04427     }
04428     offset_high = block_offset >> (32 - zip_size_shift);
04429     offset_low = (block_offset << zip_size_shift & 0xFFFFFFFFUL)
04430       + byte_offset;
04431     ut_a(node->size - block_offset
04432          >= (len + (zip_size - 1)) / zip_size);
04433   }
04434 
04435   /* Do aio */
04436 
04437   ut_a(byte_offset % OS_FILE_LOG_BLOCK_SIZE == 0);
04438   ut_a((len % OS_FILE_LOG_BLOCK_SIZE) == 0);
04439 
04440 #ifdef UNIV_HOTBACKUP
04441   /* In ibbackup do normal i/o, not aio */
04442   if (type == OS_FILE_READ) {
04443     ret = os_file_read(node->handle, buf, offset_low, offset_high,
04444            len);
04445   } else {
04446     ret = os_file_write(node->name, node->handle, buf,
04447             offset_low, offset_high, len);
04448   }
04449 #else
04450   /* Queue the aio request */
04451   ret = os_aio(type, mode | wake_later, node->name, node->handle, buf,
04452          offset_low, offset_high, len, node, message);
04453 #endif
04454   ut_a(ret);
04455 
04456   if (mode == OS_AIO_SYNC) {
04457     /* The i/o operation is already completed when we return from
04458     os_aio: */
04459 
04460     mutex_enter(&fil_system->mutex);
04461 
04462     fil_node_complete_io(node, fil_system, type);
04463 
04464     mutex_exit(&fil_system->mutex);
04465 
04466     ut_ad(fil_validate());
04467   }
04468 
04469   return(DB_SUCCESS);
04470 }
04471 
04472 /********************************************************************/
04474 UNIV_INTERN
04475 bool
04476 fil_is_exist(
04477 /*=========*/
04478   ulint space_id, 
04479   ulint block_offset) 
04480 {
04481   fil_space_t*  space;
04482   fil_node_t* node;
04483 
04484   /* Reserve the fil_system mutex and make sure that we can open at
04485   least one file while holding it, if the file is not already open */
04486 
04487   fil_mutex_enter_and_prepare_for_io(space_id);
04488 
04489   space = fil_space_get_by_id(space_id);
04490 
04491   if (!space) {
04492     mutex_exit(&fil_system->mutex);
04493     return(false);
04494   }
04495 
04496   node = UT_LIST_GET_FIRST(space->chain);
04497 
04498   for (;;) {
04499     if (UNIV_UNLIKELY(node == NULL)) {
04500       mutex_exit(&fil_system->mutex);
04501       return(false);
04502     }
04503 
04504     if (space->id != 0 && node->size == 0) {
04505       /* We do not know the size of a single-table tablespace
04506       before we open the file */
04507 
04508       break;
04509     }
04510 
04511     if (node->size > block_offset) {
04512       /* Found! */
04513       break;
04514     } else {
04515       block_offset -= node->size;
04516       node = UT_LIST_GET_NEXT(chain, node);
04517     }
04518   }
04519 
04520   /* Open file if closed */
04521   fil_node_prepare_for_io(node, fil_system, space);
04522   fil_node_complete_io(node, fil_system, OS_FILE_READ);
04523 
04524   /* Check that at least the start offset is within the bounds of a
04525   single-table tablespace */
04526   if (UNIV_UNLIKELY(node->size <= block_offset)
04527       && space->id != 0 && space->purpose == FIL_TABLESPACE) {
04528     mutex_exit(&fil_system->mutex);
04529     return(false);
04530   }
04531 
04532   mutex_exit(&fil_system->mutex);
04533   return(true);
04534 }
04535 
04536 #ifndef UNIV_HOTBACKUP
04537 /**********************************************************************/
04542 UNIV_INTERN
04543 void
04544 fil_aio_wait(
04545 /*=========*/
04546   ulint segment)  
04548 {
04549   ibool   ret;
04550   fil_node_t* fil_node;
04551   void*   message;
04552   ulint   type;
04553 
04554   ut_ad(fil_validate());
04555 
04556   if (srv_use_native_aio) {
04557     srv_set_io_thread_op_info(segment, "native aio handle");
04558 #ifdef WIN_ASYNC_IO
04559     ret = os_aio_windows_handle(segment, 0, &fil_node,
04560               &message, &type);
04561 #elif defined(LINUX_NATIVE_AIO)
04562     ret = os_aio_linux_handle(segment, &fil_node,
04563             &message, &type);
04564 #else
04565     ret = 0; /* Eliminate compiler warning */
04566     ut_error;
04567 #endif
04568   } else {
04569     srv_set_io_thread_op_info(segment, "simulated aio handle");
04570 
04571     ret = os_aio_simulated_handle(segment, &fil_node,
04572                 &message, &type);
04573   }
04574 
04575   ut_a(ret);
04576 
04577   srv_set_io_thread_op_info(segment, "complete io for fil node");
04578 
04579   mutex_enter(&fil_system->mutex);
04580 
04581   fil_node_complete_io(fil_node, fil_system, type);
04582 
04583   mutex_exit(&fil_system->mutex);
04584 
04585   ut_ad(fil_validate());
04586 
04587   /* Do the i/o handling */
04588   /* IMPORTANT: since i/o handling for reads will read also the insert
04589   buffer in tablespace 0, you have to be very careful not to introduce
04590   deadlocks in the i/o system. We keep tablespace 0 data files always
04591   open, and use a special i/o thread to serve insert buffer requests. */
04592 
04593   if (fil_node->space->purpose == FIL_TABLESPACE) {
04594     srv_set_io_thread_op_info(segment, "complete io for buf page");
04595     buf_page_io_complete(static_cast<buf_page_t *>(message));
04596   } else {
04597     srv_set_io_thread_op_info(segment, "complete io for log");
04598     log_io_complete(static_cast<log_group_t *>(message));
04599   }
04600 }
04601 #endif /* UNIV_HOTBACKUP */
04602 
04603 /**********************************************************************/
04606 UNIV_INTERN
04607 void
04608 fil_flush(
04609 /*======*/
04610   ulint space_id) 
04612 {
04613   fil_space_t*  space;
04614   fil_node_t* node;
04615   os_file_t file;
04616   ib_int64_t  old_mod_counter;
04617 
04618   mutex_enter(&fil_system->mutex);
04619 
04620   space = fil_space_get_by_id(space_id);
04621 
04622   if (!space || space->is_being_deleted) {
04623     mutex_exit(&fil_system->mutex);
04624 
04625     return;
04626   }
04627 
04628   space->n_pending_flushes++; 
04630   node = UT_LIST_GET_FIRST(space->chain);
04631 
04632   while (node) {
04633     if (node->modification_counter > node->flush_counter) {
04634       ut_a(node->open);
04635 
04636       /* We want to flush the changes at least up to
04637       old_mod_counter */
04638       old_mod_counter = node->modification_counter;
04639 
04640       if (space->purpose == FIL_TABLESPACE) {
04641         fil_n_pending_tablespace_flushes++;
04642       } else {
04643         fil_n_pending_log_flushes++;
04644         fil_n_log_flushes++;
04645       }
04646 #ifdef __WIN__
04647       if (node->is_raw_disk) {
04648 
04649         goto skip_flush;
04650       }
04651 #endif
04652 retry:
04653       if (node->n_pending_flushes > 0) {
04654         /* We want to avoid calling os_file_flush() on
04655         the file twice at the same time, because we do
04656         not know what bugs OS's may contain in file
04657         i/o; sleep for a while */
04658 
04659         mutex_exit(&fil_system->mutex);
04660 
04661         os_thread_sleep(20000);
04662 
04663         mutex_enter(&fil_system->mutex);
04664 
04665         if (node->flush_counter >= old_mod_counter) {
04666 
04667           goto skip_flush;
04668         }
04669 
04670         goto retry;
04671       }
04672 
04673       ut_a(node->open);
04674       file = node->handle;
04675       node->n_pending_flushes++;
04676 
04677       mutex_exit(&fil_system->mutex);
04678 
04679       /* fprintf(stderr, "Flushing to file %s\n",
04680       node->name); */
04681 
04682       os_file_flush(file);
04683 
04684       mutex_enter(&fil_system->mutex);
04685 
04686       node->n_pending_flushes--;
04687 skip_flush:
04688       if (node->flush_counter < old_mod_counter) {
04689         node->flush_counter = old_mod_counter;
04690 
04691         if (space->is_in_unflushed_spaces
04692             && fil_space_is_flushed(space)) {
04693 
04694           space->is_in_unflushed_spaces = FALSE;
04695 
04696           UT_LIST_REMOVE(
04697             unflushed_spaces,
04698             fil_system->unflushed_spaces,
04699             space);
04700         }
04701       }
04702 
04703       if (space->purpose == FIL_TABLESPACE) {
04704         fil_n_pending_tablespace_flushes--;
04705       } else {
04706         fil_n_pending_log_flushes--;
04707       }
04708     }
04709 
04710     node = UT_LIST_GET_NEXT(chain, node);
04711   }
04712 
04713   space->n_pending_flushes--;
04714 
04715   mutex_exit(&fil_system->mutex);
04716 }
04717 
04718 /**********************************************************************/
04721 UNIV_INTERN
04722 void
04723 fil_flush_file_spaces(
04724 /*==================*/
04725   ulint purpose)  
04726 {
04727   fil_space_t*  space;
04728   ulint*    space_ids;
04729   ulint   n_space_ids;
04730   ulint   i;
04731 
04732   mutex_enter(&fil_system->mutex);
04733 
04734   n_space_ids = UT_LIST_GET_LEN(fil_system->unflushed_spaces);
04735   if (n_space_ids == 0) {
04736 
04737     mutex_exit(&fil_system->mutex);
04738     return;
04739   }
04740 
04741   /* Assemble a list of space ids to flush.  Previously, we
04742   traversed fil_system->unflushed_spaces and called UT_LIST_GET_NEXT()
04743   on a space that was just removed from the list by fil_flush().
04744   Thus, the space could be dropped and the memory overwritten. */
04745   space_ids = static_cast<unsigned long *>(mem_alloc(n_space_ids * sizeof *space_ids));
04746 
04747   n_space_ids = 0;
04748 
04749   for (space = UT_LIST_GET_FIRST(fil_system->unflushed_spaces);
04750        space;
04751        space = UT_LIST_GET_NEXT(unflushed_spaces, space)) {
04752 
04753     if (space->purpose == purpose && !space->is_being_deleted) {
04754 
04755       space_ids[n_space_ids++] = space->id;
04756     }
04757   }
04758 
04759   mutex_exit(&fil_system->mutex);
04760 
04761   /* Flush the spaces.  It will not hurt to call fil_flush() on
04762   a non-existing space id. */
04763   for (i = 0; i < n_space_ids; i++) {
04764 
04765     fil_flush(space_ids[i]);
04766   }
04767 
04768   mem_free(space_ids);
04769 }
04770 
04771 /******************************************************************/
04774 UNIV_INTERN
04775 ibool
04776 fil_validate(void)
04777 /*==============*/
04778 {
04779   fil_space_t*  space;
04780   fil_node_t* fil_node;
04781   ulint   n_open    = 0;
04782   ulint   i;
04783 
04784   mutex_enter(&fil_system->mutex);
04785 
04786   /* Look for spaces in the hash table */
04787 
04788   for (i = 0; i < hash_get_n_cells(fil_system->spaces); i++) {
04789 
04790     space = static_cast<fil_space_t *>(HASH_GET_FIRST(fil_system->spaces, i));
04791 
04792     while (space != NULL) {
04793       UT_LIST_VALIDATE(chain, fil_node_t, space->chain,
04794            ut_a(ut_list_node_313->open
04795                 || !ut_list_node_313->n_pending));
04796 
04797       fil_node = UT_LIST_GET_FIRST(space->chain);
04798 
04799       while (fil_node != NULL) {
04800         if (fil_node->n_pending > 0) {
04801           ut_a(fil_node->open);
04802         }
04803 
04804         if (fil_node->open) {
04805           n_open++;
04806         }
04807         fil_node = UT_LIST_GET_NEXT(chain, fil_node);
04808       }
04809       space = static_cast<fil_space_t *>(HASH_GET_NEXT(hash, space));
04810     }
04811   }
04812 
04813   ut_a(fil_system->n_open == n_open);
04814 
04815   UT_LIST_VALIDATE(LRU, fil_node_t, fil_system->LRU, (void) 0);
04816 
04817   fil_node = UT_LIST_GET_FIRST(fil_system->LRU);
04818 
04819   while (fil_node != NULL) {
04820     ut_a(fil_node->n_pending == 0);
04821     ut_a(fil_node->open);
04822     ut_a(fil_node->space->purpose == FIL_TABLESPACE);
04823     ut_a(fil_node->space->id != 0);
04824 
04825     fil_node = UT_LIST_GET_NEXT(LRU, fil_node);
04826   }
04827 
04828   mutex_exit(&fil_system->mutex);
04829 
04830   return(TRUE);
04831 }
04832 
04833 /********************************************************************/
04836 UNIV_INTERN
04837 ibool
04838 fil_addr_is_null(
04839 /*=============*/
04840   fil_addr_t  addr) 
04841 {
04842   return(addr.page == FIL_NULL);
04843 }
04844 
04845 /********************************************************************/
04848 UNIV_INTERN
04849 ulint
04850 fil_page_get_prev(
04851 /*==============*/
04852   const byte* page) 
04853 {
04854   return(mach_read_from_4(page + FIL_PAGE_PREV));
04855 }
04856 
04857 /********************************************************************/
04860 UNIV_INTERN
04861 ulint
04862 fil_page_get_next(
04863 /*==============*/
04864   const byte* page) 
04865 {
04866   return(mach_read_from_4(page + FIL_PAGE_NEXT));
04867 }
04868 
04869 /*********************************************************************/
04871 UNIV_INTERN
04872 void
04873 fil_page_set_type(
04874 /*==============*/
04875   byte* page, 
04876   ulint type) 
04877 {
04878   ut_ad(page);
04879 
04880   mach_write_to_2(page + FIL_PAGE_TYPE, type);
04881 }
04882 
04883 /*********************************************************************/
04887 UNIV_INTERN
04888 ulint
04889 fil_page_get_type(
04890 /*==============*/
04891   const byte* page) 
04892 {
04893   ut_ad(page);
04894 
04895   return(mach_read_from_2(page + FIL_PAGE_TYPE));
04896 }
04897 
04898 /****************************************************************/
04900 UNIV_INTERN
04901 void
04902 fil_close(void)
04903 /*===========*/
04904 {
04905 #ifndef UNIV_HOTBACKUP
04906   /* The mutex should already have been freed. */
04907   ut_ad(fil_system->mutex.magic_n == 0);
04908 #endif /* !UNIV_HOTBACKUP */
04909 
04910   hash_table_free(fil_system->spaces);
04911 
04912   hash_table_free(fil_system->name_hash);
04913 
04914   ut_a(UT_LIST_GET_LEN(fil_system->LRU) == 0);
04915   ut_a(UT_LIST_GET_LEN(fil_system->unflushed_spaces) == 0);
04916   ut_a(UT_LIST_GET_LEN(fil_system->space_list) == 0);
04917 
04918   mem_free(fil_system);
04919 
04920   fil_system = NULL;
04921 }