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 #ifndef UNIV_HOTBACKUP
00044 # include "buf0lru.h"
00045 # include "ibuf0ibuf.h"
00046 # include "sync0sync.h"
00047 # include "os0sync.h"
00048 #else /* !UNIV_HOTBACKUP */
00049 static ulint srv_data_read, srv_data_written;
00050 #endif /* !UNIV_HOTBACKUP */
00051 
00052 /*
00053     IMPLEMENTATION OF THE TABLESPACE MEMORY CACHE
00054     =============================================
00055 
00056 The tablespace cache is responsible for providing fast read/write access to
00057 tablespaces and logs of the database. File creation and deletion is done
00058 in other modules which know more of the logic of the operation, however.
00059 
00060 A tablespace consists of a chain of files. The size of the files does not
00061 have to be divisible by the database block size, because we may just leave
00062 the last incomplete block unused. When a new file is appended to the
00063 tablespace, the maximum size of the file is also specified. At the moment,
00064 we think that it is best to extend the file to its maximum size already at
00065 the creation of the file, because then we can avoid dynamically extending
00066 the file when more space is needed for the tablespace.
00067 
00068 A block's position in the tablespace is specified with a 32-bit unsigned
00069 integer. The files in the chain are thought to be catenated, and the block
00070 corresponding to an address n is the nth block in the catenated file (where
00071 the first block is named the 0th block, and the incomplete block fragments
00072 at the end of files are not taken into account). A tablespace can be extended
00073 by appending a new file at the end of the chain.
00074 
00075 Our tablespace concept is similar to the one of Oracle.
00076 
00077 To acquire more speed in disk transfers, a technique called disk striping is
00078 sometimes used. This means that logical block addresses are divided in a
00079 round-robin fashion across several disks. Windows NT supports disk striping,
00080 so there we do not need to support it in the database. Disk striping is
00081 implemented in hardware in RAID disks. We conclude that it is not necessary
00082 to implement it in the database. Oracle 7 does not support disk striping,
00083 either.
00084 
00085 Another trick used at some database sites is replacing tablespace files by
00086 raw disks, that is, the whole physical disk drive, or a partition of it, is
00087 opened as a single file, and it is accessed through byte offsets calculated
00088 from the start of the disk or the partition. This is recommended in some
00089 books on database tuning to achieve more speed in i/o. Using raw disk
00090 certainly prevents the OS from fragmenting disk space, but it is not clear
00091 if it really adds speed. We measured on the Pentium 100 MHz + NT + NTFS file
00092 system + EIDE Conner disk only a negligible difference in speed when reading
00093 from a file, versus reading from a raw disk.
00094 
00095 To have fast access to a tablespace or a log file, we put the data structures
00096 to a hash table. Each tablespace and log file is given an unique 32-bit
00097 identifier.
00098 
00099 Some operating systems do not support many open files at the same time,
00100 though NT seems to tolerate at least 900 open files. Therefore, we put the
00101 open files in an LRU-list. If we need to open another file, we may close the
00102 file at the end of the LRU-list. When an i/o-operation is pending on a file,
00103 the file cannot be closed. We take the file nodes with pending i/o-operations
00104 out of the LRU-list and keep a count of pending operations. When an operation
00105 completes, we decrement the count and return the file node to the LRU-list if
00106 the count drops to zero. */
00107 
00111 UNIV_INTERN const char* fil_path_to_mysql_datadir = ".";
00112 
00114 UNIV_INTERN ulint fil_n_log_flushes     = 0;
00115 
00117 UNIV_INTERN ulint fil_n_pending_log_flushes   = 0;
00119 UNIV_INTERN ulint fil_n_pending_tablespace_flushes  = 0;
00120 
00122 UNIV_INTERN fil_addr_t  fil_addr_null = {FIL_NULL, 0};
00123 
00124 #ifdef UNIV_PFS_MUTEX
00125 /* Key to register fil_system_mutex with performance schema */
00126 UNIV_INTERN mysql_pfs_key_t fil_system_mutex_key;
00127 #endif /* UNIV_PFS_MUTEX */
00128 
00129 #ifdef UNIV_PFS_RWLOCK
00130 /* Key to register file space latch with performance schema */
00131 UNIV_INTERN mysql_pfs_key_t fil_space_latch_key;
00132 #endif /* UNIV_PFS_RWLOCK */
00133 
00135 struct fil_node_struct {
00136   fil_space_t*  space;  
00138   char*   name; 
00139   ibool   open; 
00140   os_file_t handle; 
00141   ibool   is_raw_disk;
00143   ulint   size; 
00146   ulint   n_pending;
00150   ulint   n_pending_flushes;
00154   ib_int64_t  modification_counter;
00156   ib_int64_t  flush_counter;
00159   UT_LIST_NODE_T(fil_node_t) chain;
00161   UT_LIST_NODE_T(fil_node_t) LRU;
00163   ulint   magic_n;
00164 };
00165 
00167 #define FIL_NODE_MAGIC_N  89389
00168 
00170 struct fil_space_struct {
00171   char*   name; 
00173   ulint   id; 
00174   ib_int64_t  tablespace_version;
00180   ibool   mark; 
00184   ibool   stop_ios;
00188   ibool   stop_ibuf_merges;
00191   ibool   is_being_deleted;
00198   ulint   purpose;
00200   UT_LIST_BASE_NODE_T(fil_node_t) chain;
00202   ulint   size; 
00206   ulint   flags;  
00207   ulint   n_reserved_extents;
00210   ulint   n_pending_flushes; 
00213   ulint   n_pending_ibuf_merges;
00219   hash_node_t hash; 
00220   hash_node_t name_hash;
00221 #ifndef UNIV_HOTBACKUP
00222   rw_lock_t latch;  
00224 #endif /* !UNIV_HOTBACKUP */
00225   UT_LIST_NODE_T(fil_space_t) unflushed_spaces;
00228   ibool   is_in_unflushed_spaces; 
00230   UT_LIST_NODE_T(fil_space_t) space_list;
00232   ulint   magic_n;
00233 };
00234 
00236 #define FIL_SPACE_MAGIC_N 89472
00237 
00239 typedef struct fil_system_struct  fil_system_t;
00240 
00245 struct fil_system_struct {
00246 #ifndef UNIV_HOTBACKUP
00247   mutex_t   mutex;    
00248 #endif /* !UNIV_HOTBACKUP */
00249   hash_table_t* spaces;   
00252   hash_table_t* name_hash;  
00254   UT_LIST_BASE_NODE_T(fil_node_t) LRU;
00265   UT_LIST_BASE_NODE_T(fil_space_t) unflushed_spaces;
00271   ulint   n_open;   
00272   ulint   max_n_open; 
00274   ib_int64_t  modification_counter;
00276   ulint   max_assigned_id;
00282   ib_int64_t  tablespace_version;
00290   UT_LIST_BASE_NODE_T(fil_space_t) space_list;
00292   ibool   space_id_reuse_warned;
00293           /* !< TRUE if fil_space_create()
00294           has issued a warning about
00295           potential space_id reuse */
00296 };
00297 
00300 static fil_system_t*  fil_system  = NULL;
00301 
00302 
00303 /********************************************************************/
00310 static
00311 void
00312 fil_node_prepare_for_io(
00313 /*====================*/
00314   fil_node_t* node, 
00315   fil_system_t* system, 
00316   fil_space_t*  space); 
00317 /********************************************************************/
00320 static
00321 void
00322 fil_node_complete_io(
00323 /*=================*/
00324   fil_node_t* node, 
00325   fil_system_t* system, 
00326   ulint   type);  
00329 /*******************************************************************/
00333 static
00334 ulint
00335 fil_get_space_id_for_table(
00336 /*=======================*/
00337   const char* name);  
00339 /*******************************************************************/
00344 static
00345 ibool
00346 fil_space_free(
00347 /*===========*/
00348   ulint   id,   /* in: space id */
00349   ibool   x_latched); /* in: TRUE if caller has space->latch
00350           in X mode */
00351 /********************************************************************/
00357 UNIV_INLINE
00358 ulint
00359 fil_read(
00360 /*=====*/
00361   ibool sync,   
00362   ulint space_id, 
00363   ulint zip_size, 
00365   ulint block_offset, 
00366   ulint byte_offset,  
00368   ulint len,    
00371   void* buf,    
00373   void* message)  
00375 {
00376   return(fil_io(OS_FILE_READ, sync, space_id, zip_size, block_offset,
00377             byte_offset, len, buf, message));
00378 }
00379 
00380 /********************************************************************/
00386 UNIV_INLINE
00387 ulint
00388 fil_write(
00389 /*======*/
00390   ibool sync,   
00391   ulint space_id, 
00392   ulint zip_size, 
00394   ulint block_offset, 
00395   ulint byte_offset,  
00397   ulint len,    
00400   void* buf,    
00402   void* message)  
00404 {
00405   return(fil_io(OS_FILE_WRITE, sync, space_id, zip_size, block_offset,
00406              byte_offset, len, buf, message));
00407 }
00408 
00409 /*******************************************************************/
00411 UNIV_INLINE
00412 fil_space_t*
00413 fil_space_get_by_id(
00414 /*================*/
00415   ulint id) 
00416 {
00417   fil_space_t*  space;
00418 
00419   ut_ad(mutex_own(&fil_system->mutex));
00420 
00421   HASH_SEARCH(hash, fil_system->spaces, id,
00422         fil_space_t*, space,
00423         ut_ad(space->magic_n == FIL_SPACE_MAGIC_N),
00424         space->id == id);
00425 
00426   return(space);
00427 }
00428 
00429 /*******************************************************************/
00431 UNIV_INLINE
00432 fil_space_t*
00433 fil_space_get_by_name(
00434 /*==================*/
00435   const char* name) 
00436 {
00437   fil_space_t*  space;
00438   ulint   fold;
00439 
00440   ut_ad(mutex_own(&fil_system->mutex));
00441 
00442   fold = ut_fold_string(name);
00443 
00444   HASH_SEARCH(name_hash, fil_system->name_hash, fold,
00445         fil_space_t*, space,
00446         ut_ad(space->magic_n == FIL_SPACE_MAGIC_N),
00447         !strcmp(name, space->name));
00448 
00449   return(space);
00450 }
00451 
00452 #ifndef UNIV_HOTBACKUP
00453 /*******************************************************************/
00457 UNIV_INTERN
00458 ib_int64_t
00459 fil_space_get_version(
00460 /*==================*/
00461   ulint id) 
00462 {
00463   fil_space_t*  space;
00464   ib_int64_t  version   = -1;
00465 
00466   ut_ad(fil_system);
00467 
00468   mutex_enter(&fil_system->mutex);
00469 
00470   space = fil_space_get_by_id(id);
00471 
00472   if (space) {
00473     version = space->tablespace_version;
00474   }
00475 
00476   mutex_exit(&fil_system->mutex);
00477 
00478   return(version);
00479 }
00480 
00481 /*******************************************************************/
00484 UNIV_INTERN
00485 rw_lock_t*
00486 fil_space_get_latch(
00487 /*================*/
00488   ulint id, 
00489   ulint*  flags)  
00490 {
00491   fil_space_t*  space;
00492 
00493   ut_ad(fil_system);
00494 
00495   mutex_enter(&fil_system->mutex);
00496 
00497   space = fil_space_get_by_id(id);
00498 
00499   ut_a(space);
00500 
00501   if (flags) {
00502     *flags = space->flags;
00503   }
00504 
00505   mutex_exit(&fil_system->mutex);
00506 
00507   return(&(space->latch));
00508 }
00509 
00510 /*******************************************************************/
00513 UNIV_INTERN
00514 ulint
00515 fil_space_get_type(
00516 /*===============*/
00517   ulint id) 
00518 {
00519   fil_space_t*  space;
00520 
00521   ut_ad(fil_system);
00522 
00523   mutex_enter(&fil_system->mutex);
00524 
00525   space = fil_space_get_by_id(id);
00526 
00527   ut_a(space);
00528 
00529   mutex_exit(&fil_system->mutex);
00530 
00531   return(space->purpose);
00532 }
00533 #endif /* !UNIV_HOTBACKUP */
00534 
00535 /**********************************************************************/
00539 static
00540 ibool
00541 fil_space_is_flushed(
00542 /*=================*/
00543   fil_space_t*  space)  
00544 {
00545   fil_node_t* node;
00546 
00547   ut_ad(mutex_own(&fil_system->mutex));
00548 
00549   node = UT_LIST_GET_FIRST(space->chain);
00550 
00551   while (node) {
00552     if (node->modification_counter > node->flush_counter) {
00553 
00554       return(FALSE);
00555     }
00556 
00557     node = UT_LIST_GET_NEXT(chain, node);
00558   }
00559 
00560   return(TRUE);
00561 }
00562 
00563 /*******************************************************************/
00565 UNIV_INTERN
00566 void
00567 fil_node_create(
00568 /*============*/
00569   const char* name, 
00570   ulint   size, 
00572   ulint   id, 
00573   ibool   is_raw) 
00575 {
00576   fil_node_t* node;
00577   fil_space_t*  space;
00578 
00579   ut_a(fil_system);
00580   ut_a(name);
00581 
00582   mutex_enter(&fil_system->mutex);
00583 
00584   node = static_cast<fil_node_t *>(mem_alloc(sizeof(fil_node_t)));
00585 
00586   node->name = mem_strdup(name);
00587   node->open = FALSE;
00588 
00589   ut_a(!is_raw || srv_start_raw_disk_in_use);
00590 
00591   node->is_raw_disk = is_raw;
00592   node->size = size;
00593   node->magic_n = FIL_NODE_MAGIC_N;
00594   node->n_pending = 0;
00595   node->n_pending_flushes = 0;
00596 
00597   node->modification_counter = 0;
00598   node->flush_counter = 0;
00599 
00600   space = fil_space_get_by_id(id);
00601 
00602   if (!space) {
00603     ut_print_timestamp(stderr);
00604     fprintf(stderr,
00605       "  InnoDB: Error: Could not find tablespace %lu for\n"
00606       "InnoDB: file ", (ulong) id);
00607     ut_print_filename(stderr, name);
00608     fputs(" in the tablespace memory cache.\n", stderr);
00609     mem_free(node->name);
00610 
00611     mem_free(node);
00612 
00613     mutex_exit(&fil_system->mutex);
00614 
00615     return;
00616   }
00617 
00618   space->size += size;
00619 
00620   node->space = space;
00621 
00622   UT_LIST_ADD_LAST(chain, space->chain, node);
00623 
00624   if (id < SRV_LOG_SPACE_FIRST_ID && fil_system->max_assigned_id < id) {
00625 
00626     fil_system->max_assigned_id = id;
00627   }
00628 
00629   mutex_exit(&fil_system->mutex);
00630 }
00631 
00632 /********************************************************************/
00635 static
00636 void
00637 fil_node_open_file(
00638 /*===============*/
00639   fil_node_t* node, 
00640   fil_system_t* system, 
00641   fil_space_t*  space)  
00642 {
00643   ib_int64_t  size_bytes;
00644   ulint   size_low;
00645   ulint   size_high;
00646   ibool   ret;
00647   ibool   success;
00648   byte*   buf2;
00649   byte*   page;
00650   ulint   space_id;
00651   ulint   flags;
00652 
00653   ut_ad(mutex_own(&(system->mutex)));
00654   ut_a(node->n_pending == 0);
00655   ut_a(node->open == FALSE);
00656 
00657   if (node->size == 0) {
00658     /* It must be a single-table tablespace and we do not know the
00659     size of the file yet. First we open the file in the normal
00660     mode, no async I/O here, for simplicity. Then do some checks,
00661     and close the file again.
00662     NOTE that we could not use the simple file read function
00663     os_file_read() in Windows to read from a file opened for
00664     async I/O! */
00665 
00666     node->handle = os_file_create_simple_no_error_handling(
00667       innodb_file_data_key, node->name, OS_FILE_OPEN,
00668       OS_FILE_READ_ONLY, &success);
00669     if (!success) {
00670       /* The following call prints an error message */
00671       os_file_get_last_error(TRUE);
00672 
00673       ut_print_timestamp(stderr);
00674 
00675       fprintf(stderr,
00676         "  InnoDB: Fatal error: cannot open %s\n."
00677         "InnoDB: Have you deleted .ibd files"
00678         " under a running mysqld server?\n",
00679         node->name);
00680       ut_a(0);
00681     }
00682 
00683     os_file_get_size(node->handle, &size_low, &size_high);
00684 
00685     size_bytes = (((ib_int64_t)size_high) << 32)
00686       + (ib_int64_t)size_low;
00687 #ifdef UNIV_HOTBACKUP
00688     if (space->id == 0) {
00689       node->size = (ulint) (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   ib_int64_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 static
03452 int
03453 fil_file_readdir_next_file(
03454 /*=======================*/
03455   ulint*    err,  
03457   const char* dirname,
03458   os_file_dir_t dir,  
03459   os_file_stat_t* info) 
03460 {
03461   ulint i;
03462   int ret;
03463 
03464   for (i = 0; i < 100; i++) {
03465     ret = os_file_readdir_next_file(dirname, dir, info);
03466 
03467     if (ret != -1) {
03468 
03469       return(ret);
03470     }
03471 
03472     fprintf(stderr,
03473       "InnoDB: Error: os_file_readdir_next_file()"
03474       " returned -1 in\n"
03475       "InnoDB: directory %s\n"
03476       "InnoDB: Crash recovery may have failed"
03477       " for some .ibd files!\n", dirname);
03478 
03479     *err = DB_ERROR;
03480   }
03481 
03482   return(-1);
03483 }
03484 
03485 /********************************************************************/
03493 UNIV_INTERN
03494 ulint
03495 fil_load_single_table_tablespaces(void)
03496 /*===================================*/
03497 {
03498   int   ret;
03499   char*   dbpath    = NULL;
03500   ulint   dbpath_len  = 100;
03501   os_file_dir_t dir;
03502   os_file_dir_t dbdir;
03503   os_file_stat_t  dbinfo;
03504   os_file_stat_t  fileinfo;
03505   ulint   err   = DB_SUCCESS;
03506 
03507   /* The datadir of MySQL is always the default directory of mysqld */
03508 
03509   dir = os_file_opendir(fil_path_to_mysql_datadir, TRUE);
03510 
03511   if (dir == NULL) {
03512 
03513     return(DB_ERROR);
03514   }
03515 
03516   dbpath = static_cast<char *>(mem_alloc(dbpath_len));
03517 
03518   /* Scan all directories under the datadir. They are the database
03519   directories of MySQL. */
03520 
03521   ret = fil_file_readdir_next_file(&err, fil_path_to_mysql_datadir, dir,
03522            &dbinfo);
03523   while (ret == 0) {
03524     ulint len;
03525     /* printf("Looking at %s in datadir\n", dbinfo.name); */
03526 
03527     if (dbinfo.type == OS_FILE_TYPE_FILE
03528         || dbinfo.type == OS_FILE_TYPE_UNKNOWN) {
03529 
03530       goto next_datadir_item;
03531     }
03532 
03533     /* We found a symlink or a directory; try opening it to see
03534     if a symlink is a directory */
03535 
03536     len = strlen(fil_path_to_mysql_datadir)
03537       + strlen (dbinfo.name) + 2;
03538     if (len > dbpath_len) {
03539       dbpath_len = len;
03540 
03541       if (dbpath) {
03542         mem_free(dbpath);
03543       }
03544 
03545       dbpath = static_cast<char *>(mem_alloc(dbpath_len));
03546     }
03547     sprintf(dbpath, "%s/%s", fil_path_to_mysql_datadir,
03548       dbinfo.name);
03549     srv_normalize_path_for_win(dbpath);
03550 
03551     dbdir = os_file_opendir(dbpath, FALSE);
03552 
03553     if (dbdir != NULL) {
03554       /* printf("Opened dir %s\n", dbinfo.name); */
03555 
03556       /* We found a database directory; loop through it,
03557       looking for possible .ibd files in it */
03558 
03559       ret = fil_file_readdir_next_file(&err, dbpath, dbdir,
03560                &fileinfo);
03561       while (ret == 0) {
03562         /* printf(
03563         "     Looking at file %s\n", fileinfo.name); */
03564 
03565         if (fileinfo.type == OS_FILE_TYPE_DIR) {
03566 
03567           goto next_file_item;
03568         }
03569 
03570         /* We found a symlink or a file */
03571         if (strlen(fileinfo.name) > 4
03572             && 0 == strcmp(fileinfo.name
03573                + strlen(fileinfo.name) - 4,
03574                ".ibd")) {
03575           /* The name ends in .ibd; try opening
03576           the file */
03577           fil_load_single_table_tablespace(
03578             dbinfo.name, fileinfo.name);
03579         }
03580 next_file_item:
03581         ret = fil_file_readdir_next_file(&err,
03582                  dbpath, dbdir,
03583                  &fileinfo);
03584       }
03585 
03586       if (0 != os_file_closedir(dbdir)) {
03587         fputs("InnoDB: Warning: could not"
03588               " close database directory ", stderr);
03589         ut_print_filename(stderr, dbpath);
03590         putc('\n', stderr);
03591 
03592         err = DB_ERROR;
03593       }
03594     }
03595 
03596 next_datadir_item:
03597     ret = fil_file_readdir_next_file(&err,
03598              fil_path_to_mysql_datadir,
03599              dir, &dbinfo);
03600   }
03601 
03602   mem_free(dbpath);
03603 
03604   if (0 != os_file_closedir(dir)) {
03605     fprintf(stderr,
03606       "InnoDB: Error: could not close MySQL datadir\n");
03607 
03608     return(DB_ERROR);
03609   }
03610 
03611   return(err);
03612 }
03613 
03614 /*******************************************************************/
03618 UNIV_INTERN
03619 ibool
03620 fil_tablespace_deleted_or_being_deleted_in_mem(
03621 /*===========================================*/
03622   ulint   id, 
03623   ib_int64_t  version)
03626 {
03627   fil_space_t*  space;
03628 
03629   ut_ad(fil_system);
03630 
03631   mutex_enter(&fil_system->mutex);
03632 
03633   space = fil_space_get_by_id(id);
03634 
03635   if (space == NULL || space->is_being_deleted) {
03636     mutex_exit(&fil_system->mutex);
03637 
03638     return(TRUE);
03639   }
03640 
03641   if (version != ((ib_int64_t)-1)
03642       && space->tablespace_version != version) {
03643     mutex_exit(&fil_system->mutex);
03644 
03645     return(TRUE);
03646   }
03647 
03648   mutex_exit(&fil_system->mutex);
03649 
03650   return(FALSE);
03651 }
03652 
03653 /*******************************************************************/
03656 UNIV_INTERN
03657 ibool
03658 fil_tablespace_exists_in_mem(
03659 /*=========================*/
03660   ulint id) 
03661 {
03662   fil_space_t*  space;
03663 
03664   ut_ad(fil_system);
03665 
03666   mutex_enter(&fil_system->mutex);
03667 
03668   space = fil_space_get_by_id(id);
03669 
03670   mutex_exit(&fil_system->mutex);
03671 
03672   return(space != NULL);
03673 }
03674 
03675 /*******************************************************************/
03680 UNIV_INTERN
03681 ibool
03682 fil_space_for_table_exists_in_mem(
03683 /*==============================*/
03684   ulint   id,   
03685   const char* name,   
03688   ibool   is_temp,  
03690   ibool   mark_space, 
03696   ibool   print_error_if_does_not_exist)
03701 {
03702   fil_space_t*  tablespace;
03703   fil_space_t*  space;
03704   char*   path;
03705 
03706   ut_ad(fil_system);
03707 
03708   mutex_enter(&fil_system->mutex);
03709 
03710   path = fil_make_ibd_name(name, is_temp);
03711 
03712   /* Look if there is a space with the same id */
03713 
03714   space = fil_space_get_by_id(id);
03715 
03716   /* Look if there is a space with the same name; the name is the
03717   directory path from the datadir to the file */
03718 
03719   tablespace = fil_space_get_by_name(path);
03720   if (space && space == tablespace) {
03721     /* Found */
03722 
03723     if (mark_space) {
03724       space->mark = TRUE;
03725     }
03726 
03727     mem_free(path);
03728     mutex_exit(&fil_system->mutex);
03729 
03730     return(TRUE);
03731   }
03732 
03733   if (!print_error_if_does_not_exist) {
03734 
03735     mem_free(path);
03736     mutex_exit(&fil_system->mutex);
03737 
03738     return(FALSE);
03739   }
03740 
03741   if (space == NULL) {
03742     if (tablespace == NULL) {
03743       ut_print_timestamp(stderr);
03744       fputs("  InnoDB: Error: table ", stderr);
03745       ut_print_filename(stderr, name);
03746       fprintf(stderr, "\n"
03747         "InnoDB: in InnoDB data dictionary"
03748         " has tablespace id %lu,\n"
03749         "InnoDB: but tablespace with that id"
03750         " or name does not exist. Have\n"
03751         "InnoDB: you deleted or moved .ibd files?\n"
03752         "InnoDB: This may also be a table created with"
03753         " CREATE TEMPORARY TABLE\n"
03754         "InnoDB: whose .ibd and .frm files"
03755         " MySQL automatically removed, but the\n"
03756         "InnoDB: table still exists in the"
03757         " InnoDB internal data dictionary.\n",
03758         (ulong) id);
03759     } else {
03760       ut_print_timestamp(stderr);
03761       fputs("  InnoDB: Error: table ", stderr);
03762       ut_print_filename(stderr, name);
03763       fprintf(stderr, "\n"
03764         "InnoDB: in InnoDB data dictionary has"
03765         " tablespace id %lu,\n"
03766         "InnoDB: but a tablespace with that id"
03767         " does not exist. There is\n"
03768         "InnoDB: a tablespace of name %s and id %lu,"
03769         " though. Have\n"
03770         "InnoDB: you deleted or moved .ibd files?\n",
03771         (ulong) id, tablespace->name,
03772         (ulong) tablespace->id);
03773     }
03774 error_exit:
03775     fputs("InnoDB: Please refer to\n"
03776           "InnoDB: " REFMAN "innodb-troubleshooting-datadict.html\n"
03777           "InnoDB: for how to resolve the issue.\n", stderr);
03778 
03779     mem_free(path);
03780     mutex_exit(&fil_system->mutex);
03781 
03782     return(FALSE);
03783   }
03784 
03785   if (0 != strcmp(space->name, path)) {
03786     ut_print_timestamp(stderr);
03787     fputs("  InnoDB: Error: table ", stderr);
03788     ut_print_filename(stderr, name);
03789     fprintf(stderr, "\n"
03790       "InnoDB: in InnoDB data dictionary has"
03791       " tablespace id %lu,\n"
03792       "InnoDB: but the tablespace with that id"
03793       " has name %s.\n"
03794       "InnoDB: Have you deleted or moved .ibd files?\n",
03795       (ulong) id, space->name);
03796 
03797     if (tablespace != NULL) {
03798       fputs("InnoDB: There is a tablespace"
03799             " with the right name\n"
03800             "InnoDB: ", stderr);
03801       ut_print_filename(stderr, tablespace->name);
03802       fprintf(stderr, ", but its id is %lu.\n",
03803         (ulong) tablespace->id);
03804     }
03805 
03806     goto error_exit;
03807   }
03808 
03809   mem_free(path);
03810   mutex_exit(&fil_system->mutex);
03811 
03812   return(FALSE);
03813 }
03814 
03815 /*******************************************************************/
03819 static
03820 ulint
03821 fil_get_space_id_for_table(
03822 /*=======================*/
03823   const char* name) 
03825 {
03826   fil_space_t*  tablespace;
03827   ulint   id    = ULINT_UNDEFINED;
03828   char*   path;
03829 
03830   ut_ad(fil_system);
03831 
03832   mutex_enter(&fil_system->mutex);
03833 
03834   path = fil_make_ibd_name(name, FALSE);
03835 
03836   /* Look if there is a space with the same name; the name is the
03837   directory path to the file */
03838 
03839   tablespace = fil_space_get_by_name(path);
03840 
03841   if (tablespace) {
03842     id = tablespace->id;
03843   }
03844 
03845   mem_free(path);
03846 
03847   mutex_exit(&fil_system->mutex);
03848 
03849   return(id);
03850 }
03851 
03852 /**********************************************************************/
03857 UNIV_INTERN
03858 ibool
03859 fil_extend_space_to_desired_size(
03860 /*=============================*/
03861   ulint*  actual_size,  
03864   ulint space_id, 
03865   ulint size_after_extend)
03868 {
03869   fil_node_t* node;
03870   fil_space_t*  space;
03871   byte*   buf2;
03872   byte*   buf;
03873   ulint   buf_size;
03874   ulint   start_page_no;
03875   ulint   file_start_page_no;
03876   ulint   offset_high;
03877   ulint   offset_low;
03878   ulint   page_size;
03879   ibool   success   = TRUE;
03880 
03881   fil_mutex_enter_and_prepare_for_io(space_id);
03882 
03883   space = fil_space_get_by_id(space_id);
03884   ut_a(space);
03885 
03886   if (space->size >= size_after_extend) {
03887     /* Space already big enough */
03888 
03889     *actual_size = space->size;
03890 
03891     mutex_exit(&fil_system->mutex);
03892 
03893     return(TRUE);
03894   }
03895 
03896   page_size = dict_table_flags_to_zip_size(space->flags);
03897   if (!page_size) {
03898     page_size = UNIV_PAGE_SIZE;
03899   }
03900 
03901   node = UT_LIST_GET_LAST(space->chain);
03902 
03903   fil_node_prepare_for_io(node, fil_system, space);
03904 
03905   start_page_no = space->size;
03906   file_start_page_no = space->size - node->size;
03907 
03908   /* Extend at most 64 pages at a time */
03909   buf_size = ut_min(64, size_after_extend - start_page_no) * page_size;
03910   buf2 = static_cast<byte *>(mem_alloc(buf_size + page_size));
03911   buf = static_cast<byte *>(ut_align(buf2, page_size));
03912 
03913   memset(buf, 0, buf_size);
03914 
03915   while (start_page_no < size_after_extend) {
03916     ulint n_pages = ut_min(buf_size / page_size,
03917            size_after_extend - start_page_no);
03918 
03919     offset_high = (start_page_no - file_start_page_no)
03920       / (4096 * ((1024 * 1024) / page_size));
03921     offset_low  = ((start_page_no - file_start_page_no)
03922              % (4096 * ((1024 * 1024) / page_size)))
03923       * page_size;
03924 #ifdef UNIV_HOTBACKUP
03925     success = os_file_write(node->name, node->handle, buf,
03926           offset_low, offset_high,
03927           page_size * n_pages);
03928 #else
03929     success = os_aio(OS_FILE_WRITE, OS_AIO_SYNC,
03930          node->name, node->handle, buf,
03931          offset_low, offset_high,
03932          page_size * n_pages,
03933          NULL, NULL);
03934 #endif
03935     if (success) {
03936       node->size += n_pages;
03937       space->size += n_pages;
03938 
03939       os_has_said_disk_full = FALSE;
03940     } else {
03941       /* Let us measure the size of the file to determine
03942       how much we were able to extend it */
03943 
03944       n_pages = ((ulint)
03945            (os_file_get_size_as_iblonglong(
03946              node->handle)
03947             / page_size)) - node->size;
03948 
03949       node->size += n_pages;
03950       space->size += n_pages;
03951 
03952       break;
03953     }
03954 
03955     start_page_no += n_pages;
03956   }
03957 
03958   mem_free(buf2);
03959 
03960   fil_node_complete_io(node, fil_system, OS_FILE_WRITE);
03961 
03962   *actual_size = space->size;
03963 
03964 #ifndef UNIV_HOTBACKUP
03965   if (space_id == 0) {
03966     ulint pages_per_mb = (1024 * 1024) / page_size;
03967 
03968     /* Keep the last data file size info up to date, rounded to
03969     full megabytes */
03970 
03971     srv_data_file_sizes[srv_n_data_files - 1]
03972       = (node->size / pages_per_mb) * pages_per_mb;
03973   }
03974 #endif /* !UNIV_HOTBACKUP */
03975 
03976   /*
03977   printf("Extended %s to %lu, actual size %lu pages\n", space->name,
03978   size_after_extend, *actual_size); */
03979   mutex_exit(&fil_system->mutex);
03980 
03981   fil_flush(space_id);
03982 
03983   return(success);
03984 }
03985 
03986 #ifdef UNIV_HOTBACKUP
03987 /********************************************************************/
03992 UNIV_INTERN
03993 void
03994 fil_extend_tablespaces_to_stored_len(void)
03995 /*======================================*/
03996 {
03997   fil_space_t*  space;
03998   byte*   buf;
03999   ulint   actual_size;
04000   ulint   size_in_header;
04001   ulint   error;
04002   ibool   success;
04003 
04004   buf = mem_alloc(UNIV_PAGE_SIZE);
04005 
04006   mutex_enter(&fil_system->mutex);
04007 
04008   space = UT_LIST_GET_FIRST(fil_system->space_list);
04009 
04010   while (space) {
04011     ut_a(space->purpose == FIL_TABLESPACE);
04012 
04013     mutex_exit(&fil_system->mutex); /* no need to protect with a
04014                 mutex, because this is a
04015                 single-threaded operation */
04016     error = fil_read(TRUE, space->id,
04017          dict_table_flags_to_zip_size(space->flags),
04018          0, 0, UNIV_PAGE_SIZE, buf, NULL);
04019     ut_a(error == DB_SUCCESS);
04020 
04021     size_in_header = fsp_get_size_low(buf);
04022 
04023     success = fil_extend_space_to_desired_size(
04024       &actual_size, space->id, size_in_header);
04025     if (!success) {
04026       fprintf(stderr,
04027         "InnoDB: Error: could not extend the"
04028         " tablespace of %s\n"
04029         "InnoDB: to the size stored in header,"
04030         " %lu pages;\n"
04031         "InnoDB: size after extension %lu pages\n"
04032         "InnoDB: Check that you have free disk space"
04033         " and retry!\n",
04034         space->name, size_in_header, actual_size);
04035       exit(1);
04036     }
04037 
04038     mutex_enter(&fil_system->mutex);
04039 
04040     space = UT_LIST_GET_NEXT(space_list, space);
04041   }
04042 
04043   mutex_exit(&fil_system->mutex);
04044 
04045   mem_free(buf);
04046 }
04047 #endif
04048 
04049 /*========== RESERVE FREE EXTENTS (for a B-tree split, for example) ===*/
04050 
04051 /*******************************************************************/
04054 UNIV_INTERN
04055 ibool
04056 fil_space_reserve_free_extents(
04057 /*===========================*/
04058   ulint id,   
04059   ulint n_free_now, 
04060   ulint n_to_reserve) 
04061 {
04062   fil_space_t*  space;
04063   ibool   success;
04064 
04065   ut_ad(fil_system);
04066 
04067   mutex_enter(&fil_system->mutex);
04068 
04069   space = fil_space_get_by_id(id);
04070 
04071   ut_a(space);
04072 
04073   if (space->n_reserved_extents + n_to_reserve > n_free_now) {
04074     success = FALSE;
04075   } else {
04076     space->n_reserved_extents += n_to_reserve;
04077     success = TRUE;
04078   }
04079 
04080   mutex_exit(&fil_system->mutex);
04081 
04082   return(success);
04083 }
04084 
04085 /*******************************************************************/
04087 UNIV_INTERN
04088 void
04089 fil_space_release_free_extents(
04090 /*===========================*/
04091   ulint id,   
04092   ulint n_reserved) 
04093 {
04094   fil_space_t*  space;
04095 
04096   ut_ad(fil_system);
04097 
04098   mutex_enter(&fil_system->mutex);
04099 
04100   space = fil_space_get_by_id(id);
04101 
04102   ut_a(space);
04103   ut_a(space->n_reserved_extents >= n_reserved);
04104 
04105   space->n_reserved_extents -= n_reserved;
04106 
04107   mutex_exit(&fil_system->mutex);
04108 }
04109 
04110 /*******************************************************************/
04113 UNIV_INTERN
04114 ulint
04115 fil_space_get_n_reserved_extents(
04116 /*=============================*/
04117   ulint id)   
04118 {
04119   fil_space_t*  space;
04120   ulint   n;
04121 
04122   ut_ad(fil_system);
04123 
04124   mutex_enter(&fil_system->mutex);
04125 
04126   space = fil_space_get_by_id(id);
04127 
04128   ut_a(space);
04129 
04130   n = space->n_reserved_extents;
04131 
04132   mutex_exit(&fil_system->mutex);
04133 
04134   return(n);
04135 }
04136 
04137 /*============================ FILE I/O ================================*/
04138 
04139 /********************************************************************/
04146 static
04147 void
04148 fil_node_prepare_for_io(
04149 /*====================*/
04150   fil_node_t* node, 
04151   fil_system_t* system, 
04152   fil_space_t*  space)  
04153 {
04154   ut_ad(node && system && space);
04155   ut_ad(mutex_own(&(system->mutex)));
04156 
04157   if (system->n_open > system->max_n_open + 5) {
04158     ut_print_timestamp(stderr);
04159     fprintf(stderr,
04160       "  InnoDB: Warning: open files %lu"
04161       " exceeds the limit %lu\n",
04162       (ulong) system->n_open,
04163       (ulong) system->max_n_open);
04164   }
04165 
04166   if (node->open == FALSE) {
04167     /* File is closed: open it */
04168     ut_a(node->n_pending == 0);
04169 
04170     fil_node_open_file(node, system, space);
04171   }
04172 
04173   if (node->n_pending == 0 && space->purpose == FIL_TABLESPACE
04174       && space->id != 0) {
04175     /* The node is in the LRU list, remove it */
04176 
04177     ut_a(UT_LIST_GET_LEN(system->LRU) > 0);
04178 
04179     UT_LIST_REMOVE(LRU, system->LRU, node);
04180   }
04181 
04182   node->n_pending++;
04183 }
04184 
04185 /********************************************************************/
04188 static
04189 void
04190 fil_node_complete_io(
04191 /*=================*/
04192   fil_node_t* node, 
04193   fil_system_t* system, 
04194   ulint   type) 
04197 {
04198   ut_ad(node);
04199   ut_ad(system);
04200   ut_ad(mutex_own(&(system->mutex)));
04201 
04202   ut_a(node->n_pending > 0);
04203 
04204   node->n_pending--;
04205 
04206   if (type == OS_FILE_WRITE) {
04207     system->modification_counter++;
04208     node->modification_counter = system->modification_counter;
04209 
04210     if (!node->space->is_in_unflushed_spaces) {
04211 
04212       node->space->is_in_unflushed_spaces = TRUE;
04213       UT_LIST_ADD_FIRST(unflushed_spaces,
04214             system->unflushed_spaces,
04215             node->space);
04216     }
04217   }
04218 
04219   if (node->n_pending == 0 && node->space->purpose == FIL_TABLESPACE
04220       && node->space->id != 0) {
04221     /* The node must be put back to the LRU list */
04222     UT_LIST_ADD_FIRST(LRU, system->LRU, node);
04223   }
04224 }
04225 
04226 /********************************************************************/
04228 static
04229 void
04230 fil_report_invalid_page_access(
04231 /*===========================*/
04232   ulint   block_offset, 
04233   ulint   space_id, 
04234   const char* space_name, 
04235   ulint   byte_offset,  
04236   ulint   len,    
04237   ulint   type)   
04238 {
04239   fprintf(stderr,
04240     "InnoDB: Error: trying to access page number %lu"
04241     " in space %lu,\n"
04242     "InnoDB: space name %s,\n"
04243     "InnoDB: which is outside the tablespace bounds.\n"
04244     "InnoDB: Byte offset %lu, len %lu, i/o type %lu.\n"
04245     "InnoDB: If you get this error at mysqld startup,"
04246     " please check that\n"
04247     "InnoDB: your my.cnf matches the ibdata files"
04248     " that you have in the\n"
04249     "InnoDB: MySQL server.\n",
04250     (ulong) block_offset, (ulong) space_id, space_name,
04251     (ulong) byte_offset, (ulong) len, (ulong) type);
04252 }
04253 
04254 /********************************************************************/
04258 UNIV_INTERN
04259 ulint
04260 fil_io(
04261 /*===*/
04262   ulint type,   
04271   ibool sync,   
04272   ulint space_id, 
04273   ulint zip_size, 
04275   ulint block_offset, 
04276   ulint byte_offset,  
04279   ulint len,    
04282   void* buf,    
04285   void* message)  
04287 {
04288   ulint   mode;
04289   fil_space_t*  space;
04290   fil_node_t* node;
04291   ulint   offset_high;
04292   ulint   offset_low;
04293   ibool   ret;
04294   ulint   is_log;
04295   ulint   wake_later;
04296 
04297   is_log = type & OS_FILE_LOG;
04298   type = type & ~OS_FILE_LOG;
04299 
04300   wake_later = type & OS_AIO_SIMULATED_WAKE_LATER;
04301   type = type & ~OS_AIO_SIMULATED_WAKE_LATER;
04302 
04303   ut_ad(byte_offset < UNIV_PAGE_SIZE);
04304   ut_ad(!zip_size || !byte_offset);
04305   ut_ad(ut_is_2pow(zip_size));
04306   ut_ad(buf);
04307   ut_ad(len > 0);
04308 #if (1 << UNIV_PAGE_SIZE_SHIFT) != UNIV_PAGE_SIZE
04309 # error "(1 << UNIV_PAGE_SIZE_SHIFT) != UNIV_PAGE_SIZE"
04310 #endif
04311   ut_ad(fil_validate());
04312 #ifndef UNIV_HOTBACKUP
04313 # ifndef UNIV_LOG_DEBUG
04314   /* ibuf bitmap pages must be read in the sync aio mode: */
04315   ut_ad(recv_no_ibuf_operations || (type == OS_FILE_WRITE)
04316         || !ibuf_bitmap_page(zip_size, block_offset)
04317         || sync || is_log);
04318   ut_ad(!ibuf_inside() || is_log || (type == OS_FILE_WRITE)
04319         || ibuf_page(space_id, zip_size, block_offset, NULL));
04320 # endif /* UNIV_LOG_DEBUG */
04321   if (sync) {
04322     mode = OS_AIO_SYNC;
04323   } else if (is_log) {
04324     mode = OS_AIO_LOG;
04325   } else if (type == OS_FILE_READ
04326        && !recv_no_ibuf_operations
04327        && ibuf_page(space_id, zip_size, block_offset, NULL)) {
04328     mode = OS_AIO_IBUF;
04329   } else {
04330     mode = OS_AIO_NORMAL;
04331   }
04332 #else /* !UNIV_HOTBACKUP */
04333   ut_a(sync);
04334   mode = OS_AIO_SYNC;
04335 #endif /* !UNIV_HOTBACKUP */
04336 
04337   if (type == OS_FILE_READ) {
04338     srv_data_read+= len;
04339   } else if (type == OS_FILE_WRITE) {
04340     srv_data_written+= len;
04341   }
04342 
04343   /* Reserve the fil_system mutex and make sure that we can open at
04344   least one file while holding it, if the file is not already open */
04345 
04346   fil_mutex_enter_and_prepare_for_io(space_id);
04347 
04348   space = fil_space_get_by_id(space_id);
04349 
04350   if (!space) {
04351     mutex_exit(&fil_system->mutex);
04352 
04353     ut_print_timestamp(stderr);
04354     fprintf(stderr,
04355       "  InnoDB: Error: trying to do i/o"
04356       " to a tablespace which does not exist.\n"
04357       "InnoDB: i/o type %lu, space id %lu,"
04358       " page no. %lu, i/o length %lu bytes\n",
04359       (ulong) type, (ulong) space_id, (ulong) block_offset,
04360       (ulong) len);
04361 
04362     return(DB_TABLESPACE_DELETED);
04363   }
04364 
04365   ut_ad((mode != OS_AIO_IBUF) || (space->purpose == FIL_TABLESPACE));
04366 
04367   node = UT_LIST_GET_FIRST(space->chain);
04368 
04369   for (;;) {
04370     if (UNIV_UNLIKELY(node == NULL)) {
04371       fil_report_invalid_page_access(
04372         block_offset, space_id, space->name,
04373         byte_offset, len, type);
04374 
04375       ut_error;
04376     }
04377 
04378     if (space->id != 0 && node->size == 0) {
04379       /* We do not know the size of a single-table tablespace
04380       before we open the file */
04381 
04382       break;
04383     }
04384 
04385     if (node->size > block_offset) {
04386       /* Found! */
04387       break;
04388     } else {
04389       block_offset -= node->size;
04390       node = UT_LIST_GET_NEXT(chain, node);
04391     }
04392   }
04393 
04394   /* Open file if closed */
04395   fil_node_prepare_for_io(node, fil_system, space);
04396 
04397   /* Check that at least the start offset is within the bounds of a
04398   single-table tablespace */
04399   if (UNIV_UNLIKELY(node->size <= block_offset)
04400       && space->id != 0 && space->purpose == FIL_TABLESPACE) {
04401 
04402     fil_report_invalid_page_access(
04403       block_offset, space_id, space->name, byte_offset,
04404       len, type);
04405 
04406     ut_error;
04407   }
04408 
04409   /* Now we have made the changes in the data structures of fil_system */
04410   mutex_exit(&fil_system->mutex);
04411 
04412   /* Calculate the low 32 bits and the high 32 bits of the file offset */
04413 
04414   if (!zip_size) {
04415     offset_high = (block_offset >> (32 - UNIV_PAGE_SIZE_SHIFT));
04416     offset_low  = ((block_offset << UNIV_PAGE_SIZE_SHIFT)
04417              & 0xFFFFFFFFUL) + byte_offset;
04418 
04419     ut_a(node->size - block_offset
04420          >= ((byte_offset + len + (UNIV_PAGE_SIZE - 1))
04421        / UNIV_PAGE_SIZE));
04422   } else {
04423     ulint zip_size_shift;
04424     switch (zip_size) {
04425     case 1024: zip_size_shift = 10; break;
04426     case 2048: zip_size_shift = 11; break;
04427     case 4096: zip_size_shift = 12; break;
04428     case 8192: zip_size_shift = 13; break;
04429     case 16384: zip_size_shift = 14; break;
04430     default: ut_error;
04431     }
04432     offset_high = block_offset >> (32 - zip_size_shift);
04433     offset_low = (block_offset << zip_size_shift & 0xFFFFFFFFUL)
04434       + byte_offset;
04435     ut_a(node->size - block_offset
04436          >= (len + (zip_size - 1)) / zip_size);
04437   }
04438 
04439   /* Do aio */
04440 
04441   ut_a(byte_offset % OS_FILE_LOG_BLOCK_SIZE == 0);
04442   ut_a((len % OS_FILE_LOG_BLOCK_SIZE) == 0);
04443 
04444 #ifdef UNIV_HOTBACKUP
04445   /* In ibbackup do normal i/o, not aio */
04446   if (type == OS_FILE_READ) {
04447     ret = os_file_read(node->handle, buf, offset_low, offset_high,
04448            len);
04449   } else {
04450     ret = os_file_write(node->name, node->handle, buf,
04451             offset_low, offset_high, len);
04452   }
04453 #else
04454   /* Queue the aio request */
04455   ret = os_aio(type, mode | wake_later, node->name, node->handle, buf,
04456          offset_low, offset_high, len, node, message);
04457 #endif
04458   ut_a(ret);
04459 
04460   if (mode == OS_AIO_SYNC) {
04461     /* The i/o operation is already completed when we return from
04462     os_aio: */
04463 
04464     mutex_enter(&fil_system->mutex);
04465 
04466     fil_node_complete_io(node, fil_system, type);
04467 
04468     mutex_exit(&fil_system->mutex);
04469 
04470     ut_ad(fil_validate());
04471   }
04472 
04473   return(DB_SUCCESS);
04474 }
04475 
04476 #ifndef UNIV_HOTBACKUP
04477 /**********************************************************************/
04482 UNIV_INTERN
04483 void
04484 fil_aio_wait(
04485 /*=========*/
04486   ulint segment)  
04488 {
04489   ibool   ret;
04490   fil_node_t* fil_node;
04491   void*   message;
04492   ulint   type;
04493 
04494   ut_ad(fil_validate());
04495 
04496   if (srv_use_native_aio) {
04497     srv_set_io_thread_op_info(segment, "native aio handle");
04498 #ifdef WIN_ASYNC_IO
04499     ret = os_aio_windows_handle(segment, 0, &fil_node,
04500               &message, &type);
04501 #elif defined(LINUX_NATIVE_AIO)
04502     ret = os_aio_linux_handle(segment, &fil_node,
04503             &message, &type);
04504 #else
04505     ret = 0; /* Eliminate compiler warning */
04506     ut_error;
04507 #endif
04508   } else {
04509     srv_set_io_thread_op_info(segment, "simulated aio handle");
04510 
04511     ret = os_aio_simulated_handle(segment, &fil_node,
04512                 &message, &type);
04513   }
04514 
04515   ut_a(ret);
04516 
04517   srv_set_io_thread_op_info(segment, "complete io for fil node");
04518 
04519   mutex_enter(&fil_system->mutex);
04520 
04521   fil_node_complete_io(fil_node, fil_system, type);
04522 
04523   mutex_exit(&fil_system->mutex);
04524 
04525   ut_ad(fil_validate());
04526 
04527   /* Do the i/o handling */
04528   /* IMPORTANT: since i/o handling for reads will read also the insert
04529   buffer in tablespace 0, you have to be very careful not to introduce
04530   deadlocks in the i/o system. We keep tablespace 0 data files always
04531   open, and use a special i/o thread to serve insert buffer requests. */
04532 
04533   if (fil_node->space->purpose == FIL_TABLESPACE) {
04534     srv_set_io_thread_op_info(segment, "complete io for buf page");
04535     buf_page_io_complete(static_cast<buf_page_t *>(message));
04536   } else {
04537     srv_set_io_thread_op_info(segment, "complete io for log");
04538     log_io_complete(static_cast<log_group_t *>(message));
04539   }
04540 }
04541 #endif /* UNIV_HOTBACKUP */
04542 
04543 /**********************************************************************/
04546 UNIV_INTERN
04547 void
04548 fil_flush(
04549 /*======*/
04550   ulint space_id) 
04552 {
04553   fil_space_t*  space;
04554   fil_node_t* node;
04555   os_file_t file;
04556   ib_int64_t  old_mod_counter;
04557 
04558   mutex_enter(&fil_system->mutex);
04559 
04560   space = fil_space_get_by_id(space_id);
04561 
04562   if (!space || space->is_being_deleted) {
04563     mutex_exit(&fil_system->mutex);
04564 
04565     return;
04566   }
04567 
04568   space->n_pending_flushes++; 
04570   node = UT_LIST_GET_FIRST(space->chain);
04571 
04572   while (node) {
04573     if (node->modification_counter > node->flush_counter) {
04574       ut_a(node->open);
04575 
04576       /* We want to flush the changes at least up to
04577       old_mod_counter */
04578       old_mod_counter = node->modification_counter;
04579 
04580       if (space->purpose == FIL_TABLESPACE) {
04581         fil_n_pending_tablespace_flushes++;
04582       } else {
04583         fil_n_pending_log_flushes++;
04584         fil_n_log_flushes++;
04585       }
04586 #ifdef __WIN__
04587       if (node->is_raw_disk) {
04588 
04589         goto skip_flush;
04590       }
04591 #endif
04592 retry:
04593       if (node->n_pending_flushes > 0) {
04594         /* We want to avoid calling os_file_flush() on
04595         the file twice at the same time, because we do
04596         not know what bugs OS's may contain in file
04597         i/o; sleep for a while */
04598 
04599         mutex_exit(&fil_system->mutex);
04600 
04601         os_thread_sleep(20000);
04602 
04603         mutex_enter(&fil_system->mutex);
04604 
04605         if (node->flush_counter >= old_mod_counter) {
04606 
04607           goto skip_flush;
04608         }
04609 
04610         goto retry;
04611       }
04612 
04613       ut_a(node->open);
04614       file = node->handle;
04615       node->n_pending_flushes++;
04616 
04617       mutex_exit(&fil_system->mutex);
04618 
04619       /* fprintf(stderr, "Flushing to file %s\n",
04620       node->name); */
04621 
04622       os_file_flush(file);
04623 
04624       mutex_enter(&fil_system->mutex);
04625 
04626       node->n_pending_flushes--;
04627 skip_flush:
04628       if (node->flush_counter < old_mod_counter) {
04629         node->flush_counter = old_mod_counter;
04630 
04631         if (space->is_in_unflushed_spaces
04632             && fil_space_is_flushed(space)) {
04633 
04634           space->is_in_unflushed_spaces = FALSE;
04635 
04636           UT_LIST_REMOVE(
04637             unflushed_spaces,
04638             fil_system->unflushed_spaces,
04639             space);
04640         }
04641       }
04642 
04643       if (space->purpose == FIL_TABLESPACE) {
04644         fil_n_pending_tablespace_flushes--;
04645       } else {
04646         fil_n_pending_log_flushes--;
04647       }
04648     }
04649 
04650     node = UT_LIST_GET_NEXT(chain, node);
04651   }
04652 
04653   space->n_pending_flushes--;
04654 
04655   mutex_exit(&fil_system->mutex);
04656 }
04657 
04658 /**********************************************************************/
04661 UNIV_INTERN
04662 void
04663 fil_flush_file_spaces(
04664 /*==================*/
04665   ulint purpose)  
04666 {
04667   fil_space_t*  space;
04668   ulint*    space_ids;
04669   ulint   n_space_ids;
04670   ulint   i;
04671 
04672   mutex_enter(&fil_system->mutex);
04673 
04674   n_space_ids = UT_LIST_GET_LEN(fil_system->unflushed_spaces);
04675   if (n_space_ids == 0) {
04676 
04677     mutex_exit(&fil_system->mutex);
04678     return;
04679   }
04680 
04681   /* Assemble a list of space ids to flush.  Previously, we
04682   traversed fil_system->unflushed_spaces and called UT_LIST_GET_NEXT()
04683   on a space that was just removed from the list by fil_flush().
04684   Thus, the space could be dropped and the memory overwritten. */
04685   space_ids = static_cast<unsigned long *>(mem_alloc(n_space_ids * sizeof *space_ids));
04686 
04687   n_space_ids = 0;
04688 
04689   for (space = UT_LIST_GET_FIRST(fil_system->unflushed_spaces);
04690        space;
04691        space = UT_LIST_GET_NEXT(unflushed_spaces, space)) {
04692 
04693     if (space->purpose == purpose && !space->is_being_deleted) {
04694 
04695       space_ids[n_space_ids++] = space->id;
04696     }
04697   }
04698 
04699   mutex_exit(&fil_system->mutex);
04700 
04701   /* Flush the spaces.  It will not hurt to call fil_flush() on
04702   a non-existing space id. */
04703   for (i = 0; i < n_space_ids; i++) {
04704 
04705     fil_flush(space_ids[i]);
04706   }
04707 
04708   mem_free(space_ids);
04709 }
04710 
04711 /******************************************************************/
04714 UNIV_INTERN
04715 ibool
04716 fil_validate(void)
04717 /*==============*/
04718 {
04719   fil_space_t*  space;
04720   fil_node_t* fil_node;
04721   ulint   n_open    = 0;
04722   ulint   i;
04723 
04724   mutex_enter(&fil_system->mutex);
04725 
04726   /* Look for spaces in the hash table */
04727 
04728   for (i = 0; i < hash_get_n_cells(fil_system->spaces); i++) {
04729 
04730     space = static_cast<fil_space_t *>(HASH_GET_FIRST(fil_system->spaces, i));
04731 
04732     while (space != NULL) {
04733       UT_LIST_VALIDATE(chain, fil_node_t, space->chain,
04734            ut_a(ut_list_node_313->open
04735                 || !ut_list_node_313->n_pending));
04736 
04737       fil_node = UT_LIST_GET_FIRST(space->chain);
04738 
04739       while (fil_node != NULL) {
04740         if (fil_node->n_pending > 0) {
04741           ut_a(fil_node->open);
04742         }
04743 
04744         if (fil_node->open) {
04745           n_open++;
04746         }
04747         fil_node = UT_LIST_GET_NEXT(chain, fil_node);
04748       }
04749       space = static_cast<fil_space_t *>(HASH_GET_NEXT(hash, space));
04750     }
04751   }
04752 
04753   ut_a(fil_system->n_open == n_open);
04754 
04755   UT_LIST_VALIDATE(LRU, fil_node_t, fil_system->LRU, (void) 0);
04756 
04757   fil_node = UT_LIST_GET_FIRST(fil_system->LRU);
04758 
04759   while (fil_node != NULL) {
04760     ut_a(fil_node->n_pending == 0);
04761     ut_a(fil_node->open);
04762     ut_a(fil_node->space->purpose == FIL_TABLESPACE);
04763     ut_a(fil_node->space->id != 0);
04764 
04765     fil_node = UT_LIST_GET_NEXT(LRU, fil_node);
04766   }
04767 
04768   mutex_exit(&fil_system->mutex);
04769 
04770   return(TRUE);
04771 }
04772 
04773 /********************************************************************/
04776 UNIV_INTERN
04777 ibool
04778 fil_addr_is_null(
04779 /*=============*/
04780   fil_addr_t  addr) 
04781 {
04782   return(addr.page == FIL_NULL);
04783 }
04784 
04785 /********************************************************************/
04788 UNIV_INTERN
04789 ulint
04790 fil_page_get_prev(
04791 /*==============*/
04792   const byte* page) 
04793 {
04794   return(mach_read_from_4(page + FIL_PAGE_PREV));
04795 }
04796 
04797 /********************************************************************/
04800 UNIV_INTERN
04801 ulint
04802 fil_page_get_next(
04803 /*==============*/
04804   const byte* page) 
04805 {
04806   return(mach_read_from_4(page + FIL_PAGE_NEXT));
04807 }
04808 
04809 /*********************************************************************/
04811 UNIV_INTERN
04812 void
04813 fil_page_set_type(
04814 /*==============*/
04815   byte* page, 
04816   ulint type) 
04817 {
04818   ut_ad(page);
04819 
04820   mach_write_to_2(page + FIL_PAGE_TYPE, type);
04821 }
04822 
04823 /*********************************************************************/
04827 UNIV_INTERN
04828 ulint
04829 fil_page_get_type(
04830 /*==============*/
04831   const byte* page) 
04832 {
04833   ut_ad(page);
04834 
04835   return(mach_read_from_2(page + FIL_PAGE_TYPE));
04836 }
04837 
04838 /****************************************************************/
04840 UNIV_INTERN
04841 void
04842 fil_close(void)
04843 /*===========*/
04844 {
04845 #ifndef UNIV_HOTBACKUP
04846   /* The mutex should already have been freed. */
04847   ut_ad(fil_system->mutex.magic_n == 0);
04848 #endif /* !UNIV_HOTBACKUP */
04849 
04850   hash_table_free(fil_system->spaces);
04851 
04852   hash_table_free(fil_system->name_hash);
04853 
04854   ut_a(UT_LIST_GET_LEN(fil_system->LRU) == 0);
04855   ut_a(UT_LIST_GET_LEN(fil_system->unflushed_spaces) == 0);
04856   ut_a(UT_LIST_GET_LEN(fil_system->space_list) == 0);
04857 
04858   mem_free(fil_system);
04859 
04860   fil_system = NULL;
04861 }