List:Commits« Previous MessageNext Message »
From:gni Date:August 29 2006 5:45am
Subject:bk commit into 5.1 tree (gni:1.2283)
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of root. When root does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2006-08-29 13:43:04+08:00, gni@dev3-127.(none) +30 -0
  Merge dev3-127.(none):/mnt/mysql/home/ngb/bug19873
  into  dev3-127.(none):/mnt/mysql/home/ngb/mysql-5.1-bug19873
  MERGE: 1.1810.1697.128

  client/mysqltest.c@stripped, 2006-08-29 13:42:06+08:00, gni@dev3-127.(none) +3 -0
    MERGE: 1.155.9.50

  include/config-netware.h@stripped, 2006-08-29 13:40:31+08:00, gni@dev3-127.(none) +0 -0
    Auto merged
    MERGE: 1.14.2.1

  mysql-test/r/csv.result@stripped, 2006-08-29 13:42:22+08:00, gni@dev3-127.(none) +0 -10
    MERGE: 1.4.1.1

  mysql-test/r/func_time.result@stripped, 2006-08-29 13:40:31+08:00, gni@dev3-127.(none) +0 -0
    Auto merged
    MERGE: 1.47.1.19

  mysql-test/t/csv.test@stripped, 2006-08-29 13:42:31+08:00, gni@dev3-127.(none) +0 -24
    MERGE: 1.5.1.1

  mysql-test/t/func_time.test@stripped, 2006-08-29 13:40:31+08:00, gni@dev3-127.(none) +0 -0
    Auto merged
    MERGE: 1.41.1.13

  sql/ha_innodb.cc@stripped, 2006-08-29 13:40:32+08:00, gni@dev3-127.(none) +0 -0
    Auto merged
    MERGE: 1.202.1.96

  sql/ha_ndbcluster.cc@stripped, 2006-08-29 13:40:32+08:00, gni@dev3-127.(none) +0 -0
    Auto merged
    MERGE: 1.175.1.103

  sql/item_timefunc.cc@stripped, 2006-08-29 13:40:32+08:00, gni@dev3-127.(none) +0 -0
    Auto merged
    MERGE: 1.100.1.24

  sql/sql_acl.cc@stripped, 2006-08-29 13:40:32+08:00, gni@dev3-127.(none) +0 -0
    Auto merged
    MERGE: 1.128.1.76

  sql/sql_base.cc@stripped, 2006-08-29 13:40:32+08:00, gni@dev3-127.(none) +0 -0
    Auto merged
    MERGE: 1.235.1.115

  sql/sql_view.cc@stripped, 2006-08-29 13:40:32+08:00, gni@dev3-127.(none) +0 -0
    Auto merged
    MERGE: 1.78.1.15

  storage/csv/ha_tina.cc@stripped, 2006-08-29 13:42:39+08:00, gni@dev3-127.(none) +19 -8
    MERGE: 1.10.1.15

  storage/csv/ha_tina.cc@stripped, 2006-08-29 13:40:31+08:00, gni@dev3-127.(none) +0 -0
    Merge rename: sql/examples/ha_tina.cc -> storage/csv/ha_tina.cc

  storage/innobase/btr/btr0btr.c@stripped, 2006-08-29 13:40:32+08:00, gni@dev3-127.(none) +0 -0
    Auto merged
    MERGE: 1.38.3.2

  storage/innobase/btr/btr0btr.c@stripped, 2006-08-29 13:40:30+08:00, gni@dev3-127.(none) +0 -0
    Merge rename: innobase/btr/btr0btr.c -> storage/innobase/btr/btr0btr.c

  storage/innobase/buf/buf0buf.c@stripped, 2006-08-29 13:40:33+08:00, gni@dev3-127.(none) +0 -0
    Auto merged
    MERGE: 1.45.6.2

  storage/innobase/buf/buf0buf.c@stripped, 2006-08-29 13:40:31+08:00, gni@dev3-127.(none) +0 -0
    Merge rename: innobase/buf/buf0buf.c -> storage/innobase/buf/buf0buf.c

  storage/innobase/dict/dict0dict.c@stripped, 2006-08-29 13:40:33+08:00, gni@dev3-127.(none) +0 -0
    Auto merged
    MERGE: 1.65.11.2

  storage/innobase/dict/dict0dict.c@stripped, 2006-08-29 13:40:31+08:00, gni@dev3-127.(none) +0 -0
    Merge rename: innobase/dict/dict0dict.c -> storage/innobase/dict/dict0dict.c

  storage/innobase/fil/fil0fil.c@stripped, 2006-08-29 13:40:33+08:00, gni@dev3-127.(none) +0 -0
    Auto merged
    MERGE: 1.54.11.2

  storage/innobase/fil/fil0fil.c@stripped, 2006-08-29 13:40:31+08:00, gni@dev3-127.(none) +0 -0
    Merge rename: innobase/fil/fil0fil.c -> storage/innobase/fil/fil0fil.c

  storage/innobase/fsp/fsp0fsp.c@stripped, 2006-08-29 13:40:33+08:00, gni@dev3-127.(none) +0 -0
    Auto merged
    MERGE: 1.25.2.2

  storage/innobase/fsp/fsp0fsp.c@stripped, 2006-08-29 13:40:31+08:00, gni@dev3-127.(none) +0 -0
    Merge rename: innobase/fsp/fsp0fsp.c -> storage/innobase/fsp/fsp0fsp.c

  storage/innobase/include/btr0cur.ic@stripped, 2006-08-29 13:42:45+08:00, gni@dev3-127.(none) +4 -1
    MERGE: 1.2.2.2

  storage/innobase/include/btr0cur.ic@stripped, 2006-08-29 13:40:31+08:00, gni@dev3-127.(none) +0 -0
    Merge rename: innobase/include/btr0cur.ic -> storage/innobase/include/btr0cur.ic

  storage/innobase/include/buf0buf.ic@stripped, 2006-08-29 13:40:33+08:00, gni@dev3-127.(none) +0 -0
    Auto merged
    MERGE: 1.17.2.2

  storage/innobase/include/buf0buf.ic@stripped, 2006-08-29 13:40:31+08:00, gni@dev3-127.(none) +0 -0
    Merge rename: innobase/include/buf0buf.ic -> storage/innobase/include/buf0buf.ic

  storage/innobase/log/log0log.c@stripped, 2006-08-29 13:40:33+08:00, gni@dev3-127.(none) +0 -0
    Auto merged
    MERGE: 1.41.4.2

  storage/innobase/log/log0log.c@stripped, 2006-08-29 13:40:31+08:00, gni@dev3-127.(none) +0 -0
    Merge rename: innobase/log/log0log.c -> storage/innobase/log/log0log.c

  storage/innobase/log/log0recv.c@stripped, 2006-08-29 13:40:33+08:00, gni@dev3-127.(none) +0 -0
    Auto merged
    MERGE: 1.46.5.2

  storage/innobase/log/log0recv.c@stripped, 2006-08-29 13:40:31+08:00, gni@dev3-127.(none) +0 -0
    Merge rename: innobase/log/log0recv.c -> storage/innobase/log/log0recv.c

  storage/innobase/os/os0file.c@stripped, 2006-08-29 13:40:33+08:00, gni@dev3-127.(none) +0 -0
    Auto merged
    MERGE: 1.103.10.2

  storage/innobase/os/os0file.c@stripped, 2006-08-29 13:40:30+08:00, gni@dev3-127.(none) +0 -0
    Merge rename: innobase/os/os0file.c -> storage/innobase/os/os0file.c

  storage/innobase/row/row0mysql.c@stripped, 2006-08-29 13:42:59+08:00, gni@dev3-127.(none) +13 -13
    MERGE: 1.103.15.2

  storage/innobase/row/row0mysql.c@stripped, 2006-08-29 13:40:30+08:00, gni@dev3-127.(none) +0 -0
    Merge rename: innobase/row/row0mysql.c -> storage/innobase/row/row0mysql.c

  storage/innobase/row/row0sel.c@stripped, 2006-08-29 13:40:33+08:00, gni@dev3-127.(none) +0 -0
    Auto merged
    MERGE: 1.92.8.2

  storage/innobase/row/row0sel.c@stripped, 2006-08-29 13:40:31+08:00, gni@dev3-127.(none) +0 -0
    Merge rename: innobase/row/row0sel.c -> storage/innobase/row/row0sel.c

  storage/innobase/srv/srv0start.c@stripped, 2006-08-29 13:40:33+08:00, gni@dev3-127.(none) +0 -0
    Auto merged
    MERGE: 1.80.10.2

  storage/innobase/srv/srv0start.c@stripped, 2006-08-29 13:40:31+08:00, gni@dev3-127.(none) +0 -0
    Merge rename: innobase/srv/srv0start.c -> storage/innobase/srv/srv0start.c

  storage/innobase/ut/ut0dbg.c@stripped, 2006-08-29 13:40:33+08:00, gni@dev3-127.(none) +0 -0
    Auto merged
    MERGE: 1.7.2.2

  storage/innobase/ut/ut0dbg.c@stripped, 2006-08-29 13:40:31+08:00, gni@dev3-127.(none) +0 -0
    Merge rename: innobase/ut/ut0dbg.c -> storage/innobase/ut/ut0dbg.c

  storage/ndb/src/mgmclient/CommandInterpreter.cpp@stripped, 2006-08-29 13:40:33+08:00, gni@dev3-127.(none) +0 -0
    Auto merged
    MERGE: 1.49.21.4

  storage/ndb/src/mgmclient/CommandInterpreter.cpp@stripped, 2006-08-29 13:40:31+08:00, gni@dev3-127.(none) +0 -0
    Merge rename: ndb/src/mgmclient/CommandInterpreter.cpp -> storage/ndb/src/mgmclient/CommandInterpreter.cpp

  storage/ndb/src/ndbapi/ndberror.c@stripped, 2006-08-29 13:40:33+08:00, gni@dev3-127.(none) +0 -0
    Auto merged
    MERGE: 1.30.28.2

  storage/ndb/src/ndbapi/ndberror.c@stripped, 2006-08-29 13:40:31+08:00, gni@dev3-127.(none) +0 -0
    Merge rename: ndb/src/ndbapi/ndberror.c -> storage/ndb/src/ndbapi/ndberror.c

  tests/mysql_client_test.c@stripped, 2006-08-29 13:40:34+08:00, gni@dev3-127.(none) +0 -0
    Auto merged
    MERGE: 1.167.1.37

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	gni
# Host:	dev3-127.(none)
# Root:	/mnt/mysql/home/ngb/mysql-5.1-bug19873/RESYNC

--- 1.131/sql/item_timefunc.cc	2006-08-29 13:44:11 +08:00
+++ 1.132/sql/item_timefunc.cc	2006-08-29 13:44:11 +08:00
@@ -224,7 +224,7 @@
 	tmp= (char*) val + min(2, val_len);
 	l_time->day= (int) my_strtoll10(val, &tmp, &error);
 	/* Skip 'st, 'nd, 'th .. */
-	val= tmp + min((int) (end-tmp), 2);
+	val= tmp + min((int) (val_end-tmp), 2);
 	break;
 
 	/* Hour */

--- 1.206/sql/sql_acl.cc	2006-08-29 13:44:11 +08:00
+++ 1.207/sql/sql_acl.cc	2006-08-29 13:44:11 +08:00
@@ -1006,6 +1006,7 @@
             sql_print_information("X509 issuer mismatch: should be '%s' "
 			      "but is '%s'", acl_user->x509_issuer, ptr);
           free(ptr);
+          user_access=NO_ACCESS;
           break;
         }
         user_access= acl_user->access;
@@ -1021,11 +1022,13 @@
         if (strcmp(acl_user->x509_subject,ptr))
         {
           if (global_system_variables.log_warnings)
-            sql_print_information("X509 subject mismatch: '%s' vs '%s'",
+            sql_print_information("X509 subject mismatch: should be '%s' but is '%s'",
                             acl_user->x509_subject, ptr);
+          free(ptr);
+          user_access=NO_ACCESS;
+          break;
         }
-        else
-          user_access= acl_user->access;
+        user_access= acl_user->access;
         free(ptr);
       }
       break;

--- 1.10.1.14/sql/examples/ha_tina.cc	2006-08-29 13:44:11 +08:00
+++ 1.56/storage/csv/ha_tina.cc	2006-08-29 13:44:11 +08:00
@@ -17,18 +17,22 @@
 /*
   Make sure to look at ha_tina.h for more details.
 
-  First off, this is a play thing for me, there are a number of things wrong with it:
- *) It was designed for csv and therefor its performance is highly questionable.
- *) Indexes have not been implemented. This is because the files can be traded in
- and out of the table directory without having to worry about rebuilding anything.
- *) NULLs and "" are treated equally (like a spreadsheet).
- *) There was in the beginning no point to anyone seeing this other then me, so there
- is a good chance that I haven't quite documented it well.
- *) Less design, more "make it work"
-
- Now there are a few cool things with it:
- *) Errors can result in corrupted data files.
- *) Data files can be read by spreadsheets directly.
+  First off, this is a play thing for me, there are a number of things
+  wrong with it:
+    *) It was designed for csv and therefore its performance is highly
+       questionable.
+    *) Indexes have not been implemented. This is because the files can
+       be traded in and out of the table directory without having to worry
+       about rebuilding anything.
+    *) NULLs and "" are treated equally (like a spreadsheet).
+    *) There was in the beginning no point to anyone seeing this other
+       then me, so there is a good chance that I haven't quite documented
+       it well.
+    *) Less design, more "make it work"
+
+  Now there are a few cool things with it:
+    *) Errors can result in corrupted data files.
+    *) Data files can be read by spreadsheets directly.
 
 TODO:
  *) Move to a block system for larger files
@@ -44,39 +48,83 @@
 
 #include "mysql_priv.h"
 
-#ifdef HAVE_CSV_DB
-
 #include "ha_tina.h"
-#include <sys/mman.h>
+
+#include <mysql/plugin.h>
+
+/*
+  uchar + uchar + ulonglong + ulonglong + ulonglong + ulonglong + uchar
+*/
+#define META_BUFFER_SIZE sizeof(uchar) + sizeof(uchar) + sizeof(ulonglong) \
+  + sizeof(ulonglong) + sizeof(ulonglong) + sizeof(ulonglong) + sizeof(uchar)
+#define TINA_CHECK_HEADER 254 // The number we use to determine corruption
+
+/* The file extension */
+#define CSV_EXT ".CSV"               // The data file
+#define CSN_EXT ".CSN"               // Files used during repair and update
+#define CSM_EXT ".CSM"               // Meta file
+
+
+static TINA_SHARE *get_share(const char *table_name, TABLE *table);
+static int free_share(TINA_SHARE *share);
+static int read_meta_file(File meta_file, ha_rows *rows);
+static int write_meta_file(File meta_file, ha_rows rows, bool dirty);
 
 /* Stuff for shares */
 pthread_mutex_t tina_mutex;
 static HASH tina_open_tables;
 static int tina_init= 0;
+static handler *tina_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root);
+static int tina_init_func();
 
-handlerton tina_hton= {
-  "CSV",
-  SHOW_OPTION_YES,
-  "CSV storage engine", 
-  DB_TYPE_CSV_DB,
-  NULL,    /* One needs to be written! */
-  0,       /* slot */
-  0,       /* savepoint size. */
-  NULL,    /* close_connection */
-  NULL,    /* savepoint */
-  NULL,    /* rollback to savepoint */
-  NULL,    /* release savepoint */
-  NULL,    /* commit */
-  NULL,    /* rollback */
-  NULL,    /* prepare */
-  NULL,    /* recover */
-  NULL,    /* commit_by_xid */
-  NULL,    /* rollback_by_xid */
-  NULL,    /* create_cursor_read_view */
-  NULL,    /* set_cursor_read_view */
-  NULL,    /* close_cursor_read_view */
-  HTON_CAN_RECREATE
-};
+off_t Transparent_file::read_next()
+{
+  off_t bytes_read;
+
+  /*
+     No need to seek here, as the file managed by Transparent_file class
+     always points to upper_bound byte
+  */
+  if ((bytes_read= my_read(filedes, buff, buff_size, MYF(0))) == MY_FILE_ERROR)
+    return -1;
+
+  /* end of file */
+  if (!bytes_read)
+    return -1;
+
+  lower_bound= upper_bound;
+  upper_bound+= bytes_read;
+
+  return lower_bound;
+}
+
+
+char Transparent_file::get_value(off_t offset)
+{
+  off_t bytes_read;
+
+  /* check boundaries */
+  if ((lower_bound <= offset) && (offset < upper_bound))
+    return buff[offset - lower_bound];
+  else
+  {
+    VOID(my_seek(filedes, offset, MY_SEEK_SET, MYF(0)));
+    /* read appropriate portion of the file */
+    if ((bytes_read= my_read(filedes, buff, buff_size,
+                             MYF(0))) == MY_FILE_ERROR)
+      return 0;
+
+    lower_bound= offset;
+    upper_bound= lower_bound + bytes_read;
+
+    /* end of file */
+    if (upper_bound == offset)
+      return 0;
+
+    return buff[0];
+  }
+}
+handlerton tina_hton;
 
 /*****************************************************************************
  ** TINA tables
@@ -91,7 +139,7 @@
     We assume that intervals do not intersect. So, it is enought to compare
     any two points. Here we take start of intervals for comparison.
   */
-  return ( a->begin > b->begin ? -1 : ( a->begin < b->begin ? 1 : 0 ) );
+  return ( a->begin > b->begin ? 1 : ( a->begin < b->begin ? -1 : 0 ) );
 }
 
 static byte* tina_get_key(TINA_SHARE *share,uint *length,
@@ -101,141 +149,120 @@
   return (byte*) share->table_name;
 }
 
-
-int free_mmap(TINA_SHARE *share)
+static int tina_init_func()
 {
-  DBUG_ENTER("ha_tina::free_mmap");
-  if (share->mapped_file)
+  if (!tina_init)
   {
-    /*
-      Invalidate the mapped in pages. Some operating systems (eg OpenBSD)
-      would reuse already cached pages even if the file has been altered
-      using fd based I/O. This may be optimized by perhaps only invalidating
-      the last page but optimization of deprecated code is not important.
-    */
-    msync(share->mapped_file, 0, MS_INVALIDATE);
-    if (munmap(share->mapped_file, share->file_stat.st_size))
-      DBUG_RETURN(1);
+    tina_init++;
+    VOID(pthread_mutex_init(&tina_mutex,MY_MUTEX_INIT_FAST));
+    (void) hash_init(&tina_open_tables,system_charset_info,32,0,0,
+                     (hash_get_key) tina_get_key,0,0);
+    tina_hton.state= SHOW_OPTION_YES;
+    tina_hton.db_type= DB_TYPE_CSV_DB;
+    tina_hton.create= tina_create_handler;
+    tina_hton.panic= tina_end;
+    tina_hton.flags= HTON_CAN_RECREATE;
   }
-  share->mapped_file= NULL;
-  DBUG_RETURN(0);
+  return 0;
 }
 
-/*
-  Reloads the mmap file.
-*/
-int get_mmap(TINA_SHARE *share, int write)
+static int tina_done_func()
 {
-  DBUG_ENTER("ha_tina::get_mmap");
-  
-  if (free_mmap(share))
-    DBUG_RETURN(1);
-
-  if (my_fstat(share->data_file, &share->file_stat, MYF(MY_WME)) == -1)
-    DBUG_RETURN(1);
-
-  if (share->file_stat.st_size) 
+  if (tina_init)
   {
-    if (write)
-      share->mapped_file= (byte *)mmap(NULL, share->file_stat.st_size, 
-                                       PROT_READ|PROT_WRITE, MAP_SHARED,
-                                       share->data_file, 0);
-    else
-      share->mapped_file= (byte *)mmap(NULL, share->file_stat.st_size, 
-                                       PROT_READ, MAP_PRIVATE,
-                                       share->data_file, 0);
-    if ((share->mapped_file ==(caddr_t)-1)) 
+    if (tina_open_tables.records)
     {
-      /*
-        Bad idea you think? See the problem is that nothing actually checks
-        the return value of ::rnd_init(), so tossing an error is about
-        it for us.
-        Never going to happen right? :)
-      */
-      my_message(errno, "Woops, blew up opening a mapped file", 0);
-      DBUG_ASSERT(0);
-      DBUG_RETURN(1);
+      return 1;
     }
+    hash_free(&tina_open_tables);
+    pthread_mutex_destroy(&tina_mutex);
+    tina_init--;
   }
-  else 
-    share->mapped_file= NULL;
-
-  DBUG_RETURN(0);
+  return 0;
 }
 
+
 /*
   Simple lock controls.
 */
 static TINA_SHARE *get_share(const char *table_name, TABLE *table)
 {
   TINA_SHARE *share;
+  char meta_file_name[FN_REFLEN];
+  MY_STAT file_stat;                /* Stat information for the data file */
   char *tmp_name;
   uint length;
 
   if (!tina_init)
-  {
-    /* Hijack a mutex for init'ing the storage engine */
-    pthread_mutex_lock(&LOCK_mysql_create_db);
-    if (!tina_init)
-    {
-      tina_init++;
-      VOID(pthread_mutex_init(&tina_mutex,MY_MUTEX_INIT_FAST));
-      (void) hash_init(&tina_open_tables,system_charset_info,32,0,0,
-                       (hash_get_key) tina_get_key,0,0);
-    }
-    pthread_mutex_unlock(&LOCK_mysql_create_db);
-  }
+     tina_init_func();
+
   pthread_mutex_lock(&tina_mutex);
   length=(uint) strlen(table_name);
+
+  /*
+    If share is not present in the hash, create a new share and
+    initialize its members.
+  */
   if (!(share=(TINA_SHARE*) hash_search(&tina_open_tables,
                                         (byte*) table_name,
-                                        length)))
+                                       length)))
   {
-    char data_file_name[FN_REFLEN];
     if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
                          &share, sizeof(*share),
                          &tmp_name, length+1,
-                         NullS)) 
+                         NullS))
     {
       pthread_mutex_unlock(&tina_mutex);
       return NULL;
     }
 
-    share->use_count=0;
-    share->table_name_length=length;
-    share->table_name=tmp_name;
-    strmov(share->table_name,table_name);
-    fn_format(data_file_name, table_name, "", ".CSV",
-              MY_REPLACE_EXT | MY_UNPACK_FILENAME);
-
-    if ((share->data_file= my_open(data_file_name, O_RDWR|O_APPEND,
-                                   MYF(0))) == -1)
-      goto error;
-
+    share->use_count= 0;
+    share->is_log_table= FALSE;
+    share->table_name_length= length;
+    share->table_name= tmp_name;
+    share->crashed= FALSE;
+    share->rows_recorded= 0;
+    share->update_file_opened= FALSE;
+    share->tina_write_opened= FALSE;
+    strmov(share->table_name, table_name);
+    fn_format(share->data_file_name, table_name, "", CSV_EXT,
+              MY_REPLACE_EXT|MY_UNPACK_FILENAME);
+    fn_format(meta_file_name, table_name, "", CSM_EXT,
+              MY_REPLACE_EXT|MY_UNPACK_FILENAME);
     if (my_hash_insert(&tina_open_tables, (byte*) share))
       goto error;
     thr_lock_init(&share->lock);
     pthread_mutex_init(&share->mutex,MY_MUTEX_INIT_FAST);
 
-    /* We only use share->data_file for writing, so we scan to the end to append */
-    if (my_seek(share->data_file, 0, SEEK_END, MYF(0)) == MY_FILEPOS_ERROR)
-      goto error2;
+    /*
+      Open or create the meta file. In the latter case, we'll get
+      an error during read_meta_file and mark the table as crashed.
+      Usually this will result in auto-repair, and we will get a good
+      meta-file in the end.
+    */
+    if ((share->meta_file= my_open(meta_file_name,
+                                   O_RDWR|O_CREAT, MYF(0))) == -1)
+      share->crashed= TRUE;
+
+    /*
+      If the meta file will not open we assume it is crashed and
+      mark it as such.
+    */
+    if (read_meta_file(share->meta_file, &share->rows_recorded))
+      share->crashed= TRUE;
 
-    share->mapped_file= NULL; // We don't know the state since we just allocated it
-    if (get_mmap(share, 0) > 0)
-      goto error3;
+    if (my_stat(share->data_file_name, &file_stat, MYF(MY_WME)) == NULL)
+      goto error2;
+    share->saved_data_file_length= file_stat.st_size;
   }
   share->use_count++;
   pthread_mutex_unlock(&tina_mutex);
 
   return share;
 
-error3:
-  my_close(share->data_file,MYF(0));
 error2:
   thr_lock_delete(&share->lock);
   pthread_mutex_destroy(&share->mutex);
-  hash_delete(&tina_open_tables, (byte*) share);
 error:
   pthread_mutex_unlock(&tina_mutex);
   my_free((gptr) share, MYF(0));
@@ -244,7 +271,153 @@
 }
 
 
-/* 
+/*
+  Read CSV meta-file
+
+  SYNOPSIS
+    read_meta_file()
+    meta_file   The meta-file filedes
+    ha_rows     Pointer to the var we use to store rows count.
+                These are read from the meta-file.
+
+  DESCRIPTION
+
+    Read the meta-file info. For now we are only interested in
+    rows counf, crashed bit and magic number.
+
+  RETURN
+    0 - OK
+    non-zero - error occurred
+*/
+
+static int read_meta_file(File meta_file, ha_rows *rows)
+{
+  uchar meta_buffer[META_BUFFER_SIZE];
+  uchar *ptr= meta_buffer;
+
+  DBUG_ENTER("ha_tina::read_meta_file");
+
+  VOID(my_seek(meta_file, 0, MY_SEEK_SET, MYF(0)));
+  if (my_read(meta_file, (byte*)meta_buffer, META_BUFFER_SIZE, 0)
+      != META_BUFFER_SIZE)
+    DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
+
+  /*
+    Parse out the meta data, we ignore version at the moment
+  */
+
+  ptr+= sizeof(uchar)*2; // Move past header
+  *rows= (ha_rows)uint8korr(ptr);
+  ptr+= sizeof(ulonglong); // Move past rows
+  /*
+    Move past check_point, auto_increment and forced_flushes fields.
+    They are present in the format, but we do not use them yet.
+  */
+  ptr+= 3*sizeof(ulonglong);
+
+  /* check crashed bit and magic number */
+  if ((meta_buffer[0] != (uchar)TINA_CHECK_HEADER) ||
+      ((bool)(*ptr)== TRUE))
+    DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
+
+  my_sync(meta_file, MYF(MY_WME));
+
+  DBUG_RETURN(0);
+}
+
+
+/*
+  Write CSV meta-file
+
+  SYNOPSIS
+    write_meta_file()
+    meta_file   The meta-file filedes
+    ha_rows     The number of rows we have in the datafile.
+    dirty       A flag, which marks whether we have a corrupt table
+
+  DESCRIPTION
+
+    Write meta-info the the file. Only rows count, crashed bit and
+    magic number matter now.
+
+  RETURN
+    0 - OK
+    non-zero - error occurred
+*/
+
+static int write_meta_file(File meta_file, ha_rows rows, bool dirty)
+{
+  uchar meta_buffer[META_BUFFER_SIZE];
+  uchar *ptr= meta_buffer;
+
+  DBUG_ENTER("ha_tina::write_meta_file");
+
+  *ptr= (uchar)TINA_CHECK_HEADER;
+  ptr+= sizeof(uchar);
+  *ptr= (uchar)TINA_VERSION;
+  ptr+= sizeof(uchar);
+  int8store(ptr, (ulonglong)rows);
+  ptr+= sizeof(ulonglong);
+  memset(ptr, 0, 3*sizeof(ulonglong));
+  /*
+     Skip over checkpoint, autoincrement and forced_flushes fields.
+     We'll need them later.
+  */
+  ptr+= 3*sizeof(ulonglong);
+  *ptr= (uchar)dirty;
+
+  VOID(my_seek(meta_file, 0, MY_SEEK_SET, MYF(0)));
+  if (my_write(meta_file, (byte *)meta_buffer, META_BUFFER_SIZE, 0)
+      != META_BUFFER_SIZE)
+    DBUG_RETURN(-1);
+
+  my_sync(meta_file, MYF(MY_WME));
+
+  DBUG_RETURN(0);
+}
+
+bool ha_tina::check_and_repair(THD *thd)
+{
+  HA_CHECK_OPT check_opt;
+  DBUG_ENTER("ha_tina::check_and_repair");
+
+  check_opt.init();
+
+  DBUG_RETURN(repair(thd, &check_opt));
+}
+
+
+int ha_tina::init_tina_writer()
+{
+  DBUG_ENTER("ha_tina::init_tina_writer");
+
+  /*
+    Mark the file as crashed. We will set the flag back when we close
+    the file. In the case of the crash it will remain marked crashed,
+    which enforce recovery.
+  */
+  (void)write_meta_file(share->meta_file, share->rows_recorded, TRUE);
+
+  if ((share->tina_write_filedes=
+        my_open(share->data_file_name, O_RDWR|O_APPEND, MYF(0))) == -1)
+  {
+    DBUG_PRINT("info", ("Could not open tina file writes"));
+    share->crashed= TRUE;
+    DBUG_RETURN(1);
+  }
+  share->tina_write_opened= TRUE;
+
+  DBUG_RETURN(0);
+}
+
+
+bool ha_tina::is_crashed() const
+{
+  DBUG_ENTER("ha_tina::is_crashed");
+  DBUG_RETURN(share->crashed);
+}
+
+/*
   Free lock controls.
 */
 static int free_share(TINA_SHARE *share)
@@ -253,9 +426,18 @@
   pthread_mutex_lock(&tina_mutex);
   int result_code= 0;
   if (!--share->use_count){
-    /* Drop the mapped file */
-    free_mmap(share);
-    result_code= my_close(share->data_file,MYF(0));
+    /* Write the meta file. Mark it as crashed if needed. */
+    (void)write_meta_file(share->meta_file, share->rows_recorded,
+                          share->crashed ? TRUE :FALSE);
+    if (my_close(share->meta_file, MYF(0)))
+      result_code= 1;
+    if (share->tina_write_opened)
+    {
+      if (my_close(share->tina_write_filedes, MYF(0)))
+        result_code= 1;
+      share->tina_write_opened= FALSE;
+    }
+
     hash_delete(&tina_open_tables, (byte*) share);
     thr_lock_delete(&share->lock);
     pthread_mutex_destroy(&share->mutex);
@@ -266,62 +448,104 @@
   DBUG_RETURN(result_code);
 }
 
-bool tina_end()
+int tina_end(ha_panic_function type)
 {
-  if (tina_init)
-  {
-    hash_free(&tina_open_tables);
-    VOID(pthread_mutex_destroy(&tina_mutex));
-  }
-  tina_init= 0;
-  return FALSE;
+  return tina_done_func();
 }
 
-/* 
-  Finds the end of a line.
-  Currently only supports files written on a UNIX OS.
+
+/*
+  This function finds the end of a line and returns the length
+  of the line ending.
+
+  We support three kinds of line endings:
+  '\r'     --  Old Mac OS line ending
+  '\n'     --  Traditional Unix and Mac OS X line ending
+  '\r''\n' --  DOS\Windows line ending
 */
-byte * find_eoln(byte *data, off_t begin, off_t end) 
+
+off_t find_eoln_buff(Transparent_file *data_buff, off_t begin,
+                     off_t end, int *eoln_len)
 {
-  for (off_t x= begin; x < end; x++) 
-    if (data[x] == '\n')
-      return data + x;
+  *eoln_len= 0;
+
+  for (off_t x= begin; x < end; x++)
+  {
+    /* Unix (includes Mac OS X) */
+    if (data_buff->get_value(x) == '\n')
+      *eoln_len= 1;
+    else
+      if (data_buff->get_value(x) == '\r') // Mac or Dos
+      {
+        /* old Mac line ending */
+        if (x + 1 == end || (data_buff->get_value(x + 1) != '\n'))
+          *eoln_len= 1;
+        else // DOS style ending
+          *eoln_len= 2;
+      }
+
+    if (*eoln_len)  // end of line was found
+      return x;
+  }
 
   return 0;
 }
 
 
-ha_tina::ha_tina(TABLE *table_arg)
+static handler *tina_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
+{
+  return new (mem_root) ha_tina(table);
+}
+
+
+ha_tina::ha_tina(TABLE_SHARE *table_arg)
   :handler(&tina_hton, table_arg),
   /*
-    These definitions are found in hanler.h
-    These are not probably completely right.
+    These definitions are found in handler.h
+    They are not probably completely right.
   */
-  current_position(0), next_position(0), chain_alloced(0),
-  chain_size(DEFAULT_CHAIN_LENGTH), records_is_known(0)
+  current_position(0), next_position(0), local_saved_data_file_length(0),
+  file_buff(0), chain_alloced(0), chain_size(DEFAULT_CHAIN_LENGTH),
+  records_is_known(0)
 {
   /* Set our original buffers from pre-allocated memory */
-  buffer.set(byte_buffer, IO_SIZE, system_charset_info);
+  buffer.set((char*)byte_buffer, IO_SIZE, system_charset_info);
   chain= chain_buffer;
+  file_buff= new Transparent_file();
 }
 
+
 /*
   Encode a buffer into the quoted format.
 */
-int ha_tina::encode_quote(byte *buf) 
+
+int ha_tina::encode_quote(byte *buf)
 {
   char attribute_buffer[1024];
-  String attribute(attribute_buffer, sizeof(attribute_buffer), &my_charset_bin);
+  String attribute(attribute_buffer, sizeof(attribute_buffer),
+                   &my_charset_bin);
 
+  my_bitmap_map *org_bitmap= dbug_tmp_use_all_columns(table, table->read_set);
   buffer.length(0);
   for (Field **field=table->field ; *field ; field++)
   {
     const char *ptr;
     const char *end_ptr;
 
-    (*field)->val_str(&attribute,&attribute);
-    ptr= attribute.ptr();
-    end_ptr= attribute.length() + ptr;
+    /*
+      Write an empty string to the buffer in case of a NULL value.
+      Basically this is a safety check, as no one ensures that the
+      field content is cleaned up every time we use Field::set_null()
+      in the code.
+    */
+    if ((*field)->is_null())
+      ptr= end_ptr= 0;
+    else
+    {
+      (*field)->val_str(&attribute,&attribute);
+      ptr= attribute.ptr();
+      end_ptr= attribute.length() + ptr;
+    }
 
     buffer.append('"');
 
@@ -362,17 +586,20 @@
   buffer.append('\n');
   //buffer.replace(buffer.length(), 0, "\n", 1);
 
+  dbug_tmp_restore_column_map(table->read_set, org_bitmap);
   return (buffer.length());
 }
 
 /*
-  chain_append() adds delete positions to the chain that we use to keep track of space.
+  chain_append() adds delete positions to the chain that we use to keep
+  track of space. Then the chain will be used to cleanup "holes", occurred
+  due to deletes and updates.
 */
 int ha_tina::chain_append()
 {
   if ( chain_ptr != chain && (chain_ptr -1)->end == current_position)
     (chain_ptr -1)->end= next_position;
-  else 
+  else
   {
     /* We set up for the next position */
     if ((off_t)(chain_ptr - chain) == (chain_size -1))
@@ -382,12 +609,14 @@
       if (chain_alloced)
       {
         /* Must cast since my_malloc unlike malloc doesn't have a void ptr */
-        if ((chain= (tina_set *)my_realloc((gptr)chain,chain_size,MYF(MY_WME))) == NULL)
+        if ((chain= (tina_set *) my_realloc((gptr)chain,
+                                            chain_size, MYF(MY_WME))) == NULL)
           return -1;
       }
       else
       {
-        tina_set *ptr= (tina_set *)my_malloc(chain_size * sizeof(tina_set),MYF(MY_WME));
+        tina_set *ptr= (tina_set *) my_malloc(chain_size * sizeof(tina_set),
+                                              MYF(MY_WME));
         memcpy(ptr, chain, DEFAULT_CHAIN_LENGTH * sizeof(tina_set));
         chain= ptr;
         chain_alloced++;
@@ -403,55 +632,87 @@
 }
 
 
-/* 
+/*
   Scans for a row.
 */
 int ha_tina::find_current_row(byte *buf)
 {
-  byte *mapped_ptr= (byte *)share->mapped_file + current_position;
-  byte *end_ptr;
+  off_t end_offset, curr_offset= current_position;
+  int eoln_len;
+  my_bitmap_map *org_bitmap;
   DBUG_ENTER("ha_tina::find_current_row");
 
-  /* EOF should be counted as new line */
-  if ((end_ptr=  find_eoln(share->mapped_file, current_position, share->file_stat.st_size)) == 0)
+  /*
+    We do not read further then local_saved_data_file_length in order
+    not to conflict with undergoing concurrent insert.
+  */
+  if ((end_offset=
+        find_eoln_buff(file_buff, current_position,
+                       local_saved_data_file_length, &eoln_len)) == 0)
     DBUG_RETURN(HA_ERR_END_OF_FILE);
 
+  /* Avoid asserts in ::store() for columns that are not going to be updated */
+  org_bitmap= dbug_tmp_use_all_columns(table, table->write_set);
+
   for (Field **field=table->field ; *field ; field++)
   {
     buffer.length(0);
-    mapped_ptr++; // Increment past the first quote
-    for(;mapped_ptr != end_ptr; mapped_ptr++)
+    if (file_buff->get_value(curr_offset) == '"')
+      curr_offset++; // Incrementpast the first quote
+    else
+    {
+      dbug_tmp_restore_column_map(table->write_set, org_bitmap);
+      DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
+    }
+    for(;curr_offset != end_offset; curr_offset++)
     {
-      //Need to convert line feeds!
-      if (*mapped_ptr == '"' && 
-          (((mapped_ptr[1] == ',') && (mapped_ptr[2] == '"')) || (mapped_ptr == end_ptr -1 )))
+      // Need to convert line feeds!
+      if (file_buff->get_value(curr_offset) == '"' &&
+          (((file_buff->get_value(curr_offset + 1) == ',') &&
+            (file_buff->get_value(curr_offset + 2) == '"')) ||
+           (curr_offset == end_offset -1 )))
       {
-        mapped_ptr += 2; // Move past the , and the "
+        curr_offset+= 2; // Move past the , and the "
         break;
-      } 
-      if (*mapped_ptr == '\\' && mapped_ptr != (end_ptr - 1)) 
+      }
+      if (file_buff->get_value(curr_offset) == '\\' &&
+          curr_offset != (end_offset - 1))
       {
-        mapped_ptr++;
-        if (*mapped_ptr == 'r')
+        curr_offset++;
+        if (file_buff->get_value(curr_offset) == 'r')
           buffer.append('\r');
-        else if (*mapped_ptr == 'n' )
+        else if (file_buff->get_value(curr_offset) == 'n' )
           buffer.append('\n');
-        else if ((*mapped_ptr == '\\') || (*mapped_ptr == '"'))
-          buffer.append(*mapped_ptr);
+        else if ((file_buff->get_value(curr_offset) == '\\') ||
+                 (file_buff->get_value(curr_offset) == '"'))
+          buffer.append(file_buff->get_value(curr_offset));
         else  /* This could only happed with an externally created file */
         {
           buffer.append('\\');
-          buffer.append(*mapped_ptr);
+          buffer.append(file_buff->get_value(curr_offset));
         }
-      } 
-      else
-        buffer.append(*mapped_ptr);
+      }
+      else // ordinary symbol
+      {
+        /*
+          We are at final symbol and no last quote was found =>
+          we are working with a damaged file.
+        */
+        if (curr_offset == end_offset - 1)
+        {
+          dbug_tmp_restore_column_map(table->write_set, org_bitmap);
+          DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
+        }
+        buffer.append(file_buff->get_value(curr_offset));
+      }
     }
-    (*field)->store(buffer.ptr(), buffer.length(), system_charset_info);
+    if (bitmap_is_set(table->read_set, (*field)->field_index))
+      (*field)->store(buffer.ptr(), buffer.length(), system_charset_info);
   }
-  next_position= (end_ptr - share->mapped_file)+1;
+  next_position= end_offset + eoln_len;
   /* Maybe use \N for null? */
   memset(buf, 0, table->s->null_bytes); /* We do not implement nulls! */
+  dbug_tmp_restore_column_map(table->write_set, org_bitmap);
 
   DBUG_RETURN(0);
 }
@@ -461,7 +722,8 @@
   extensions exist for this handler.
 */
 static const char *ha_tina_exts[] = {
-  ".CSV",
+  CSV_EXT,
+  CSM_EXT,
   NullS
 };
 
@@ -470,36 +732,147 @@
   return ha_tina_exts;
 }
 
+/*
+  Three functions below are needed to enable concurrent insert functionality
+  for CSV engine. For more details see mysys/thr_lock.c
+*/
 
-/* 
+void tina_get_status(void* param, int concurrent_insert)
+{
+  ha_tina *tina= (ha_tina*) param;
+  tina->get_status();
+}
+
+void tina_update_status(void* param)
+{
+  ha_tina *tina= (ha_tina*) param;
+  tina->update_status();
+}
+
+/* this should exist and return 0 for concurrent insert to work */
+my_bool tina_check_status(void* param)
+{
+  return 0;
+}
+
+/*
+  Save the state of the table
+
+  SYNOPSIS
+    get_status()
+
+  DESCRIPTION
+    This function is used to retrieve the file length. During the lock
+    phase of concurrent insert. For more details see comment to
+    ha_tina::update_status below.
+*/
+
+void ha_tina::get_status()
+{
+  if (share->is_log_table)
+  {
+    /*
+      We have to use mutex to follow pthreads memory visibility
+      rules for share->saved_data_file_length
+    */
+    pthread_mutex_lock(&share->mutex);
+    local_saved_data_file_length= share->saved_data_file_length;
+    pthread_mutex_unlock(&share->mutex);
+    return;
+  }
+  local_saved_data_file_length= share->saved_data_file_length;
+}
+
+
+/*
+  Correct the state of the table. Called by unlock routines
+  before the write lock is released.
+
+  SYNOPSIS
+    update_status()
+
+  DESCRIPTION
+    When we employ concurrent insert lock, we save current length of the file
+    during the lock phase. We do not read further saved value, as we don't
+    want to interfere with undergoing concurrent insert. Writers update file
+    length info during unlock with update_status().
+
+  NOTE
+    For log tables concurrent insert works different. The reason is that
+    log tables are always opened and locked. And as they do not unlock
+    tables, the file length after writes should be updated in a different
+    way. For this purpose we need is_log_table flag. When this flag is set
+    we call update_status() explicitly after each row write.
+*/
+
+void ha_tina::update_status()
+{
+  /* correct local_saved_data_file_length for writers */
+  share->saved_data_file_length= local_saved_data_file_length;
+}
+
+
+bool ha_tina::check_if_locking_is_allowed(uint sql_command,
+                                          ulong type, TABLE *table,
+                                          uint count,
+                                          bool called_by_logger_thread)
+{
+  if (!called_by_logger_thread)
+    return check_if_log_table_locking_is_allowed(sql_command, type, table);
+
+  return TRUE;
+}
+
+/*
   Open a database file. Keep in mind that tables are caches, so
   this will not be called for every request. Any sort of positions
   that need to be reset should be kept in the ::extra() call.
 */
-int ha_tina::open(const char *name, int mode, uint test_if_locked)
+int ha_tina::open(const char *name, int mode, uint open_options)
 {
   DBUG_ENTER("ha_tina::open");
 
   if (!(share= get_share(name, table)))
-    DBUG_RETURN(1);
-  thr_lock_data_init(&share->lock,&lock,NULL);
+    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+
+  if (share->crashed && !(open_options & HA_OPEN_FOR_REPAIR))
+  {
+    free_share(share);
+    DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
+  }
+
+  if ((data_file= my_open(share->data_file_name, O_RDONLY, MYF(0))) == -1)
+    DBUG_RETURN(0);
+
+  /*
+    Init locking. Pass handler object to the locking routines,
+    so that they could save/update local_saved_data_file_length value
+    during locking. This is needed to enable concurrent inserts.
+  */
+  thr_lock_data_init(&share->lock, &lock, (void*) this);
   ref_length=sizeof(off_t);
 
+  share->lock.get_status= tina_get_status;
+  share->lock.update_status= tina_update_status;
+  share->lock.check_status= tina_check_status;
+
   DBUG_RETURN(0);
 }
 
 
 /*
   Close a database file. We remove ourselves from the shared strucutre.
-  If it is empty we destroy it and free the mapped file.
+  If it is empty we destroy it.
 */
 int ha_tina::close(void)
 {
+  int rc= 0;
   DBUG_ENTER("ha_tina::close");
-  DBUG_RETURN(free_share(share));
+  rc= my_close(data_file, MYF(0));
+  DBUG_RETURN(free_share(share) || rc);
 }
 
-/* 
+/*
   This is an INSERT. At the moment this handler just seeks to the end
   of the file and appends the data. In an error case it really should
   just truncate to the original position (this is not done yet).
@@ -509,40 +882,61 @@
   int size;
   DBUG_ENTER("ha_tina::write_row");
 
-  statistic_increment(table->in_use->status_var.ha_write_count, &LOCK_status);
+  if (share->crashed)
+      DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
+
+  ha_statistic_increment(&SSV::ha_write_count);
 
   if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
     table->timestamp_field->set_time();
 
   size= encode_quote(buf);
 
-  /*
-    we are going to alter the file so we must invalidate the in memory pages
-    otherwise we risk a race between the in memory pages and the disk pages.
-  */
-  if (free_mmap(share))
-    DBUG_RETURN(-1);
+  if (!share->tina_write_opened)
+    if (init_tina_writer())
+      DBUG_RETURN(-1);
 
-  if (my_write(share->data_file, buffer.ptr(), size, MYF(MY_WME | MY_NABP)))
+   /* use pwrite, as concurrent reader could have changed the position */
+  if (my_write(share->tina_write_filedes, (byte*)buffer.ptr(), size,
+               MYF(MY_WME | MY_NABP)))
     DBUG_RETURN(-1);
 
-  /* 
-    Ok, this is means that we will be doing potentially bad things 
-    during a bulk insert on some OS'es. What we need is a cleanup
-    call for ::write_row that would let us fix up everything after the bulk
-    insert. The archive handler does this with an extra mutx call, which
-    might be a solution for this.
-  */
-  if (get_mmap(share, 0) > 0) 
-    DBUG_RETURN(-1);
-  records++;
+  /* update local copy of the max position to see our own changes */
+  local_saved_data_file_length+= size;
+
+  /* update shared info */
+  pthread_mutex_lock(&share->mutex);
+  share->rows_recorded++;
+  /* update status for the log tables */
+  if (share->is_log_table)
+    update_status();
+  pthread_mutex_unlock(&share->mutex);
+
+  stats.records++;
   DBUG_RETURN(0);
 }
 
 
-/* 
+int ha_tina::open_update_temp_file_if_needed()
+{
+  char updated_fname[FN_REFLEN];
+
+  if (!share->update_file_opened)
+  {
+    if ((update_temp_file=
+           my_create(fn_format(updated_fname, share->table_name,
+                               "", CSN_EXT,
+                               MY_REPLACE_EXT | MY_UNPACK_FILENAME),
+                     0, O_RDWR | O_TRUNC, MYF(MY_WME))) < 0)
+      return 1;
+    share->update_file_opened= TRUE;
+  }
+  return 0;
+}
+
+/*
   This is called for an update.
-  Make sure you put in code to increment the auto increment, also 
+  Make sure you put in code to increment the auto increment, also
   update any timestamp data. Currently auto increment is not being
   fixed since autoincrements have yet to be added to this table handler.
   This will be called in a table scan right before the previous ::rnd_next()
@@ -553,8 +947,7 @@
   int size;
   DBUG_ENTER("ha_tina::update_row");
 
-  statistic_increment(table->in_use->status_var.ha_read_rnd_next_count,
-		      &LOCK_status);
+  ha_statistic_increment(&SSV::ha_read_rnd_next_count);
 
   if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
     table->timestamp_field->set_time();
@@ -564,125 +957,48 @@
   if (chain_append())
     DBUG_RETURN(-1);
 
-  /*
-    we are going to alter the file so we must invalidate the in memory pages
-    otherwise we risk a race between the in memory pages and the disk pages.
-  */
-  if (free_mmap(share))
+  if (open_update_temp_file_if_needed())
     DBUG_RETURN(-1);
 
-  if (my_write(share->data_file, buffer.ptr(), size, MYF(MY_WME | MY_NABP)))
+  if (my_write(update_temp_file, (byte*)buffer.ptr(), size,
+               MYF(MY_WME | MY_NABP)))
     DBUG_RETURN(-1);
 
-  /* 
-    Ok, this is means that we will be doing potentially bad things 
-    during a bulk update on some OS'es. Ideally, we should extend the length
-    of the file, redo the mmap and then write all the updated rows. Upon
-    finishing the bulk update, truncate the file length to the final length.
-    Since this code is all being deprecated, not point now to optimize.
-  */
-  if (get_mmap(share, 0) > 0) 
-    DBUG_RETURN(-1);
+  /* UPDATE should never happen on the log tables */
+  DBUG_ASSERT(!share->is_log_table);
 
   DBUG_RETURN(0);
 }
 
 
-/* 
-  Deletes a row. First the database will find the row, and then call this method.
-  In the case of a table scan, the previous call to this will be the ::rnd_next()
-  that found this row.
-  The exception to this is an ORDER BY. This will cause the table handler to walk
-  the table noting the positions of all rows that match a query. The table will
-  then be deleted/positioned based on the ORDER (so RANDOM, DESC, ASC).
+/*
+  Deletes a row. First the database will find the row, and then call this
+  method. In the case of a table scan, the previous call to this will be
+  the ::rnd_next() that found this row.
+  The exception to this is an ORDER BY. This will cause the table handler
+  to walk the table noting the positions of all rows that match a query.
+  The table will then be deleted/positioned based on the ORDER (so RANDOM,
+  DESC, ASC).
 */
 int ha_tina::delete_row(const byte * buf)
 {
   DBUG_ENTER("ha_tina::delete_row");
-  statistic_increment(table->in_use->status_var.ha_delete_count,&LOCK_status);
+  ha_statistic_increment(&SSV::ha_delete_count);
 
   if (chain_append())
     DBUG_RETURN(-1);
 
-  --records;
-
-  DBUG_RETURN(0);
-}
+  stats.records--;
 
-/*
-  Fill buf with value from key. Simply this is used for a single index read 
-  with a key.
-*/
-int ha_tina::index_read(byte * buf, const byte * key,
-                        uint key_len __attribute__((unused)),
-                        enum ha_rkey_function find_flag
-                        __attribute__((unused)))
-{
-  DBUG_ENTER("ha_tina::index_read");
-  DBUG_ASSERT(0);
-  DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
-}
-
-/*
-  Fill buf with value from key. Simply this is used for a single index read 
-  with a key.
-  Whatever the current key is we will use it. This is what will be in "index".
-*/
-int ha_tina::index_read_idx(byte * buf, uint index, const byte * key,
-                            uint key_len __attribute__((unused)),
-                            enum ha_rkey_function find_flag
-                            __attribute__((unused)))
-{
-  DBUG_ENTER("ha_tina::index_read_idx");
-  DBUG_ASSERT(0);
-  DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
-}
+  /* DELETE should never happen on the log table */
+  DBUG_ASSERT(!share->is_log_table);
 
-
-/*
-  Read the next position in the index.
-*/
-int ha_tina::index_next(byte * buf)
-{
-  DBUG_ENTER("ha_tina::index_next");
-  DBUG_ASSERT(0);
-  DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
+  DBUG_RETURN(0);
 }
 
-/*
-  Read the previous position in the index.
-*/
-int ha_tina::index_prev(byte * buf)
-{
-  DBUG_ENTER("ha_tina::index_prev");
-  DBUG_ASSERT(0);
-  DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
-}
 
 /*
-  Read the first position in the index
-*/
-int ha_tina::index_first(byte * buf)
-{
-  DBUG_ENTER("ha_tina::index_first");
-  DBUG_ASSERT(0);
-  DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
-}
-
-/*
-  Read the last position in the index
-  With this we don't need to do a filesort() with index.
-  We just read the last row and call previous.
-*/
-int ha_tina::index_last(byte * buf)
-{
-  DBUG_ENTER("ha_tina::index_last");
-  DBUG_ASSERT(0);
-  DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
-}
-
-/* 
-  All table scans call this first. 
+  All table scans call this first.
   The order of a table scan is:
 
   ha_tina::store_lock
@@ -706,8 +1022,8 @@
   ha_tina::extra
   ENUM HA_EXTRA_RESET   Reset database to after open
 
-  Each call to ::rnd_next() represents a row returned in the can. When no more 
-  rows can be returned, rnd_next() returns a value of HA_ERR_END_OF_FILE. 
+  Each call to ::rnd_next() represents a row returned in the can. When no more
+  rows can be returned, rnd_next() returns a value of HA_ERR_END_OF_FILE.
   The ::info() call is just for the optimizer.
 
 */
@@ -716,53 +1032,63 @@
 {
   DBUG_ENTER("ha_tina::rnd_init");
 
+  /* set buffer to the beginning of the file */
+  file_buff->init_buff(data_file);
+  if (share->crashed)
+      DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
+
   current_position= next_position= 0;
-  records= 0;
+  stats.records= 0;
   records_is_known= 0;
   chain_ptr= chain;
-#ifdef HAVE_MADVISE
-  if (scan)
-    (void)madvise(share->mapped_file,share->file_stat.st_size,MADV_SEQUENTIAL);
-#endif
 
   DBUG_RETURN(0);
 }
 
 /*
-  ::rnd_next() does all the heavy lifting for a table scan. You will need to populate *buf
-  with the correct field data. You can walk the field to determine at what position you 
-  should store the data (take a look at how ::find_current_row() works). The structure
-  is something like:
+  ::rnd_next() does all the heavy lifting for a table scan. You will need to
+  populate *buf with the correct field data. You can walk the field to
+  determine at what position you should store the data (take a look at how
+  ::find_current_row() works). The structure is something like:
   0Foo  Dog  Friend
-  The first offset is for the first attribute. All space before that is reserved for null count.
-  Basically this works as a mask for which rows are nulled (compared to just empty).
-  This table handler doesn't do nulls and does not know the difference between NULL and "". This
-  is ok since this table handler is for spreadsheets and they don't know about them either :)
+  The first offset is for the first attribute. All space before that is
+  reserved for null count.
+  Basically this works as a mask for which rows are nulled (compared to just
+  empty).
+  This table handler doesn't do nulls and does not know the difference between
+  NULL and "". This is ok since this table handler is for spreadsheets and
+  they don't know about them either :)
 */
 int ha_tina::rnd_next(byte *buf)
 {
+  int rc;
   DBUG_ENTER("ha_tina::rnd_next");
 
-  statistic_increment(table->in_use->status_var.ha_read_rnd_next_count,
-		      &LOCK_status);
+  if (share->crashed)
+      DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
+
+  ha_statistic_increment(&SSV::ha_read_rnd_next_count);
 
   current_position= next_position;
-  if (!share->mapped_file) 
-    DBUG_RETURN(HA_ERR_END_OF_FILE);
-  if (HA_ERR_END_OF_FILE == find_current_row(buf) ) 
+
+  /* don't scan an empty file */
+  if (!local_saved_data_file_length)
     DBUG_RETURN(HA_ERR_END_OF_FILE);
 
-  records++;
+  if ((rc= find_current_row(buf)))
+    DBUG_RETURN(rc);
+
+  stats.records++;
   DBUG_RETURN(0);
 }
 
 /*
   In the case of an order by rows will need to be sorted.
-  ::position() is called after each call to ::rnd_next(), 
+  ::position() is called after each call to ::rnd_next(),
   the data it stores is to a byte array. You can store this
-  data via my_store_ptr(). ref_length is a variable defined to the 
-  class that is the sizeof() of position being stored. In our case  
-  its just a position. Look at the bdb code if you want to see a case 
+  data via my_store_ptr(). ref_length is a variable defined to the
+  class that is the sizeof() of position being stored. In our case
+  its just a position. Look at the bdb code if you want to see a case
   where something other then a number is stored.
 */
 void ha_tina::position(const byte *record)
@@ -773,17 +1099,16 @@
 }
 
 
-/* 
-  Used to fetch a row from a posiion stored with ::position(). 
+/*
+  Used to fetch a row from a posiion stored with ::position().
   my_get_ptr() retrieves the data for you.
 */
 
 int ha_tina::rnd_pos(byte * buf, byte *pos)
 {
   DBUG_ENTER("ha_tina::rnd_pos");
-  statistic_increment(table->in_use->status_var.ha_read_rnd_next_count,
-		      &LOCK_status);
-  current_position= my_get_ptr(pos,ref_length);
+  ha_statistic_increment(&SSV::ha_read_rnd_next_count);
+  current_position= (off_t)my_get_ptr(pos,ref_length);
   DBUG_RETURN(find_current_row(buf));
 }
 
@@ -796,8 +1121,8 @@
 {
   DBUG_ENTER("ha_tina::info");
   /* This is a lie, but you don't want the optimizer to see zero or 1 */
-  if (!records_is_known && records < 2) 
-    records= 2;
+  if (!records_is_known && stats.records < 2) 
+    stats.records= 2;
   DBUG_VOID_RETURN;
 }
 
@@ -809,105 +1134,294 @@
 int ha_tina::extra(enum ha_extra_function operation)
 {
   DBUG_ENTER("ha_tina::extra");
+ if (operation == HA_EXTRA_MARK_AS_LOG_TABLE)
+ {
+   pthread_mutex_lock(&share->mutex);
+   share->is_log_table= TRUE;
+   pthread_mutex_unlock(&share->mutex);
+ }
   DBUG_RETURN(0);
 }
 
-/* 
-  This is no longer used.
-*/
-int ha_tina::reset(void)
-{
-  DBUG_ENTER("ha_tina::reset");
-  ha_tina::extra(HA_EXTRA_RESET);
-  DBUG_RETURN(0);
+/*
+  Set end_pos to the last valid byte of continuous area, closest
+  to the given "hole", stored in the buffer. "Valid" here means,
+  not listed in the chain of deleted records ("holes").
+*/
+bool ha_tina::get_write_pos(off_t *end_pos, tina_set *closest_hole)
+{
+  if (closest_hole == chain_ptr) /* no more chains */
+    *end_pos= file_buff->end();
+  else
+    *end_pos= min(file_buff->end(),
+                  closest_hole->begin);
+  return (closest_hole != chain_ptr) && (*end_pos == closest_hole->begin);
 }
 
 
 /*
-  Called after deletes, inserts, and updates. This is where we clean up all of
-  the dead space we have collected while writing the file. 
+  Called after each table scan. In particular after deletes,
+  and updates. In the last case we employ chain of deleted
+  slots to clean up all of the dead space we have collected while
+  performing deletes/updates.
 */
 int ha_tina::rnd_end()
 {
+  char updated_fname[FN_REFLEN];
+  off_t file_buffer_start= 0;
   DBUG_ENTER("ha_tina::rnd_end");
 
   records_is_known= 1;
 
-  /* First position will be truncate position, second will be increment */
   if ((chain_ptr - chain)  > 0)
   {
-    tina_set *ptr;
-    off_t length;
+    tina_set *ptr= chain;
 
-    /* 
-      Setting up writable map, this will contain all of the data after the
-      get_mmap call that we have added to the file.
+    /*
+      Re-read the beginning of a file (as the buffer should point to the
+      end of file after the scan).
     */
-    if (get_mmap(share, 1) > 0) 
-      DBUG_RETURN(-1);
-    length= share->file_stat.st_size;
+    file_buff->init_buff(data_file);
 
     /*
-      The sort handles updates/deletes with random orders.
-      It also sorts so that we move the final blocks to the
-      beginning so that we move the smallest amount of data possible.
+      The sort is needed when there were updates/deletes with random orders.
+      It sorts so that we move the firts blocks to the beginning.
     */
-    qsort(chain, (size_t)(chain_ptr - chain), sizeof(tina_set), (qsort_cmp)sort_set);
-    for (ptr= chain; ptr < chain_ptr; ptr++)
+    qsort(chain, (size_t)(chain_ptr - chain), sizeof(tina_set),
+          (qsort_cmp)sort_set);
+
+    off_t write_begin= 0, write_end;
+
+    /* create the file to write updated table if it wasn't yet created */
+    if (open_update_temp_file_if_needed())
+      DBUG_RETURN(-1);
+
+    /* write the file with updated info */
+    while ((file_buffer_start != -1))     // while not end of file
     {
-      memmove(share->mapped_file + ptr->begin, share->mapped_file + ptr->end,
-              length - (size_t)ptr->end);
-      length= length - (size_t)(ptr->end - ptr->begin);
+      bool in_hole= get_write_pos(&write_end, ptr);
+
+      /* if there is something to write, write it */
+      if ((write_end - write_begin) &&
+          (my_write(update_temp_file,
+                    (byte*)(file_buff->ptr() +
+                            (write_begin - file_buff->start())),
+                    write_end - write_begin, MYF_RW)))
+        goto error;
+
+      if (in_hole)
+      {
+        /* skip hole */
+        while (file_buff->end() <= ptr->end && file_buffer_start != -1)
+          file_buffer_start= file_buff->read_next();
+        write_begin= ptr->end;
+        ptr++;
+      }
+      else
+        write_begin= write_end;
+
+      if (write_end == file_buff->end())
+        file_buffer_start= file_buff->read_next(); /* shift the buffer */
+
     }
 
-    /* Invalidate all cached mmap pages */
-    if (free_mmap(share))
+    if (my_sync(update_temp_file, MYF(MY_WME)) ||
+        my_close(update_temp_file, MYF(0)))
       DBUG_RETURN(-1);
 
-    /* Truncate the file to the new size */
-    if (my_chsize(share->data_file, length, 0, MYF(MY_WME)))
+    share->update_file_opened= FALSE;
+
+    if (share->tina_write_opened)
+    {
+      if (my_close(share->tina_write_filedes, MYF(0)))
+        DBUG_RETURN(-1);
+      /*
+        Mark that the writer fd is closed, so that init_tina_writer()
+        will reopen it later.
+      */
+      share->tina_write_opened= FALSE;
+    }
+
+    /*
+      Close opened fildes's. Then move updated file in place
+      of the old datafile.
+    */
+    if (my_close(data_file, MYF(0)) ||
+        my_rename(fn_format(updated_fname, share->table_name, "", CSN_EXT,
+                            MY_REPLACE_EXT | MY_UNPACK_FILENAME),
+                  share->data_file_name, MYF(0)))
       DBUG_RETURN(-1);
 
-    if (get_mmap(share, 0) > 0) 
+    /* Open the file again */
+    if (((data_file= my_open(share->data_file_name, O_RDONLY, MYF(0))) == -1))
       DBUG_RETURN(-1);
+    /*
+      The datafile is consistent at this point and the write filedes is
+      closed, so nothing worrying will happen to it in case of a crash.
+      Here we record this fact to the meta-file.
+    */
+    (void)write_meta_file(share->meta_file, share->rows_recorded, FALSE);
   }
 
   DBUG_RETURN(0);
+error:
+  my_close(update_temp_file, MYF(0));
+  share->update_file_opened= FALSE;
+  DBUG_RETURN(-1);
 }
 
-/* 
-  DELETE without WHERE calls it
-*/
-int ha_tina::delete_all_rows()
-{
-  DBUG_ENTER("ha_tina::delete_all_rows");
 
-  if (!records_is_known)
-    return (my_errno=HA_ERR_WRONG_COMMAND);
+/*
+  Repair CSV table in the case, it is crashed.
 
-  /* Invalidate all cached mmap pages */
-  if (free_mmap(share)) 
-    DBUG_RETURN(-1);
+  SYNOPSIS
+    repair()
+    thd         The thread, performing repair
+    check_opt   The options for repair. We do not use it currently.
+
+  DESCRIPTION
+    If the file is empty, change # of rows in the file and complete recovery.
+    Otherwise, scan the table looking for bad rows. If none were found,
+    we mark file as a good one and return. If a bad row was encountered,
+    we truncate the datafile up to the last good row.
+
+   TODO: Make repair more clever - it should try to recover subsequent
+         rows (after the first bad one) as well.
+*/
+
+int ha_tina::repair(THD* thd, HA_CHECK_OPT* check_opt)
+{
+  char repaired_fname[FN_REFLEN];
+  byte *buf;
+  File repair_file;
+  int rc;
+  ha_rows rows_repaired= 0;
+  off_t write_begin= 0, write_end;
+  DBUG_ENTER("ha_tina::repair");
+
+  /* empty file */
+  if (!share->saved_data_file_length)
+  {
+    share->rows_recorded= 0;
+    goto end;
+  }
+
+  /* Don't assert in field::val() functions */
+  table->use_all_columns();
+  if (!(buf= (byte*) my_malloc(table->s->reclength, MYF(MY_WME))))
+    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+
+  /* position buffer to the start of the file */
+  file_buff->init_buff(data_file);
+
+  /*
+    Local_saved_data_file_length is initialized during the lock phase.
+    Sometimes this is not getting executed before ::repair (e.g. for
+    the log tables). We set it manually here.
+  */
+  local_saved_data_file_length= share->saved_data_file_length;
+  /* set current position to the beginning of the file */
+  current_position= next_position= 0;
+
+  /* Read the file row-by-row. If everything is ok, repair is not needed. */
+  while (!(rc= find_current_row(buf)))
+  {
+    rows_repaired++;
+    current_position= next_position;
+  }
+
+  my_free((char*)buf, MYF(0));
+
+  if (rc == HA_ERR_END_OF_FILE)
+  {
+    /*
+      All rows were read ok until end of file, the file does not need repair.
+      If rows_recorded != rows_repaired, we should update rows_recorded value
+      to the current amount of rows.
+    */
+    share->rows_recorded= rows_repaired;
+    goto end;
+  }
+
+  /*
+    Otherwise we've encountered a bad row => repair is needed.
+    Let us create a temporary file.
+  */
+  if ((repair_file= my_create(fn_format(repaired_fname, share->table_name,
+                                        "", CSN_EXT,
+                                        MY_REPLACE_EXT|MY_UNPACK_FILENAME),
+                           0, O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
+    DBUG_RETURN(HA_ERR_CRASHED_ON_REPAIR);
+
+  file_buff->init_buff(data_file);
 
-  int rc= my_chsize(share->data_file, 0, 0, MYF(MY_WME));
 
-  if (get_mmap(share, 0) > 0) 
+  /* we just truncated the file up to the first bad row. update rows count. */
+  share->rows_recorded= rows_repaired;
+
+  /* write repaired file */
+  while (1)
+  {
+    write_end= min(file_buff->end(), current_position);
+    if ((write_end - write_begin) &&
+        (my_write(repair_file, (byte*)file_buff->ptr(),
+                  write_end - write_begin, MYF_RW)))
+      DBUG_RETURN(-1);
+
+    write_begin= write_end;
+    if (write_end== current_position)
+      break;
+    else
+      file_buff->read_next(); /* shift the buffer */
+  }
+
+  /*
+    Close the files and rename repaired file to the datafile.
+    We have to close the files, as on Windows one cannot rename
+    a file, which descriptor is still open. EACCES will be returned
+    when trying to delete the "to"-file in my_rename().
+  */
+  if (my_close(data_file,MYF(0)) || my_close(repair_file, MYF(0)) ||
+      my_rename(repaired_fname, share->data_file_name, MYF(0)))
     DBUG_RETURN(-1);
 
-  records=0;
-  DBUG_RETURN(rc);
+  /* Open the file again, it should now be repaired */
+  if ((data_file= my_open(share->data_file_name, O_RDWR|O_APPEND,
+                          MYF(0))) == -1)
+     DBUG_RETURN(-1);
+
+  /* Set new file size. The file size will be updated by ::update_status() */
+  local_saved_data_file_length= (size_t) current_position;
+
+end:
+  share->crashed= FALSE;
+  DBUG_RETURN(HA_ADMIN_OK);
 }
 
 /*
-  Always called by the start of a transaction (or by "lock tables");
+  DELETE without WHERE calls this
 */
-int ha_tina::external_lock(THD *thd, int lock_type)
+
+int ha_tina::delete_all_rows()
 {
-  DBUG_ENTER("ha_tina::external_lock");
-  DBUG_RETURN(0);          // No external locking
+  int rc;
+  DBUG_ENTER("ha_tina::delete_all_rows");
+
+  if (!records_is_known)
+    DBUG_RETURN(my_errno=HA_ERR_WRONG_COMMAND);
+
+  if (!share->tina_write_opened)
+    if (init_tina_writer())
+      DBUG_RETURN(-1);
+
+  /* Truncate the file to zero size */
+  rc= my_chsize(share->tina_write_filedes, 0, 0, MYF(MY_WME));
+
+  stats.records=0;
+  DBUG_RETURN(rc);
 }
 
-/* 
+/*
   Called by the database to lock the table. Keep in mind that this
   is an internal lock.
 */
@@ -926,19 +1440,94 @@
   this (the database will call ::open() if it needs to).
 */
 
-int ha_tina::create(const char *name, TABLE *table_arg, HA_CREATE_INFO *create_info)
+int ha_tina::create(const char *name, TABLE *table_arg,
+                    HA_CREATE_INFO *create_info)
 {
   char name_buff[FN_REFLEN];
   File create_file;
   DBUG_ENTER("ha_tina::create");
 
-  if ((create_file= my_create(fn_format(name_buff,name,"",".CSV",MY_REPLACE_EXT|MY_UNPACK_FILENAME),0,
+  if ((create_file= my_create(fn_format(name_buff, name, "", CSM_EXT,
+                                        MY_REPLACE_EXT|MY_UNPACK_FILENAME), 0,
                               O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
     DBUG_RETURN(-1);
 
-  my_close(create_file,MYF(0));
+  write_meta_file(create_file, 0, FALSE);
+  my_close(create_file, MYF(0));
+
+  if ((create_file= my_create(fn_format(name_buff, name, "", CSV_EXT,
+                                        MY_REPLACE_EXT|MY_UNPACK_FILENAME),0,
+                              O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
+    DBUG_RETURN(-1);
+
+  my_close(create_file, MYF(0));
 
   DBUG_RETURN(0);
 }
 
-#endif /* enable CSV */
+int ha_tina::check(THD* thd, HA_CHECK_OPT* check_opt)
+{
+  int rc= 0;
+  byte *buf;
+  const char *old_proc_info;
+  ha_rows count= share->rows_recorded;
+  DBUG_ENTER("ha_tina::check");
+
+  old_proc_info= thd_proc_info(thd, "Checking table");
+  if (!(buf= (byte*) my_malloc(table->s->reclength, MYF(MY_WME))))
+    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+
+  /* position buffer to the start of the file */
+  file_buff->init_buff(data_file);
+
+  /*
+    Local_saved_data_file_length is initialized during the lock phase.
+    Check does not use store_lock in certain cases. So, we set it
+    manually here.
+  */
+  local_saved_data_file_length= share->saved_data_file_length;
+  /* set current position to the beginning of the file */
+  current_position= next_position= 0;
+  /* Read the file row-by-row. If everything is ok, repair is not needed. */
+  while (!(rc= find_current_row(buf)))
+  {
+    count--;
+    current_position= next_position;
+  }
+
+  my_free((char*)buf, MYF(0));
+  thd_proc_info(thd, old_proc_info);
+
+  if ((rc != HA_ERR_END_OF_FILE) || count)
+  {
+    share->crashed= TRUE;
+    DBUG_RETURN(HA_ADMIN_CORRUPT);
+  }
+  else
+    DBUG_RETURN(HA_ADMIN_OK);
+}
+
+
+bool ha_tina::check_if_incompatible_data(HA_CREATE_INFO *info,
+					   uint table_changes)
+{
+  return COMPATIBLE_DATA_YES;
+}
+
+struct st_mysql_storage_engine csv_storage_engine=
+{ MYSQL_HANDLERTON_INTERFACE_VERSION, &tina_hton };
+
+mysql_declare_plugin(csv)
+{
+  MYSQL_STORAGE_ENGINE_PLUGIN,
+  &csv_storage_engine,
+  "CSV",
+  "Brian Aker, MySQL AB",
+  "CSV storage engine",
+  tina_init_func, /* Plugin Init */
+  tina_done_func, /* Plugin Deinit */
+  0x0100 /* 1.0 */,
+  0
+}
+mysql_declare_plugin_end;
+

--- 1.49.21.3/ndb/src/mgmclient/CommandInterpreter.cpp	2006-08-29 13:45:10 +08:00
+++ 1.72/storage/ndb/src/mgmclient/CommandInterpreter.cpp	2006-08-29 13:45:10 +08:00
@@ -16,14 +16,7 @@
 
 #include <ndb_global.h>
 #include <my_sys.h>
-
-//#define HAVE_GLOBAL_REPLICATION
-
 #include <Vector.hpp>
-#ifdef  HAVE_GLOBAL_REPLICATION
-#include "../rep/repapi/repapi.h"
-#endif
-
 #include <mgmapi.h>
 #include <util/BaseString.hpp>
 
@@ -167,11 +160,6 @@
   int m_verbose;
   int try_reconnect;
   int m_error;
-#ifdef HAVE_GLOBAL_REPLICATION  
-  NdbRepHandle m_repserver;
-  const char *rep_host;
-  bool rep_connected;
-#endif
   struct NdbThread* m_event_thread;
   NdbMutex *m_print_mutex;
 };
@@ -236,10 +224,6 @@
 #include <NdbMem.h>
 #include <EventLogger.hpp>
 #include <signaldata/SetLogLevelOrd.hpp>
-#include <signaldata/GrepImpl.hpp>
-#ifdef HAVE_GLOBAL_REPLICATION
-
-#endif // HAVE_GLOBAL_REPLICATION
 #include "MgmtErrorReporter.hpp"
 #include <Parser.hpp>
 #include <SocketServer.hpp>
@@ -267,9 +251,6 @@
 "---------------------------------------------------------------------------\n"
 "HELP                                   Print help text\n"
 "HELP COMMAND                           Print detailed help for COMMAND(e.g. SHOW)\n"
-#ifdef HAVE_GLOBAL_REPLICATION
-"HELP REPLICATION                       Help for global replication\n"
-#endif // HAVE_GLOBAL_REPLICATION
 #ifdef VM_TRACE // DEBUG ONLY
 "HELP DEBUG                             Help for debug compiled version\n"
 #endif
@@ -293,9 +274,6 @@
 "EXIT SINGLE USER MODE                  Exit single user mode\n"
 "<id> STATUS                            Print status\n"
 "<id> CLUSTERLOG {<category>=<level>}+  Set log level for cluster log\n"
-#ifdef HAVE_GLOBAL_REPLICATION
-"REP CONNECT <host:port>                Connect to REP server on host:port\n"
-#endif
 "PURGE STALE SESSIONS                   Reset reserved nodeid's in the mgmt server\n"
 "CONNECT [<connectstring>]              Connect to management server (reconnect if already connected)\n"
 "QUIT                                   Quit management client\n"
@@ -595,39 +573,6 @@
 ;
 
 
-#ifdef HAVE_GLOBAL_REPLICATION
-static const char* helpTextRep =
-"---------------------------------------------------------------------------\n"
-" NDB Cluster -- Management Client -- Help for Global Replication\n"
-"---------------------------------------------------------------------------\n"
-"Commands should be executed on the standby NDB Cluster\n"
-"These features are in an experimental release state.\n"
-"\n"
-"Simple Commands:\n"
-"REP START              Start Global Replication\n" 
-"REP START REQUESTOR    Start Global Replication Requestor\n" 
-"REP STATUS             Show Global Replication status\n" 
-"REP STOP               Stop Global Replication\n"
-"REP STOP REQUESTOR     Stop Global Replication Requestor\n"
-"\n" 
-"Advanced Commands:\n"
-"REP START <protocol>   Starts protocol\n"
-"REP STOP <protocol>    Stops protocol\n"
-"<protocol> = TRANSFER | APPLY | DELETE\n"
-"\n"
-#ifdef VM_TRACE // DEBUG ONLY
-"Debugging commands:\n"
-"REP DELETE             Removes epochs stored in primary and standy systems\n"
-"REP DROP <tableid>     Drop a table in SS identified by table id\n"
-"REP SLOWSTOP           Stop Replication (Tries to synchonize with primary)\n" 
-"REP FASTSTOP           Stop Replication (Stops in consistent state)\n" 
-"<component> = SUBSCRIPTION\n"
-"              METALOG | METASCAN | DATALOG | DATASCAN\n"
-"              REQUESTOR | TRANSFER | APPLY | DELETE\n"
-#endif
-;
-#endif // HAVE_GLOBAL_REPLICATION
-
 #ifdef VM_TRACE // DEBUG ONLY
 static const char* helpTextDebug =
 "---------------------------------------------------------------------------\n"
@@ -680,10 +625,6 @@
   {"PURGE STALE SESSIONS", helpTextPurgeStaleSessions},
   {"CONNECT", helpTextConnect},
   {"QUIT", helpTextQuit},
-#ifdef HAVE_GLOBAL_REPLICATION
-  {"REPLICATION", helpTextRep},
-  {"REP", helpTextRep},
-#endif // HAVE_GLOBAL_REPLICATION
 #ifdef VM_TRACE // DEBUG ONLY
   {"DEBUG", helpTextDebug},
 #endif //VM_TRACE
@@ -723,11 +664,6 @@
   m_event_thread= NULL;
   try_reconnect = 0;
   m_print_mutex= NdbMutex_Create();
-#ifdef HAVE_GLOBAL_REPLICATION
-  rep_host = NULL;
-  m_repserver = NULL;
-  rep_connected = false;
-#endif
 }
 
 /*
@@ -1063,13 +999,6 @@
     executePurge(allAfterFirstToken);
     DBUG_RETURN(true);
   } 
-#ifdef HAVE_GLOBAL_REPLICATION
-  else if(strcasecmp(firstToken, "REPLICATION") == 0 ||
-	  strcasecmp(firstToken, "REP") == 0) {
-    executeRep(allAfterFirstToken);
-    DBUG_RETURN(true);
-  }
-#endif // HAVE_GLOBAL_REPLICATION
   else if(strcasecmp(firstToken, "ENTER") == 0 &&
 	  allAfterFirstToken != NULL &&
 	  strncasecmp(allAfterFirstToken, "SINGLE USER MODE ", 
@@ -1611,8 +1540,6 @@
       case NDB_MGM_NODE_TYPE_UNKNOWN:
         ndbout << "Error: Unknown Node Type" << endl;
         return;
-      case NDB_MGM_NODE_TYPE_REP:
-	abort();
       }
     }
 
@@ -2565,226 +2492,5 @@
   ndbout << "Invalid arguments: expected <BackupId>" << endl;
   return;
 }
-
-#ifdef HAVE_GLOBAL_REPLICATION
-/*****************************************************************************
- * Global Replication
- *
- * For information about the different commands, see
- * GrepReq::Request in file signaldata/grepImpl.cpp.
- *
- * Below are commands as of 2003-07-05 (may change!):
- * START = 0,            ///< Start Global Replication (all phases)
- * START_METALOG = 1,    ///< Start Global Replication (all phases)
- * START_METASCAN = 2,   ///< Start Global Replication (all phases)
- * START_DATALOG = 3,    ///< Start Global Replication (all phases)
- * START_DATASCAN = 4,   ///< Start Global Replication (all phases)
- * START_REQUESTOR = 5,  ///< Start Global Replication (all phases)
- * ABORT = 6,            ///< Immediate stop (removes subscription)
- * SLOW_STOP = 7,        ///< Stop after finishing applying current GCI epoch
- * FAST_STOP = 8,        ///< Stop after finishing applying all PS GCI epochs
- * START_TRANSFER = 9,   ///< Start SS-PS transfer
- * STOP_TRANSFER = 10,   ///< Stop SS-PS transfer
- * START_APPLY = 11,     ///< Start applying GCI epochs in SS
- * STOP_APPLY = 12,      ///< Stop applying GCI epochs in SS
- * STATUS = 13,           ///< Status
- * START_SUBSCR = 14,
- * REMOVE_BUFFERS = 15,
- * DROP_TABLE = 16
-
- *****************************************************************************/
-
-void
-CommandInterpreter::executeRep(char* parameters) 
-{
-  if (emptyString(parameters)) {
-    ndbout << helpTextRep;
-    return;
-  }
-
-  char * line = my_strdup(parameters,MYF(MY_WME));
-  My_auto_ptr<char> ap1((char*)line);
-  char * firstToken = strtok(line, " ");
-  
-  struct ndb_rep_reply  reply;
-  unsigned int          repId;
-
-
-  if (!strcasecmp(firstToken, "CONNECT")) {
-    char * host = strtok(NULL, "\0");
-    for (unsigned int i = 0; i < strlen(host); ++i) {
-      host[i] = tolower(host[i]);
-    }
-    
-    if(host == NULL)
-    {
-      ndbout_c("host:port must be specified.");
-      return;
-    }
-    
-    if(rep_connected) {
-      if(m_repserver != NULL) {
-	ndb_rep_disconnect(m_repserver);
-	rep_connected = false;
-      }       
-    }
-          
-    if(m_repserver == NULL)
-      m_repserver = ndb_rep_create_handle();
-    if(ndb_rep_connect(m_repserver, host) < 0)
-      ndbout_c("Failed to connect to %s", host); 
-    else
-      rep_connected=true;
-    return;
-    
-    if(!rep_connected) {
-      ndbout_c("Not connected to REP server");
-    }
-  }
-    
-  /********
-   * START 
-   ********/
-  if (!strcasecmp(firstToken, "START")) {
-    
-    unsigned int          req;
-    char *startType = strtok(NULL, "\0");
-    
-    if (startType == NULL) {                
-      req = GrepReq::START;
-    } else if (!strcasecmp(startType, "SUBSCRIPTION")) {  
-      req = GrepReq::START_SUBSCR;
-    } else if (!strcasecmp(startType, "METALOG")) { 
-      req = GrepReq::START_METALOG;
-    } else if (!strcasecmp(startType, "METASCAN")) {
-      req = GrepReq::START_METASCAN;
-    } else if (!strcasecmp(startType, "DATALOG")) {
-      req = GrepReq::START_DATALOG;
-    } else if (!strcasecmp(startType, "DATASCAN")) {
-      req = GrepReq::START_DATASCAN;
-    } else if (!strcasecmp(startType, "REQUESTOR")) {
-      req = GrepReq::START_REQUESTOR;
-    } else if (!strcasecmp(startType, "TRANSFER")) {
-      req = GrepReq::START_TRANSFER;
-    } else if (!strcasecmp(startType, "APPLY")) {
-      req = GrepReq::START_APPLY;
-    } else if (!strcasecmp(startType, "DELETE")) {
-      req = GrepReq::START_DELETE;
-    } else {
-      ndbout_c("Illegal argument to command 'REPLICATION START'");
-      return;
-    }
-
-    int result = ndb_rep_command(m_repserver, req, &repId, &reply);
-    
-    if (result != 0) {
-      ndbout << "Start of Global Replication failed" << endl;
-    } else {
-      ndbout << "Start of Global Replication ordered" << endl;
-    }
-    return;
-  }
-
-  /********
-   * STOP
-   ********/
-  if (!strcasecmp(firstToken, "STOP")) {    
-    unsigned int          req;
-    char *startType = strtok(NULL, " ");
-    unsigned int epoch = 0;
-    
-    if (startType == NULL) {                 
-      /**
-       * Stop immediately
-       */
-      req = GrepReq::STOP;
-    } else if (!strcasecmp(startType, "EPOCH")) {  
-      char *strEpoch = strtok(NULL, "\0");
-      if(strEpoch == NULL) {
-	ndbout_c("Epoch expected!");
-	return;
-      }
-      req = GrepReq::STOP;
-      epoch=atoi(strEpoch);      
-    } else if (!strcasecmp(startType, "SUBSCRIPTION")) {  
-      req = GrepReq::STOP_SUBSCR;
-    } else if (!strcasecmp(startType, "METALOG")) { 
-      req = GrepReq::STOP_METALOG;
-    } else if (!strcasecmp(startType, "METASCAN")) {
-      req = GrepReq::STOP_METASCAN;
-    } else if (!strcasecmp(startType, "DATALOG")) {
-      req = GrepReq::STOP_DATALOG;
-    } else if (!strcasecmp(startType, "DATASCAN")) {
-      req = GrepReq::STOP_DATASCAN;
-    } else if (!strcasecmp(startType, "REQUESTOR")) {
-      req = GrepReq::STOP_REQUESTOR;
-    } else if (!strcasecmp(startType, "TRANSFER")) {
-      req = GrepReq::STOP_TRANSFER;
-    } else if (!strcasecmp(startType, "APPLY")) {
-      req = GrepReq::STOP_APPLY;
-    } else if (!strcasecmp(startType, "DELETE")) {
-      req = GrepReq::STOP_DELETE;
-    } else {
-      ndbout_c("Illegal argument to command 'REPLICATION STOP'");
-      return;
-    }
-    int result = ndb_rep_command(m_repserver, req, &repId, &reply, epoch);
-    
-    if (result != 0) {
-      ndbout << "Stop command failed" << endl;
-    } else {
-      ndbout << "Stop ordered" << endl;
-    }
-    return;
-  }
-
-  /*********
-   * STATUS
-   *********/
-  if (!strcasecmp(firstToken, "STATUS")) {
-    struct rep_state repstate;
-    int result = 
-      ndb_rep_get_status(m_repserver, &repId, &reply, &repstate);
-    
-    if (result != 0) {
-      ndbout << "Status request of Global Replication failed" << endl;
-    } else {
-      ndbout << "Status request of Global Replication ordered" << endl;
-      ndbout << "See printout at one of the DB nodes" << endl;
-      ndbout << "(Better status report is under development.)" << endl;
-      ndbout << " SubscriptionId " << repstate.subid 
-	     << " SubscriptionKey " << repstate.subkey << endl;
-    }
-    return;
-  }
-
-  /*********
-   * QUERY (see repapi.h for querable counters)
-   *********/
-  if (!strcasecmp(firstToken, "QUERY")) {
-    char *query = strtok(NULL, "\0");
-    int queryCounter=-1;
-    if(query != NULL) {
-      queryCounter = atoi(query);
-    }
-    struct rep_state repstate;
-    unsigned repId = 0;
-    int result = ndb_rep_query(m_repserver, (QueryCounter)queryCounter,
-			       &repId, &reply, &repstate);
-    
-    if (result != 0) {
-      ndbout << "Query repserver failed" << endl;
-    } else {
-      ndbout << "Query repserver sucessful" << endl;
-      ndbout_c("repstate : QueryCounter %d, f=%d l=%d"
-	       " nodegroups %d" , 
-	       repstate.queryCounter,
-	       repstate.first[0], repstate.last[0],
-	       repstate.no_of_nodegroups );
-    }
-    return;
-  }
-}
-#endif // HAVE_GLOBAL_REPLICATION
 
 template class Vector<char const*>;

--- 1.38.3.1/innobase/btr/btr0btr.c	2006-08-29 13:45:10 +08:00
+++ 1.45/storage/innobase/btr/btr0btr.c	2006-08-29 13:45:10 +08:00
@@ -5,7 +5,7 @@
 
 Created 6/2/1994 Heikki Tuuri
 *******************************************************/
- 
+
 #include "btr0btr.h"
 
 #ifdef UNIV_NONINL
@@ -56,7 +56,7 @@
 which are >= P in the alphabetical order, but < P1 if there is
 a next node pointer on the level, and P1 is its prefix.
 
-If a node pointer with a prefix P points to a non-leaf child, 
+If a node pointer with a prefix P points to a non-leaf child,
 then the leftmost record in the child must have the same
 prefix P. If it points to a leaf node, the child is not required
 to contain any record with a prefix equal to P. The leaf case
@@ -138,14 +138,14 @@
 	ulint	space;
 	ulint	root_page_no;
 	page_t*	root;
-	
+
 	space = dict_tree_get_space(tree);
 	root_page_no = dict_tree_get_page(tree);
 
 	root = btr_page_get(space, root_page_no, RW_X_LATCH, mtr);
 	ut_a((ibool)!!page_is_comp(root) ==
-			UT_LIST_GET_FIRST(tree->tree_indexes)->table->comp);
-	
+			dict_table_is_comp(tree->tree_index->table));
+
 	return(root);
 }
 
@@ -175,21 +175,25 @@
 			return(prev_rec);
 		}
 	}
-	
+
 	page = buf_frame_align(rec);
 	prev_page_no = btr_page_get_prev(page, mtr);
 	space = buf_frame_get_space_id(page);
-	
+
 	if (prev_page_no != FIL_NULL) {
 
 		prev_page = buf_page_get_with_no_latch(space, prev_page_no,
 									mtr);
 		/* The caller must already have a latch to the brother */
 		ut_ad((mtr_memo_contains(mtr, buf_block_align(prev_page),
-		      				MTR_MEMO_PAGE_S_FIX))
-		      || (mtr_memo_contains(mtr, buf_block_align(prev_page),
-		      				MTR_MEMO_PAGE_X_FIX)));
+						MTR_MEMO_PAGE_S_FIX))
+			|| (mtr_memo_contains(mtr, buf_block_align(prev_page),
+					MTR_MEMO_PAGE_X_FIX)));
 		ut_a(page_is_comp(prev_page) == page_is_comp(page));
+#ifdef UNIV_BTR_DEBUG
+		ut_a(btr_page_get_next(prev_page, mtr)
+				== buf_frame_get_page_no(page));
+#endif /* UNIV_BTR_DEBUG */
 
 		return(page_rec_get_prev(page_get_supremum_rec(prev_page)));
 	}
@@ -223,20 +227,24 @@
 			return(next_rec);
 		}
 	}
-	
+
 	page = buf_frame_align(rec);
 	next_page_no = btr_page_get_next(page, mtr);
 	space = buf_frame_get_space_id(page);
-	
+
 	if (next_page_no != FIL_NULL) {
 
 		next_page = buf_page_get_with_no_latch(space, next_page_no,
 									mtr);
 		/* The caller must already have a latch to the brother */
 		ut_ad((mtr_memo_contains(mtr, buf_block_align(next_page),
-		      				MTR_MEMO_PAGE_S_FIX))
-		      || (mtr_memo_contains(mtr, buf_block_align(next_page),
-		      				MTR_MEMO_PAGE_X_FIX)));
+						MTR_MEMO_PAGE_S_FIX))
+			|| (mtr_memo_contains(mtr, buf_block_align(next_page),
+						MTR_MEMO_PAGE_X_FIX)));
+#ifdef UNIV_BTR_DEBUG
+		ut_a(btr_page_get_prev(next_page, mtr)
+				== buf_frame_get_page_no(page));
+#endif /* UNIV_BTR_DEBUG */
 
 		ut_a(page_is_comp(next_page) == page_is_comp(page));
 		return(page_rec_get_next(page_get_infimum_rec(next_page)));
@@ -257,11 +265,11 @@
 	mtr_t*		mtr)	/* in: mtr */
 {
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
-			      				MTR_MEMO_PAGE_X_FIX));
+							MTR_MEMO_PAGE_X_FIX));
 	page_create(page, mtr,
-			UT_LIST_GET_FIRST(tree->tree_indexes)->table->comp);
+			dict_table_is_comp(tree->tree_index->table));
 	buf_block_align(page)->check_index_page_at_flush = TRUE;
-	
+
 	btr_page_set_index_id(page, tree->id, mtr);
 }
 
@@ -281,7 +289,7 @@
 	page_t*		new_page;
 
 	root = btr_root_get(tree, mtr);
-	
+
 	node_addr = flst_get_first(root + PAGE_HEADER
 					+ PAGE_BTR_IBUF_FREE_LIST, mtr);
 	ut_a(node_addr.page != FIL_NULL);
@@ -293,7 +301,7 @@
 #endif /* UNIV_SYNC_DEBUG */
 
 	flst_remove(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
-		    new_page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE,
+		new_page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE,
 									mtr);
 	ut_ad(flst_validate(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, mtr));
 
@@ -328,7 +336,7 @@
 	}
 
 	root = btr_root_get(tree, mtr);
-		
+
 	if (level == 0) {
 		seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
 	} else {
@@ -338,7 +346,7 @@
 	/* Parameter TRUE below states that the caller has made the
 	reservation for free extents, and thus we know that a page can
 	be allocated: */
-	
+
 	new_page_no = fseg_alloc_free_page_general(seg_header, hint_page_no,
 						file_direction, TRUE, mtr);
 	if (new_page_no == FIL_NULL) {
@@ -351,9 +359,9 @@
 #ifdef UNIV_SYNC_DEBUG
 	buf_page_dbg_add_level(new_page, SYNC_TREE_NODE_NEW);
 #endif /* UNIV_SYNC_DEBUG */
-							
+
 	return(new_page);
-}	
+}
 
 /******************************************************************
 Gets the number of pages in a B-tree. */
@@ -376,20 +384,20 @@
 	mtr_s_lock(dict_tree_get_lock(index->tree), &mtr);
 
 	root = btr_root_get(index->tree, &mtr);
-		
+
 	if (flag == BTR_N_LEAF_PAGES) {
 		seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
-		
+
 		fseg_n_reserved_pages(seg_header, &n, &mtr);
-		
+
 	} else if (flag == BTR_TOTAL_SIZE) {
 		seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_TOP;
 
 		n = fseg_n_reserved_pages(seg_header, &dummy, &mtr);
-		
+
 		seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
-		
-		n += fseg_n_reserved_pages(seg_header, &dummy, &mtr);		
+
+		n += fseg_n_reserved_pages(seg_header, &dummy, &mtr);
 	} else {
 		ut_error;
 	}
@@ -397,7 +405,7 @@
 	mtr_commit(&mtr);
 
 	return(n);
-}	
+}
 
 /******************************************************************
 Frees a page used in an ibuf tree. Puts the page to the free list of the
@@ -407,17 +415,17 @@
 btr_page_free_for_ibuf(
 /*===================*/
 	dict_tree_t*	tree,	/* in: index tree */
-	page_t*		page,	/* in: page to be freed, x-latched */	
+	page_t*		page,	/* in: page to be freed, x-latched */
 	mtr_t*		mtr)	/* in: mtr */
 {
 	page_t*		root;
 
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
-			      				MTR_MEMO_PAGE_X_FIX));
+							MTR_MEMO_PAGE_X_FIX));
 	root = btr_root_get(tree, mtr);
-	
+
 	flst_add_first(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
-		       page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, mtr);
+		page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, mtr);
 
 	ut_ad(flst_validate(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
 									mtr));
@@ -432,7 +440,7 @@
 btr_page_free_low(
 /*==============*/
 	dict_tree_t*	tree,	/* in: index tree */
-	page_t*		page,	/* in: page to be freed, x-latched */	
+	page_t*		page,	/* in: page to be freed, x-latched */
 	ulint		level,	/* in: page level */
 	mtr_t*		mtr)	/* in: mtr */
 {
@@ -442,12 +450,12 @@
 	ulint		page_no;
 
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
-			      				MTR_MEMO_PAGE_X_FIX));
+							MTR_MEMO_PAGE_X_FIX));
 	/* The page gets invalid for optimistic searches: increment the frame
 	modify clock */
 
 	buf_frame_modify_clock_inc(page);
-	
+
 	if (tree->type & DICT_IBUF) {
 
 		btr_page_free_for_ibuf(tree, page, mtr);
@@ -456,7 +464,7 @@
 	}
 
 	root = btr_root_get(tree, mtr);
-	
+
 	if (level == 0) {
 		seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
 	} else {
@@ -465,9 +473,9 @@
 
 	space = buf_frame_get_space_id(page);
 	page_no = buf_frame_get_page_no(page);
-	
+
 	fseg_free_page(seg_header, space, page_no, mtr);
-}	
+}
 
 /******************************************************************
 Frees a file page used in an index tree. NOTE: cannot free field external
@@ -477,17 +485,17 @@
 btr_page_free(
 /*==========*/
 	dict_tree_t*	tree,	/* in: index tree */
-	page_t*		page,	/* in: page to be freed, x-latched */	
+	page_t*		page,	/* in: page to be freed, x-latched */
 	mtr_t*		mtr)	/* in: mtr */
 {
 	ulint		level;
 
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
-			      				MTR_MEMO_PAGE_X_FIX));
+							MTR_MEMO_PAGE_X_FIX));
 	level = btr_page_get_level(page, mtr);
-	
+
 	btr_page_free_low(tree, page, level, mtr);
-}	
+}
 
 /******************************************************************
 Sets the child node file address in a node pointer. */
@@ -507,12 +515,12 @@
 	ut_ad(0 < btr_page_get_level(buf_frame_align(rec), mtr));
 	ut_ad(!rec_offs_comp(offsets) || rec_get_node_ptr_flag(rec));
 
-	/* The child address is in the last field */	
+	/* The child address is in the last field */
 	field = rec_get_nth_field(rec, offsets,
 					rec_offs_n_fields(offsets) - 1, &len);
 
 	ut_ad(len == 4);
-	
+
 	mlog_write_ulint(field, page_no, MLOG_4BYTES, mtr);
 }
 
@@ -536,7 +544,7 @@
 	page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
 
 	page = btr_page_get(space, page_no, RW_X_LATCH, mtr);
-	
+
 	return(page);
 }
 
@@ -567,14 +575,14 @@
 	ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree),
 							MTR_MEMO_X_LOCK));
 	ut_a(page_rec_is_user_rec(user_rec));
-	
+
 	ut_ad(dict_tree_get_page(tree) != buf_frame_get_page_no(page));
 
 	heap = mem_heap_create(100);
 
 	tuple = dict_tree_build_node_ptr(tree, user_rec, 0, heap,
 					 btr_page_get_level(page, mtr));
-	index = UT_LIST_GET_FIRST(tree->tree_indexes);
+	index = tree->tree_index;
 
 	/* In the following, we choose just any index from the tree as the
 	first parameter for btr_cur_search_to_nth_level. */
@@ -589,7 +597,7 @@
 						ULINT_UNDEFINED, &heap);
 
 	if (btr_node_ptr_get_child_page_no(node_ptr, offsets) !=
-                                                buf_frame_get_page_no(page)) {
+						buf_frame_get_page_no(page)) {
 		rec_t*	print_rec;
 		fputs("InnoDB: Dump of the child page:\n", stderr);
 		buf_page_print(buf_frame_align(page));
@@ -597,9 +605,9 @@
 		buf_page_print(buf_frame_align(node_ptr));
 
 		fputs("InnoDB: Corruption of an index tree: table ", stderr);
-		ut_print_name(stderr, NULL, index->table_name);
+		ut_print_name(stderr, NULL, TRUE, index->table_name);
 		fputs(", index ", stderr);
-		ut_print_name(stderr, NULL, index->name);
+		ut_print_name(stderr, NULL, FALSE, index->name);
 		fprintf(stderr, ",\n"
 "InnoDB: father ptr page no %lu, child page no %lu\n",
 			(ulong)
@@ -677,13 +685,13 @@
 		buf_page_dbg_add_level(ibuf_hdr_frame, SYNC_TREE_NODE_NEW);
 #endif /* UNIV_SYNC_DEBUG */
 		ut_ad(buf_frame_get_page_no(ibuf_hdr_frame)
- 						== IBUF_HEADER_PAGE_NO);
+						== IBUF_HEADER_PAGE_NO);
 		/* Allocate then the next page to the segment: it will be the
- 		tree root page */
+		tree root page */
 
- 		page_no = fseg_alloc_free_page(
+		page_no = fseg_alloc_free_page(
 				ibuf_hdr_frame + IBUF_HEADER
- 				+ IBUF_TREE_SEG_HEADER, IBUF_TREE_ROOT_PAGE_NO,
+				+ IBUF_TREE_SEG_HEADER, IBUF_TREE_ROOT_PAGE_NO,
 				FSP_UP, mtr);
 		ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO);
 
@@ -692,14 +700,14 @@
 		frame = fseg_create(space, 0, PAGE_HEADER + PAGE_BTR_SEG_TOP,
 									mtr);
 	}
-	
+
 	if (frame == NULL) {
 
 		return(FIL_NULL);
 	}
 
 	page_no = buf_frame_get_page_no(frame);
-	
+
 #ifdef UNIV_SYNC_DEBUG
 	buf_page_dbg_add_level(frame, SYNC_TREE_NODE_NEW);
 #endif /* UNIV_SYNC_DEBUG */
@@ -708,9 +716,9 @@
 		/* It is an insert buffer tree: initialize the free list */
 
 		ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO);
-		
+
 		flst_init(frame + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, mtr);
-	} else {	
+	} else {
 		/* It is a non-ibuf tree: create a file segment for leaf
 		pages */
 		fseg_create(space, page_no, PAGE_HEADER + PAGE_BTR_SEG_LEAF,
@@ -721,7 +729,7 @@
 		buf_page_dbg_add_level(frame, SYNC_TREE_NODE_NEW);
 #endif /* UNIV_SYNC_DEBUG */
 	}
-	
+
 	/* Create a new index page on the the allocated segment page */
 	page = page_create(frame, mtr, comp);
 	buf_block_align(page)->check_index_page_at_flush = TRUE;
@@ -731,7 +739,7 @@
 
 	/* Set the level of the new index page */
 	btr_page_set_level(page, 0, mtr);
-	
+
 	/* Set the next node and previous node fields */
 	btr_page_set_next(page, FIL_NULL, mtr);
 	btr_page_set_prev(page, FIL_NULL, mtr);
@@ -739,7 +747,7 @@
 	/* We reset the free bits for the page to allow creation of several
 	trees in the same mtr, otherwise the latch on a bitmap page would
 	prevent it because of the latching order */
-	
+
 	ibuf_reset_free_bits_with_type(type, page);
 
 	/* In the following assertion we test that two records of maximum
@@ -765,10 +773,10 @@
 	page_t*	root;
 	mtr_t	mtr;
 
-leaf_loop:	
+leaf_loop:
 	mtr_start(&mtr);
-	
-	root = btr_page_get(space, root_page_no, RW_X_LATCH, &mtr);	
+
+	root = btr_page_get(space, root_page_no, RW_X_LATCH, &mtr);
 
 	/* NOTE: page hash indexes are dropped when a page is freed inside
 	fsp0fsp. */
@@ -783,8 +791,8 @@
 	}
 top_loop:
 	mtr_start(&mtr);
-	
-	root = btr_page_get(space, root_page_no, RW_X_LATCH, &mtr);	
+
+	root = btr_page_get(space, root_page_no, RW_X_LATCH, &mtr);
 
 	finished = fseg_free_step_not_header(
 				root + PAGE_HEADER + PAGE_BTR_SEG_TOP, &mtr);
@@ -793,7 +801,7 @@
 	if (!finished) {
 
 		goto top_loop;
-	}	
+	}
 }
 
 /****************************************************************
@@ -812,14 +820,14 @@
 
 	root = btr_page_get(space, root_page_no, RW_X_LATCH, mtr);
 
-	btr_search_drop_page_hash_index(root);	
-top_loop:	
+	btr_search_drop_page_hash_index(root);
+top_loop:
 	finished = fseg_free_step(
 				root + PAGE_HEADER + PAGE_BTR_SEG_TOP, mtr);
 	if (!finished) {
 
 		goto top_loop;
-	}	
+	}
 }
 
 /*****************************************************************
@@ -845,8 +853,8 @@
 	ulint	max_ins_size2;
 
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
-			      				MTR_MEMO_PAGE_X_FIX));
-	ut_ad(!!page_is_comp(page) == index->table->comp);
+							MTR_MEMO_PAGE_X_FIX));
+	ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
 	data_size1 = page_get_data_size(page);
 	max_ins_size1 = page_get_max_insert_size_after_reorganize(page, 1);
 
@@ -872,7 +880,7 @@
 
 	page_create(page, mtr, page_is_comp(page));
 	buf_block_align(page)->check_index_page_at_flush = TRUE;
-	
+
 	/* Copy the records from the temporary space to the recreated page;
 	do not copy the lock bits yet */
 
@@ -880,7 +888,7 @@
 				page_get_infimum_rec(new_page), index, mtr);
 	/* Copy max trx id to recreated page */
 	page_set_max_trx_id(page, page_get_max_trx_id(new_page));
-	
+
 	if (!recovery) {
 		/* Update the record lock bitmaps */
 		lock_move_reorganize_page(page, new_page);
@@ -892,7 +900,7 @@
 	if (data_size1 != data_size2 || max_ins_size1 != max_ins_size2) {
 		buf_page_print(page);
 		buf_page_print(new_page);
-	        fprintf(stderr,
+		fprintf(stderr,
 "InnoDB: Error: page old data size %lu new data size %lu\n"
 "InnoDB: Error: page old max ins size %lu new max ins size %lu\n"
 "InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n",
@@ -955,7 +963,7 @@
 	mtr_t*	mtr)	/* in: mtr */
 {
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
-			      				MTR_MEMO_PAGE_X_FIX));
+							MTR_MEMO_PAGE_X_FIX));
 	btr_search_drop_page_hash_index(page);
 
 	/* Recreate the page: note that global data on page (possible
@@ -990,10 +998,10 @@
 	rec_t*		rec;
 	mem_heap_t*	heap;
 	dtuple_t*	node_ptr;
-	ulint		level;	
+	ulint		level;
 	rec_t*		node_ptr_rec;
 	page_cur_t*	page_cursor;
-	
+
 	root = btr_cur_get_page(cursor);
 	tree = btr_cur_get_tree(cursor);
 
@@ -1001,24 +1009,24 @@
 	ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree),
 							MTR_MEMO_X_LOCK));
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(root),
-			      				MTR_MEMO_PAGE_X_FIX));
+							MTR_MEMO_PAGE_X_FIX));
 	btr_search_drop_page_hash_index(root);
 
 	/* Allocate a new page to the tree. Root splitting is done by first
 	moving the root records to the new page, emptying the root, putting
 	a node pointer to the new page, and then splitting the new page. */
-	
+
 	new_page = btr_page_alloc(tree, 0, FSP_NO_DIR,
 				  btr_page_get_level(root, mtr), mtr);
 
 	btr_page_create(new_page, tree, mtr);
 
 	level = btr_page_get_level(root, mtr);
-	
+
 	/* Set the levels of the new index page and root page */
 	btr_page_set_level(new_page, level, mtr);
 	btr_page_set_level(root, level + 1, mtr);
-	
+
 	/* Set the next node and previous node fields of new page */
 	btr_page_set_next(new_page, FIL_NULL, mtr);
 	btr_page_set_prev(new_page, FIL_NULL, mtr);
@@ -1031,7 +1039,7 @@
 	perform a pessimistic update then we have stored the lock
 	information of the record to be inserted on the infimum of the
 	root page: we cannot discard the lock structs on the root page */
-	
+
 	lock_update_root_raise(new_page, root);
 
 	/* Create a memory heap where the node pointer is stored */
@@ -1039,17 +1047,17 @@
 
 	rec = page_rec_get_next(page_get_infimum_rec(new_page));
 	new_page_no = buf_frame_get_page_no(new_page);
-	
+
 	/* Build the node pointer (= node key and page address) for the
 	child */
 
 	node_ptr = dict_tree_build_node_ptr(tree, rec, new_page_no, heap,
-					                          level);
+								  level);
 	/* Reorganize the root to get free space */
 	btr_page_reorganize(root, cursor->index, mtr);
 
 	page_cursor = btr_cur_get_page_cur(cursor);
-	
+
 	/* Insert node pointer to the root */
 
 	page_cur_set_before_first(root, page_cursor);
@@ -1064,7 +1072,7 @@
 	node of a level: */
 
 	btr_set_min_rec_mark(node_ptr_rec, page_is_comp(root), mtr);
-		
+
 	/* Free the memory heap */
 	mem_heap_free(heap);
 
@@ -1073,15 +1081,14 @@
 /*	fprintf(stderr, "Root raise new page no %lu\n",
 					buf_frame_get_page_no(new_page)); */
 
-	ibuf_reset_free_bits(UT_LIST_GET_FIRST(tree->tree_indexes),
-								new_page);
+	ibuf_reset_free_bits(tree->tree_index, new_page);
 	/* Reposition the cursor to the child node */
 	page_cur_search(new_page, cursor->index, tuple,
 				PAGE_CUR_LE, page_cursor);
-	
+
 	/* Split the child and insert tuple */
 	return(btr_page_split_and_insert(cursor, tuple, mtr));
-}	
+}
 
 /*****************************************************************
 Decides if the page should be split at the convergence point of inserts
@@ -1105,22 +1112,22 @@
 	insert_point = btr_cur_get_rec(cursor);
 
 	if (page_header_get_ptr(page, PAGE_LAST_INSERT)
-	    == page_rec_get_next(insert_point)) {
+		== page_rec_get_next(insert_point)) {
+
+		infimum = page_get_infimum_rec(page);
 
-	     	infimum = page_get_infimum_rec(page);
-		
 		/* If the convergence is in the middle of a page, include also
 		the record immediately before the new insert to the upper
 		page. Otherwise, we could repeatedly move from page to page
 		lots of records smaller than the convergence point. */
 
 		if (infimum != insert_point
-		    && page_rec_get_next(infimum) != insert_point) {
+			&& page_rec_get_next(infimum) != insert_point) {
 
 			*split_rec = insert_point;
 		} else {
-	     		*split_rec = page_rec_get_next(insert_point);
-	     	}
+			*split_rec = page_rec_get_next(insert_point);
+		}
 
 		return(TRUE);
 	}
@@ -1162,7 +1169,7 @@
 		if (page_rec_is_supremum(next_rec)) {
 split_at_new:
 			/* Split at the new record to insert */
-	     		*split_rec = NULL;
+			*split_rec = NULL;
 		} else {
 			rec_t*	next_next_rec = page_rec_get_next(next_rec);
 			if (page_rec_is_supremum(next_next_rec)) {
@@ -1176,7 +1183,7 @@
 			index, as they can do the necessary checks of the right
 			search position just by looking at the records on this
 			page. */
-		
+
 			*split_rec = next_next_rec;
 		}
 
@@ -1199,7 +1206,7 @@
 					upper half-page */
 	btr_cur_t*	cursor,		/* in: cursor at which insert
 					should be made */
-	dtuple_t*	tuple)		/* in: tuple to insert */	
+	dtuple_t*	tuple)		/* in: tuple to insert */
 {
 	page_t*	page;
 	ulint	insert_size;
@@ -1216,7 +1223,7 @@
 	ulint*	offsets;
 
 	page = btr_cur_get_page(cursor);
-	
+
 	insert_size = rec_get_converted_size(cursor->index, tuple);
 	free_space  = page_get_free_space_of_empty(page_is_comp(page));
 
@@ -1263,15 +1270,15 @@
 		}
 
 		n++;
-		
+
 		if (incl_data + page_dir_calc_reserved_space(n)
-                    >= total_space / 2) {
+			>= total_space / 2) {
 
-                    	if (incl_data + page_dir_calc_reserved_space(n)
-                    	    <= free_space) {
-                    	    	/* The next record will be the first on
-                    	    	the right half page if it is not the
-                    	    	supremum record of page */
+			if (incl_data + page_dir_calc_reserved_space(n)
+				<= free_space) {
+				/* The next record will be the first on
+				the right half page if it is not the
+				supremum record of page */
 
 				if (rec == ins_rec) {
 					rec = NULL;
@@ -1286,7 +1293,7 @@
 				if (!page_rec_is_supremum(next_rec)) {
 					rec = next_rec;
 				}
-                    	}
+			}
 
 func_exit:
 			if (UNIV_LIKELY_NULL(heap)) {
@@ -1295,7 +1302,7 @@
 			return(rec);
 		}
 	}
-}		
+}
 
 /*****************************************************************
 Returns TRUE if the insert fits on the appropriate half-page with the
@@ -1323,7 +1330,7 @@
 	rec_t*	rec;
 	rec_t*	end_rec;
 	ulint*	offs;
-	
+
 	page = btr_cur_get_page(cursor);
 
 	ut_ad(!split_rec == !offsets);
@@ -1339,11 +1346,11 @@
 
 	total_data   = page_get_data_size(page) + insert_size;
 	total_n_recs = page_get_n_recs(page) + 1;
-	
+
 	/* We determine which records (from rec to end_rec, not including
 	end_rec) will end up on the other half page from tuple when it is
 	inserted. */
-	
+
 	if (split_rec == NULL) {
 		rec = page_rec_get_next(page_get_infimum_rec(page));
 		end_rec = page_rec_get_next(btr_cur_get_rec(cursor));
@@ -1351,14 +1358,14 @@
 	} else if (cmp_dtuple_rec(tuple, split_rec, offsets) >= 0) {
 
 		rec = page_rec_get_next(page_get_infimum_rec(page));
- 		end_rec = split_rec;
+		end_rec = split_rec;
 	} else {
 		rec = split_rec;
 		end_rec = page_get_supremum_rec(page);
 	}
 
 	if (total_data + page_dir_calc_reserved_space(total_n_recs)
-	    <= free_space) {
+		<= free_space) {
 
 		/* Ok, there will be enough available space on the
 		half page where the tuple is inserted */
@@ -1379,7 +1386,7 @@
 		total_n_recs--;
 
 		if (total_data + page_dir_calc_reserved_space(total_n_recs)
-                    <= free_space) {
+			<= free_space) {
 
 			/* Ok, there will be enough available space on the
 			half page where the tuple is inserted */
@@ -1391,7 +1398,7 @@
 	}
 
 	return(FALSE);
-}		
+}
 
 /***********************************************************
 Inserts a data tuple to a tree on a non-leaf level. It is assumed
@@ -1406,25 +1413,22 @@
 	mtr_t*		mtr)	/* in: mtr */
 {
 	big_rec_t*	dummy_big_rec;
-	btr_cur_t	cursor;		
+	btr_cur_t	cursor;
 	ulint		err;
 	rec_t*		rec;
 
 	ut_ad(level > 0);
-	
+
 	/* In the following, choose just any index from the tree as the
 	first parameter for btr_cur_search_to_nth_level. */
 
-	btr_cur_search_to_nth_level(UT_LIST_GET_FIRST(tree->tree_indexes),
-				    level, tuple, PAGE_CUR_LE,
-				    BTR_CONT_MODIFY_TREE,
-				    &cursor, 0, mtr);
+	btr_cur_search_to_nth_level(tree->tree_index,
+		level, tuple, PAGE_CUR_LE, BTR_CONT_MODIFY_TREE,
+		&cursor, 0, mtr);
 
 	err = btr_cur_pessimistic_insert(BTR_NO_LOCKING_FLAG
-					| BTR_KEEP_SYS_FLAG
-					| BTR_NO_UNDO_LOG_FLAG,
-					&cursor, tuple,
-					&rec, &dummy_big_rec, NULL, mtr);
+		| BTR_KEEP_SYS_FLAG | BTR_NO_UNDO_LOG_FLAG,
+		&cursor, tuple, &rec, &dummy_big_rec, NULL, mtr);
 	ut_a(err == DB_SUCCESS);
 }
 
@@ -1455,12 +1459,12 @@
 	ulint		lower_page_no;
 	ulint		upper_page_no;
 	dtuple_t*	node_ptr_upper;
-	mem_heap_t* 	heap;
+	mem_heap_t*	heap;
 
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
-			      				MTR_MEMO_PAGE_X_FIX));
+							MTR_MEMO_PAGE_X_FIX));
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(new_page),
-			      				MTR_MEMO_PAGE_X_FIX));
+							MTR_MEMO_PAGE_X_FIX));
 	ut_a(page_is_comp(page) == page_is_comp(new_page));
 
 	/* Create a memory heap where the data tuple is stored */
@@ -1477,12 +1481,12 @@
 		/* Look from the tree for the node pointer to page */
 		node_ptr = btr_page_get_father_node_ptr(tree, page, mtr);
 
-		/* Replace the address of the old child node (= page) with the 
+		/* Replace the address of the old child node (= page) with the
 		address of the new lower half */
 
 		btr_node_ptr_set_child_page_no(node_ptr,
 			rec_get_offsets(node_ptr,
-					UT_LIST_GET_FIRST(tree->tree_indexes),
+					tree->tree_index,
 					NULL, ULINT_UNDEFINED, &heap),
 			lower_page_no, mtr);
 		mem_heap_empty(heap);
@@ -1492,7 +1496,7 @@
 		lower_page = page;
 		upper_page = new_page;
 	}
-				   
+
 	/* Get the level of the split pages */
 	level = btr_page_get_level(page, mtr);
 
@@ -1500,13 +1504,13 @@
 	half */
 
 	node_ptr_upper = dict_tree_build_node_ptr(tree, split_rec,
-					     upper_page_no, heap, level);
+		upper_page_no, heap, level);
 
 	/* Insert it next to the pointer to the lower half. Note that this
 	may generate recursion leading to a split on the higher level. */
 
 	btr_insert_on_non_leaf_level(tree, level + 1, node_ptr_upper, mtr);
-		
+
 	/* Free the memory heap */
 	mem_heap_free(heap);
 
@@ -1515,13 +1519,17 @@
 	prev_page_no = btr_page_get_prev(page, mtr);
 	next_page_no = btr_page_get_next(page, mtr);
 	space = buf_frame_get_space_id(page);
-	
+
 	/* Update page links of the level */
-	
+
 	if (prev_page_no != FIL_NULL) {
 
 		prev_page = btr_page_get(space, prev_page_no, RW_X_LATCH, mtr);
 		ut_a(page_is_comp(prev_page) == page_is_comp(page));
+#ifdef UNIV_BTR_DEBUG
+		ut_a(btr_page_get_next(prev_page, mtr)
+				== buf_frame_get_page_no(page));
+#endif /* UNIV_BTR_DEBUG */
 
 		btr_page_set_next(prev_page, lower_page_no, mtr);
 	}
@@ -1533,7 +1541,7 @@
 
 		btr_page_set_prev(next_page, upper_page_no, mtr);
 	}
-	
+
 	btr_page_set_prev(lower_page, prev_page_no, mtr);
 	btr_page_set_next(lower_page, upper_page_no, mtr);
 	btr_page_set_level(lower_page, level, mtr);
@@ -1590,7 +1598,7 @@
 	mem_heap_empty(heap);
 	offsets = NULL;
 	tree = btr_cur_get_tree(cursor);
-	
+
 	ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree),
 							MTR_MEMO_X_LOCK));
 #ifdef UNIV_SYNC_DEBUG
@@ -1600,9 +1608,9 @@
 	page = btr_cur_get_page(cursor);
 
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
-			      				MTR_MEMO_PAGE_X_FIX));
+							MTR_MEMO_PAGE_X_FIX));
 	ut_ad(page_get_n_recs(page) >= 2);
-	
+
 	page_no = buf_frame_get_page_no(page);
 
 	/* 1. Decide the split record; split_rec == NULL means that the
@@ -1613,7 +1621,7 @@
 		direction = FSP_UP;
 		hint_page_no = page_no + 1;
 		split_rec = btr_page_get_sure_split_rec(cursor, tuple);
-		
+
 	} else if (btr_page_get_split_rec_to_right(cursor, &split_rec)) {
 		direction = FSP_UP;
 		hint_page_no = page_no + 1;
@@ -1631,7 +1639,7 @@
 	new_page = btr_page_alloc(tree, hint_page_no, direction,
 					btr_page_get_level(page, mtr), mtr);
 	btr_page_create(new_page, tree, mtr);
-	
+
 	/* 3. Calculate the first record on the upper half-page, and the
 	first record (move_limit) on original page which ends up on the
 	upper half */
@@ -1646,7 +1654,7 @@
 							cursor->index, tuple);
 		move_limit = page_rec_get_next(btr_cur_get_rec(cursor));
 	}
-	
+
 	/* 4. Do first the modifications in the tree structure */
 
 	btr_attach_half_pages(tree, page, first_rec, new_page, direction, mtr);
@@ -1670,7 +1678,7 @@
 		insert_will_fit = btr_page_insert_fits(cursor,
 					NULL, NULL, tuple, heap);
 	}
-	
+
 	if (insert_will_fit && (btr_page_get_level(page, mtr) == 0)) {
 
 		mtr_memo_release(mtr, dict_tree_get_lock(tree),
@@ -1737,7 +1745,7 @@
 		mem_heap_free(heap);
 		return(rec);
 	}
-	
+
 	/* 8. If insert did not fit, try page reorganization */
 
 	btr_page_reorganize(insert_page, cursor->index, mtr);
@@ -1749,7 +1757,7 @@
 	if (rec == NULL) {
 		/* The insert did not fit on the page: loop back to the
 		start of the function for a new split */
-		
+
 		/* We play safe and reset the free bits for new_page */
 		ibuf_reset_free_bits(cursor->index, new_page);
 
@@ -1771,8 +1779,8 @@
 				buf_frame_get_page_no(left_page),
 				buf_frame_get_page_no(right_page)); */
 
-	ut_ad(page_validate(left_page, UT_LIST_GET_FIRST(tree->tree_indexes)));
-	ut_ad(page_validate(right_page, UT_LIST_GET_FIRST(tree->tree_indexes)));
+	ut_ad(page_validate(left_page, tree->tree_index));
+	ut_ad(page_validate(right_page, tree->tree_index));
 
 	mem_heap_free(heap);
 	return(rec);
@@ -1787,28 +1795,32 @@
 	dict_tree_t*	tree __attribute__((unused)), /* in: index tree */
 	page_t*		page,	/* in: page to remove */
 	mtr_t*		mtr)	/* in: mtr */
-{	
+{
 	ulint	space;
 	ulint	prev_page_no;
 	page_t*	prev_page;
 	ulint	next_page_no;
 	page_t*	next_page;
-	
+
 	ut_ad(tree && page && mtr);
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
-			      				MTR_MEMO_PAGE_X_FIX));
+							MTR_MEMO_PAGE_X_FIX));
 	/* Get the previous and next page numbers of page */
 
 	prev_page_no = btr_page_get_prev(page, mtr);
 	next_page_no = btr_page_get_next(page, mtr);
 	space = buf_frame_get_space_id(page);
-	
+
 	/* Update page links of the level */
-	
+
 	if (prev_page_no != FIL_NULL) {
 
 		prev_page = btr_page_get(space, prev_page_no, RW_X_LATCH, mtr);
 		ut_a(page_is_comp(prev_page) == page_is_comp(page));
+#ifdef UNIV_BTR_DEBUG
+		ut_a(btr_page_get_next(prev_page, mtr)
+				== buf_frame_get_page_no(page));
+#endif /* UNIV_BTR_DEBUG */
 
 		btr_page_set_next(prev_page, next_page_no, mtr);
 	}
@@ -1817,11 +1829,15 @@
 
 		next_page = btr_page_get(space, next_page_no, RW_X_LATCH, mtr);
 		ut_a(page_is_comp(next_page) == page_is_comp(page));
+#ifdef UNIV_BTR_DEBUG
+		ut_a(btr_page_get_prev(next_page, mtr)
+				== buf_frame_get_page_no(page));
+#endif /* UNIV_BTR_DEBUG */
 
 		btr_page_set_prev(next_page, prev_page_no, mtr);
 	}
 }
-	
+
 /********************************************************************
 Writes the redo log record for setting an index record as the predefined
 minimum record. */
@@ -1906,15 +1922,14 @@
 	btr_cur_t	cursor;
 	ibool		compressed;
 	ulint		err;
-	
+
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
 							MTR_MEMO_PAGE_X_FIX));
 	/* Delete node pointer on father page */
 
 	node_ptr = btr_page_get_father_node_ptr(tree, page, mtr);
 
-	btr_cur_position(UT_LIST_GET_FIRST(tree->tree_indexes), node_ptr,
-								&cursor);
+	btr_cur_position(tree->tree_index, node_ptr, &cursor);
 	compressed = btr_cur_pessimistic_delete(&err, TRUE, &cursor, FALSE,
 									mtr);
 	ut_a(err == DB_SUCCESS);
@@ -1945,33 +1960,33 @@
 	ut_ad(btr_page_get_prev(page, mtr) == FIL_NULL);
 	ut_ad(btr_page_get_next(page, mtr) == FIL_NULL);
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
-			      				MTR_MEMO_PAGE_X_FIX));
+							MTR_MEMO_PAGE_X_FIX));
 	father_page = buf_frame_align(
 			btr_page_get_father_node_ptr(tree, page, mtr));
-	
+
 	page_level = btr_page_get_level(page, mtr);
-	index = UT_LIST_GET_FIRST(tree->tree_indexes);
+	index = tree->tree_index;
 
 	btr_search_drop_page_hash_index(page);
-	
+
 	/* Make the father empty */
 	btr_page_empty(father_page, mtr);
 
 	/* Move records to the father */
- 	page_copy_rec_list_end(father_page, page, page_get_infimum_rec(page),
+	page_copy_rec_list_end(father_page, page, page_get_infimum_rec(page),
 								index, mtr);
 	lock_update_copy_and_discard(father_page, page);
 
 	btr_page_set_level(father_page, page_level, mtr);
 
 	/* Free the file page */
-	btr_page_free(tree, page, mtr);		
+	btr_page_free(tree, page, mtr);
 
 	/* We play safe and reset the free bits for the father */
 	ibuf_reset_free_bits(index, father_page);
 	ut_ad(page_validate(father_page, index));
 	ut_ad(btr_check_node_ptr(tree, father_page, mtr));
-}	
+}
 
 /*****************************************************************
 Tries to merge the page first to the left immediate brother if such a
@@ -2014,7 +2029,7 @@
 	page = btr_cur_get_page(cursor);
 	tree = btr_cur_get_tree(cursor);
 	comp = page_is_comp(page);
-	ut_a((ibool)!!comp == cursor->index->table->comp);
+	ut_a((ibool)!!comp == dict_table_is_comp(cursor->index->table));
 
 	ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree),
 							MTR_MEMO_X_LOCK));
@@ -2037,16 +2052,24 @@
 	/* Decide the page to which we try to merge and which will inherit
 	the locks */
 
-	if (left_page_no != FIL_NULL) {
+	is_left = left_page_no != FIL_NULL;
+
+	if (is_left) {
 
-		is_left = TRUE;
 		merge_page = btr_page_get(space, left_page_no, RW_X_LATCH,
 									mtr);
+#ifdef UNIV_BTR_DEBUG
+		ut_a(btr_page_get_next(merge_page, mtr)
+				== buf_frame_get_page_no(page));
+#endif /* UNIV_BTR_DEBUG */
 	} else if (right_page_no != FIL_NULL) {
 
-		is_left = FALSE;
 		merge_page = btr_page_get(space, right_page_no, RW_X_LATCH,
 									mtr);
+#ifdef UNIV_BTR_DEBUG
+		ut_a(btr_page_get_prev(merge_page, mtr)
+				== buf_frame_get_page_no(page));
+#endif /* UNIV_BTR_DEBUG */
 	} else {
 		/* The page is the only one on the level, lift the records
 		to the father */
@@ -2054,7 +2077,7 @@
 
 		return;
 	}
-	
+
 	n_recs = page_get_n_recs(page);
 	data_size = page_get_data_size(page);
 	ut_a(page_is_comp(merge_page) == comp);
@@ -2071,7 +2094,7 @@
 	ut_ad(page_validate(merge_page, cursor->index));
 
 	max_ins_size = page_get_max_insert_size(merge_page, n_recs);
-	
+
 	if (data_size > max_ins_size) {
 
 		/* We have to reorganize merge_page */
@@ -2103,7 +2126,7 @@
 		mem_heap_t*	heap		= NULL;
 		ulint		offsets_[REC_OFFS_NORMAL_SIZE];
 		*offsets_ = (sizeof offsets_) / sizeof *offsets_;
-		/* Replace the address of the old child node (= page) with the 
+		/* Replace the address of the old child node (= page) with the
 		address of the merge page to the right */
 
 		btr_node_ptr_set_child_page_no(node_ptr,
@@ -2115,7 +2138,7 @@
 		}
 		btr_node_ptr_delete(tree, merge_page, mtr);
 	}
-	
+
 	/* Move records to the merge page */
 	if (is_left) {
 		orig_pred = page_rec_get_prev(
@@ -2136,14 +2159,14 @@
 	/* We have added new records to merge_page: update its free bits */
 	ibuf_update_free_bits_if_full(cursor->index, merge_page,
 					UNIV_PAGE_SIZE, ULINT_UNDEFINED);
-					
+
 	ut_ad(page_validate(merge_page, cursor->index));
 
 	/* Free the file page */
-	btr_page_free(tree, page, mtr);		
+	btr_page_free(tree, page, mtr);
 
 	ut_ad(btr_check_node_ptr(tree, merge_page, mtr));
-}	
+}
 
 /*****************************************************************
 Discards a page that is the only page on its level. */
@@ -2158,7 +2181,7 @@
 	rec_t*	node_ptr;
 	page_t*	father_page;
 	ulint	page_level;
-	
+
 	ut_ad(btr_page_get_prev(page, mtr) == FIL_NULL);
 	ut_ad(btr_page_get_next(page, mtr) == FIL_NULL);
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
@@ -2175,7 +2198,7 @@
 	btr_page_set_level(father_page, page_level, mtr);
 
 	/* Free the file page */
-	btr_page_free(tree, page, mtr);		
+	btr_page_free(tree, page, mtr);
 
 	if (buf_frame_get_page_no(father_page) == dict_tree_get_page(tree)) {
 		/* The father is the root page */
@@ -2183,14 +2206,13 @@
 		btr_page_empty(father_page, mtr);
 
 		/* We play safe and reset the free bits for the father */
-		ibuf_reset_free_bits(UT_LIST_GET_FIRST(tree->tree_indexes),
-								father_page);
+		ibuf_reset_free_bits(tree->tree_index, father_page);
 	} else {
 		ut_ad(page_get_n_recs(father_page) == 1);
 
 		btr_discard_only_page_on_level(tree, father_page, mtr);
 	}
-}	
+}
 
 /*****************************************************************
 Discards a page from a B-tree. This is used to remove the last record from
@@ -2209,10 +2231,9 @@
 	ulint		left_page_no;
 	ulint		right_page_no;
 	page_t*		merge_page;
-	ibool		is_left;
 	page_t*		page;
 	rec_t*		node_ptr;
-	
+
 	page = btr_cur_get_page(cursor);
 	tree = btr_cur_get_tree(cursor);
 
@@ -2222,20 +2243,26 @@
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
 							MTR_MEMO_PAGE_X_FIX));
 	space = dict_tree_get_space(tree);
-	
+
 	/* Decide the page which will inherit the locks */
 
 	left_page_no = btr_page_get_prev(page, mtr);
 	right_page_no = btr_page_get_next(page, mtr);
 
 	if (left_page_no != FIL_NULL) {
-		is_left = TRUE;
 		merge_page = btr_page_get(space, left_page_no, RW_X_LATCH,
 									mtr);
+#ifdef UNIV_BTR_DEBUG
+		ut_a(btr_page_get_next(merge_page, mtr)
+				== buf_frame_get_page_no(page));
+#endif /* UNIV_BTR_DEBUG */
 	} else if (right_page_no != FIL_NULL) {
-		is_left = FALSE;
 		merge_page = btr_page_get(space, right_page_no, RW_X_LATCH,
 									mtr);
+#ifdef UNIV_BTR_DEBUG
+		ut_a(btr_page_get_prev(merge_page, mtr)
+				== buf_frame_get_page_no(page));
+#endif /* UNIV_BTR_DEBUG */
 	} else {
 		btr_discard_only_page_on_level(tree, page, mtr);
 
@@ -2244,7 +2271,7 @@
 
 	ut_a(page_is_comp(merge_page) == page_is_comp(page));
 	btr_search_drop_page_hash_index(page);
-	
+
 	if (left_page_no == FIL_NULL && btr_page_get_level(page, mtr) > 0) {
 
 		/* We have to mark the leftmost node pointer on the right
@@ -2255,25 +2282,25 @@
 		ut_ad(page_rec_is_user_rec(node_ptr));
 
 		btr_set_min_rec_mark(node_ptr, page_is_comp(merge_page), mtr);
-	}	
-	
+	}
+
 	btr_node_ptr_delete(tree, page, mtr);
 
 	/* Remove the page from the level list */
 	btr_level_list_remove(tree, page, mtr);
 
-	if (is_left) {
+	if (left_page_no != FIL_NULL) {
 		lock_update_discard(page_get_supremum_rec(merge_page), page);
 	} else {
 		lock_update_discard(page_rec_get_next(
-				    page_get_infimum_rec(merge_page)), page);
+				page_get_infimum_rec(merge_page)), page);
 	}
 
 	/* Free the file page */
-	btr_page_free(tree, page, mtr);		
+	btr_page_free(tree, page, mtr);
 
 	ut_ad(btr_check_node_ptr(tree, merge_page, mtr));
-}	
+}
 
 #ifdef UNIV_BTR_PRINT
 /*****************************************************************
@@ -2297,7 +2324,7 @@
 	}
 
 	mtr_start(&mtr);
-	
+
 	root = btr_root_get(tree, &mtr);
 
 	seg = root + PAGE_HEADER + PAGE_BTR_SEG_TOP;
@@ -2313,7 +2340,7 @@
 		fseg_print(seg, &mtr);
 	}
 
-	mtr_commit(&mtr); 	
+	mtr_commit(&mtr);
 }
 
 /****************************************************************
@@ -2341,14 +2368,14 @@
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
 							MTR_MEMO_PAGE_X_FIX));
 	fprintf(stderr, "NODE ON LEVEL %lu page number %lu\n",
-	       (ulong) btr_page_get_level(page, mtr),
-	       (ulong) buf_frame_get_page_no(page));
-	
+		(ulong) btr_page_get_level(page, mtr),
+		(ulong) buf_frame_get_page_no(page));
+
 	index = UT_LIST_GET_FIRST(tree->tree_indexes);
 	page_print(page, index, width, width);
-	
+
 	n_recs = page_get_n_recs(page);
-	
+
 	page_cur_set_before_first(page, &cursor);
 	page_cur_move_to_next(&cursor);
 
@@ -2413,6 +2440,7 @@
 }
 #endif /* UNIV_BTR_PRINT */
 
+#ifdef UNIV_DEBUG
 /****************************************************************
 Checks that the node pointer to a page is appropriate. */
 
@@ -2436,28 +2464,29 @@
 	}
 
 	node_ptr = btr_page_get_father_node_ptr(tree, page, mtr);
- 
+
 	if (btr_page_get_level(page, mtr) == 0) {
 
 		return(TRUE);
 	}
-	
+
 	heap = mem_heap_create(256);
-		
+
 	node_ptr_tuple = dict_tree_build_node_ptr(
 				tree,
 				page_rec_get_next(page_get_infimum_rec(page)),
 				0, heap, btr_page_get_level(page, mtr));
-				
+
 	ut_a(cmp_dtuple_rec(node_ptr_tuple, node_ptr,
 			rec_get_offsets(node_ptr,
-			dict_tree_find_index(tree, node_ptr),
+			tree->tree_index,
 			NULL, ULINT_UNDEFINED, &heap)) == 0);
 
 	mem_heap_free(heap);
 
 	return(TRUE);
 }
+#endif /* UNIV_DEBUG */
 
 /****************************************************************
 Display identification information for a record. */
@@ -2481,7 +2510,7 @@
 
 ibool
 btr_index_rec_validate(
-/*====================*/
+/*===================*/
 					/* out: TRUE if ok */
 	rec_t*		rec,		/* in: index record */
 	dict_index_t*	index,		/* in: index */
@@ -2501,18 +2530,20 @@
 	page = buf_frame_align(rec);
 
 	if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
-	        /* The insert buffer index tree can contain records from any
-	        other index: we cannot check the number of fields or
-	        their length */
+		/* The insert buffer index tree can contain records from any
+		other index: we cannot check the number of fields or
+		their length */
 
-	        return(TRUE);
+		return(TRUE);
 	}
 
-	if (UNIV_UNLIKELY((ibool)!!page_is_comp(page) != index->table->comp)) {
+	if (UNIV_UNLIKELY((ibool)!!page_is_comp(page)
+			!= dict_table_is_comp(index->table))) {
 		btr_index_rec_validate_report(page, rec, index);
 		fprintf(stderr, "InnoDB: compact flag=%lu, should be %lu\n",
 			(ulong) !!page_is_comp(page),
-			(ulong) index->table->comp);
+			(ulong) dict_table_is_comp(index->table));
+
 		return(FALSE);
 	}
 
@@ -2546,12 +2577,12 @@
 		their type is CHAR. */
 
 		if ((dict_index_get_nth_field(index, i)->prefix_len == 0
-		    && len != UNIV_SQL_NULL && fixed_size
-		    && len != fixed_size)
+				&& len != UNIV_SQL_NULL && fixed_size
+				&& len != fixed_size)
 		   ||
 		   (dict_index_get_nth_field(index, i)->prefix_len > 0
-		    && len != UNIV_SQL_NULL
-		    && len >
+			   && len != UNIV_SQL_NULL
+			   && len >
 			   dict_index_get_nth_field(index, i)->prefix_len)) {
 
 			btr_index_rec_validate_report(page, rec, index);
@@ -2576,7 +2607,7 @@
 	if (UNIV_LIKELY_NULL(heap)) {
 		mem_heap_free(heap);
 	}
-	return(TRUE);			
+	return(TRUE);
 }
 
 /****************************************************************
@@ -2590,9 +2621,9 @@
 	page_t*		page,	/* in: index page */
 	dict_index_t*	index)	/* in: index */
 {
-	page_cur_t 	cur;
+	page_cur_t	cur;
 	ibool		ret	= TRUE;
-	
+
 	page_cur_set_before_first(page, &cur);
 	page_cur_move_to_next(&cur);
 
@@ -2610,7 +2641,7 @@
 		page_cur_move_to_next(&cur);
 	}
 
-	return(ret);	
+	return(ret);
 }
 
 /****************************************************************
@@ -2686,12 +2717,12 @@
 	mtr_start(&mtr);
 
 	mtr_x_lock(dict_tree_get_lock(tree), &mtr);
-	
+
 	page = btr_root_get(tree, &mtr);
 
 	space = buf_frame_get_space_id(page);
 
-	index = UT_LIST_GET_FIRST(tree->tree_indexes);
+	index = tree->tree_index;
 
 	while (level != btr_page_get_level(page, &mtr)) {
 
@@ -2733,21 +2764,43 @@
 			ret = FALSE;
 		}
 	}
-	
+
 	ut_a(btr_page_get_level(page, &mtr) == level);
 
 	right_page_no = btr_page_get_next(page, &mtr);
 	left_page_no = btr_page_get_prev(page, &mtr);
 
 	ut_a((page_get_n_recs(page) > 0)
-	     || ((level == 0) &&
+		|| ((level == 0) &&
 		  (buf_frame_get_page_no(page) == dict_tree_get_page(tree))));
 
 	if (right_page_no != FIL_NULL) {
 		rec_t*	right_rec;
 		right_page = btr_page_get(space, right_page_no, RW_X_LATCH,
 									&mtr);
-		ut_a(page_is_comp(right_page) == page_is_comp(page));
+		if (UNIV_UNLIKELY(btr_page_get_prev(right_page, &mtr)
+				!= buf_frame_get_page_no(page))) {
+			btr_validate_report2(index, level, page, right_page);
+			fputs("InnoDB: broken FIL_PAGE_NEXT"
+				" or FIL_PAGE_PREV links\n", stderr);
+			buf_page_print(page);
+			buf_page_print(right_page);
+
+			ret = FALSE;
+		}
+
+		if (UNIV_UNLIKELY(page_is_comp(right_page)
+				!= page_is_comp(page))) {
+			btr_validate_report2(index, level, page, right_page);
+			fputs("InnoDB: 'compact' flag mismatch\n", stderr);
+			buf_page_print(page);
+			buf_page_print(right_page);
+
+			ret = FALSE;
+
+			goto node_ptr_fails;
+		}
+
 		rec = page_rec_get_prev(page_get_supremum_rec(page));
 		right_rec = page_rec_get_next(
 					page_get_infimum_rec(right_page));
@@ -2755,8 +2808,8 @@
 					offsets, ULINT_UNDEFINED, &heap);
 		offsets2 = rec_get_offsets(right_rec, index,
 					offsets2, ULINT_UNDEFINED, &heap);
-		if (cmp_rec_rec(rec, right_rec, offsets, offsets2, index)
-				>= 0) {
+		if (UNIV_UNLIKELY(cmp_rec_rec(rec, right_rec,
+				offsets, offsets2, index) >= 0)) {
 
 			btr_validate_report2(index, level, page, right_page);
 
@@ -2776,10 +2829,10 @@
 			rec_print(stderr, rec, index);
 			putc('\n', stderr);
 
-	  		ret = FALSE;
-	  	}
+			ret = FALSE;
+		}
 	}
-	
+
 	if (level > 0 && left_page_no == FIL_NULL) {
 		ut_a(REC_INFO_MIN_REC_FLAG & rec_get_info_bits(
 			page_rec_get_next(page_get_infimum_rec(page)),
@@ -2789,7 +2842,7 @@
 	if (buf_frame_get_page_no(page) != dict_tree_get_page(tree)) {
 
 		/* Check father node pointers */
-	
+
 		node_ptr = btr_page_get_father_node_ptr(tree, page, &mtr);
 		father_page = buf_frame_align(node_ptr);
 		offsets	= rec_get_offsets(node_ptr, index,
@@ -2822,25 +2875,25 @@
 				&mtr);
 			rec_print(stderr, rec, index);
 			putc('\n', stderr);
-		   	ret = FALSE;
+			ret = FALSE;
 
-		   	goto node_ptr_fails;
+			goto node_ptr_fails;
 		}
 
 		if (btr_page_get_level(page, &mtr) > 0) {
 			offsets	= rec_get_offsets(node_ptr, index,
 					offsets, ULINT_UNDEFINED, &heap);
-		
+
 			node_ptr_tuple = dict_tree_build_node_ptr(
 					tree,
 					page_rec_get_next(
 						page_get_infimum_rec(page)),
 						0, heap,
-       					btr_page_get_level(page, &mtr));
+					btr_page_get_level(page, &mtr));
 
 			if (cmp_dtuple_rec(node_ptr_tuple, node_ptr,
 								offsets)) {
-			  	rec_t*	first_rec	= page_rec_get_next(
+				rec_t*	first_rec	= page_rec_get_next(
 					page_get_infimum_rec(page));
 
 				btr_validate_report1(index, level, page);
@@ -2855,9 +2908,9 @@
 				fputs("InnoDB: first rec ", stderr);
 				rec_print(stderr, first_rec, index);
 				putc('\n', stderr);
-		   		ret = FALSE;
+				ret = FALSE;
 
-		   		goto node_ptr_fails;
+				goto node_ptr_fails;
 			}
 		}
 
@@ -2871,10 +2924,7 @@
 			ut_a(node_ptr == page_rec_get_prev(
 				page_get_supremum_rec(father_page)));
 			ut_a(btr_page_get_next(father_page, &mtr) == FIL_NULL);
-		}
-
-		if (right_page_no != FIL_NULL) {
-
+		} else {
 			right_node_ptr = btr_page_get_father_node_ptr(tree,
 							right_page, &mtr);
 			if (page_rec_get_next(node_ptr) !=
@@ -2897,9 +2947,9 @@
 			} else {
 				right_father_page = buf_frame_align(
 							right_node_ptr);
-							
+
 				if (right_node_ptr != page_rec_get_next(
-					   		page_get_infimum_rec(
+							page_get_infimum_rec(
 							right_father_page))) {
 					ret = FALSE;
 					fputs(
@@ -2931,19 +2981,20 @@
 					buf_page_print(page);
 					buf_page_print(right_page);
 				}
-			}					
+			}
 		}
 	}
 
 node_ptr_fails:
+	/* Commit the mini-transaction to release the latch on 'page'.
+	Re-acquire the latch on right_page, which will become 'page'
+	on the next loop.  The page has already been checked. */
 	mtr_commit(&mtr);
 
 	if (right_page_no != FIL_NULL) {
-		ulint	comp = page_is_comp(page);
 		mtr_start(&mtr);
-	
+
 		page = btr_page_get(space, right_page_no, RW_X_LATCH, &mtr);
-		ut_a(page_is_comp(page) == comp);
 
 		goto loop;
 	}

--- 1.45.6.1/innobase/buf/buf0buf.c	2006-08-29 13:45:10 +08:00
+++ 1.54/storage/innobase/buf/buf0buf.c	2006-08-29 13:45:10 +08:00
@@ -1,14 +1,14 @@
 /*   Innobase relational database engine; Copyright (C) 2001 Innobase Oy
-     
+
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License 2
      as published by the Free Software Foundation in June 1991.
-     
+
      This program is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU General Public License for more details.
-     
+
      You should have received a copy of the GNU General Public License 2
      along with this program (in file COPYING); if not, write to the Free
      Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
@@ -42,7 +42,7 @@
 		IMPLEMENTATION OF THE BUFFER POOL
 		=================================
 
-Performance improvement: 
+Performance improvement:
 ------------------------
 Thread scheduling in NT may be so slow that the OS wait mechanism should
 not be used even in waiting for disk reads to complete.
@@ -239,33 +239,33 @@
 ulint
 buf_calc_page_new_checksum(
 /*=======================*/
-		       /* out: checksum */
-	byte*    page) /* in: buffer page */
+			/* out: checksum */
+	byte*	 page)	/* in: buffer page */
 {
-  	ulint checksum;
+	ulint checksum;
 
-        /* Since the field FIL_PAGE_FILE_FLUSH_LSN, and in versions <= 4.1.x
-        ..._ARCH_LOG_NO, are written outside the buffer pool to the first
-        pages of data files, we have to skip them in the page checksum
-        calculation.
+	/* Since the field FIL_PAGE_FILE_FLUSH_LSN, and in versions <= 4.1.x
+	..._ARCH_LOG_NO, are written outside the buffer pool to the first
+	pages of data files, we have to skip them in the page checksum
+	calculation.
 	We must also skip the field FIL_PAGE_SPACE_OR_CHKSUM where the
 	checksum is stored, and also the last 8 bytes of page because
 	there we store the old formula checksum. */
-  	
-  	checksum = ut_fold_binary(page + FIL_PAGE_OFFSET,
+
+	checksum = ut_fold_binary(page + FIL_PAGE_OFFSET,
 				 FIL_PAGE_FILE_FLUSH_LSN - FIL_PAGE_OFFSET)
-  		   + ut_fold_binary(page + FIL_PAGE_DATA, 
-				           UNIV_PAGE_SIZE - FIL_PAGE_DATA
-				           - FIL_PAGE_END_LSN_OLD_CHKSUM);
-  	checksum = checksum & 0xFFFFFFFFUL;
+		   + ut_fold_binary(page + FIL_PAGE_DATA,
+					   UNIV_PAGE_SIZE - FIL_PAGE_DATA
+					   - FIL_PAGE_END_LSN_OLD_CHKSUM);
+	checksum = checksum & 0xFFFFFFFFUL;
 
-  	return(checksum);
+	return(checksum);
 }
 
 /************************************************************************
 In versions < 4.0.14 and < 4.1.1 there was a bug that the checksum only
 looked at the first few bytes of the page. This calculates that old
-checksum. 
+checksum.
 NOTE: we must first store the new formula checksum to
 FIL_PAGE_SPACE_OR_CHKSUM before calculating and storing this old checksum
 because this takes that field as an input! */
@@ -273,16 +273,16 @@
 ulint
 buf_calc_page_old_checksum(
 /*=======================*/
-		       /* out: checksum */
-	byte*    page) /* in: buffer page */
+			/* out: checksum */
+	byte*	 page)	/* in: buffer page */
 {
-  	ulint checksum;
-  	
-  	checksum = ut_fold_binary(page, FIL_PAGE_FILE_FLUSH_LSN);
+	ulint checksum;
+
+	checksum = ut_fold_binary(page, FIL_PAGE_FILE_FLUSH_LSN);
 
-  	checksum = checksum & 0xFFFFFFFFUL;
+	checksum = checksum & 0xFFFFFFFFUL;
 
-  	return(checksum);
+	return(checksum);
 }
 
 /************************************************************************
@@ -302,11 +302,11 @@
 	dulint	current_lsn;
 #endif
 	if (mach_read_from_4(read_buf + FIL_PAGE_LSN + 4)
-	     != mach_read_from_4(read_buf + UNIV_PAGE_SIZE
-				- FIL_PAGE_END_LSN_OLD_CHKSUM + 4)) {
+		!= mach_read_from_4(read_buf + UNIV_PAGE_SIZE
+			- FIL_PAGE_END_LSN_OLD_CHKSUM + 4)) {
 
 		/* Stored log sequence numbers at the start and the end
-		of page do not match */
+		   of page do not match */
 
 		return(TRUE);
 	}
@@ -314,8 +314,8 @@
 #ifndef UNIV_HOTBACKUP
 	if (recv_lsn_checks_on && log_peek_lsn(&current_lsn)) {
 		if (ut_dulint_cmp(current_lsn,
-				  mach_read_from_8(read_buf + FIL_PAGE_LSN))
-				 < 0) {
+				mach_read_from_8(read_buf + FIL_PAGE_LSN))
+			< 0) {
 			ut_print_timestamp(stderr);
 
 			fprintf(stderr,
@@ -325,53 +325,58 @@
 "InnoDB: tablespace but not the InnoDB log files. See\n"
 "InnoDB: http://dev.mysql.com/doc/refman/5.0/en/forcing-recovery.html\n"
 "InnoDB: for more information.\n",
-		        (ulong) mach_read_from_4(read_buf + FIL_PAGE_OFFSET),
-			(ulong) ut_dulint_get_high(
-				mach_read_from_8(read_buf + FIL_PAGE_LSN)),
-			(ulong) ut_dulint_get_low(
-				mach_read_from_8(read_buf + FIL_PAGE_LSN)),
-			(ulong) ut_dulint_get_high(current_lsn),
-			(ulong) ut_dulint_get_low(current_lsn));
+				(ulong) mach_read_from_4(read_buf + FIL_PAGE_OFFSET),
+				(ulong) ut_dulint_get_high(
+					mach_read_from_8(read_buf + FIL_PAGE_LSN)),
+				(ulong) ut_dulint_get_low(
+					mach_read_from_8(read_buf + FIL_PAGE_LSN)),
+				(ulong) ut_dulint_get_high(current_lsn),
+				(ulong) ut_dulint_get_low(current_lsn));
 		}
 	}
 #endif
-  
-  /* If we use checksums validation, make additional check before returning
-  TRUE to ensure that the checksum is not equal to BUF_NO_CHECKSUM_MAGIC which
-  might be stored by InnoDB with checksums disabled.
-     Otherwise, skip checksum calculation and return FALSE */
-  
-  if (srv_use_checksums) {
-    old_checksum = buf_calc_page_old_checksum(read_buf); 
-
-    old_checksum_field = mach_read_from_4(read_buf + UNIV_PAGE_SIZE
-					- FIL_PAGE_END_LSN_OLD_CHKSUM);
-
-    /* There are 2 valid formulas for old_checksum_field:
-	  1. Very old versions of InnoDB only stored 8 byte lsn to the start
-	  and the end of the page.
-	  2. Newer InnoDB versions store the old formula checksum there. */
-	
-    if (old_checksum_field != mach_read_from_4(read_buf + FIL_PAGE_LSN)
-        && old_checksum_field != old_checksum
-        && old_checksum_field != BUF_NO_CHECKSUM_MAGIC) {
-
-      return(TRUE);
-    }
-
-    checksum = buf_calc_page_new_checksum(read_buf);
-    checksum_field = mach_read_from_4(read_buf + FIL_PAGE_SPACE_OR_CHKSUM);
-
-    /* InnoDB versions < 4.0.14 and < 4.1.1 stored the space id
-	  (always equal to 0), to FIL_PAGE_SPACE_SPACE_OR_CHKSUM */
-
-    if (checksum_field != 0 && checksum_field != checksum
-        && checksum_field != BUF_NO_CHECKSUM_MAGIC) {
-
-      return(TRUE);
-    }
-  }
-  
+
+	/* If we use checksums validation, make additional check before
+	returning TRUE to ensure that the checksum is not equal to
+	BUF_NO_CHECKSUM_MAGIC which might be stored by InnoDB with checksums
+	disabled. Otherwise, skip checksum calculation and return FALSE */
+
+	if (srv_use_checksums) {
+		old_checksum = buf_calc_page_old_checksum(read_buf);
+
+		old_checksum_field = mach_read_from_4(read_buf + UNIV_PAGE_SIZE
+			- FIL_PAGE_END_LSN_OLD_CHKSUM);
+
+		/* There are 2 valid formulas for old_checksum_field:
+
+		1. Very old versions of InnoDB only stored 8 byte lsn to the
+		start and the end of the page.
+
+		2. Newer InnoDB versions store the old formula checksum
+		there. */
+
+		if (old_checksum_field != mach_read_from_4(read_buf
+				+ FIL_PAGE_LSN)
+			&& old_checksum_field != old_checksum
+			&& old_checksum_field != BUF_NO_CHECKSUM_MAGIC) {
+
+			return(TRUE);
+		}
+
+		checksum = buf_calc_page_new_checksum(read_buf);
+		checksum_field = mach_read_from_4(read_buf +
+			FIL_PAGE_SPACE_OR_CHKSUM);
+
+		/* InnoDB versions < 4.0.14 and < 4.1.1 stored the space id
+		(always equal to 0), to FIL_PAGE_SPACE_SPACE_OR_CHKSUM */
+
+		if (checksum_field != 0 && checksum_field != checksum
+			&& checksum_field != BUF_NO_CHECKSUM_MAGIC) {
+
+			return(TRUE);
+		}
+	}
+
 	return(FALSE);
 }
 
@@ -394,12 +399,12 @@
 	fputs("InnoDB: End of page dump\n", stderr);
 
 	checksum = srv_use_checksums ?
-    buf_calc_page_new_checksum(read_buf) : BUF_NO_CHECKSUM_MAGIC;
+		buf_calc_page_new_checksum(read_buf) : BUF_NO_CHECKSUM_MAGIC;
 	old_checksum = srv_use_checksums ?
-    buf_calc_page_old_checksum(read_buf) : BUF_NO_CHECKSUM_MAGIC;
+		buf_calc_page_old_checksum(read_buf) : BUF_NO_CHECKSUM_MAGIC;
 
 	ut_print_timestamp(stderr);
-	fprintf(stderr, 
+	fprintf(stderr,
 "  InnoDB: Page checksum %lu, prior-to-4.0.14-form checksum %lu\n"
 "InnoDB: stored checksum %lu, prior-to-4.0.14-form stored checksum %lu\n",
 			(ulong) checksum, (ulong) old_checksum,
@@ -418,18 +423,19 @@
 		(ulong) mach_read_from_4(read_buf + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID));
 
 	if (mach_read_from_2(read_buf + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE)
-	    == TRX_UNDO_INSERT) {
-	    	fprintf(stderr,
+		== TRX_UNDO_INSERT) {
+		fprintf(stderr,
 			"InnoDB: Page may be an insert undo log page\n");
 	} else if (mach_read_from_2(read_buf + TRX_UNDO_PAGE_HDR
 						+ TRX_UNDO_PAGE_TYPE)
-	    	== TRX_UNDO_UPDATE) {
-	    	fprintf(stderr,
+		== TRX_UNDO_UPDATE) {
+		fprintf(stderr,
 			"InnoDB: Page may be an update undo log page\n");
 	}
 
-	if (fil_page_get_type(read_buf) == FIL_PAGE_INDEX) {
-	    	fprintf(stderr,
+	switch (fil_page_get_type(read_buf)) {
+	case FIL_PAGE_INDEX:
+		fprintf(stderr,
 "InnoDB: Page may be an index page where index id is %lu %lu\n",
 			(ulong) ut_dulint_get_high(btr_page_get_index_id(read_buf)),
 			(ulong) ut_dulint_get_low(btr_page_get_index_id(read_buf)));
@@ -439,19 +445,50 @@
 
 		if (dict_sys != NULL) {
 
-		        index = dict_index_find_on_id_low(
+			index = dict_index_find_on_id_low(
 					btr_page_get_index_id(read_buf));
-		        if (index) {
+			if (index) {
 				fputs("InnoDB: (", stderr);
 				dict_index_name_print(stderr, NULL, index);
 				fputs(")\n", stderr);
 			}
 		}
-	} else if (fil_page_get_type(read_buf) == FIL_PAGE_INODE) {
+		break;
+	case FIL_PAGE_INODE:
 		fputs("InnoDB: Page may be an 'inode' page\n", stderr);
-	} else if (fil_page_get_type(read_buf) == FIL_PAGE_IBUF_FREE_LIST) {
+		break;
+	case FIL_PAGE_IBUF_FREE_LIST:
 		fputs("InnoDB: Page may be an insert buffer free list page\n",
 			stderr);
+		break;
+	case FIL_PAGE_TYPE_ALLOCATED:
+		fputs("InnoDB: Page may be a freshly allocated page\n",
+			stderr);
+		break;
+	case FIL_PAGE_IBUF_BITMAP:
+		fputs("InnoDB: Page may be an insert buffer bitmap page\n",
+			stderr);
+		break;
+	case FIL_PAGE_TYPE_SYS:
+		fputs("InnoDB: Page may be a system page\n",
+			stderr);
+		break;
+	case FIL_PAGE_TYPE_TRX_SYS:
+		fputs("InnoDB: Page may be a transaction system page\n",
+			stderr);
+		break;
+	case FIL_PAGE_TYPE_FSP_HDR:
+		fputs("InnoDB: Page may be a file space header page\n",
+			stderr);
+		break;
+	case FIL_PAGE_TYPE_XDES:
+		fputs("InnoDB: Page may be an extent descriptor page\n",
+			stderr);
+		break;
+	case FIL_PAGE_TYPE_BLOB:
+		fputs("InnoDB: Page may be a BLOB page\n",
+			stderr);
+		break;
 	}
 }
 
@@ -468,7 +505,7 @@
 	block->magic_n = 0;
 
 	block->state = BUF_BLOCK_NOT_USED;
-	
+
 	block->frame = frame;
 
 	block->awe_info = NULL;
@@ -477,7 +514,7 @@
 	block->io_fix = 0;
 
 	block->modify_clock = ut_dulint_zero;
-	
+
 	block->file_page_was_freed = FALSE;
 
 	block->check_index_page_at_flush = FALSE;
@@ -488,12 +525,11 @@
 
 	block->n_pointers = 0;
 
-	rw_lock_create(&(block->lock));
+	rw_lock_create(&block->lock, SYNC_LEVEL_VARYING);
 	ut_ad(rw_lock_validate(&(block->lock)));
 
 #ifdef UNIV_SYNC_DEBUG
-	rw_lock_create(&(block->debug_latch));
-	rw_lock_set_level(&(block->debug_latch), SYNC_NO_ORDER_CHECK);
+	rw_lock_create(&block->debug_latch, SYNC_NO_ORDER_CHECK);
 #endif /* UNIV_SYNC_DEBUG */
 }
 
@@ -519,12 +555,12 @@
 	byte*		frame;
 	ulint		i;
 	buf_block_t*	block;
-	
+
 	ut_a(max_size == curr_size);
 	ut_a(srv_use_awe || n_frames == max_size);
-	
+
 	if (n_frames > curr_size) {
-	        fprintf(stderr,
+		fprintf(stderr,
 "InnoDB: AWE: Error: you must specify in my.cnf .._awe_mem_mb larger\n"
 "InnoDB: than .._buffer_pool_size. Now the former is %lu pages,\n"
 "InnoDB: the latter %lu pages.\n", (ulong) curr_size, (ulong) n_frames);
@@ -536,8 +572,7 @@
 
 	/* 1. Initialize general fields
 	   ---------------------------- */
-	mutex_create(&(buf_pool->mutex));
-	mutex_set_level(&(buf_pool->mutex), SYNC_BUF_POOL);
+	mutex_create(&buf_pool->mutex, SYNC_BUF_POOL);
 
 	mutex_enter(&(buf_pool->mutex));
 
@@ -548,18 +583,18 @@
 
 		buf_pool->frame_mem = os_awe_allocate_virtual_mem_window(
 					UNIV_PAGE_SIZE * (n_frames + 1));
-					
+
 		/* Allocate the physical memory for AWE and the AWE info array
 		for buf_pool */
 
 		if ((curr_size % ((1024 * 1024) / UNIV_PAGE_SIZE)) != 0) {
 
-		        fprintf(stderr,
+			fprintf(stderr,
 "InnoDB: AWE: Error: physical memory must be allocated in full megabytes.\n"
-"InnoDB: Trying to allocate %lu database pages.\n", 
+"InnoDB: Trying to allocate %lu database pages.\n",
 			  (ulong) curr_size);
 
-		        return(NULL);
+			return(NULL);
 		}
 
 		if (!os_awe_allocate_physical_mem(&(buf_pool->awe_info),
@@ -611,7 +646,7 @@
 	}
 
 	buf_pool->blocks_of_frames = ut_malloc(sizeof(void*) * n_frames);
-	
+
 	if (buf_pool->blocks_of_frames == NULL) {
 
 		return(NULL);
@@ -632,7 +667,7 @@
 		} else {
 			frame = NULL;
 		}
-		
+
 		buf_block_init(block, frame);
 
 		if (srv_use_awe) {
@@ -653,14 +688,14 @@
 	buf_pool->n_pages_written = 0;
 	buf_pool->n_pages_created = 0;
 	buf_pool->n_pages_awe_remapped = 0;
-	
+
 	buf_pool->n_page_gets = 0;
 	buf_pool->n_page_gets_old = 0;
 	buf_pool->n_pages_read_old = 0;
 	buf_pool->n_pages_written_old = 0;
 	buf_pool->n_pages_created_old = 0;
 	buf_pool->n_pages_awe_remapped_old = 0;
-	
+
 	/* 2. Initialize flushing fields
 	   ---------------------------- */
 	UT_LIST_INIT(buf_pool->flush_list);
@@ -675,7 +710,7 @@
 
 	buf_pool->ulint_clock = 1;
 	buf_pool->freed_page_clock = 0;
-	
+
 	/* 3. Initialize LRU fields
 	   ---------------------------- */
 	UT_LIST_INIT(buf_pool->LRU);
@@ -701,7 +736,7 @@
 			if (srv_use_awe) {
 				/* Add to the list of blocks mapped to
 				frames */
-				
+
 				UT_LIST_ADD_LAST(awe_LRU_free_mapped,
 					buf_pool->awe_LRU_free_mapped, block);
 			}
@@ -714,15 +749,15 @@
 	mutex_exit(&(buf_pool->mutex));
 
 	if (srv_use_adaptive_hash_indexes) {
-	  	btr_search_sys_create(
+		btr_search_sys_create(
 			  curr_size * UNIV_PAGE_SIZE / sizeof(void*) / 64);
 	} else {
-	        /* Create only a small dummy system */
-	        btr_search_sys_create(1000);
+		/* Create only a small dummy system */
+		btr_search_sys_create(1000);
 	}
 
 	return(buf_pool);
-}	
+}
 
 /************************************************************************
 Maps the page of block to a frame, if not mapped yet. Unmaps some page
@@ -755,9 +790,9 @@
 
 	bck = UT_LIST_GET_LAST(buf_pool->awe_LRU_free_mapped);
 
-	while (bck) {	
+	while (bck) {
 		if (bck->state == BUF_BLOCK_FILE_PAGE
-	    	    && (bck->buf_fix_count != 0 || bck->io_fix != 0)) {
+			&& (bck->buf_fix_count != 0 || bck->io_fix != 0)) {
 
 			/* We have to skip this */
 			bck = UT_LIST_GET_PREV(awe_LRU_free_mapped, bck);
@@ -776,7 +811,7 @@
 						- buf_pool->frame_zero))
 						>> UNIV_PAGE_SIZE_SHIFT))
 				= block;
-			
+
 			bck->frame = NULL;
 			UT_LIST_REMOVE(awe_LRU_free_mapped,
 					buf_pool->awe_LRU_free_mapped,
@@ -789,7 +824,7 @@
 			}
 
 			buf_pool->n_pages_awe_remapped++;
-			
+
 			return;
 		}
 	}
@@ -828,7 +863,7 @@
 /*=================*/
 	buf_block_t*	block)	/* in: block to make younger */
 {
-	if (buf_pool->freed_page_clock >= block->freed_page_clock 
+	if (buf_pool->freed_page_clock >= block->freed_page_clock
 				+ 1 + (buf_pool->curr_size / 1024)) {
 
 		/* There has been freeing activity in the LRU list:
@@ -845,11 +880,11 @@
 
 void
 buf_page_make_young(
-/*=================*/
+/*================*/
 	buf_frame_t*	frame)	/* in: buffer frame of a file page */
 {
 	buf_block_t*	block;
-	
+
 	mutex_enter(&(buf_pool->mutex));
 
 	block = buf_block_align(frame);
@@ -899,7 +934,7 @@
 {
 	buf_block_free(buf_block_align(frame));
 }
-	
+
 /************************************************************************
 Returns the buffer control block if the page can be found in the buffer
 pool. NOTE that it is possible that the page is not yet read
@@ -944,7 +979,7 @@
 	if (block) {
 		block->check_index_page_at_flush = FALSE;
 	}
-	
+
 	mutex_exit(&(buf_pool->mutex));
 }
 
@@ -1080,14 +1115,14 @@
 	ulint		fix_type;
 	ibool		success;
 	ibool		must_read;
-	
+
 	ut_ad(mtr);
 	ut_ad((rw_latch == RW_S_LATCH)
-	      || (rw_latch == RW_X_LATCH)
-	      || (rw_latch == RW_NO_LATCH));
+		|| (rw_latch == RW_X_LATCH)
+		|| (rw_latch == RW_NO_LATCH));
 	ut_ad((mode != BUF_GET_NO_LATCH) || (rw_latch == RW_NO_LATCH));
 	ut_ad((mode == BUF_GET) || (mode == BUF_GET_IF_IN_POOL)
-	      || (mode == BUF_GET_NO_LATCH) || (mode == BUF_GET_NOWAIT));
+		|| (mode == BUF_GET_NO_LATCH) || (mode == BUF_GET_NOWAIT));
 #ifndef UNIV_LOG_DEBUG
 	ut_ad(!ibuf_inside() || ibuf_page(space, offset));
 #endif
@@ -1096,7 +1131,7 @@
 	mutex_enter_fast(&(buf_pool->mutex));
 
 	block = NULL;
-	
+
 	if (guess) {
 		block = buf_block_align(guess);
 
@@ -1136,7 +1171,7 @@
 	ut_a(block->state == BUF_BLOCK_FILE_PAGE);
 
 	must_read = FALSE;
-	
+
 	if (block->io_fix == BUF_IO_READ) {
 
 		must_read = TRUE;
@@ -1148,7 +1183,7 @@
 
 			return(NULL);
 		}
-	}		
+	}
 
 	/* If AWE is enabled and the page is not mapped to a frame, then
 	map it */
@@ -1159,10 +1194,10 @@
 		/* We set second parameter TRUE because the block is in the
 		LRU list and we must put it to awe_LRU_free_mapped list once
 		mapped to a frame */
-		
+
 		buf_awe_map_page_to_frame(block, TRUE);
 	}
-	
+
 #ifdef UNIV_SYNC_DEBUG
 	buf_block_buf_fix_inc_debug(block, file, line);
 #else
@@ -1178,7 +1213,7 @@
 
 #ifdef UNIV_DEBUG_FILE_ACCESSES
 	ut_a(block->file_page_was_freed == FALSE);
-#endif	
+#endif
 	mutex_exit(&(buf_pool->mutex));
 
 #ifdef UNIV_DEBUG
@@ -1209,7 +1244,7 @@
 			block->buf_fix_count--;
 #ifdef UNIV_SYNC_DEBUG
 			rw_lock_s_unlock(&(block->debug_latch));
-#endif			
+#endif
 			mutex_exit(&(buf_pool->mutex));
 
 			return(NULL);
@@ -1217,24 +1252,24 @@
 	} else if (rw_latch == RW_NO_LATCH) {
 
 		if (must_read) {
-		        /* Let us wait until the read operation
+			/* Let us wait until the read operation
 			completes */
 
-		        for (;;) {
-			        mutex_enter(&(buf_pool->mutex));
+			for (;;) {
+				mutex_enter(&(buf_pool->mutex));
+
+				if (block->io_fix == BUF_IO_READ) {
 
-		                if (block->io_fix == BUF_IO_READ) {
+					mutex_exit(&(buf_pool->mutex));
 
-				        mutex_exit(&(buf_pool->mutex));
-				  
-				        /* Sleep 20 milliseconds */
+					/* Sleep 20 milliseconds */
 
-				        os_thread_sleep(20000);
+					os_thread_sleep(20000);
 				} else {
-				  
-				       mutex_exit(&(buf_pool->mutex));
 
-				       break;
+					mutex_exit(&(buf_pool->mutex));
+
+					break;
 				}
 			}
 		}
@@ -1263,7 +1298,7 @@
 #ifdef UNIV_IBUF_DEBUG
 	ut_a(ibuf_count_get(block->space, block->offset) == 0);
 #endif
-	return(block->frame);		
+	return(block->frame);
 }
 
 /************************************************************************
@@ -1290,11 +1325,11 @@
 
 	ut_ad(mtr && block);
 	ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
-	
+
 	mutex_enter(&(buf_pool->mutex));
 
 	/* If AWE is used, block may have a different frame now, e.g., NULL */
-	
+
 	if (UNIV_UNLIKELY(block->state != BUF_BLOCK_FILE_PAGE)
 			|| UNIV_UNLIKELY(block->frame != guess)) {
 	exit_func:
@@ -1332,7 +1367,7 @@
 
 	if (UNIV_UNLIKELY(!success)) {
 		mutex_enter(&(buf_pool->mutex));
-		
+
 		block->buf_fix_count--;
 #ifdef UNIV_SYNC_DEBUG
 		rw_lock_s_unlock(&(block->debug_latch));
@@ -1351,7 +1386,7 @@
 		}
 
 		mutex_enter(&(buf_pool->mutex));
-		
+
 		block->buf_fix_count--;
 #ifdef UNIV_SYNC_DEBUG
 		rw_lock_s_unlock(&(block->debug_latch));
@@ -1412,20 +1447,20 @@
 
 	ut_ad(mtr);
 	ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
-	
+
 	mutex_enter(&(buf_pool->mutex));
 
 	block = buf_block_align(guess);
 
 	if (block->state == BUF_BLOCK_REMOVE_HASH) {
-	        /* Another thread is just freeing the block from the LRU list
-	        of the buffer pool: do not try to access this page; this
+		/* Another thread is just freeing the block from the LRU list
+		of the buffer pool: do not try to access this page; this
 		attempt to access the page can only come through the hash
 		index because when the buffer block state is ..._REMOVE_HASH,
 		we have already removed it from the page address hash table
 		of the buffer pool. */
 
-	        mutex_exit(&(buf_pool->mutex));
+		mutex_exit(&(buf_pool->mutex));
 
 		return(FALSE);
 	}
@@ -1454,14 +1489,14 @@
 								file, line);
 		fix_type = MTR_MEMO_PAGE_X_FIX;
 	}
-	
+
 	if (!success) {
 		mutex_enter(&(buf_pool->mutex));
-		
+
 		block->buf_fix_count--;
 #ifdef UNIV_SYNC_DEBUG
 		rw_lock_s_unlock(&(block->debug_latch));
-#endif		
+#endif
 		mutex_exit(&(buf_pool->mutex));
 
 		return(FALSE);
@@ -1505,27 +1540,27 @@
 	/* Set the state of the block */
 	block->magic_n		= BUF_BLOCK_MAGIC_N;
 
-	block->state 		= BUF_BLOCK_FILE_PAGE;
-	block->space 		= space;
-	block->offset 		= offset;
+	block->state		= BUF_BLOCK_FILE_PAGE;
+	block->space		= space;
+	block->offset		= offset;
 
 	block->lock_hash_val	= 0;
 	block->lock_mutex	= NULL;
-	
+
 	block->freed_page_clock = 0;
 
 	block->newest_modification = ut_dulint_zero;
 	block->oldest_modification = ut_dulint_zero;
-	
+
 	block->accessed		= FALSE;
-	block->buf_fix_count 	= 0;
+	block->buf_fix_count	= 0;
 	block->io_fix		= 0;
 
 	block->n_hash_helps	= 0;
 	block->is_hashed	= FALSE;
-	block->n_fields         = 1;
-	block->n_bytes          = 0;
-	block->side             = BTR_SEARCH_LEFT_SIDE;
+	block->n_fields		= 1;
+	block->n_bytes		= 0;
+	block->side		= BTR_SEARCH_LEFT_SIDE;
 
 	block->file_page_was_freed = FALSE;
 }
@@ -1549,31 +1584,31 @@
 	/* Set the state of the block */
 	block->magic_n		= BUF_BLOCK_MAGIC_N;
 
-	block->state 		= BUF_BLOCK_FILE_PAGE;
-	block->space 		= space;
-	block->offset 		= offset;
+	block->state		= BUF_BLOCK_FILE_PAGE;
+	block->space		= space;
+	block->offset		= offset;
 
 	block->check_index_page_at_flush = FALSE;
 	block->index		= NULL;
-	
+
 	block->lock_hash_val	= lock_rec_hash(space, offset);
 	block->lock_mutex	= NULL;
-	
+
 	/* Insert into the hash table of file pages */
 
-        if (buf_page_hash_get(space, offset)) {
-                fprintf(stderr,
+	if (buf_page_hash_get(space, offset)) {
+		fprintf(stderr,
 "InnoDB: Error: page %lu %lu already found from the hash table\n",
 			(ulong) space,
 			(ulong) offset);
 #ifdef UNIV_DEBUG
-                buf_print();
-                buf_LRU_print();
-                buf_validate();
-                buf_LRU_validate();
+		buf_print();
+		buf_LRU_print();
+		buf_validate();
+		buf_LRU_validate();
 #endif /* UNIV_DEBUG */
-                ut_a(0);
-        }
+		ut_a(0);
+	}
 
 	HASH_INSERT(buf_block_t, hash, buf_pool->page_hash,
 				buf_page_address_fold(space, offset), block);
@@ -1582,16 +1617,16 @@
 
 	block->newest_modification = ut_dulint_zero;
 	block->oldest_modification = ut_dulint_zero;
-	
+
 	block->accessed		= FALSE;
-	block->buf_fix_count 	= 0;
+	block->buf_fix_count	= 0;
 	block->io_fix		= 0;
 
 	block->n_hash_helps	= 0;
 	block->is_hashed	= FALSE;
-	block->n_fields         = 1;
-	block->n_bytes          = 0;
-	block->side             = BTR_SEARCH_LEFT_SIDE;
+	block->n_fields		= 1;
+	block->n_bytes		= 0;
+	block->side		= BTR_SEARCH_LEFT_SIDE;
 
 	block->file_page_was_freed = FALSE;
 }
@@ -1606,7 +1641,7 @@
 on the buffer frame. The io-handler must take care that the flag is cleared
 and the lock released later. This is one of the functions which perform the
 state transition NOT_USED => FILE_PAGE to a block (the other is
-buf_page_create). */ 
+buf_page_create). */
 
 buf_block_t*
 buf_page_init_for_read(
@@ -1632,9 +1667,9 @@
 
 		ut_ad(!ibuf_bitmap_page(offset));
 		ut_ad(ibuf_inside());
-	
+
 		mtr_start(&mtr);
-	
+
 		if (!ibuf_page_low(space, offset, &mtr)) {
 
 			mtr_commit(&mtr);
@@ -1644,7 +1679,7 @@
 	} else {
 		ut_ad(mode == BUF_READ_ANY_PAGE);
 	}
-	
+
 	block = buf_block_alloc();
 
 	ut_a(block);
@@ -1657,7 +1692,7 @@
 	}
 
 	if (*err == DB_TABLESPACE_DELETED
-	    || NULL != buf_page_hash_get(space, offset)) {
+		|| NULL != buf_page_hash_get(space, offset)) {
 
 		/* The page belongs to a space which has been deleted or is
 		being deleted, or the page is already in buf_pool, return */
@@ -1674,26 +1709,26 @@
 	}
 
 	ut_ad(block);
-	
+
 	buf_page_init(space, offset, block);
 
 	/* The block must be put to the LRU list, to the old blocks */
 
-	buf_LRU_add_block(block, TRUE); 	/* TRUE == to old blocks */
-	
+	buf_LRU_add_block(block, TRUE);		/* TRUE == to old blocks */
+
 	block->io_fix = BUF_IO_READ;
 	buf_pool->n_pend_reads++;
-	
+
 	/* We set a pass-type x-lock on the frame because then the same
 	thread which called for the read operation (and is running now at
 	this point of code) can wait for the read to complete by waiting
 	for the x-lock on the frame; if the x-lock were recursive, the
 	same thread would illegally get the x-lock before the page read
 	is completed. The x-lock is cleared by the io-handler thread. */
-	
+
 	rw_lock_x_lock_gen(&(block->lock), BUF_IO_READ);
-	
- 	mutex_exit(&(buf_pool->mutex));
+
+	mutex_exit(&(buf_pool->mutex));
 
 	if (mode == BUF_READ_IBUF_PAGES_ONLY) {
 
@@ -1701,7 +1736,7 @@
 	}
 
 	return(block);
-}	
+}
 
 /************************************************************************
 Initializes a page to the buffer buf_pool. The page is usually not read
@@ -1721,11 +1756,11 @@
 	buf_frame_t*	frame;
 	buf_block_t*	block;
 	buf_block_t*	free_block	= NULL;
-	
+
 	ut_ad(mtr);
 
 	free_block = buf_LRU_get_free_block();
-	
+
 	mutex_enter(&(buf_pool->mutex));
 
 	block = buf_page_hash_get(space, offset);
@@ -1756,12 +1791,12 @@
 #endif /* UNIV_DEBUG */
 
 	block = free_block;
-	
+
 	buf_page_init(space, offset, block);
 
 	/* The block must be put to the LRU list */
 	buf_LRU_add_block(block, FALSE);
-		
+
 #ifdef UNIV_SYNC_DEBUG
 	buf_block_buf_fix_inc_debug(block, __FILE__, __LINE__);
 #else
@@ -1770,7 +1805,7 @@
 	mtr_memo_push(mtr, block, MTR_MEMO_BUF_FIX);
 
 	block->accessed = TRUE;
-	
+
 	buf_pool->n_pages_created++;
 
 	mutex_exit(&(buf_pool->mutex));
@@ -1785,6 +1820,10 @@
 
 	frame = block->frame;
 
+	memset(frame + FIL_PAGE_PREV, 0xff, 4);
+	memset(frame + FIL_PAGE_NEXT, 0xff, 4);
+	mach_write_to_2(frame + FIL_PAGE_TYPE, FIL_PAGE_TYPE_ALLOCATED);
+
 	/* Reset to zero the file flush lsn field in the page; if the first
 	page of an ibdata file is 'created' in this function into the buffer
 	pool then we lose the original contents of the file flush lsn stamp.
@@ -1816,8 +1855,7 @@
 	buf_block_t*	block)	/* in: pointer to the block in question */
 {
 	ulint		io_type;
-	ulint		read_page_no;
-	
+
 	ut_ad(block);
 
 	ut_a(block->state == BUF_BLOCK_FILE_PAGE);
@@ -1826,33 +1864,51 @@
 
 	if (io_type == BUF_IO_READ) {
 		/* If this page is not uninitialized and not in the
-		doublewrite buffer, then the page number should be the
-		same as in block */
-
-		read_page_no = mach_read_from_4((block->frame)
+		doublewrite buffer, then the page number and space id
+		should be the same as in block. */
+		ulint	read_page_no = mach_read_from_4((block->frame)
 						+ FIL_PAGE_OFFSET);
-		if (read_page_no != 0
-			&& !trx_doublewrite_page_inside(read_page_no)
-	    		&& read_page_no != block->offset) {
+		ulint	read_space_id = mach_read_from_4((block->frame)
+					 + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
 
+		if (!block->space && trx_doublewrite_page_inside(
+				block->offset)) {
+
+			ut_print_timestamp(stderr);
+			fprintf(stderr,
+"  InnoDB: Error: reading page %lu\n"
+"InnoDB: which is in the doublewrite buffer!\n",
+				(ulong) block->offset);
+		} else if (!read_space_id && !read_page_no) {
+			/* This is likely an uninitialized page. */
+		} else if ((block->space && block->space != read_space_id)
+				|| block->offset != read_page_no) {
+			/* We did not compare space_id to read_space_id
+			if block->space == 0, because the field on the
+			page may contain garbage in MySQL < 4.1.1,
+			which only supported block->space == 0. */
+
+			ut_print_timestamp(stderr);
 			fprintf(stderr,
-"InnoDB: Error: page n:o stored in the page read in is %lu, should be %lu!\n",
-				(ulong) read_page_no, (ulong) block->offset);
+"  InnoDB: Error: space id and page n:o stored in the page\n"
+"InnoDB: read in are %lu:%lu, should be %lu:%lu!\n",
+				(ulong) read_space_id, (ulong) read_page_no,
+				(ulong) block->space, (ulong) block->offset);
 		}
 		/* From version 3.23.38 up we store the page checksum
 		   to the 4 first bytes of the page end lsn field */
 
 		if (buf_page_is_corrupted(block->frame)) {
-		  	fprintf(stderr,
+			fprintf(stderr,
 		"InnoDB: Database page corruption on disk or a failed\n"
 		"InnoDB: file read of page %lu.\n", (ulong) block->offset);
-			  
+
 			fputs(
 		"InnoDB: You may have to recover from a backup.\n", stderr);
 
 			buf_page_print(block->frame);
 
-		  	fprintf(stderr,
+			fprintf(stderr,
 		"InnoDB: Database page corruption on disk or a failed\n"
 		"InnoDB: file read of page %lu.\n", (ulong) block->offset);
 			fputs(
@@ -1870,13 +1926,13 @@
 		"InnoDB: See also "
 "InnoDB: http://dev.mysql.com/doc/refman/5.0/en/forcing-recovery.html\n"
 		"InnoDB: about forcing recovery.\n", stderr);
-			  
+
 			if (srv_force_recovery < SRV_FORCE_IGNORE_CORRUPT) {
 				fputs(
 	"InnoDB: Ending processing because of a corrupt database page.\n",
 					stderr);
-		  		exit(1);
-		  	}
+				exit(1);
+			}
 		}
 
 		if (recv_recovery_is_on()) {
@@ -1889,24 +1945,24 @@
 					block->space, block->offset, TRUE);
 		}
 	}
-	
+
 #ifdef UNIV_IBUF_DEBUG
 	ut_a(ibuf_count_get(block->space, block->offset) == 0);
 #endif
 	mutex_enter(&(buf_pool->mutex));
-	
+
 	/* Because this thread which does the unlocking is not the same that
 	did the locking, we use a pass value != 0 in unlock, which simply
 	removes the newest lock debug record, without checking the thread
 	id. */
 
 	block->io_fix = 0;
-	
+
 	if (io_type == BUF_IO_READ) {
 		/* NOTE that the call to ibuf may have moved the ownership of
 		the x-latch to this OS thread: do not let this confuse you in
-		debugging! */		
-	
+		debugging! */
+
 		ut_ad(buf_pool->n_pend_reads > 0);
 		buf_pool->n_pend_reads--;
 		buf_pool->n_pages_read++;
@@ -1936,7 +1992,7 @@
 		}
 #endif /* UNIV_DEBUG */
 	}
-	
+
 	mutex_exit(&(buf_pool->mutex));
 
 #ifdef UNIV_DEBUG
@@ -1959,13 +2015,13 @@
 	ibool	freed;
 
 	ut_ad(buf_all_freed());
-	
+
 	freed = TRUE;
 
 	while (freed) {
 		freed = buf_LRU_search_and_free_block(100);
 	}
-	
+
 	mutex_enter(&(buf_pool->mutex));
 
 	ut_ad(UT_LIST_GET_LEN(buf_pool->LRU) == 0);
@@ -1990,7 +2046,7 @@
 	ulint		n_flush		= 0;
 	ulint		n_free		= 0;
 	ulint		n_page		= 0;
-	
+
 	ut_ad(buf_pool);
 
 	mutex_enter(&(buf_pool->mutex));
@@ -2007,8 +2063,8 @@
 
 #ifdef UNIV_IBUF_DEBUG
 			ut_a((block->io_fix == BUF_IO_READ)
-			     || ibuf_count_get(block->space, block->offset)
-								== 0);
+				|| ibuf_count_get(block->space, block->offset)
+				== 0);
 #endif
 			if (block->io_fix == BUF_IO_WRITE) {
 
@@ -2031,18 +2087,18 @@
 				ut_a(rw_lock_is_locked(&(block->lock),
 							RW_LOCK_EX));
 			}
-			
+
 			n_lru++;
 
 			if (ut_dulint_cmp(block->oldest_modification,
 						ut_dulint_zero) > 0) {
 					n_flush++;
-			}	
-		
+			}
+
 		} else if (block->state == BUF_BLOCK_NOT_USED) {
 			n_free++;
 		}
- 	}
+	}
 
 	if (n_lru + n_free > buf_pool->curr_size) {
 		fprintf(stderr, "n LRU %lu, n free %lu\n", (ulong) n_lru, (ulong) n_free);
@@ -2060,14 +2116,14 @@
 	ut_a(buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE] == n_single_flush);
 	ut_a(buf_pool->n_flush[BUF_FLUSH_LIST] == n_list_flush);
 	ut_a(buf_pool->n_flush[BUF_FLUSH_LRU] == n_lru_flush);
-	
+
 	mutex_exit(&(buf_pool->mutex));
 
 	ut_a(buf_LRU_validate());
 	ut_a(buf_flush_validate());
 
 	return(TRUE);
-}	
+}
 
 /*************************************************************************
 Prints info of the buffer buf_pool data structure. */
@@ -2083,9 +2139,9 @@
 	ulint		j;
 	dulint		id;
 	ulint		n_found;
-	buf_frame_t* 	frame;
+	buf_frame_t*	frame;
 	dict_index_t*	index;
-	
+
 	ut_ad(buf_pool);
 
 	size = buf_pool->curr_size;
@@ -2094,7 +2150,7 @@
 	counts = mem_alloc(sizeof(ulint) * size);
 
 	mutex_enter(&(buf_pool->mutex));
-	
+
 	fprintf(stderr,
 		"buf_pool size %lu\n"
 		"database pages %lu\n"
@@ -2115,7 +2171,7 @@
 		(ulong) buf_pool->n_pages_written);
 
 	/* Count the number of blocks belonging to each index in the buffer */
-	
+
 	n_found = 0;
 
 	for (i = 0; i < size; i++) {
@@ -2153,8 +2209,8 @@
 
 		fprintf(stderr,
 			"Block count for index %lu in buffer is about %lu",
-		       (ulong) ut_dulint_get_low(index_ids[i]),
-		       (ulong) counts[i]);
+			(ulong) ut_dulint_get_low(index_ids[i]),
+			(ulong) counts[i]);
 
 		if (index) {
 			putc(' ', stderr);
@@ -2163,12 +2219,12 @@
 
 		putc('\n', stderr);
 	}
-	
+
 	mem_free(index_ids);
 	mem_free(counts);
 
 	ut_a(buf_validate());
-}	
+}
 #endif /* UNIV_DEBUG */
 
 /*************************************************************************
@@ -2177,23 +2233,24 @@
 ulint
 buf_get_latched_pages_number(void)
 {
-        buf_block_t* block;
-        ulint i;
-        ulint fixed_pages_number = 0;
+	buf_block_t* block;
+	ulint i;
+	ulint fixed_pages_number = 0;
 
-        mutex_enter(&(buf_pool->mutex));
+	mutex_enter(&(buf_pool->mutex));
 
-        for (i = 0; i < buf_pool->curr_size; i++) {
+	for (i = 0; i < buf_pool->curr_size; i++) {
 
-               block = buf_pool_get_nth_block(buf_pool, i);
+		block = buf_pool_get_nth_block(buf_pool, i);
+
+		if (((block->buf_fix_count != 0) || (block->io_fix != 0)) &&
+			block->magic_n == BUF_BLOCK_MAGIC_N )
+			fixed_pages_number++;
+	}
 
-               if (((block->buf_fix_count != 0) || (block->io_fix != 0)) &&
-                    block->magic_n == BUF_BLOCK_MAGIC_N )
-                       fixed_pages_number++;
-        }
+	mutex_exit(&(buf_pool->mutex));
 
-        mutex_exit(&(buf_pool->mutex));
-        return fixed_pages_number;
+	return(fixed_pages_number);
 }
 
 /*************************************************************************
@@ -2222,10 +2279,10 @@
 	mutex_enter(&(buf_pool->mutex));
 
 	ratio = (100 * UT_LIST_GET_LEN(buf_pool->flush_list))
-		     / (1 + UT_LIST_GET_LEN(buf_pool->LRU)
-		        + UT_LIST_GET_LEN(buf_pool->free));
+		/ (1 + UT_LIST_GET_LEN(buf_pool->LRU)
+			+ UT_LIST_GET_LEN(buf_pool->free));
 
-		       /* 1 + is there to avoid division by zero */   
+	/* 1 + is there to avoid division by zero */
 
 	mutex_exit(&(buf_pool->mutex));
 
@@ -2243,17 +2300,17 @@
 	time_t	current_time;
 	double	time_elapsed;
 	ulint	size;
-	
+
 	ut_ad(buf_pool);
 	size = buf_pool->curr_size;
 
 	mutex_enter(&(buf_pool->mutex));
-	
+
 	if (srv_use_awe) {
 		fprintf(stderr,
 		"AWE: Buffer pool memory frames                        %lu\n",
 				(ulong) buf_pool->n_frames);
-		
+
 		fprintf(stderr,
 		"AWE: Database pages and free buffers mapped in frames %lu\n",
 				(ulong) UT_LIST_GET_LEN(buf_pool->awe_LRU_free_mapped));
@@ -2300,13 +2357,12 @@
 				- buf_pool->n_pages_awe_remapped_old)
 			/ time_elapsed);
 	}
-		
+
 	if (buf_pool->n_page_gets > buf_pool->n_page_gets_old) {
 		fprintf(file, "Buffer pool hit rate %lu / 1000\n",
-       (ulong) (1000
-		- ((1000 *
-		    (buf_pool->n_pages_read - buf_pool->n_pages_read_old))
-		/ (buf_pool->n_page_gets - buf_pool->n_page_gets_old))));
+			(ulong) (1000 -
+			((1000 * (buf_pool->n_pages_read - buf_pool->n_pages_read_old))
+			/ (buf_pool->n_page_gets - buf_pool->n_page_gets_old))));
 	} else {
 		fputs("No buffer pool page gets since the last printout\n",
 			file);
@@ -2328,12 +2384,12 @@
 buf_refresh_io_stats(void)
 /*======================*/
 {
-        buf_pool->last_printout_time = time(NULL);
+	buf_pool->last_printout_time = time(NULL);
 	buf_pool->n_page_gets_old = buf_pool->n_page_gets;
 	buf_pool->n_pages_read_old = buf_pool->n_pages_read;
 	buf_pool->n_pages_created_old = buf_pool->n_pages_created;
 	buf_pool->n_pages_written_old = buf_pool->n_pages_written;
-	buf_pool->n_pages_awe_remapped_old = buf_pool->n_pages_awe_remapped; 
+	buf_pool->n_pages_awe_remapped_old = buf_pool->n_pages_awe_remapped;
 }
 
 /*************************************************************************
@@ -2345,7 +2401,7 @@
 {
 	buf_block_t*	block;
 	ulint		i;
-	
+
 	ut_ad(buf_pool);
 
 	mutex_enter(&(buf_pool->mutex));
@@ -2361,15 +2417,15 @@
 				fprintf(stderr,
 					"Page %lu %lu still fixed or dirty\n",
 					(ulong) block->space, (ulong) block->offset);
-			    	ut_error;
+				ut_error;
 			}
 		}
- 	}
+	}
 
 	mutex_exit(&(buf_pool->mutex));
 
 	return(TRUE);
-}	
+}
 
 /*************************************************************************
 Checks that there currently are no pending i/o-operations for the buffer

--- 1.65.11.1/innobase/dict/dict0dict.c	2006-08-29 13:45:10 +08:00
+++ 1.84/storage/innobase/dict/dict0dict.c	2006-08-29 13:45:10 +08:00
@@ -26,6 +26,9 @@
 #include "pars0sym.h"
 #include "que0que.h"
 #include "rem0cmp.h"
+#ifndef UNIV_HOTBACKUP
+# include "m_ctype.h" /* my_isspace() */
+#endif /* !UNIV_HOTBACKUP */
 
 dict_sys_t*	dict_sys	= NULL;	/* the dictionary system */
 
@@ -55,6 +58,42 @@
 
 #ifndef UNIV_HOTBACKUP
 /**********************************************************************
+Converts an identifier to a table name.
+
+NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
+this function, you MUST change also the prototype here! */
+extern
+void
+innobase_convert_from_table_id(
+/*===========================*/
+	char*		to,	/* out: converted identifier */
+	const char*	from,	/* in: identifier to convert */
+	ulint		len);	/* in: length of 'to', in bytes;
+				should be at least 5 * strlen(to) + 1 */
+/**********************************************************************
+Converts an identifier to UTF-8.
+
+NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
+this function, you MUST change also the prototype here! */
+extern
+void
+innobase_convert_from_id(
+/*=====================*/
+	char*		to,	/* out: converted identifier */
+	const char*	from,	/* in: identifier to convert */
+	ulint		len);	/* in: length of 'to', in bytes;
+				should be at least 3 * strlen(to) + 1 */
+/**********************************************************************
+Removes the filename encoding of a table or database name.
+
+NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
+this function, you MUST change also the prototype here! */
+extern
+void
+innobase_convert_from_filename(
+/*===========================*/
+	char*		s);	/* in: identifier; out: decoded identifier */
+/**********************************************************************
 Compares NUL-terminated UTF-8 strings case insensitively.
 
 NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
@@ -77,6 +116,17 @@
 innobase_casedn_str(
 /*================*/
 	char*	a);	/* in/out: string to put in lower case */
+
+/**************************************************************************
+Determines the connection character set.
+
+NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
+this function, you MUST change also the prototype here! */
+struct charset_info_st*
+innobase_get_charset(
+/*=================*/
+				/* out: connection character set */
+	void*	mysql_thd);	/* in: MySQL thread handle */
 #endif /* !UNIV_HOTBACKUP */
 
 /**************************************************************************
@@ -132,7 +182,7 @@
 /*=================*/
 				/* out: TRUE if success */
 	dict_table_t*	table,	/* in: table */
-	dict_index_t*	index);	/* in: index */	
+	dict_index_t*	index);	/* in: index */
 /***********************************************************************
 Builds the internal dictionary cache representation for a clustered
 index, containing also system fields not defined by the user. */
@@ -144,7 +194,7 @@
 				of the clustered index */
 	dict_table_t*	table,	/* in: table */
 	dict_index_t*	index);	/* in: user representation of a clustered
-				index */	
+				index */
 /***********************************************************************
 Builds the internal dictionary cache representation for a non-clustered
 index, containing also system fields not defined by the user. */
@@ -156,7 +206,7 @@
 				of the non-clustered index */
 	dict_table_t*	table,	/* in: table */
 	dict_index_t*	index);	/* in: user representation of a non-clustered
-				index */	
+				index */
 /**************************************************************************
 Removes a foreign constraint struct from the dictionary cache. */
 static
@@ -196,9 +246,10 @@
 /* Stream for storing detailed information about the latest foreign key
 and unique key errors */
 FILE*	dict_foreign_err_file		= NULL;
-mutex_t	dict_foreign_err_mutex; 	/* mutex protecting the foreign
+mutex_t	dict_foreign_err_mutex;		/* mutex protecting the foreign
 					and unique error buffers */
-	
+
+#ifndef UNIV_HOTBACKUP
 /**********************************************************************
 Makes all characters in a NUL-terminated UTF-8 string lower case. */
 
@@ -209,6 +260,7 @@
 {
 	innobase_casedn_str(a);
 }
+#endif /* !UNIV_HOTBACKUP */
 
 /************************************************************************
 Checks if the database name in two table names is the same. */
@@ -233,7 +285,7 @@
 
 /************************************************************************
 Return the end of table name where we have removed dbname and '/'. */
-static
+
 const char*
 dict_remove_db_name(
 /*================*/
@@ -241,11 +293,10 @@
 	const char*	name)	/* in: table name in the form
 				dbname '/' tablename */
 {
-	const char*	s;
-	s = strchr(name, '/');
+	const char*	s = strchr(name, '/');
 	ut_a(s);
-	if (s) s++;
-	return(s);
+
+	return(s + 1);
 }
 
 /************************************************************************
@@ -263,7 +314,7 @@
 	ut_a(s);
 	return(s - name);
 }
-	
+
 /************************************************************************
 Reserves the dictionary system mutex for MySQL. */
 
@@ -273,7 +324,7 @@
 {
 	mutex_enter(&(dict_sys->mutex));
 }
-	
+
 /************************************************************************
 Releases the dictionary system mutex for MySQL. */
 
@@ -283,7 +334,7 @@
 {
 	mutex_exit(&(dict_sys->mutex));
 }
-	
+
 /************************************************************************
 Decrements the count of open MySQL handles to a table. */
 
@@ -297,7 +348,7 @@
 	ut_a(table->n_mysql_handles_opened > 0);
 
 	table->n_mysql_handles_opened--;
-	
+
 	mutex_exit(&(dict_sys->mutex));
 }
 
@@ -350,7 +401,7 @@
 {
 	return(dict_table_get_index(table, name));
 }
-	
+
 /************************************************************************
 Initializes the autoinc counter. It is not an error to initialize an already
 initialized counter. */
@@ -390,7 +441,7 @@
 		value = table->autoinc;
 		table->autoinc = table->autoinc + 1;
 	}
-	
+
 	mutex_exit(&(table->autoinc_mutex));
 
 	return(value);
@@ -407,7 +458,7 @@
 	mutex_enter(&(table->autoinc_mutex));
 
 	table->autoinc = table->autoinc - 1;
-	
+
 	mutex_exit(&(table->autoinc_mutex));
 }
 
@@ -431,7 +482,7 @@
 	} else {
 		value = table->autoinc;
 	}
-	
+
 	mutex_exit(&(table->autoinc_mutex));
 
 	return(value);
@@ -476,7 +527,7 @@
 		if (value >= table->autoinc) {
 			table->autoinc = value + 1;
 		}
-	}	
+	}
 
 	mutex_exit(&(table->autoinc_mutex));
 }
@@ -497,7 +548,7 @@
 	dict_col_t*	col;
 	ulint		pos;
 	ulint		n_fields;
-	
+
 	ut_ad(index);
 	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
 
@@ -509,7 +560,7 @@
 	}
 
 	n_fields = dict_index_get_n_fields(index);
-	
+
 	for (pos = 0; pos < n_fields; pos++) {
 		field = dict_index_get_nth_field(index, pos);
 
@@ -537,7 +588,7 @@
 	dict_col_t*	col;
 	ulint		pos;
 	ulint		n_fields;
-	
+
 	ut_ad(index);
 	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
 
@@ -549,7 +600,7 @@
 	col = dict_table_get_nth_col(index->table, n);
 
 	n_fields = dict_index_get_n_fields(index);
-	
+
 	for (pos = 0; pos < n_fields; pos++) {
 		field = dict_index_get_nth_field(index, pos);
 
@@ -582,21 +633,21 @@
 	dict_field_t*	field2;
 	ulint		n_fields;
 	ulint		pos;
-	
+
 	ut_ad(index);
 	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
 
 	field2 = dict_index_get_nth_field(index2, n);
 
 	n_fields = dict_index_get_n_fields(index);
-	
+
 	for (pos = 0; pos < n_fields; pos++) {
 		field = dict_index_get_nth_field(index, pos);
 
 		if (field->col == field2->col
-		    && (field->prefix_len == 0
+			&& (field->prefix_len == 0
 			|| (field->prefix_len >= field2->prefix_len
-			    && field2->prefix_len != 0))) {
+				&& field2->prefix_len != 0))) {
 
 			return(pos);
 		}
@@ -606,7 +657,7 @@
 }
 
 /**************************************************************************
-Returns a table object, based on table id, and memoryfixes it. */
+Returns a table object based on table id. */
 
 dict_table_t*
 dict_table_get_on_id(
@@ -616,7 +667,7 @@
 	trx_t*	trx)		/* in: transaction handle */
 {
 	dict_table_t*	table;
-	
+
 	if (ut_dulint_cmp(table_id, DICT_FIELDS_ID) <= 0
 	   || trx->dict_operation_lock_mode == RW_X_LATCH) {
 		/* It is a system table which will always exist in the table
@@ -628,13 +679,13 @@
 		ut_ad(mutex_own(&(dict_sys->mutex)));
 #endif /* UNIV_SYNC_DEBUG */
 
-		return(dict_table_get_on_id_low(table_id, trx));
+		return(dict_table_get_on_id_low(table_id));
 	}
 
 	mutex_enter(&(dict_sys->mutex));
 
-	table = dict_table_get_on_id_low(table_id, trx);
-	
+	table = dict_table_get_on_id_low(table_id);
+
 	mutex_exit(&(dict_sys->mutex));
 
 	return(table);
@@ -656,6 +707,19 @@
 }
 
 /************************************************************************
+Check whether the table uses the compact page format. */
+
+ibool
+dict_table_is_comp_noninline(
+/*=========================*/
+					/* out: TRUE if table uses the
+					compact page format */
+	const dict_table_t*	table)	/* in: table */
+{
+	return(dict_table_is_comp(table));
+}
+
+/************************************************************************
 Checks if a column is in the ordering columns of the clustered index of a
 table. Column prefixes are treated like whole columns. */
 
@@ -672,7 +736,7 @@
 	dict_col_t*	col;
 	ulint		pos;
 	ulint		n_fields;
-	
+
 	ut_ad(table);
 
 	col = dict_table_get_nth_col(table, n);
@@ -680,7 +744,7 @@
 	index = dict_table_get_first_index(table);
 
 	n_fields = dict_index_get_n_unique(index);
-	
+
 	for (pos = 0; pos < n_fields; pos++) {
 		field = dict_index_get_nth_field(index, pos);
 
@@ -702,8 +766,7 @@
 {
 	dict_sys = mem_alloc(sizeof(dict_sys_t));
 
-	mutex_create(&(dict_sys->mutex));
-	mutex_set_level(&(dict_sys->mutex), SYNC_DICT);
+	mutex_create(&dict_sys->mutex, SYNC_DICT);
 
 	dict_sys->table_hash = hash_create(buf_pool_get_max_size() /
 					(DICT_POOL_PER_TABLE_HASH *
@@ -718,44 +781,40 @@
 
 	UT_LIST_INIT(dict_sys->table_LRU);
 
-	rw_lock_create(&dict_operation_lock);
-	rw_lock_set_level(&dict_operation_lock, SYNC_DICT_OPERATION);
+	rw_lock_create(&dict_operation_lock, SYNC_DICT_OPERATION);
 
 	dict_foreign_err_file = os_file_create_tmpfile();
 	ut_a(dict_foreign_err_file);
-	mutex_create(&dict_foreign_err_mutex);
-	mutex_set_level(&dict_foreign_err_mutex, SYNC_ANY_LATCH);
+
+	mutex_create(&dict_foreign_err_mutex, SYNC_ANY_LATCH);
 }
 
 /**************************************************************************
-Returns a table object and memoryfixes it. NOTE! This is a high-level
-function to be used mainly from outside the 'dict' directory. Inside this
-directory dict_table_get_low is usually the appropriate function. */
+Returns a table object. NOTE! This is a high-level function to be used
+mainly from outside the 'dict' directory. Inside this directory
+dict_table_get_low is usually the appropriate function. */
 
 dict_table_t*
 dict_table_get(
 /*===========*/
 					/* out: table, NULL if
 					does not exist */
-	const char*	table_name,	/* in: table name */
-	trx_t*		trx)		/* in: transaction handle or NULL */
+	const char*	table_name)	/* in: table name */
 {
 	dict_table_t*	table;
 
-	UT_NOT_USED(trx);
-
 	mutex_enter(&(dict_sys->mutex));
-	
+
 	table = dict_table_get_low(table_name);
 
 	mutex_exit(&(dict_sys->mutex));
 
 	if (table != NULL) {
-	        if (!table->stat_initialized) {
+		if (!table->stat_initialized) {
 			dict_update_statistics(table);
 		}
 	}
-	
+
 	return(table);
 }
 
@@ -767,30 +826,27 @@
 /*======================================*/
 					/* out: table, NULL if
 					does not exist */
-	const char*	table_name,	/* in: table name */
-	trx_t*		trx)		/* in: transaction handle or NULL */
+	const char*	table_name)	/* in: table name */
 {
 	dict_table_t*	table;
 
-	UT_NOT_USED(trx);
-
 	mutex_enter(&(dict_sys->mutex));
-	
+
 	table = dict_table_get_low(table_name);
 
 	if (table != NULL) {
 
-	        table->n_mysql_handles_opened++;
+		table->n_mysql_handles_opened++;
 	}
 
 	mutex_exit(&(dict_sys->mutex));
 
 	if (table != NULL) {
-	        if (!table->stat_initialized && !table->ibd_file_missing) {
+		if (!table->stat_initialized && !table->ibd_file_missing) {
 			dict_update_statistics(table);
 		}
 	}
-	
+
 	return(table);
 }
 
@@ -805,7 +861,8 @@
 	ulint	fold;
 	ulint	id_fold;
 	ulint	i;
-	
+	ulint	row_len;
+
 	ut_ad(table);
 #ifdef UNIV_SYNC_DEBUG
 	ut_ad(mutex_own(&(dict_sys->mutex)));
@@ -813,12 +870,12 @@
 	ut_ad(table->n_def == table->n_cols - DATA_N_SYS_COLS);
 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
 	ut_ad(table->cached == FALSE);
-	
+
 	fold = ut_fold_string(table->name);
 	id_fold = ut_fold_dulint(table->id);
-	
+
 	table->cached = TRUE;
-	
+
 	/* NOTE: the system columns MUST be added in the following order
 	(so that they can be indexed by the numerical value of DATA_ROW_ID,
 	etc.) and as the last columns of the table memory object.
@@ -847,11 +904,29 @@
 #endif
 
 	/* This check reminds that if a new system column is added to
-	the program, it should be dealt with here */ 
+	the program, it should be dealt with here */
 #if DATA_N_SYS_COLS != 4
 #error "DATA_N_SYS_COLS != 4"
 #endif
 
+	row_len = 0;
+	for (i = 0; i < table->n_def; i++) {
+		ulint	col_len = dtype_get_max_size(
+			dict_col_get_type(dict_table_get_nth_col(table, i)));
+
+		/* If we have a single unbounded field, or several gigantic
+		fields, mark the maximum row size as ULINT_MAX. */
+		if (ut_max(col_len, row_len) >= (ULINT_MAX / 2)) {
+			row_len = ULINT_MAX;
+
+			break;
+		}
+
+		row_len += col_len;
+	}
+
+	table->max_row_size = row_len;
+
 	/* Look for a table with the same name: error if such exists */
 	{
 		dict_table_t*	table2;
@@ -868,13 +943,6 @@
 		ut_a(table2 == NULL);
 	}
 
-	if (table->type == DICT_TABLE_CLUSTER_MEMBER) {
-
-		table->mix_id_len = mach_dulint_get_compressed_size(
-								table->mix_id);
-		mach_dulint_write_compressed(table->mix_id_buf, table->mix_id);
-	}
-
 	/* Add the columns to the column hash table */
 	for (i = 0; i < table->n_cols; i++) {
 		dict_col_add_to_cache(table, dict_table_get_nth_col(table, i));
@@ -890,10 +958,7 @@
 	/* Add table to LRU list of tables */
 	UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table);
 
-	/* If the dictionary cache grows too big, trim the table LRU list */
-
 	dict_sys->size += mem_heap_get_size(table->heap);
-	/* dict_table_LRU_trim(); */
 }
 
 /**************************************************************************
@@ -909,7 +974,7 @@
 {
 	dict_table_t*	table;
 	dict_index_t*	index;
-	
+
 	table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
 
 	while (table) {
@@ -951,16 +1016,16 @@
 	char*		old_name;
 	ibool		success;
 	ulint		i;
-	
+
 	ut_ad(table);
 #ifdef UNIV_SYNC_DEBUG
 	ut_ad(mutex_own(&(dict_sys->mutex)));
 #endif /* UNIV_SYNC_DEBUG */
 
 	old_size = mem_heap_get_size(table->heap);
-	
+
 	fold = ut_fold_string(new_name);
-	
+
 	/* Look for a table with the same name: error if such exists */
 	{
 		dict_table_t*	table2;
@@ -969,7 +1034,7 @@
 		if (table2) {
 			fprintf(stderr,
 "InnoDB: Error: dictionary cache already contains a table of name %s\n",
-	 							     new_name);
+				new_name);
 			return(FALSE);
 		}
 	}
@@ -1018,7 +1083,7 @@
 
 	while (index != NULL) {
 		index->table_name = table->name;
-		
+
 		index = dict_table_get_next_index(index);
 	}
 
@@ -1030,7 +1095,7 @@
 		constraints from the dictionary cache here. The foreign key
 		constraints will be inherited to the new table from the
 		system tables through a call of dict_load_foreigns. */
-	
+
 		/* Remove the foreign constraints from the cache */
 		foreign = UT_LIST_GET_LAST(table->foreign_list);
 
@@ -1046,14 +1111,14 @@
 		while (foreign != NULL) {
 			foreign->referenced_table = NULL;
 			foreign->referenced_index = NULL;
-		
+
 			foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
 		}
 
 		/* Make the list of referencing constraints empty */
 
 		UT_LIST_INIT(table->referenced_list);
-		
+
 		return(TRUE);
 	}
 
@@ -1085,10 +1150,10 @@
 			old_id = mem_strdup(foreign->id);
 
 			if (ut_strlen(foreign->id) > ut_strlen(old_name)
-						+ ((sizeof dict_ibfk) - 1)
-			    && 0 == ut_memcmp(foreign->id, old_name,
-						ut_strlen(old_name))
-			    && 0 == ut_memcmp(
+				+ ((sizeof dict_ibfk) - 1)
+				&& 0 == ut_memcmp(foreign->id, old_name,
+					ut_strlen(old_name))
+				&& 0 == ut_memcmp(
 					foreign->id + ut_strlen(old_name),
 					dict_ibfk, (sizeof dict_ibfk) - 1)) {
 
@@ -1096,11 +1161,11 @@
 
 				if (ut_strlen(table->name) > ut_strlen(old_name)) {
 					foreign->id = mem_heap_alloc(
-					     foreign->heap,
+						foreign->heap,
 						ut_strlen(table->name)
 						+ ut_strlen(old_id) + 1);
 				}
-				
+
 				/* Replace the prefix 'databasename/tablename'
 				with the new names */
 				strcpy(foreign->id, table->name);
@@ -1112,16 +1177,16 @@
 				db_len = dict_get_db_name_len(table->name) + 1;
 
 				if (dict_get_db_name_len(table->name)
-			    	    > dict_get_db_name_len(foreign->id)) {
+					> dict_get_db_name_len(foreign->id)) {
 
 					foreign->id = mem_heap_alloc(
-					     foreign->heap,
-				 	     db_len + ut_strlen(old_id) + 1);
+						foreign->heap,
+						db_len + ut_strlen(old_id) + 1);
 				}
 
 				/* Replace the database prefix in id with the
 				one from table->name */
-			
+
 				ut_memcpy(foreign->id, table->name, db_len);
 
 				strcpy(foreign->id + db_len,
@@ -1194,7 +1259,7 @@
 	dict_index_t*	index;
 	ulint		size;
 	ulint		i;
-	
+
 	ut_ad(table);
 #ifdef UNIV_SYNC_DEBUG
 	ut_ad(mutex_own(&(dict_sys->mutex)));
@@ -1222,7 +1287,7 @@
 	while (foreign != NULL) {
 		foreign->referenced_table = NULL;
 		foreign->referenced_index = NULL;
-		
+
 		foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
 	}
 
@@ -1259,38 +1324,6 @@
 }
 
 /**************************************************************************
-Frees tables from the end of table_LRU if the dictionary cache occupies
-too much space. Currently not used! */
-
-void
-dict_table_LRU_trim(void)
-/*=====================*/
-{
-	dict_table_t*	table;
-	dict_table_t*	prev_table;
-
-	ut_error;
-
-#ifdef UNIV_SYNC_DEBUG
-	ut_ad(mutex_own(&(dict_sys->mutex)));
-#endif /* UNIV_SYNC_DEBUG */
-
-	table = UT_LIST_GET_LAST(dict_sys->table_LRU);
-
-	while (table && (dict_sys->size >
-			 buf_pool_get_max_size() / DICT_POOL_PER_VARYING)) {
-
-		prev_table = UT_LIST_GET_PREV(table_LRU, table);
-
-		if (table->mem_fix == 0) {
-			dict_table_remove_from_cache(table);
-		}
-
-		table = prev_table;
-	}
-}
-
-/**************************************************************************
 Adds a column to the data dictionary hash table. */
 static
 void
@@ -1306,7 +1339,7 @@
 	ut_ad(mutex_own(&(dict_sys->mutex)));
 #endif /* UNIV_SYNC_DEBUG */
 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
-	
+
 	fold = ut_fold_ulint_pair(ut_fold_string(table->name),
 				  ut_fold_string(col->name));
 
@@ -1316,7 +1349,7 @@
 		HASH_SEARCH(hash, dict_sys->col_hash, fold, col2,
 			(ut_strcmp(col->name, col2->name) == 0)
 			&& (ut_strcmp((col2->table)->name, table->name)
-							== 0));  
+							== 0));
 		ut_a(col2 == NULL);
 	}
 
@@ -1339,7 +1372,7 @@
 	ut_ad(mutex_own(&(dict_sys->mutex)));
 #endif /* UNIV_SYNC_DEBUG */
 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
-	
+
 	fold = ut_fold_ulint_pair(ut_fold_string(table->name),
 				  ut_fold_string(col->name));
 
@@ -1364,7 +1397,7 @@
 	ut_ad(mutex_own(&(dict_sys->mutex)));
 #endif /* UNIV_SYNC_DEBUG */
 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
-	
+
 	fold = ut_fold_ulint_pair(ut_fold_string(table->name),
 				  ut_fold_string(col->name));
 
@@ -1372,7 +1405,7 @@
 
 	fold = ut_fold_ulint_pair(ut_fold_string(new_name),
 				  ut_fold_string(col->name));
-				  
+
 	HASH_INSERT(dict_col_t, hash, dict_sys->col_hash, fold, col);
 }
 
@@ -1422,21 +1455,21 @@
 {
 	dict_index_t*	new_index;
 	dict_tree_t*	tree;
-	dict_table_t*	cluster;
 	dict_field_t*	field;
 	ulint		n_ord;
 	ibool		success;
 	ulint		i;
-	
+
 	ut_ad(index);
 #ifdef UNIV_SYNC_DEBUG
 	ut_ad(mutex_own(&(dict_sys->mutex)));
 #endif /* UNIV_SYNC_DEBUG */
 	ut_ad(index->n_def == index->n_fields);
 	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
-	
+
 	ut_ad(mem_heap_validate(index->heap));
 
+#ifdef UNIV_DEBUG
 	{
 		dict_index_t*	index2;
 		index2 = UT_LIST_GET_FIRST(table->indexes);
@@ -1446,10 +1479,11 @@
 
 			index2 = UT_LIST_GET_NEXT(indexes, index2);
 		}
-
-		ut_a(UT_LIST_GET_LEN(table->indexes) == 0
-	      			|| (index->type & DICT_CLUSTERED) == 0);
 	}
+#endif /* UNIV_DEBUG */
+
+	ut_a(!(index->type & DICT_CLUSTERED)
+			|| UT_LIST_GET_LEN(table->indexes) == 0);
 
 	success = dict_index_find_cols(table, index);
 
@@ -1458,7 +1492,7 @@
 
 		return(FALSE);
 	}
-	
+
 	/* Build the cache internal representation of the index,
 	containing also the added system fields */
 
@@ -1469,15 +1503,15 @@
 	}
 
 	new_index->search_info = btr_search_info_create(new_index->heap);
-	
+
 	/* Set the n_fields value in new_index to the actual defined
 	number of fields in the cache internal representation */
 
 	new_index->n_fields = new_index->n_def;
-	
+
 	/* Add the new index as the last index for the table */
 
-	UT_LIST_ADD_LAST(indexes, table->indexes, new_index);	
+	UT_LIST_ADD_LAST(indexes, table->indexes, new_index);
 	new_index->table = table;
 	new_index->table_name = table->name;
 
@@ -1496,21 +1530,11 @@
 		dict_field_get_col(field)->ord_part++;
 	}
 
-	if (table->type == DICT_TABLE_CLUSTER_MEMBER) {
-		/* The index tree is found from the cluster object */
-	    
-		cluster = dict_table_get_low(table->cluster_name);
-
-		tree = dict_index_get_tree(
-					UT_LIST_GET_FIRST(cluster->indexes));
-		new_index->tree = tree;
-	} else {
-		/* Create an index tree memory object for the index */
-		tree = dict_tree_create(new_index, page_no);
-		ut_ad(tree);
+	/* Create an index tree memory object for the index */
+	tree = dict_tree_create(new_index, page_no);
+	ut_ad(tree);
 
-		new_index->tree = tree;
-	}
+	new_index->tree = tree;
 
 	if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) {
 
@@ -1526,14 +1550,11 @@
 			new_index->stat_n_diff_key_vals[i] = 100;
 		}
 	}
-	
+
 	/* Add the index to the list of indexes stored in the tree */
-	UT_LIST_ADD_LAST(tree_indexes, tree->tree_indexes, new_index); 
-	
-	/* If the dictionary cache grows too big, trim the table LRU list */
+	tree->tree_index = new_index;
 
 	dict_sys->size += mem_heap_get_size(new_index->heap);
-	/* dict_table_LRU_trim(); */
 
 	dict_mem_index_free(index);
 
@@ -1560,7 +1581,7 @@
 	ut_ad(mutex_own(&(dict_sys->mutex)));
 #endif /* UNIV_SYNC_DEBUG */
 
-	ut_ad(UT_LIST_GET_LEN((index->tree)->tree_indexes) == 1);
+	ut_ad(index->tree->tree_index);
 	dict_tree_free(index->tree);
 
 	/* Decrement the ord_part counts in columns which are ordering */
@@ -1593,13 +1614,13 @@
 /*=================*/
 				/* out: TRUE if success */
 	dict_table_t*	table,	/* in: table */
-	dict_index_t*	index)	/* in: index */	
+	dict_index_t*	index)	/* in: index */
 {
 	dict_col_t*	col;
 	dict_field_t*	field;
 	ulint		fold;
 	ulint		i;
-	
+
 	ut_ad(table && index);
 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
 #ifdef UNIV_SYNC_DEBUG
@@ -1610,15 +1631,15 @@
 		field = dict_index_get_nth_field(index, i);
 
 		fold = ut_fold_ulint_pair(ut_fold_string(table->name),
-				  	       ut_fold_string(field->name));
-			
+			ut_fold_string(field->name));
+
 		HASH_SEARCH(hash, dict_sys->col_hash, fold, col,
 				(ut_strcmp(col->name, field->name) == 0)
 				&& (ut_strcmp((col->table)->name, table->name)
-								== 0));  
+								== 0));
 		if (col == NULL) {
 
- 			return(FALSE);
+			return(FALSE);
 		} else {
 			field->col = col;
 		}
@@ -1626,7 +1647,7 @@
 
 	return(TRUE);
 }
-	
+
 /***********************************************************************
 Adds a column to index. */
 
@@ -1635,12 +1656,11 @@
 /*===============*/
 	dict_index_t*	index,		/* in: index */
 	dict_col_t*	col,		/* in: column */
-	ulint		order,		/* in: order criterion */
 	ulint		prefix_len)	/* in: column prefix length */
 {
 	dict_field_t*	field;
 
-	dict_mem_index_add_field(index, col->name, order, prefix_len);
+	dict_mem_index_add_field(index, col->name, prefix_len);
 
 	field = dict_index_get_nth_field(index, index->n_def - 1);
 
@@ -1662,17 +1682,6 @@
 	if (!(dtype_get_prtype(&col->type) & DATA_NOT_NULL)) {
 		index->n_nullable++;
 	}
-
-	if (index->n_def > 1) {
-		const dict_field_t*	field2 =
-			dict_index_get_nth_field(index, index->n_def - 2);
-		field->fixed_offs = (!field2->fixed_len ||
-					field2->fixed_offs == ULINT_UNDEFINED)
-				? ULINT_UNDEFINED
-				: field2->fixed_len + field2->fixed_offs;
-	} else {
-		field->fixed_offs = 0;
-	}
 }
 
 /***********************************************************************
@@ -1688,14 +1697,13 @@
 {
 	dict_field_t*	field;
 	ulint		i;
-	
+
 	/* Copy fields contained in index2 */
 
 	for (i = start; i < end; i++) {
 
 		field = dict_index_get_nth_field(index2, i);
-		dict_index_add_col(index1, field->col, field->order,
-						      field->prefix_len);
+		dict_index_add_col(index1, field->col, field->prefix_len);
 	}
 }
 
@@ -1740,8 +1748,6 @@
 	dtype_t*	type;
 	ulint		i;
 
-	ut_ad(!(table->type & DICT_UNIVERSAL));
-
 	for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
 
 		dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
@@ -1762,7 +1768,7 @@
 				of the clustered index */
 	dict_table_t*	table,	/* in: table */
 	dict_index_t*	index)	/* in: user representation of a clustered
-				index */	
+				index */
 {
 	dict_index_t*	new_index;
 	dict_field_t*	field;
@@ -1780,40 +1786,24 @@
 
 	/* Create a new index object with certainly enough fields */
 	new_index = dict_mem_index_create(table->name,
-				     index->name,
-				     table->space,
-				     index->type,
-				     index->n_fields + table->n_cols);
+		index->name, table->space, index->type,
+		index->n_fields + table->n_cols);
 
 	/* Copy other relevant data from the old index struct to the new
 	struct: it inherits the values */
 
 	new_index->n_user_defined_cols = index->n_fields;
-	
-	new_index->id = index->id;
 
-	if (table->type != DICT_TABLE_ORDINARY) {
-		/* The index is mixed: copy common key prefix fields */
-		
-		dict_index_copy(new_index, index, 0, table->mix_len);
-
-		/* Add the mix id column */
-		dict_index_add_col(new_index,
-			  dict_table_get_sys_col(table, DATA_MIX_ID), 0, 0);
+	new_index->id = index->id;
 
-		/* Copy the rest of fields */
-		dict_index_copy(new_index, index, table->mix_len,
-							index->n_fields);
-	} else {
-		/* Copy the fields of index */
-		dict_index_copy(new_index, index, 0, index->n_fields);
-	}
+	/* Copy the fields of index */
+	dict_index_copy(new_index, index, 0, index->n_fields);
 
 	if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
 		/* No fixed number of fields determines an entry uniquely */
 
 		new_index->n_uniq = ULINT_MAX;
-		
+
 	} else if (index->type & DICT_UNIQUE) {
 		/* Only the fields defined so far are needed to identify
 		the index entry uniquely */
@@ -1831,21 +1821,27 @@
 
 		trx_id_pos = new_index->n_def;
 
-		ut_ad(DATA_ROW_ID == 0);
-		ut_ad(DATA_TRX_ID == 1);
-		ut_ad(DATA_ROLL_PTR == 2);
+#if DATA_ROW_ID != 0
+# error "DATA_ROW_ID != 0"
+#endif
+#if DATA_TRX_ID != 1
+# error "DATA_TRX_ID != 1"
+#endif
+#if DATA_ROLL_PTR != 2
+# error "DATA_ROLL_PTR != 2"
+#endif
 
 		if (!(index->type & DICT_UNIQUE)) {
 			dict_index_add_col(new_index,
-			   dict_table_get_sys_col(table, DATA_ROW_ID), 0, 0);
+			   dict_table_get_sys_col(table, DATA_ROW_ID), 0);
 			trx_id_pos++;
 		}
 
 		dict_index_add_col(new_index,
-			   dict_table_get_sys_col(table, DATA_TRX_ID), 0, 0);
-	
+			   dict_table_get_sys_col(table, DATA_TRX_ID), 0);
+
 		dict_index_add_col(new_index,
-			   dict_table_get_sys_col(table, DATA_ROLL_PTR), 0, 0);
+			   dict_table_get_sys_col(table, DATA_ROLL_PTR), 0);
 
 		for (i = 0; i < trx_id_pos; i++) {
 
@@ -1859,7 +1855,7 @@
 			}
 
 			if (dict_index_get_nth_field(new_index, i)->prefix_len
-			    > 0) {
+				> 0) {
 				new_index->trx_id_offset = 0;
 
 				break;
@@ -1887,10 +1883,10 @@
 
 		if (field->prefix_len == 0) {
 
-		        field->col->aux = 0;
+			field->col->aux = 0;
 		}
 	}
-	
+
 	/* Add to new_index non-system columns of table not yet included
 	there */
 	for (i = 0; i < table->n_cols - DATA_N_SYS_COLS; i++) {
@@ -1899,7 +1895,7 @@
 		ut_ad(col->type.mtype != DATA_SYS);
 
 		if (col->aux == ULINT_UNDEFINED) {
-			dict_index_add_col(new_index, col, 0, 0);
+			dict_index_add_col(new_index, col, 0);
 		}
 	}
 
@@ -1914,14 +1910,14 @@
 
 		if (field->prefix_len == 0) {
 
-		        field->col->clust_pos = i;
+			field->col->clust_pos = i;
 		}
 	}
-	
+
 	new_index->cached = TRUE;
 
 	return(new_index);
-}	
+}
 
 /***********************************************************************
 Builds the internal dictionary cache representation for a non-clustered
@@ -1934,7 +1930,7 @@
 				of the non-clustered index */
 	dict_table_t*	table,	/* in: table */
 	dict_index_t*	index)	/* in: user representation of a non-clustered
-				index */	
+				index */
 {
 	dict_field_t*	field;
 	dict_index_t*	new_index;
@@ -1950,24 +1946,21 @@
 
 	/* The clustered index should be the first in the list of indexes */
 	clust_index = UT_LIST_GET_FIRST(table->indexes);
-	
+
 	ut_ad(clust_index);
 	ut_ad(clust_index->type & DICT_CLUSTERED);
 	ut_ad(!(clust_index->type & DICT_UNIVERSAL));
 
 	/* Create a new index */
 	new_index = dict_mem_index_create(table->name,
-				     index->name,
-				     index->space,
-				     index->type,
-				     index->n_fields
-				     + 1 + clust_index->n_uniq);
+		index->name, index->space, index->type,
+		index->n_fields	+ 1 + clust_index->n_uniq);
 
 	/* Copy other relevant data from the old index
 	struct to the new struct: it inherits the values */
 
 	new_index->n_user_defined_cols = index->n_fields;
-	
+
 	new_index->id = index->id;
 
 	/* Copy fields from index to new_index */
@@ -1991,7 +1984,7 @@
 
 		if (field->prefix_len == 0) {
 
-		        field->col->aux = 0;
+			field->col->aux = 0;
 		}
 	}
 
@@ -2003,8 +1996,8 @@
 		field = dict_index_get_nth_field(clust_index, i);
 
 		if (field->col->aux == ULINT_UNDEFINED) {
-			dict_index_add_col(new_index, field->col, 0,
-						      field->prefix_len);
+			dict_index_add_col(new_index, field->col,
+				field->prefix_len);
 		}
 	}
 
@@ -2022,7 +2015,7 @@
 	new_index->cached = TRUE;
 
 	return(new_index);
-}	
+}
 
 /*====================== FOREIGN KEY PROCESSING ========================*/
 
@@ -2037,7 +2030,7 @@
 	dict_table_t*	table)	/* in: InnoDB table */
 {
 	if (UT_LIST_GET_LEN(table->referenced_list) > 0) {
-		
+
 		return(TRUE);
 	}
 
@@ -2067,7 +2060,7 @@
 	ut_ad(mutex_own(&(dict_sys->mutex)));
 #endif /* UNIV_SYNC_DEBUG */
 	ut_a(foreign);
-	
+
 	if (foreign->referenced_table) {
 		UT_LIST_REMOVE(referenced_list,
 			foreign->referenced_table->referenced_list, foreign);
@@ -2108,7 +2101,7 @@
 
 		foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
 	}
-	
+
 	foreign = UT_LIST_GET_FIRST(table->referenced_list);
 
 	while (foreign) {
@@ -2121,8 +2114,9 @@
 	}
 
 	return(NULL);
-}	
+}
 
+#ifndef UNIV_HOTBACKUP
 /*************************************************************************
 Tries to find an index whose first fields are the columns in the array,
 in the same order. */
@@ -2140,11 +2134,10 @@
 					only has an effect if types_idx !=
 					NULL. */
 {
-#ifndef UNIV_HOTBACKUP
 	dict_index_t*	index;
 	const char*	col_name;
 	ulint		i;
-	
+
 	index = dict_table_get_first_index(table);
 
 	while (index != NULL) {
@@ -2157,22 +2150,22 @@
 						->prefix_len != 0) {
 					/* We do not accept column prefix
 					indexes here */
-					
+
 					break;
 				}
 
 				if (0 != innobase_strcasecmp(columns[i],
 								col_name)) {
-				  	break;
+					break;
 				}
 
 				if (types_idx && !cmp_types_are_equal(
-				     dict_index_get_nth_type(index, i),
-				     dict_index_get_nth_type(types_idx, i),
-				     check_charsets)) {
+					    dict_index_get_nth_type(index, i),
+					    dict_index_get_nth_type(types_idx, i),
+					    check_charsets)) {
 
-				  	break;
-				}		
+					break;
+				}
 			}
 
 			if (i == n_cols) {
@@ -2186,12 +2179,6 @@
 	}
 
 	return(NULL);
-#else /* UNIV_HOTBACKUP */
-	/* This function depends on MySQL code that is not included in
-	InnoDB Hot Backup builds.  Besides, this function should never
-	be called in InnoDB Hot Backup. */
-	ut_error;
-#endif /* UNIV_HOTBACKUP */
 }
 
 /**************************************************************************
@@ -2227,7 +2214,7 @@
 	putc('\n', file);
 	if (fk->foreign_index) {
 		fputs("The index in the foreign key in table is ", file);
-		ut_print_name(file, NULL, fk->foreign_index->name);
+		ut_print_name(file, NULL, FALSE, fk->foreign_index->name);
 		fputs("\n"
 "See http://dev.mysql.com/doc/refman/5.0/en/innodb-foreign-key-constraints.html\n"
 "for correct foreign key definition.\n",
@@ -2255,7 +2242,7 @@
 	dict_foreign_t*	for_in_cache		= NULL;
 	dict_index_t*	index;
 	ibool		added_to_referenced_list= FALSE;
-	FILE*		ef 			= dict_foreign_err_file;
+	FILE*		ef			= dict_foreign_err_file;
 
 #ifdef UNIV_SYNC_DEBUG
 	ut_ad(mutex_own(&(dict_sys->mutex)));
@@ -2263,7 +2250,7 @@
 
 	for_table = dict_table_check_if_in_cache_low(
 					foreign->foreign_table_name);
-	
+
 	ref_table = dict_table_check_if_in_cache_low(
 					foreign->referenced_table_name);
 	ut_a(for_table || ref_table);
@@ -2299,7 +2286,7 @@
 				mem_heap_free(foreign->heap);
 			}
 
-		    	return(DB_CANNOT_ADD_CONSTRAINT);
+			return(DB_CANNOT_ADD_CONSTRAINT);
 		}
 
 		for_in_cache->referenced_table = ref_table;
@@ -2328,11 +2315,11 @@
 						ref_table->referenced_list,
 						for_in_cache);
 				}
-			
+
 				mem_heap_free(foreign->heap);
 			}
 
-		    	return(DB_CANNOT_ADD_CONSTRAINT);
+			return(DB_CANNOT_ADD_CONSTRAINT);
 		}
 
 		for_in_cache->foreign_table = for_table;
@@ -2390,12 +2377,13 @@
 
 /*************************************************************************
 Accepts a specified string. Comparisons are case-insensitive. */
-
+static
 const char*
 dict_accept(
 /*========*/
 				/* out: if string was accepted, the pointer
 				is moved after that, else ptr is returned */
+	struct charset_info_st*	cs,/* in: the character set of ptr */
 	const char*	ptr,	/* in: scan from this */
 	const char*	string,	/* in: accept only this string as the next
 				non-whitespace string */
@@ -2405,15 +2393,15 @@
 	const char*	old_ptr2;
 
 	*success = FALSE;
-	
-	while (isspace(*ptr)) {
+
+	while (my_isspace(cs, *ptr)) {
 		ptr++;
 	}
 
 	old_ptr2 = ptr;
-	
+
 	ptr = dict_scan_to(ptr, string);
-	
+
 	if (*ptr == '\0' || old_ptr2 != ptr) {
 		return(old_ptr);
 	}
@@ -2431,12 +2419,15 @@
 dict_scan_id(
 /*=========*/
 				/* out: scanned to */
+	struct charset_info_st*	cs,/* in: the character set of ptr */
 	const char*	ptr,	/* in: scanned to */
 	mem_heap_t*	heap,	/* in: heap where to allocate the id
 				(NULL=id will not be allocated, but it
 				will point to string near ptr) */
 	const char**	id,	/* out,own: the id; NULL if no id was
 				scannable */
+	ibool		table_id,/* in: TRUE=convert the allocated id
+				as a table name; FALSE=convert to UTF-8 */
 	ibool		accept_also_dot)
 				/* in: TRUE if also a dot can appear in a
 				non-quoted id; in a quoted id it can appear
@@ -2445,13 +2436,12 @@
 	char		quote	= '\0';
 	ulint		len	= 0;
 	const char*	s;
-	char*		d;
-	ulint		id_len;
-	byte*		b;
+	char*		str;
+	char*		dst;
 
 	*id = NULL;
 
-	while (isspace(*ptr)) {
+	while (my_isspace(cs, *ptr)) {
 		ptr++;
 	}
 
@@ -2482,9 +2472,9 @@
 			len++;
 		}
 	} else {
-		while (!isspace(*ptr) && *ptr != '(' && *ptr != ')'
-		       && (accept_also_dot || *ptr != '.')
-		       && *ptr != ',' && *ptr != '\0') {
+		while (!my_isspace(cs, *ptr) && *ptr != '(' && *ptr != ')'
+			&& (accept_also_dot || *ptr != '.')
+			&& *ptr != ',' && *ptr != '\0') {
 
 			ptr++;
 		}
@@ -2492,43 +2482,50 @@
 		len = ptr - s;
 	}
 
-	if (quote && heap) {
-		*id = d = mem_heap_alloc(heap, len + 1);
+	if (UNIV_UNLIKELY(!heap)) {
+		/* no heap given: id will point to source string */
+		*id = s;
+		return(ptr);
+	}
+
+	if (quote) {
+		char*	d;
+		str = d = mem_heap_alloc(heap, len + 1);
 		while (len--) {
 			if ((*d++ = *s++) == quote) {
 				s++;
 			}
 		}
 		*d++ = 0;
-		ut_a(*s == quote);
-		ut_a(s + 1 == ptr);
-	} else if (heap) {
-		*id = mem_heap_strdupl(heap, s, len);
+		len = d - str;
+		ut_ad(*s == quote);
+		ut_ad(s + 1 == ptr);
 	} else {
-		/* no heap given: id will point to source string */
-		*id = s;
+		str = mem_heap_strdupl(heap, s, len);
 	}
 
-	if (heap && !quote) {
-		/* EMS MySQL Manager sometimes adds characters 0xA0 (in
-		latin1, a 'non-breakable space') to the end of a table name.
-		But isspace(0xA0) is not true, which confuses our foreign key
-		parser. After the UTF-8 conversion in ha_innodb.cc, bytes 0xC2
-		and 0xA0 are at the end of the string.
-
-		TODO: we should lex the string using thd->charset_info, and
-		my_isspace(). Only after that, convert id names to UTF-8. */
-
-		b = (byte*)(*id);
-		id_len = strlen((char*) b);
-		
-		if (id_len >= 3 && b[id_len - 1] == 0xA0
-			       && b[id_len - 2] == 0xC2) {
-
-			/* Strip the 2 last bytes */
+	if (!table_id) {
+convert_id:
+		/* Convert the identifier from connection character set
+		to UTF-8. */
+		len = 3 * len + 1;
+		*id = dst = mem_heap_alloc(heap, len);
+
+		innobase_convert_from_id(dst, str, len);
+	} else if (!strncmp(str, srv_mysql50_table_name_prefix,
+				sizeof srv_mysql50_table_name_prefix)) {
+		/* This is a pre-5.1 table name
+		containing chars other than [A-Za-z0-9].
+		Discard the prefix and use raw UTF-8 encoding. */
+		str += sizeof srv_mysql50_table_name_prefix;
+		len -= sizeof srv_mysql50_table_name_prefix;
+		goto convert_id;
+	} else {
+		/* Encode using filename-safe characters. */
+		len = 5 * len + 1;
+		*id = dst = mem_heap_alloc(heap, len);
 
-			b[id_len - 2] = '\0';
-		}
+		innobase_convert_from_table_id(dst, str, len);
 	}
 
 	return(ptr);
@@ -2541,6 +2538,7 @@
 dict_scan_col(
 /*==========*/
 				/* out: scanned to */
+	struct charset_info_st*	cs,/* in: the character set of ptr */
 	const char*	ptr,	/* in: scanned to */
 	ibool*		success,/* out: TRUE if success */
 	dict_table_t*	table,	/* in: table in which the column is */
@@ -2549,13 +2547,12 @@
 	const char**	name)	/* out,own: the column name; NULL if no name
 				was scannable */
 {
-#ifndef UNIV_HOTBACKUP
 	dict_col_t*	col;
 	ulint		i;
 
 	*success = FALSE;
 
-	ptr = dict_scan_id(ptr, heap, name, TRUE);
+	ptr = dict_scan_id(cs, ptr, heap, name, FALSE, TRUE);
 
 	if (*name == NULL) {
 
@@ -2566,29 +2563,23 @@
 		*success = TRUE;
 		*column = NULL;
 	} else {
-	    	for (i = 0; i < dict_table_get_n_cols(table); i++) {
+		for (i = 0; i < dict_table_get_n_cols(table); i++) {
 
 			col = dict_table_get_nth_col(table, i);
 
 			if (0 == innobase_strcasecmp(col->name, *name)) {
-		    		/* Found */
+				/* Found */
 
-		    		*success = TRUE;
-		    		*column = col;
-		    		strcpy((char*) *name, col->name);
+				*success = TRUE;
+				*column = col;
+				strcpy((char*) *name, col->name);
 
-		    		break;
+				break;
 			}
 		}
 	}
-	
+
 	return(ptr);
-#else /* UNIV_HOTBACKUP */
-	/* This function depends on MySQL code that is not included in
-	InnoDB Hot Backup builds.  Besides, this function should never
-	be called in InnoDB Hot Backup. */
-	ut_error;
-#endif /* UNIV_HOTBACKUP */
 }
 
 /*************************************************************************
@@ -2598,6 +2589,7 @@
 dict_scan_table_name(
 /*=================*/
 				/* out: scanned to */
+	struct charset_info_st*	cs,/* in: the character set of ptr */
 	const char*	ptr,	/* in: scanned to */
 	dict_table_t**	table,	/* out: table object or NULL */
 	const char*	name,	/* in: foreign key table name */
@@ -2606,7 +2598,6 @@
 	const char**	ref_name)/* out,own: the table name;
 				NULL if no name was scannable */
 {
-#ifndef UNIV_HOTBACKUP
 	const char*	database_name	= NULL;
 	ulint		database_name_len = 0;
 	const char*	table_name	= NULL;
@@ -2616,11 +2607,11 @@
 
 	*success = FALSE;
 	*table = NULL;
-	
-	ptr = dict_scan_id(ptr, heap, &scan_name, FALSE);	
+
+	ptr = dict_scan_id(cs, ptr, heap, &scan_name, TRUE, FALSE);
 
 	if (scan_name == NULL) {
-		
+
 		return(ptr);	/* Syntax error */
 	}
 
@@ -2632,7 +2623,7 @@
 		database_name = scan_name;
 		database_name_len = strlen(database_name);
 
-		ptr = dict_scan_id(ptr, heap, &table_name, FALSE);
+		ptr = dict_scan_id(cs, ptr, heap, &table_name, TRUE, FALSE);
 
 		if (table_name == NULL) {
 
@@ -2688,12 +2679,6 @@
 	*table = dict_table_get_low(ref);
 
 	return(ptr);
-#else /* UNIV_HOTBACKUP */
-	/* This function depends on MySQL code that is not included in
-	InnoDB Hot Backup builds.  Besides, this function should never
-	be called in InnoDB Hot Backup. */
-	ut_error;
-#endif /* UNIV_HOTBACKUP */
 }
 
 /*************************************************************************
@@ -2703,20 +2688,21 @@
 dict_skip_word(
 /*===========*/
 				/* out: scanned to */
+	struct charset_info_st*	cs,/* in: the character set of ptr */
 	const char*	ptr,	/* in: scanned to */
 	ibool*		success)/* out: TRUE if success, FALSE if just spaces
 				left in string or a syntax error */
 {
 	const char*	start;
-	
+
 	*success = FALSE;
 
-	ptr = dict_scan_id(ptr, NULL, &start, TRUE);
+	ptr = dict_scan_id(cs, ptr, NULL, &start, FALSE, TRUE);
 
 	if (start) {
 		*success = TRUE;
 	}
-	
+
 	return(ptr);
 }
 
@@ -2738,8 +2724,8 @@
 	char*		str;
 	const char*	sptr;
 	char*		ptr;
- 	/* unclosed quote character (0 if none) */
- 	char		quote	= 0;
+	/* unclosed quote character (0 if none) */
+	char		quote	= 0;
 
 	str = mem_alloc(strlen(sql_string) + 1);
 
@@ -2767,15 +2753,15 @@
 			/* Starting quote: remember the quote character. */
 			quote = *sptr;
 		} else if (*sptr == '#'
-                           || (sptr[0] == '-' && sptr[1] == '-' &&
-                               sptr[2] == ' ')) {
+			|| (sptr[0] == '-' && sptr[1] == '-' &&
+				sptr[2] == ' ')) {
 			for (;;) {
 				/* In Unix a newline is 0x0A while in Windows
 				it is 0x0D followed by 0x0A */
 
 				if (*sptr == (char)0x0A
-				    || *sptr == (char)0x0D
-				    || *sptr == '\0') {
+					|| *sptr == (char)0x0D
+					|| *sptr == '\0') {
 
 					goto scan_more;
 				}
@@ -2786,7 +2772,7 @@
 			for (;;) {
 				if (*sptr == '*' && *(sptr + 1) == '/') {
 
-				     	sptr += 2;
+					sptr += 2;
 
 					goto scan_more;
 				}
@@ -2832,10 +2818,10 @@
 
 	while (foreign) {
 		if (ut_strlen(foreign->id) > ((sizeof dict_ibfk) - 1) + len
-		    && 0 == ut_memcmp(foreign->id, table->name, len)
-		    && 0 == ut_memcmp(foreign->id + len,
+			&& 0 == ut_memcmp(foreign->id, table->name, len)
+			&& 0 == ut_memcmp(foreign->id + len,
 				dict_ibfk, (sizeof dict_ibfk) - 1)
-		    && foreign->id[len + ((sizeof dict_ibfk) - 1)] != '0') {
+			&& foreign->id[len + ((sizeof dict_ibfk) - 1)] != '0') {
 			/* It is of the >= 4.0.18 format */
 
 			id = strtoul(foreign->id + len + ((sizeof dict_ibfk) - 1),
@@ -2889,6 +2875,7 @@
 				/* out: error code or DB_SUCCESS */
 	trx_t*		trx,	/* in: transaction */
 	mem_heap_t*	heap,	/* in: memory heap */
+	struct charset_info_st*	cs,/* in: the character set of sql_string */
 	const char*	sql_string,
 				/* in: CREATE TABLE or ALTER TABLE statement
 				where foreign keys are declared like:
@@ -2909,7 +2896,7 @@
 	ulint		highest_id_so_far	= 0;
 	dict_index_t*	index;
 	dict_foreign_t*	foreign;
- 	const char*	ptr			= sql_string;
+	const char*	ptr			= sql_string;
 	const char*	start_of_latest_foreign	= sql_string;
 	FILE*		ef			= dict_foreign_err_file;
 	const char*	constraint_name;
@@ -2925,7 +2912,7 @@
 	dict_col_t*	columns[500];
 	const char*	column_names[500];
 	const char*	referenced_table_name;
-	
+
 #ifdef UNIV_SYNC_DEBUG
 	ut_ad(mutex_own(&(dict_sys->mutex)));
 #endif /* UNIV_SYNC_DEBUG */
@@ -2946,14 +2933,14 @@
 	/* First check if we are actually doing an ALTER TABLE, and in that
 	case look for the table being altered */
 
-	ptr = dict_accept(ptr, "ALTER", &success);
+	ptr = dict_accept(cs, ptr, "ALTER", &success);
 
 	if (!success) {
 
 		goto loop;
 	}
 
-	ptr = dict_accept(ptr, "TABLE", &success);
+	ptr = dict_accept(cs, ptr, "TABLE", &success);
 
 	if (!success) {
 
@@ -2962,7 +2949,7 @@
 
 	/* We are doing an ALTER TABLE: scan the table name we are altering */
 
-	ptr = dict_scan_table_name(ptr, &table_to_alter, name,
+	ptr = dict_scan_table_name(cs, ptr, &table_to_alter, name,
 				&success, heap, &referenced_table_name);
 	if (!success) {
 		fprintf(stderr,
@@ -3002,21 +2989,22 @@
 		of the constraint to system tables. */
 		ptr = ptr1;
 
-		ptr = dict_accept(ptr, "CONSTRAINT", &success);
+		ptr = dict_accept(cs, ptr, "CONSTRAINT", &success);
 
 		ut_a(success);
 
-		if (!isspace(*ptr) && *ptr != '"' && *ptr != '`') {
-	        	goto loop;
+		if (!my_isspace(cs, *ptr) && *ptr != '"' && *ptr != '`') {
+			goto loop;
 		}
 
-		while (isspace(*ptr)) {
+		while (my_isspace(cs, *ptr)) {
 			ptr++;
 		}
 
 		/* read constraint name unless got "CONSTRAINT FOREIGN" */
 		if (ptr != ptr2) {
-			ptr = dict_scan_id(ptr, heap, &constraint_name, FALSE);
+			ptr = dict_scan_id(cs, ptr, heap,
+					&constraint_name, FALSE, FALSE);
 		}
 	} else {
 		ptr = ptr2;
@@ -3030,15 +3018,15 @@
 		   command, determine if there are any foreign keys, and
 		   if so, immediately reject the command if the table is a
 		   temporary one. For now, this kludge will work. */
-		if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0))
-		{
-			return DB_CANNOT_ADD_CONSTRAINT;
+		if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) {
+
+			return(DB_CANNOT_ADD_CONSTRAINT);
 		}
-		
+
 		/**********************************************************/
 		/* The following call adds the foreign key constraints
 		to the data dictionary system tables on disk */
-		
+
 		error = dict_create_add_foreigns_to_dictionary(
 						highest_id_so_far, table, trx);
 		return(error);
@@ -3046,28 +3034,28 @@
 
 	start_of_latest_foreign = ptr;
 
-	ptr = dict_accept(ptr, "FOREIGN", &success);		
-	
+	ptr = dict_accept(cs, ptr, "FOREIGN", &success);
+
 	if (!success) {
 		goto loop;
 	}
 
-	if (!isspace(*ptr)) {
-	        goto loop;
+	if (!my_isspace(cs, *ptr)) {
+		goto loop;
 	}
 
-	ptr = dict_accept(ptr, "KEY", &success);
+	ptr = dict_accept(cs, ptr, "KEY", &success);
 
 	if (!success) {
 		goto loop;
 	}
 
-	ptr = dict_accept(ptr, "(", &success);
+	ptr = dict_accept(cs, ptr, "(", &success);
 
 	if (!success) {
 		/* MySQL allows also an index id before the '('; we
 		skip it */
-		ptr = dict_skip_word(ptr, &success);
+		ptr = dict_skip_word(cs, ptr, &success);
 
 		if (!success) {
 			dict_foreign_report_syntax_err(name,
@@ -3076,13 +3064,13 @@
 			return(DB_CANNOT_ADD_CONSTRAINT);
 		}
 
-		ptr = dict_accept(ptr, "(", &success);
+		ptr = dict_accept(cs, ptr, "(", &success);
 
 		if (!success) {
 			/* We do not flag a syntax error here because in an
 			ALTER TABLE we may also have DROP FOREIGN KEY abc */
 
-		        goto loop;
+			goto loop;
 		}
 	}
 
@@ -3091,7 +3079,7 @@
 	/* Scan the columns in the first list */
 col_loop1:
 	ut_a(i < (sizeof column_names) / sizeof *column_names);
-	ptr = dict_scan_col(ptr, &success, table, columns + i,
+	ptr = dict_scan_col(cs, ptr, &success, table, columns + i,
 				heap, column_names + i);
 	if (!success) {
 		mutex_enter(&dict_foreign_err_mutex);
@@ -3104,14 +3092,14 @@
 	}
 
 	i++;
-	
-	ptr = dict_accept(ptr, ",", &success);
+
+	ptr = dict_accept(cs, ptr, ",", &success);
 
 	if (success) {
 		goto col_loop1;
 	}
-	
-	ptr = dict_accept(ptr, ")", &success);
+
+	ptr = dict_accept(cs, ptr, ")", &success);
 
 	if (!success) {
 		dict_foreign_report_syntax_err(name, start_of_latest_foreign,
@@ -3128,7 +3116,7 @@
 		mutex_enter(&dict_foreign_err_mutex);
 		dict_foreign_error_report_low(ef, name);
 		fputs("There is no index in table ", ef);
-		ut_print_name(ef, NULL, name);
+		ut_print_name(ef, NULL, TRUE, name);
 		fprintf(ef, " where the columns appear\n"
 "as the first columns. Constraint:\n%s\n"
 "See http://dev.mysql.com/doc/refman/5.0/en/innodb-foreign-key-constraints.html\n"
@@ -3138,9 +3126,9 @@
 
 		return(DB_CANNOT_ADD_CONSTRAINT);
 	}
-	ptr = dict_accept(ptr, "REFERENCES", &success);
+	ptr = dict_accept(cs, ptr, "REFERENCES", &success);
 
-	if (!success || !isspace(*ptr)) {
+	if (!success || !my_isspace(cs, *ptr)) {
 		dict_foreign_report_syntax_err(name, start_of_latest_foreign,
 									ptr);
 		return(DB_CANNOT_ADD_CONSTRAINT);
@@ -3151,7 +3139,7 @@
 	foreign = dict_mem_foreign_create();
 
 	if (constraint_name) {
-		ulint	db_len;	
+		ulint	db_len;
 
 		/* Catenate 'databasename/' to the constraint name specified
 		by the user: we conceive the constraint as belonging to the
@@ -3179,8 +3167,8 @@
 		foreign->foreign_col_names[i] =
 			mem_heap_strdup(foreign->heap, columns[i]->name);
 	}
-	
-	ptr = dict_scan_table_name(ptr, &referenced_table, name,
+
+	ptr = dict_scan_table_name(cs, ptr, &referenced_table, name,
 				&success, heap, &referenced_table_name);
 
 	/* Note that referenced_table can be NULL if the user has suppressed
@@ -3198,8 +3186,8 @@
 
 		return(DB_CANNOT_ADD_CONSTRAINT);
 	}
-	
-	ptr = dict_accept(ptr, "(", &success);
+
+	ptr = dict_accept(cs, ptr, "(", &success);
 
 	if (!success) {
 		dict_foreign_free(foreign);
@@ -3212,10 +3200,10 @@
 	i = 0;
 
 col_loop2:
-	ptr = dict_scan_col(ptr, &success, referenced_table, columns + i,
+	ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i,
 				heap, column_names + i);
 	i++;
-	
+
 	if (!success) {
 		dict_foreign_free(foreign);
 
@@ -3229,17 +3217,17 @@
 		return(DB_CANNOT_ADD_CONSTRAINT);
 	}
 
-	ptr = dict_accept(ptr, ",", &success);
+	ptr = dict_accept(cs, ptr, ",", &success);
 
 	if (success) {
 		goto col_loop2;
 	}
-	
-	ptr = dict_accept(ptr, ")", &success);
+
+	ptr = dict_accept(cs, ptr, ")", &success);
 
 	if (!success || foreign->n_fields != i) {
 		dict_foreign_free(foreign);
-		
+
 		dict_foreign_report_syntax_err(name, start_of_latest_foreign,
 									ptr);
 		return(DB_CANNOT_ADD_CONSTRAINT);
@@ -3247,25 +3235,25 @@
 
 	n_on_deletes = 0;
 	n_on_updates = 0;
-	
+
 scan_on_conditions:
 	/* Loop here as long as we can find ON ... conditions */
 
-	ptr = dict_accept(ptr, "ON", &success);
+	ptr = dict_accept(cs, ptr, "ON", &success);
 
 	if (!success) {
 
 		goto try_find_index;
 	}
 
-	ptr = dict_accept(ptr, "DELETE", &success);
+	ptr = dict_accept(cs, ptr, "DELETE", &success);
 
 	if (!success) {
-		ptr = dict_accept(ptr, "UPDATE", &success);
+		ptr = dict_accept(cs, ptr, "UPDATE", &success);
 
 		if (!success) {
 			dict_foreign_free(foreign);
-		
+
 			dict_foreign_report_syntax_err(name,
 						start_of_latest_foreign, ptr);
 			return(DB_CANNOT_ADD_CONSTRAINT);
@@ -3278,13 +3266,13 @@
 		n_on_deletes++;
 	}
 
-	ptr = dict_accept(ptr, "RESTRICT", &success);
+	ptr = dict_accept(cs, ptr, "RESTRICT", &success);
 
 	if (success) {
 		goto scan_on_conditions;
 	}
 
-	ptr = dict_accept(ptr, "CASCADE", &success);
+	ptr = dict_accept(cs, ptr, "CASCADE", &success);
 
 	if (success) {
 		if (is_on_delete) {
@@ -3296,16 +3284,16 @@
 		goto scan_on_conditions;
 	}
 
-	ptr = dict_accept(ptr, "NO", &success);
+	ptr = dict_accept(cs, ptr, "NO", &success);
 
 	if (success) {
-		ptr = dict_accept(ptr, "ACTION", &success);
+		ptr = dict_accept(cs, ptr, "ACTION", &success);
 
 		if (!success) {
 			dict_foreign_free(foreign);
 			dict_foreign_report_syntax_err(name,
 					start_of_latest_foreign, ptr);
-		
+
 			return(DB_CANNOT_ADD_CONSTRAINT);
 		}
 
@@ -3318,7 +3306,7 @@
 		goto scan_on_conditions;
 	}
 
-	ptr = dict_accept(ptr, "SET", &success);
+	ptr = dict_accept(cs, ptr, "SET", &success);
 
 	if (!success) {
 		dict_foreign_free(foreign);
@@ -3327,7 +3315,7 @@
 		return(DB_CANNOT_ADD_CONSTRAINT);
 	}
 
-	ptr = dict_accept(ptr, "NULL", &success);
+	ptr = dict_accept(cs, ptr, "NULL", &success);
 
 	if (!success) {
 		dict_foreign_free(foreign);
@@ -3362,13 +3350,13 @@
 	} else {
 		foreign->type |= DICT_FOREIGN_ON_UPDATE_SET_NULL;
 	}
-	
+
 	goto scan_on_conditions;
 
 try_find_index:
 	if (n_on_deletes > 1 || n_on_updates > 1) {
 		/* It is an error to define more than 1 action */
-		
+
 		dict_foreign_free(foreign);
 
 		mutex_enter(&dict_foreign_err_mutex);
@@ -3416,7 +3404,7 @@
 
 	foreign->referenced_table_name = mem_heap_strdup(foreign->heap,
 						referenced_table_name);
-					
+
 	foreign->referenced_col_names = mem_heap_alloc(foreign->heap,
 							i * sizeof(void*));
 	for (i = 0; i < foreign->n_fields; i++) {
@@ -3425,7 +3413,7 @@
 	}
 
 	/* We found an ok constraint definition: add to the lists */
-	
+
 	UT_LIST_ADD_LAST(foreign_list, table->foreign_list, foreign);
 
 	if (referenced_table) {
@@ -3437,6 +3425,25 @@
 	goto loop;
 }
 
+/**************************************************************************
+Determines whether a string starts with the specified keyword. */
+
+ibool
+dict_str_starts_with_keyword(
+/*=========================*/
+					/* out: TRUE if str starts
+					with keyword */
+	void*		mysql_thd,	/* in: MySQL thread handle */
+	const char*	str,		/* in: string to scan for keyword */
+	const char*	keyword)	/* in: keyword to look for */
+{
+	struct charset_info_st*	cs	= innobase_get_charset(mysql_thd);
+	ibool			success;
+
+	dict_accept(cs, str, keyword, &success);
+	return(success);
+}
+
 /*************************************************************************
 Scans a table create SQL string and adds to the data dictionary the foreign
 key constraints declared in the string. This function should be called after
@@ -3464,20 +3471,23 @@
 					code DB_CANNOT_ADD_CONSTRAINT if
 					any foreign keys are found. */
 {
-	char*		str;
-	ulint		err;
-	mem_heap_t*	heap;
+	char*			str;
+	ulint			err;
+	mem_heap_t*		heap;
+
+	ut_a(trx && trx->mysql_thd);
 
 	str = dict_strip_comments(sql_string);
 	heap = mem_heap_create(10000);
 
-	err = dict_create_foreign_constraints_low(trx, heap, str, name,
-		reject_fks);
+	err = dict_create_foreign_constraints_low(trx, heap,
+			innobase_get_charset(trx->mysql_thd),
+			str, name, reject_fks);
 
 	mem_heap_free(heap);
 	mem_free(str);
 
-	return(err);	
+	return(err);
 }
 
 /**************************************************************************
@@ -3499,13 +3509,18 @@
 	const char***	constraints_to_drop)	/* out: id's of the
 						constraints to drop */
 {
-	dict_foreign_t*	foreign;
-	ibool		success;
-	char*		str;
-	const char*	ptr;
-	const char*	id;
-	FILE*		ef	= dict_foreign_err_file;
-	
+	dict_foreign_t*		foreign;
+	ibool			success;
+	char*			str;
+	const char*		ptr;
+	const char*		id;
+	FILE*			ef	= dict_foreign_err_file;
+	struct charset_info_st*	cs;
+
+	ut_a(trx && trx->mysql_thd);
+
+	cs = innobase_get_charset(trx->mysql_thd);
+
 	*n = 0;
 
 	*constraints_to_drop = mem_heap_alloc(heap, 1000 * sizeof(char*));
@@ -3521,32 +3536,32 @@
 
 	if (*ptr == '\0') {
 		mem_free(str);
-		
+
 		return(DB_SUCCESS);
 	}
 
-	ptr = dict_accept(ptr, "DROP", &success);
+	ptr = dict_accept(cs, ptr, "DROP", &success);
 
-	if (!isspace(*ptr)) {
+	if (!my_isspace(cs, *ptr)) {
 
-	        goto loop;
+		goto loop;
 	}
 
-	ptr = dict_accept(ptr, "FOREIGN", &success);
-	
+	ptr = dict_accept(cs, ptr, "FOREIGN", &success);
+
 	if (!success) {
 
-	        goto loop;
+		goto loop;
 	}
 
-	ptr = dict_accept(ptr, "KEY", &success);
+	ptr = dict_accept(cs, ptr, "KEY", &success);
 
 	if (!success) {
 
 		goto syntax_error;
 	}
 
-	ptr = dict_scan_id(ptr, heap, &id, TRUE);
+	ptr = dict_scan_id(cs, ptr, heap, &id, FALSE, TRUE);
 
 	if (id == NULL) {
 
@@ -3556,20 +3571,20 @@
 	ut_a(*n < 1000);
 	(*constraints_to_drop)[*n] = id;
 	(*n)++;
-	
+
 	/* Look for the given constraint id */
 
 	foreign = UT_LIST_GET_FIRST(table->foreign_list);
 
 	while (foreign != NULL) {
 		if (0 == strcmp(foreign->id, id)
-		    || (strchr(foreign->id, '/')
-			&& 0 == strcmp(id,
+			|| (strchr(foreign->id, '/')
+				&& 0 == strcmp(id,
 					dict_remove_db_name(foreign->id)))) {
 			/* Found */
 			break;
 		}
-		
+
 		foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
 	}
 
@@ -3579,12 +3594,12 @@
 		ut_print_timestamp(ef);
 		fputs(
 	" Error in dropping of a foreign key constraint of table ", ef);
-		ut_print_name(ef, NULL, table->name);
+		ut_print_name(ef, NULL, TRUE, table->name);
 		fputs(",\n"
 			"in SQL command\n", ef);
 		fputs(str, ef);
 		fputs("\nCannot find a constraint with the given id ", ef);
-		ut_print_name(ef, NULL, id);
+		ut_print_name(ef, NULL, FALSE, id);
 		fputs(".\n", ef);
 		mutex_exit(&dict_foreign_err_mutex);
 
@@ -3593,7 +3608,7 @@
 		return(DB_CANNOT_DROP_CONSTRAINT);
 	}
 
-	goto loop;	
+	goto loop;
 
 syntax_error:
 	mutex_enter(&dict_foreign_err_mutex);
@@ -3601,7 +3616,7 @@
 	ut_print_timestamp(ef);
 	fputs(
 	" Syntax error in dropping of a foreign key constraint of table ", ef);
-	ut_print_name(ef, NULL, table->name);
+	ut_print_name(ef, NULL, TRUE, table->name);
 	fprintf(ef, ",\n"
 		"close to:\n%s\n in SQL command\n%s\n", ptr, str);
 	mutex_exit(&dict_foreign_err_mutex);
@@ -3610,6 +3625,7 @@
 
 	return(DB_CANNOT_DROP_CONSTRAINT);
 }
+#endif /* UNIV_HOTBACKUP */
 
 /*==================== END OF FOREIGN KEY PROCESSING ====================*/
 
@@ -3630,7 +3646,7 @@
 	}
 
 	mutex_enter(&(dict_sys->mutex));
-	
+
 	table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
 
 	while (table) {
@@ -3678,14 +3694,12 @@
 	tree->page = page_no;
 
 	tree->id = index->id;
-	
-	UT_LIST_INIT(tree->tree_indexes);
 
-	tree->magic_n = DICT_TREE_MAGIC_N;
+	tree->tree_index = NULL;
 
-	rw_lock_create(&(tree->lock));
+	tree->magic_n = DICT_TREE_MAGIC_N;
 
-	rw_lock_set_level(&(tree->lock), SYNC_INDEX_TREE);
+	rw_lock_create(&tree->lock, SYNC_INDEX_TREE);
 
 	return(tree);
 }
@@ -3705,135 +3719,7 @@
 	mem_free(tree);
 }
 
-/**************************************************************************
-In an index tree, finds the index corresponding to a record in the tree. */
-UNIV_INLINE
-dict_index_t*
-dict_tree_find_index_low(
-/*=====================*/
-				/* out: index */
-	dict_tree_t*	tree,	/* in: index tree */
-	rec_t*		rec)	/* in: record for which to find correct
-				index */
-{
-	dict_index_t*	index;
-	dict_table_t*	table;
-	dulint		mix_id;
-	ulint		len;
-	
-	index = UT_LIST_GET_FIRST(tree->tree_indexes);
-	ut_ad(index);
-	table = index->table;
-	
-	if ((index->type & DICT_CLUSTERED)
-			&& UNIV_UNLIKELY(table->type != DICT_TABLE_ORDINARY)) {
-
-		/* Get the mix id of the record */
-		ut_a(!table->comp);
-
-		mix_id = mach_dulint_read_compressed(
-			rec_get_nth_field_old(rec, table->mix_len, &len));
-
-		while (ut_dulint_cmp(table->mix_id, mix_id) != 0) {
-
-			index = UT_LIST_GET_NEXT(tree_indexes, index);
-			table = index->table;
-			ut_ad(index);
-		}
-	}
-
-	return(index);
-}
-
-/**************************************************************************
-In an index tree, finds the index corresponding to a record in the tree. */
-
-dict_index_t*
-dict_tree_find_index(
-/*=================*/
-				/* out: index */
-	dict_tree_t*	tree,	/* in: index tree */
-	rec_t*		rec)	/* in: record for which to find correct
-				index */
-{
-	dict_index_t*	index;
-	
-	index = dict_tree_find_index_low(tree, rec);
-	
-	return(index);
-}
-
-/**************************************************************************
-In an index tree, finds the index corresponding to a dtuple which is used
-in a search to a tree. */
-
-dict_index_t*
-dict_tree_find_index_for_tuple(
-/*===========================*/
-				/* out: index; NULL if the tuple does not
-				contain the mix id field in a mixed tree */
-	dict_tree_t*	tree,	/* in: index tree */
-	dtuple_t*	tuple)	/* in: tuple for which to find index */
-{
-	dict_index_t*	index;
-	dict_table_t*	table;
-	dulint		mix_id;
-
-	ut_ad(dtuple_check_typed(tuple));
-	
-	if (UT_LIST_GET_LEN(tree->tree_indexes) == 1) {
-
-		return(UT_LIST_GET_FIRST(tree->tree_indexes));
-	}
-
-	index = UT_LIST_GET_FIRST(tree->tree_indexes);
-	ut_ad(index);
-	table = index->table;
-
-	if (dtuple_get_n_fields(tuple) <= table->mix_len) {
-
-		return(NULL);
-	}
-
-	/* Get the mix id of the record */
-
-	mix_id = mach_dulint_read_compressed(
-			dfield_get_data(
-				dtuple_get_nth_field(tuple, table->mix_len)));
-
-	while (ut_dulint_cmp(table->mix_id, mix_id) != 0) {
-
-		index = UT_LIST_GET_NEXT(tree_indexes, index);
-		table = index->table;
-		ut_ad(index);
-	}
-
-	return(index);
-}
-
-/***********************************************************************
-Checks if a table which is a mixed cluster member owns a record. */
-
-ibool
-dict_is_mixed_table_rec(
-/*====================*/
-				/* out: TRUE if the record belongs to this
-				table */
-	dict_table_t*	table,	/* in: table in a mixed cluster */
-	rec_t*		rec)	/* in: user record in the clustered index */
-{
-	byte*	mix_id_field;
-	ulint	len;
-
-	ut_ad(!table->comp);
-
-	mix_id_field = rec_get_nth_field_old(rec,
-					table->mix_len, &len);
-
-	return(len == table->mix_id_len
-		&& !ut_memcmp(table->mix_id_buf, mix_id_field, len));
-}
-
+#ifdef UNIV_DEBUG
 /**************************************************************************
 Checks that a tuple has n_fields_cmp value in a sensible range, so that
 no comparison can occur with the page number field in a node pointer. */
@@ -3845,19 +3731,14 @@
 	dict_tree_t*	tree,	/* in: index tree */
 	dtuple_t*	tuple)	/* in: tuple used in a search */
 {
-	dict_index_t*	index;
-
-	index = dict_tree_find_index_for_tuple(tree, tuple);
-
-	if (index == NULL) {
-
-		return(TRUE);
-	}
+	dict_index_t*	index	= tree->tree_index;
 
+	ut_a(index);
 	ut_a(dtuple_get_n_fields_cmp(tuple)
 				<= dict_index_get_n_unique_in_tree(index));
 	return(TRUE);
 }
+#endif /* UNIV_DEBUG */
 
 /**************************************************************************
 Builds a node pointer out of a physical record and a page number. */
@@ -3871,7 +3752,7 @@
 				pointer */
 	ulint		page_no,/* in: page number to put in node pointer */
 	mem_heap_t*	heap,	/* in: memory heap where pointer created */
-	ulint           level)  /* in: level of rec in tree: 0 means leaf
+	ulint		level)	/* in: level of rec in tree: 0 means leaf
 				level */
 {
 	dtuple_t*	tuple;
@@ -3880,22 +3761,22 @@
 	byte*		buf;
 	ulint		n_unique;
 
-	ind = dict_tree_find_index_low(tree, rec);
-	
+	ind = tree->tree_index;
+
 	if (UNIV_UNLIKELY(tree->type & DICT_UNIVERSAL)) {
 		/* In a universal index tree, we take the whole record as
 		the node pointer if the reord is on the leaf level,
 		on non-leaf levels we remove the last field, which
 		contains the page number of the child page */
 
-		ut_a(!ind->table->comp);
+		ut_a(!dict_table_is_comp(ind->table));
 		n_unique = rec_get_n_fields_old(rec);
 
 		if (level > 0) {
-		        ut_a(n_unique > 1);
-		        n_unique--;
+			ut_a(n_unique > 1);
+			n_unique--;
 		}
-	} else {	
+	} else {
 		n_unique = dict_index_get_n_unique_in_tree(ind);
 	}
 
@@ -3906,15 +3787,15 @@
 	levels in the tree there may be identical node pointers with a
 	different page number; therefore, we set the n_fields_cmp to one
 	less: */
-	
+
 	dtuple_set_n_fields_cmp(tuple, n_unique);
 
 	dict_index_copy_types(tuple, ind, n_unique);
-	
+
 	buf = mem_heap_alloc(heap, 4);
 
 	mach_write_to_4(buf, page_no);
-	
+
 	field = dtuple_get_nth_field(tuple, n_unique);
 	dfield_set_data(field, buf, 4);
 
@@ -3927,8 +3808,8 @@
 	ut_ad(dtuple_check_typed(tuple));
 
 	return(tuple);
-}	
-	
+}
+
 /**************************************************************************
 Copies an initial segment of a physical record, long enough to specify an
 index entry uniquely. */
@@ -3948,10 +3829,10 @@
 	ulint		n;
 
 	UNIV_PREFETCH_R(rec);
-	index = dict_tree_find_index_low(tree, rec);
+	index = tree->tree_index;
 
 	if (UNIV_UNLIKELY(tree->type & DICT_UNIVERSAL)) {
-		ut_a(!index->table->comp);
+		ut_a(!dict_table_is_comp(index->table));
 		n = rec_get_n_fields_old(rec);
 	} else {
 		n = dict_index_get_n_unique_in_tree(index);
@@ -3976,11 +3857,12 @@
 	dtuple_t*	tuple;
 	dict_index_t*	ind;
 
-	ind = dict_tree_find_index_low(tree, rec);
+	ind = tree->tree_index;
+
+	ut_ad(dict_table_is_comp(ind->table)
+		|| n_fields <= rec_get_n_fields_old(rec));
 
-	ut_ad(ind->table->comp || n_fields <= rec_get_n_fields_old(rec));
-	
-	tuple = dtuple_create(heap, n_fields); 
+	tuple = dtuple_create(heap, n_fields);
 
 	dict_index_copy_types(tuple, ind, n_fields);
 
@@ -3989,8 +3871,8 @@
 	ut_ad(dtuple_check_typed(tuple));
 
 	return(tuple);
-}	
-	
+}
+
 /*************************************************************************
 Calculates the minimum record length in an index. */
 
@@ -4002,7 +3884,7 @@
 	ulint	sum	= 0;
 	ulint	i;
 
-	if (UNIV_LIKELY(index->table->comp)) {
+	if (dict_table_is_comp(index->table)) {
 		ulint nullable = 0;
 		sum = REC_N_NEW_EXTRA_BYTES;
 		for (i = 0; i < dict_index_get_n_fields(index); i++) {
@@ -4047,8 +3929,8 @@
 /*=======================*/
 	dict_table_t*	table,		/* in: table */
 	ibool		has_dict_mutex __attribute__((unused)))
-                                        /* in: TRUE if the caller has the
-					dictionary mutex */	
+					/* in: TRUE if the caller has the
+					dictionary mutex */
 {
 	dict_index_t*	index;
 	ulint		size;
@@ -4076,11 +3958,11 @@
 	/* Find out the sizes of the indexes and how many different values
 	for the key they approximately have */
 
-	index = dict_table_get_first_index(table);	
+	index = dict_table_get_first_index(table);
 
 	if (index == NULL) {
 		/* Table definition is corrupt */
-	
+
 		return;
 	}
 
@@ -4099,7 +3981,7 @@
 		}
 
 		index->stat_n_leaf_pages = size;
-		
+
 		btr_estimate_number_of_different_key_vals(index);
 
 		index = dict_table_get_next_index(index);
@@ -4117,7 +3999,7 @@
 
 	table->stat_initialized = TRUE;
 
-        table->stat_modified_counter = 0;
+	table->stat_modified_counter = 0;
 }
 
 /*************************************************************************
@@ -4133,6 +4015,18 @@
 }
 
 /**************************************************************************
+A noninlined version of dict_table_get_low. */
+
+dict_table_t*
+dict_table_get_low_noninlined(
+/*==========================*/
+					/* out: table, NULL if not found */
+	const char*	table_name)	/* in: table name */
+{
+	return(dict_table_get_low(table_name));
+}
+
+/**************************************************************************
 Prints info of a foreign key constraint. */
 static
 void
@@ -4156,7 +4050,7 @@
 	fprintf(stderr, " )\n"
 		"             REFERENCES %s (",
 		foreign->referenced_table_name);
-	
+
 	for (i = 0; i < foreign->n_fields; i++) {
 		fprintf(stderr, " %s", foreign->referenced_col_names[i]);
 	}
@@ -4192,7 +4086,7 @@
 	table = dict_table_get_low(name);
 
 	ut_a(table);
-	
+
 	dict_table_print_low(table);
 	mutex_exit(&(dict_sys->mutex));
 }
@@ -4214,7 +4108,7 @@
 #endif /* UNIV_SYNC_DEBUG */
 
 	dict_update_statistics_low(table, TRUE);
-	
+
 	fprintf(stderr,
 "--------------------------------------\n"
 "TABLE: name %s, id %lu %lu, columns %lu, indexes %lu, appr.rows %lu\n"
@@ -4223,7 +4117,7 @@
 			(ulong) ut_dulint_get_high(table->id),
 			(ulong) ut_dulint_get_low(table->id),
 			(ulong) table->n_cols,
-		        (ulong) UT_LIST_GET_LEN(table->indexes),
+			(ulong) UT_LIST_GET_LEN(table->indexes),
 			(ulong) table->stat_n_rows);
 
 	for (i = 0; i < table->n_cols - 1; i++) {
@@ -4301,7 +4195,7 @@
 	}
 
 	fprintf(stderr,
-		"  INDEX: name %s, id %lu %lu, fields %lu/%lu, type %lu\n"
+		"  INDEX: name %s, id %lu %lu, fields %lu/%lu, uniq %lu, type %lu\n"
 		"   root page %lu, appr.key vals %lu,"
 		" leaf pages %lu, size pages %lu\n"
 		"   FIELDS: ",
@@ -4309,12 +4203,14 @@
 		(ulong) ut_dulint_get_high(tree->id),
 		(ulong) ut_dulint_get_low(tree->id),
 		(ulong) index->n_user_defined_cols,
-		(ulong) index->n_fields, (ulong) index->type,
+		(ulong) index->n_fields,
+		(ulong) index->n_uniq,
+		(ulong) index->type,
 		(ulong) tree->page,
 		(ulong) n_vals,
 		(ulong) index->stat_n_leaf_pages,
 		(ulong) index->stat_index_size);
-			
+
 	for (i = 0; i < index->n_fields; i++) {
 		dict_field_print_low(dict_index_get_nth_field(index, i));
 	}
@@ -4360,7 +4256,7 @@
 {
 	const char*	stripped_id;
 	ulint	i;
-	
+
 	if (strchr(foreign->id, '/')) {
 		/* Strip the preceding database name from the constraint id */
 		stripped_id = foreign->id + 1
@@ -4370,23 +4266,23 @@
 	}
 
 	putc(',', file);
-	
+
 	if (add_newline) {
 		/* SHOW CREATE TABLE wants constraints each printed nicely
 		on its own line, while error messages want no newlines
 		inserted. */
 		fputs("\n ", file);
 	}
-	
+
 	fputs(" CONSTRAINT ", file);
-	ut_print_name(file, trx, stripped_id);
+	ut_print_name(file, trx, FALSE, stripped_id);
 	fputs(" FOREIGN KEY (", file);
 
 	for (i = 0;;) {
-		ut_print_name(file, trx, foreign->foreign_col_names[i]);
+		ut_print_name(file, trx, FALSE, foreign->foreign_col_names[i]);
 		if (++i < foreign->n_fields) {
 			fputs(", ", file);
-	        } else {
+		} else {
 			break;
 		}
 	}
@@ -4396,7 +4292,7 @@
 	if (dict_tables_have_same_db(foreign->foreign_table_name,
 					foreign->referenced_table_name)) {
 		/* Do not print the database name of the referenced table */
-		ut_print_name(file, trx, dict_remove_db_name(
+		ut_print_name(file, trx, TRUE, dict_remove_db_name(
 					foreign->referenced_table_name));
 	} else {
 		/* Look for the '/' in the table name */
@@ -4406,9 +4302,10 @@
 			i++;
 		}
 
-		ut_print_namel(file, trx, foreign->referenced_table_name, i);
+		ut_print_namel(file, trx, TRUE,
+				foreign->referenced_table_name, i);
 		putc('.', file);
-		ut_print_name(file, trx,
+		ut_print_name(file, trx, TRUE,
 				foreign->referenced_table_name + i + 1);
 	}
 
@@ -4416,7 +4313,8 @@
 	putc('(', file);
 
 	for (i = 0;;) {
-		ut_print_name(file, trx, foreign->referenced_col_names[i]);
+		ut_print_name(file, trx, FALSE,
+				foreign->referenced_col_names[i]);
 		if (++i < foreign->n_fields) {
 			fputs(", ", file);
 		} else {
@@ -4429,7 +4327,7 @@
 	if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE) {
 		fputs(" ON DELETE CASCADE", file);
 	}
-	
+
 	if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) {
 		fputs(" ON DELETE SET NULL", file);
 	}
@@ -4441,7 +4339,7 @@
 	if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
 		fputs(" ON UPDATE CASCADE", file);
 	}
-	
+
 	if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
 		fputs(" ON UPDATE SET NULL", file);
 	}
@@ -4490,12 +4388,12 @@
 					putc(' ', file);
 				}
 
-				ut_print_name(file, trx,
+				ut_print_name(file, trx, FALSE,
 					foreign->foreign_col_names[i]);
 			}
 
 			fputs(") REFER ", file);
-			ut_print_name(file, trx,
+			ut_print_name(file, trx, TRUE,
 					foreign->referenced_table_name);
 			putc('(', file);
 
@@ -4503,7 +4401,7 @@
 				if (i) {
 					putc(' ', file);
 				}
-				ut_print_name(file, trx,
+				ut_print_name(file, trx, FALSE,
 					foreign->referenced_col_names[i]);
 			}
 
@@ -4512,7 +4410,7 @@
 			if (foreign->type == DICT_FOREIGN_ON_DELETE_CASCADE) {
 				fputs(" ON DELETE CASCADE", file);
 			}
-	
+
 			if (foreign->type == DICT_FOREIGN_ON_DELETE_SET_NULL) {
 				fputs(" ON DELETE SET NULL", file);
 			}
@@ -4524,7 +4422,7 @@
 			if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
 				fputs(" ON UPDATE CASCADE", file);
 			}
-	
+
 			if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
 				fputs(" ON UPDATE SET NULL", file);
 			}
@@ -4550,7 +4448,7 @@
 	const dict_index_t*	index)	/* in: index to print */
 {
 	fputs("index ", file);
-	ut_print_name(file, trx, index->name);
+	ut_print_name(file, trx, FALSE, index->name);
 	fputs(" of table ", file);
-	ut_print_name(file, trx, index->table_name);
+	ut_print_name(file, trx, TRUE, index->table_name);
 }

--- 1.54.11.1/innobase/fil/fil0fil.c	2006-08-29 13:45:10 +08:00
+++ 1.66/storage/innobase/fil/fil0fil.c	2006-08-29 13:45:10 +08:00
@@ -27,7 +27,7 @@
 #include "mtr0log.h"
 #include "dict0dict.h"
 
-	 
+
 /*
 		IMPLEMENTATION OF THE TABLESPACE MEMORY CACHE
 		=============================================
@@ -69,7 +69,7 @@
 certainly prevents the OS from fragmenting disk space, but it is not clear
 if it really adds speed. We measured on the Pentium 100 MHz + NT + NTFS file
 system + EIDE Conner disk only a negligible difference in speed when reading
-from a file, versus reading from a raw disk. 
+from a file, versus reading from a raw disk.
 
 To have fast access to a tablespace or a log file, we put the data structures
 to a hash table. Each tablespace and log file is given an unique 32-bit
@@ -90,7 +90,7 @@
 const char*	fil_path_to_mysql_datadir	= ".";
 
 /* The number of fsyncs done to the log */
-ulint	fil_n_log_flushes                       = 0;
+ulint	fil_n_log_flushes			= 0;
 
 ulint	fil_n_pending_log_flushes		= 0;
 ulint	fil_n_pending_tablespace_flushes	= 0;
@@ -117,7 +117,7 @@
 	ulint		n_pending_flushes;
 				/* count of pending flushes on this file;
 				closing of the file is not allowed if
-				this is > 0 */	
+				this is > 0 */
 	ib_longlong	modification_counter;/* when we write to the file we
 				increment this by one */
 	ib_longlong	flush_counter;/* up to what modification_counter value
@@ -165,7 +165,7 @@
 	ulint		size;	/* space size in pages; 0 if a single-table
 				tablespace whose size we do not know yet;
 				last incomplete megabytes in data files may be
-				ignored if space == 0 */ 
+				ignored if space == 0 */
 	ulint		n_reserved_extents;
 				/* number of reserved free extents for
 				ongoing operations like B-tree page split */
@@ -177,7 +177,7 @@
 				may need to access the ibuf bitmap page in the
 				tablespade: dropping of the tablespace is
 				forbidden if this is > 0 */
-	hash_node_t	hash; 	/* hash chain node */
+	hash_node_t	hash;	/* hash chain node */
 	hash_node_t	name_hash;/* hash chain the name_hash table */
 	rw_lock_t	latch;	/* latch protecting the file space storage
 				allocation */
@@ -251,6 +251,9 @@
 initialized. */
 fil_system_t*	fil_system	= NULL;
 
+/* The tablespace memory cache hash table size */
+#define	FIL_SYSTEM_HASH_SIZE	50 /* TODO: make bigger! */
+
 
 /************************************************************************
 NOTE: you must call fil_mutex_enter_and_prepare_for_io() first!
@@ -464,7 +467,7 @@
 
 	node->modification_counter = 0;
 	node->flush_counter = 0;
-	
+
 	HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
 
 	if (!space) {
@@ -488,7 +491,7 @@
 	node->space = space;
 
 	UT_LIST_ADD_LAST(chain, space->chain, node);
-				
+
 	mutex_exit(&(system->mutex));
 }
 
@@ -507,10 +510,12 @@
 	ulint		size_low;
 	ulint		size_high;
 	ibool		ret;
+	ibool		success;
+#ifndef UNIV_HOTBACKUP
 	byte*		buf2;
 	byte*		page;
-	ibool		success;
 	ulint		space_id;
+#endif /* !UNIV_HOTBACKUP */
 
 #ifdef UNIV_SYNC_DEBUG
 	ut_ad(mutex_own(&(system->mutex)));
@@ -543,24 +548,24 @@
 			ut_a(0);
 		}
 
-		ut_a(space->purpose != FIL_LOG);
-		ut_a(space->id != 0);
-
 		os_file_get_size(node->handle, &size_low, &size_high);
 
 		size_bytes = (((ib_longlong)size_high) << 32)
-				     		+ (ib_longlong)size_low;
+						+ (ib_longlong)size_low;
 #ifdef UNIV_HOTBACKUP
 		node->size = (ulint) (size_bytes / UNIV_PAGE_SIZE);
 
 #else
+		ut_a(space->purpose != FIL_LOG);
+		ut_a(space->id != 0);
+
 		if (size_bytes < FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE) {
-	        	fprintf(stderr,
+			fprintf(stderr,
 "InnoDB: Error: the size of single-table tablespace file %s\n"
 "InnoDB: is only %lu %lu, should be at least %lu!\n", node->name,
 			(ulong) size_high,
 			(ulong) size_low, (ulong) (4 * UNIV_PAGE_SIZE));
-			
+
 			ut_a(0);
 		}
 
@@ -576,22 +581,22 @@
 		space_id = fsp_header_get_space_id(page);
 
 		ut_free(buf2);
-		
+
 		/* Close the file now that we have read the space id from it */
 
 		os_file_close(node->handle);
 
 		if (space_id == ULINT_UNDEFINED || space_id == 0) {
-	        	fprintf(stderr,
+			fprintf(stderr,
 "InnoDB: Error: tablespace id %lu in file %s is not sensible\n",
 			(ulong) space_id,
 			node->name);
-			
-			ut_a(0);			
+
+			ut_a(0);
 		}
 
 		if (space_id != space->id) {
-	        	fprintf(stderr,
+			fprintf(stderr,
 "InnoDB: Error: tablespace id is %lu in the data dictionary\n"
 "InnoDB: but in file %s it is %lu!\n", space->id, node->name, space_id);
 
@@ -614,20 +619,20 @@
 	unbuffered async I/O mode, though global variables may make
 	os_file_create() to fall back to the normal file I/O mode. */
 
-	if (space->purpose == FIL_LOG) {	
+	if (space->purpose == FIL_LOG) {
 		node->handle = os_file_create(node->name, OS_FILE_OPEN,
 					OS_FILE_AIO, OS_LOG_FILE, &ret);
 	} else if (node->is_raw_disk) {
 		node->handle = os_file_create(node->name,
-				        OS_FILE_OPEN_RAW,
+					OS_FILE_OPEN_RAW,
 					OS_FILE_AIO, OS_DATA_FILE, &ret);
 	} else {
 		node->handle = os_file_create(node->name, OS_FILE_OPEN,
 					OS_FILE_AIO, OS_DATA_FILE, &ret);
 	}
-		
+
 	ut_a(ret);
-		
+
 	node->open = TRUE;
 
 	system->n_open++;
@@ -683,7 +688,7 @@
 fil_try_to_close_file_in_LRU(
 /*=========================*/
 				/* out: TRUE if success, FALSE if should retry
-				later; since i/o's generally complete in < 
+				later; since i/o's generally complete in <
 				100 ms, and as InnoDB writes at most 128 pages
 				from the buffer pool in a batch, and then
 				immediately flushes the files, there is a good
@@ -707,22 +712,22 @@
 
 	while (node != NULL) {
 		if (node->modification_counter == node->flush_counter
-		    && node->n_pending_flushes == 0) {
+			&& node->n_pending_flushes == 0) {
 
 			fil_node_close_file(node, system);
-			
+
 			return(TRUE);
 		}
-		
+
 		if (print_info && node->n_pending_flushes > 0) {
 			fputs("InnoDB: cannot close file ", stderr);
 			ut_print_filename(stderr, node->name);
 			fprintf(stderr, ", because n_pending_flushes %lu\n",
-				       (ulong) node->n_pending_flushes);
+				(ulong) node->n_pending_flushes);
 		}
 
 		if (print_info
-		    && node->modification_counter != node->flush_counter) {
+			&& node->modification_counter != node->flush_counter) {
 			fputs("InnoDB: cannot close file ", stderr);
 			ut_print_filename(stderr, node->name);
 			fprintf(stderr,
@@ -849,7 +854,7 @@
 	/* Flush tablespaces so that we can close modified files in the LRU
 	list */
 
-	fil_flush_file_spaces(FIL_TABLESPACE);		
+	fil_flush_file_spaces(FIL_TABLESPACE);
 
 	count++;
 
@@ -880,7 +885,7 @@
 		node->modification_counter = node->flush_counter;
 
 		if (space->is_in_unflushed_spaces
-		    && fil_space_is_flushed(space)) {
+			&& fil_space_is_flushed(space)) {
 
 			space->is_in_unflushed_spaces = FALSE;
 
@@ -893,7 +898,7 @@
 	}
 
 	space->size -= node->size;
-	
+
 	UT_LIST_REMOVE(chain, space->chain, node);
 
 	mem_free(node->name);
@@ -921,7 +926,7 @@
 	HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
 
 	ut_a(space);
-	
+
 	while (trunc_len > 0) {
 		node = UT_LIST_GET_FIRST(space->chain);
 
@@ -930,8 +935,8 @@
 		trunc_len -= node->size * UNIV_PAGE_SIZE;
 
 		fil_node_free(node, system, space);
-	}	
-				
+	}
+
 	mutex_exit(&(system->mutex));
 }
 
@@ -948,7 +953,7 @@
 	ulint		purpose)/* in: FIL_TABLESPACE, or FIL_LOG if log */
 {
 	fil_system_t*	system		= fil_system;
-	fil_space_t*	space;	
+	fil_space_t*	space;
 	ulint		namesake_id;
 try_again:
 	/*printf(
@@ -1036,7 +1041,7 @@
 	space->size = 0;
 
 	space->n_reserved_extents = 0;
-	
+
 	space->n_pending_flushes = 0;
 	space->n_pending_ibuf_merges = 0;
 
@@ -1044,10 +1049,9 @@
 	space->magic_n = FIL_SPACE_MAGIC_N;
 
 	space->ibuf_data = NULL;
-	
-	rw_lock_create(&(space->latch));
-	rw_lock_set_level(&(space->latch), SYNC_FSP);
-	
+
+	rw_lock_create(&space->latch, SYNC_FSP);
+
 	HASH_INSERT(fil_space_t, hash, system->spaces, id, space);
 
 	HASH_INSERT(fil_space_t, name_hash, system->name_hash,
@@ -1055,7 +1059,7 @@
 	space->is_in_unflushed_spaces = FALSE;
 
 	UT_LIST_ADD_LAST(space_list, system->space_list, space);
-				
+
 	mutex_exit(&(system->mutex));
 
 	return(TRUE);
@@ -1082,8 +1086,8 @@
 	id = system->max_assigned_id;
 
 	if (id > (SRV_LOG_SPACE_FIRST_ID / 2) && (id % 1000000UL == 0)) {
-	        ut_print_timestamp(stderr);
-	        fprintf(stderr,
+		ut_print_timestamp(stderr);
+		fprintf(stderr,
 "InnoDB: Warning: you are running out of new single-table tablespace id's.\n"
 "InnoDB: Current counter is %lu and it must not exceed %lu!\n"
 "InnoDB: To reset the counter to zero you have to dump all your tables and\n"
@@ -1092,8 +1096,8 @@
 	}
 
 	if (id >= SRV_LOG_SPACE_FIRST_ID) {
-	        ut_print_timestamp(stderr);
-	        fprintf(stderr,
+		ut_print_timestamp(stderr);
+		fprintf(stderr,
 "InnoDB: You have run out of single-table tablespace id's!\n"
 "InnoDB: Current counter is %lu.\n"
 "InnoDB: To reset the counter to zero you have to dump all your tables and\n"
@@ -1135,14 +1139,14 @@
 "InnoDB: it is not there.\n", (ulong) id);
 
 		mutex_exit(&(system->mutex));
-		
+
 		return(FALSE);
 	}
 
 	HASH_DELETE(fil_space_t, hash, system->spaces, id, space);
 
 	HASH_SEARCH(name_hash, system->name_hash, ut_fold_string(space->name),
-		    namespace, 0 == strcmp(space->name, namespace->name));
+		namespace, 0 == strcmp(space->name, namespace->name));
 	ut_a(namespace);
 	ut_a(space == namespace);
 
@@ -1167,8 +1171,8 @@
 		fil_node_free(fil_node, system, space);
 
 		fil_node = UT_LIST_GET_FIRST(space->chain);
-	}	
-	
+	}
+
 	ut_a(0 == UT_LIST_GET_LEN(space->chain));
 
 	mutex_exit(&(system->mutex));
@@ -1214,7 +1218,7 @@
 			/* out: space size, 0 if space not found */
 	ulint	id)	/* in: space id */
 {
-	fil_system_t*	system 		= fil_system;
+	fil_system_t*	system		= fil_system;
 	fil_node_t*	node;
 	fil_space_t*	space;
 	ulint		size;
@@ -1247,7 +1251,7 @@
 	}
 
 	size = space->size;
-	
+
 	mutex_exit(&(system->mutex));
 
 	return(size);
@@ -1270,7 +1274,7 @@
 	}
 
 	return(FALSE);
-}		
+}
 
 /********************************************************************
 Creates a the tablespace memory cache. */
@@ -1290,9 +1294,7 @@
 
 	system = mem_alloc(sizeof(fil_system_t));
 
-	mutex_create(&(system->mutex));
-
-	mutex_set_level(&(system->mutex), SYNC_ANY_LATCH);
+	mutex_create(&system->mutex, SYNC_ANY_LATCH);
 
 	system->spaces = hash_create(hash_size);
 	system->name_hash = hash_create(hash_size);
@@ -1321,17 +1323,11 @@
 /*=====*/
 	ulint	max_n_open)	/* in: max number of open files */
 {
-	ulint	hash_size;
-
 	ut_a(fil_system == NULL);
 
-	if (srv_file_per_table) {
-		hash_size = 50000;
-	} else {
-		hash_size = 5000;
-	}
-
-	fil_system = fil_system_create(hash_size, max_n_open);
+	/*printf("Initializing the tablespace cache with max %lu open files\n",
+	  max_n_open); */
+	fil_system = fil_system_create(FIL_SYSTEM_HASH_SIZE, max_n_open);
 }
 
 /***********************************************************************
@@ -1369,8 +1365,8 @@
 "InnoDB: tablespace files open for the whole time mysqld is running, and\n"
 "InnoDB: needs to open also some .ibd files if the file-per-table storage\n"
 "InnoDB: model is used. Current open files %lu, max allowed open files %lu.\n",
-				     (ulong) system->n_open,
-				     (ulong) system->max_n_open);
+						(ulong) system->n_open,
+						(ulong) system->max_n_open);
 				}
 				node = UT_LIST_GET_NEXT(chain, node);
 			}
@@ -1453,7 +1449,7 @@
 	space = UT_LIST_GET_FIRST(fil_system->space_list);
 
 	ut_a(space);
-        ut_a(space->purpose == FIL_TABLESPACE);	
+	ut_a(space->purpose == FIL_TABLESPACE);
 
 	space->ibuf_data = ibuf_data_init_for_space(space->id);
 }
@@ -1484,7 +1480,7 @@
 
 	fil_write(TRUE, space_id, sum_of_sizes, 0, UNIV_PAGE_SIZE, buf, NULL);
 
-	return(DB_SUCCESS);	
+	return(DB_SUCCESS);
 }
 
 /********************************************************************
@@ -1504,9 +1500,9 @@
 	ulint		err;
 
 	mutex_enter(&(fil_system->mutex));
-	
+
 	space = UT_LIST_GET_FIRST(fil_system->space_list);
-	
+
 	while (space) {
 		/* We only write the lsn to all existing data files which have
 		been open during the lifetime of the mysqld process; they are
@@ -1515,7 +1511,7 @@
 		always open. */
 
 		if (space->purpose == FIL_TABLESPACE
-		    && space->id == 0) {
+			&& space->id == 0) {
 			sum_of_sizes = 0;
 
 			node = UT_LIST_GET_FIRST(space->chain);
@@ -1568,7 +1564,7 @@
 	buf2 = ut_malloc(2 * UNIV_PAGE_SIZE);
 	/* Align the memory for a possible read from a raw device */
 	buf = ut_align(buf2, UNIV_PAGE_SIZE);
-	
+
 	os_file_read(data_file, buf, 0, 0, UNIV_PAGE_SIZE);
 
 	flushed_lsn = mach_read_from_8(buf + FIL_PAGE_FILE_FLUSH_LSN);
@@ -1616,7 +1612,7 @@
 {
 	fil_system_t*	system		= fil_system;
 	fil_space_t*	space;
-	
+
 	mutex_enter(&(system->mutex));
 
 	HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
@@ -1645,12 +1641,12 @@
 
 void
 fil_decr_pending_ibuf_merges(
-/*========================*/
+/*=========================*/
 	ulint	id)	/* in: space id */
 {
 	fil_system_t*	system		= fil_system;
 	fil_space_t*	space;
-	
+
 	mutex_enter(&(system->mutex));
 
 	HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
@@ -1711,7 +1707,7 @@
 	const char*	name,		/* in: table name in the familiar
 					'databasename/tablename' format, or
 					the file path in the case of
-					MLOG_FILE_DELETE */ 
+					MLOG_FILE_DELETE */
 	const char*	new_name,	/* in: if type is MLOG_FILE_RENAME,
 					the new table name in the
 					'databasename/tablename' format */
@@ -1770,13 +1766,13 @@
 byte*
 fil_op_log_parse_or_replay(
 /*=======================*/
-                        	/* out: end of log record, or NULL if the
+				/* out: end of log record, or NULL if the
 				record was not completely contained between
 				ptr and end_ptr */
-        byte*   ptr,    	/* in: buffer containing the log record body,
+	byte*	ptr,		/* in: buffer containing the log record body,
 				or an initial segment of it, if the record does
 				not fir completely between ptr and end_ptr */
-        byte*   end_ptr,	/* in: buffer end */
+	byte*	end_ptr,	/* in: buffer end */
 	ulint	type,		/* in: the type of this log record */
 	ibool	do_replay,	/* in: TRUE if we want to replay the
 				operation, and not just parse the log record */
@@ -1799,7 +1795,7 @@
 	ptr += 2;
 
 	if (end_ptr < ptr + name_len) {
-		
+
 		return(NULL);
 	}
 
@@ -1814,11 +1810,11 @@
 		}
 
 		new_name_len = mach_read_from_2(ptr);
-		
+
 		ptr += 2;
 
 		if (end_ptr < ptr + new_name_len) {
-		
+
 			return(NULL);
 		}
 
@@ -1844,7 +1840,7 @@
 	/* Let us try to perform the file operation, if sensible. Note that
 	ibbackup has at this stage already read in all space id info to the
 	fil0fil.c data structures.
-	
+
 	NOTE that our algorithm is not guaranteed to work correctly if there
 	were renames of tables during the backup. See ibbackup code for more
 	on the problem. */
@@ -1863,12 +1859,12 @@
 			/* Create the database directory for the new name, if
 			it does not exist yet */
 			fil_create_directory_for_tablename(new_name);
-	
+
 			/* Rename the table if there is not yet a tablespace
 			with the same name */
 
 			if (fil_get_space_id_for_table(new_name)
-			    == ULINT_UNDEFINED) {
+				== ULINT_UNDEFINED) {
 				/* We do not care of the old name, that is
 				why we pass NULL as the first argument */
 				ut_a(fil_rename_tablespace(NULL, space_id,
@@ -1890,7 +1886,7 @@
 
 			ut_a(space_id != 0);
 
-			ut_a(DB_SUCCESS == 
+			ut_a(DB_SUCCESS ==
 				fil_create_new_single_table_tablespace(
 						&space_id, name, FALSE,
 						FIL_IBD_FILE_INITIAL_SIZE));
@@ -1969,9 +1965,9 @@
 			(ulong) id);
 
 		mutex_exit(&(system->mutex));
-	
+
 		return(FALSE);
-	}	
+	}
 
 	ut_a(space);
 	ut_a(space->n_pending_ibuf_merges == 0);
@@ -2074,7 +2070,7 @@
 		fprintf(stderr,
 "InnoDB: Warning: cannot delete tablespace %lu in DISCARD TABLESPACE.\n"
 "InnoDB: But let us remove the insert buffer entries for this tablespace.\n",
-			(ulong) id); 
+			(ulong) id);
 	}
 
 	/* Remove all insert buffer entries for the tablespace */
@@ -2098,9 +2094,9 @@
 	fil_system_t*	system		= fil_system;
 	fil_space_t*	space2;
 	const char*	old_name	= space->name;
-	
+
 	HASH_SEARCH(name_hash, system->name_hash, ut_fold_string(old_name),
-			       space2, 0 == strcmp(old_name, space2->name));
+		space2, 0 == strcmp(old_name, space2->name));
 	if (space != space2) {
 		fputs("InnoDB: Error: cannot find ", stderr);
 		ut_print_filename(stderr, old_name);
@@ -2110,12 +2106,12 @@
 	}
 
 	HASH_SEARCH(name_hash, system->name_hash, ut_fold_string(path),
-			       space2, 0 == strcmp(path, space2->name));
+		space2, 0 == strcmp(path, space2->name));
 	if (space2 != NULL) {
 		fputs("InnoDB: Error: ", stderr);
 		ut_print_filename(stderr, path);
 		fputs(" is already in tablespace memory cache\n", stderr);
-		
+
 		return(FALSE);
 	}
 
@@ -2187,11 +2183,11 @@
 	fil_node_t*	node;
 	ulint		count		= 0;
 	char*		path;
-	ibool		old_name_was_specified 		= TRUE;
+	ibool		old_name_was_specified		= TRUE;
 	char*		old_path;
 
 	ut_a(id != 0);
-	
+
 	if (old_name == NULL) {
 		old_name = "(name not specified)";
 		old_name_was_specified = FALSE;
@@ -2300,7 +2296,7 @@
 
 	mutex_exit(&(system->mutex));
 
-#ifndef UNIV_HOTBACKUP	
+#ifndef UNIV_HOTBACKUP
 	if (success) {
 		mtr_t		mtr;
 
@@ -2338,7 +2334,7 @@
 					tablespace file in pages,
 					must be >= FIL_IBD_FILE_INITIAL_SIZE */
 {
-	os_file_t       file;
+	os_file_t	file;
 	ibool		ret;
 	ulint		err;
 	byte*		buf2;
@@ -2349,9 +2345,9 @@
 	ut_a(size >= FIL_IBD_FILE_INITIAL_SIZE);
 
 	path = fil_make_ibd_name(tablename, is_temp);
-	
+
 	file = os_file_create(path, OS_FILE_CREATE, OS_FILE_NORMAL,
-						    OS_DATA_FILE, &ret);
+		OS_DATA_FILE, &ret);
 	if (ret == FALSE) {
 		ut_print_timestamp(stderr);
 		fputs("  InnoDB: Error creating file ", stderr);
@@ -2359,11 +2355,11 @@
 		fputs(".\n", stderr);
 
 		/* The following call will print an error message */
-		 
+
 		err = os_file_get_last_error(TRUE);
-		
+
 		if (err == OS_FILE_ALREADY_EXISTS) {
-		        fputs(
+			fputs(
 "InnoDB: The file already exists though the corresponding table did not\n"
 "InnoDB: exist in the InnoDB data dictionary. Have you moved InnoDB\n"
 "InnoDB: .ibd files around without using the SQL commands\n"
@@ -2393,7 +2389,7 @@
 	page = ut_align(buf2, UNIV_PAGE_SIZE);
 
 	ret = os_file_set_size(path, file, size * UNIV_PAGE_SIZE, 0);
-	
+
 	if (!ret) {
 		ut_free(buf2);
 		os_file_close(file);
@@ -2431,7 +2427,7 @@
 
 	memset(page, '\0', UNIV_PAGE_SIZE);
 
-	fsp_header_write_space_id(page, *space_id);		
+	fsp_header_write_space_id(page, *space_id);
 
 	buf_flush_init_for_writing(page, ut_dulint_zero, *space_id, 0);
 
@@ -2464,14 +2460,14 @@
 	}
 
 	success = fil_space_create(path, *space_id, FIL_TABLESPACE);
-	
+
 	if (!success) {
 		goto error_exit2;
-	}	
+	}
 
 	fil_node_create(path, size, *space_id, FALSE);
 
-#ifndef UNIV_HOTBACKUP	
+#ifndef UNIV_HOTBACKUP
 	{
 	mtr_t		mtr;
 
@@ -2527,7 +2523,7 @@
 
 		ut_print_timestamp(stderr);
 
-	        fputs(
+		fputs(
 "  InnoDB: Error: trying to open a table, but could not\n"
 "InnoDB: open the tablespace file ", stderr);
 		ut_print_filename(stderr, filepath);
@@ -2561,17 +2557,17 @@
 	}
 
 	space_id = fsp_header_get_space_id(page);
-	
+
 	ut_print_timestamp(stderr);
 	fprintf(stderr,
 " InnoDB: Flush lsn in the tablespace file %lu to be imported\n"
 "InnoDB: is %lu %lu, which exceeds current system lsn %lu %lu.\n"
 "InnoDB: We reset the lsn's in the file ",
-			    (ulong) space_id,
-			    (ulong) ut_dulint_get_high(flush_lsn),
-			    (ulong) ut_dulint_get_low(flush_lsn),
-			    (ulong) ut_dulint_get_high(current_lsn),
-			    (ulong) ut_dulint_get_low(current_lsn));
+		(ulong) space_id,
+		(ulong) ut_dulint_get_high(flush_lsn),
+		(ulong) ut_dulint_get_low(flush_lsn),
+		(ulong) ut_dulint_get_high(current_lsn),
+		(ulong) ut_dulint_get_low(current_lsn));
 	ut_print_filename(stderr, filepath);
 	fputs(".\n", stderr);
 
@@ -2594,9 +2590,9 @@
 			space_id = mach_read_from_4(page
 					+ FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
 			page_no = mach_read_from_4(page + FIL_PAGE_OFFSET);
-			
+
 			buf_flush_init_for_writing(page, current_lsn, space_id,
-								      page_no);
+				page_no);
 			success = os_file_write(filepath, file, page,
 				(ulint)(offset & 0xFFFFFFFFUL),
 				(ulint)(offset >> 32), UNIV_PAGE_SIZE);
@@ -2679,7 +2675,7 @@
 
 		ut_print_timestamp(stderr);
 
-	        fputs(
+		fputs(
 "  InnoDB: Error: trying to open a table, but could not\n"
 "InnoDB: open the tablespace file ", stderr);
 		ut_print_filename(stderr, filepath);
@@ -2720,7 +2716,7 @@
 	if (space_id != id) {
 		ut_print_timestamp(stderr);
 
-	        fputs(
+		fputs(
 "  InnoDB: Error: tablespace id in file ", stderr);
 		ut_print_filename(stderr, filepath);
 		fprintf(stderr, " is %lu, but in the InnoDB\n"
@@ -2799,13 +2795,14 @@
 #ifdef UNIV_HOTBACKUP
 	fil_space_t*	space;
 #endif
-	filepath = mem_alloc(strlen(dbname) + strlen(filename) 
+	filepath = mem_alloc(strlen(dbname) + strlen(filename)
 			+ strlen(fil_path_to_mysql_datadir) + 3);
 
 	sprintf(filepath, "%s/%s/%s", fil_path_to_mysql_datadir, dbname,
 								filename);
 	srv_normalize_path_for_win(filepath);
 #ifdef __WIN__
+# ifndef UNIV_HOTBACKUP
 	/* If lower_case_table_names is 0 or 2, then MySQL allows database
 	directory names with upper case letters. On Windows, all table and
 	database names in InnoDB are internally always in lower case. Put the
@@ -2813,6 +2810,7 @@
 	internal data dictionary. */
 
 	dict_casedn_str(filepath);
+# endif /* !UNIV_HOTBACKUP */
 #endif
 	file = os_file_create_simple_no_error_handling(filepath, OS_FILE_OPEN,
 						OS_FILE_READ_ONLY, &success);
@@ -2820,7 +2818,7 @@
 		/* The following call prints an error message */
 		os_file_get_last_error(TRUE);
 
-	        fprintf(stderr,
+		fprintf(stderr,
 "InnoDB: Error: could not open single-table tablespace file\n"
 "InnoDB: %s!\n"
 "InnoDB: We do not continue the crash recovery, because the table may become\n"
@@ -2854,7 +2852,7 @@
 		/* The following call prints an error message */
 		os_file_get_last_error(TRUE);
 
-	        fprintf(stderr,
+		fprintf(stderr,
 "InnoDB: Error: could not measure the size of single-table tablespace file\n"
 "InnoDB: %s!\n"
 "InnoDB: We do not continue crash recovery, because the table will become\n"
@@ -2892,7 +2890,7 @@
 	size = (((ib_longlong)size_high) << 32) + (ib_longlong)size_low;
 #ifndef UNIV_HOTBACKUP
 	if (size < FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE) {
-	        fprintf(stderr,
+		fprintf(stderr,
 "InnoDB: Error: the size of single-table tablespace file %s\n"
 "InnoDB: is only %lu %lu, should be at least %lu!", filepath,
 			(ulong) size_high,
@@ -2921,7 +2919,7 @@
 
 #ifndef UNIV_HOTBACKUP
 	if (space_id == ULINT_UNDEFINED || space_id == 0) {
-	        fprintf(stderr,
+		fprintf(stderr,
 "InnoDB: Error: tablespace id %lu in file %s is not sensible\n",
 			(ulong) space_id,
 			filepath);
@@ -3031,7 +3029,7 @@
 
 			return(ret);
 		}
-		
+
 		fprintf(stderr,
 "InnoDB: Error: os_file_readdir_next_file() returned -1 in\n"
 "InnoDB: directory %s\n"
@@ -3063,7 +3061,7 @@
 	os_file_dir_t	dbdir;
 	os_file_stat_t	dbinfo;
 	os_file_stat_t	fileinfo;
-	ulint		err 		= DB_SUCCESS;
+	ulint		err		= DB_SUCCESS;
 
 	/* The datadir of MySQL is always the default directory of mysqld */
 
@@ -3086,9 +3084,9 @@
 		/* printf("Looking at %s in datadir\n", dbinfo.name); */
 
 		if (dbinfo.type == OS_FILE_TYPE_FILE
-		    || dbinfo.type == OS_FILE_TYPE_UNKNOWN) {
+			|| dbinfo.type == OS_FILE_TYPE_UNKNOWN) {
 
-		        goto next_datadir_item;
+			goto next_datadir_item;
 		}
 
 		/* We found a symlink or a directory; try opening it to see
@@ -3121,19 +3119,19 @@
 								&fileinfo);
 			while (ret == 0) {
 				/* printf(
-"     Looking at file %s\n", fileinfo.name); */
+				   "     Looking at file %s\n", fileinfo.name); */
 
-			        if (fileinfo.type == OS_FILE_TYPE_DIR) {
+				if (fileinfo.type == OS_FILE_TYPE_DIR) {
 
-				        goto next_file_item;
+					goto next_file_item;
 				}
 
 				/* We found a symlink or a file */
 				if (strlen(fileinfo.name) > 4
-				    && 0 == strcmp(fileinfo.name + 
+					&& 0 == strcmp(fileinfo.name +
 						strlen(fileinfo.name) - 4,
 						".ibd")) {
-				        /* The name ends in .ibd; try opening
+					/* The name ends in .ibd; try opening
 					the file */
 					fil_load_single_table_tablespace(
 						dbinfo.name, fileinfo.name);
@@ -3153,7 +3151,7 @@
 				err = DB_ERROR;
 			}
 		}
-		
+
 next_datadir_item:
 		ret = fil_file_readdir_next_file(&err,
 						fil_path_to_mysql_datadir,
@@ -3183,7 +3181,7 @@
 fil_print_orphaned_tablespaces(void)
 /*================================*/
 {
-	fil_system_t*	system 		= fil_system;
+	fil_system_t*	system		= fil_system;
 	fil_space_t*	space;
 
 	mutex_enter(&(system->mutex));
@@ -3191,7 +3189,7 @@
 	space = UT_LIST_GET_FIRST(system->space_list);
 
 	while (space) {
-	        if (space->purpose == FIL_TABLESPACE && space->id != 0
+		if (space->purpose == FIL_TABLESPACE && space->id != 0
 							  && !space->mark) {
 			fputs("InnoDB: Warning: tablespace ", stderr);
 			ut_print_filename(stderr, space->name);
@@ -3202,7 +3200,7 @@
 		space = UT_LIST_GET_NEXT(space_list, space);
 	}
 
-	mutex_exit(&(system->mutex));	
+	mutex_exit(&(system->mutex));
 }
 
 /***********************************************************************
@@ -3326,7 +3324,7 @@
 					0 == strcmp(namespace->name, path));
 	if (space && space == namespace) {
 		/* Found */
-		
+
 		if (mark_space) {
 			space->mark = TRUE;
 		}
@@ -3338,16 +3336,16 @@
 	}
 
 	if (!print_error_if_does_not_exist) {
-		
+
 		mem_free(path);
 		mutex_exit(&(system->mutex));
-		
+
 		return(FALSE);
 	}
 
 	if (space == NULL) {
 		if (namespace == NULL) {
-		        ut_print_timestamp(stderr);
+			ut_print_timestamp(stderr);
 			fputs("  InnoDB: Error: table ", stderr);
 			ut_print_filename(stderr, name);
 			fprintf(stderr, "\n"
@@ -3359,7 +3357,7 @@
 "InnoDB: table still exists in the InnoDB internal data dictionary.\n",
 				(ulong) id);
 		} else {
-		        ut_print_timestamp(stderr);
+			ut_print_timestamp(stderr);
 			fputs("  InnoDB: Error: table ", stderr);
 			ut_print_filename(stderr, name);
 			fprintf(stderr, "\n"
@@ -3440,7 +3438,7 @@
 					0 == strcmp(namespace->name, path));
 	if (namespace) {
 		id = namespace->id;
-	}	
+	}
 
 	mem_free(path);
 
@@ -3489,11 +3487,11 @@
 
 		*actual_size = space->size;
 
-		mutex_exit(&(system->mutex));	
+		mutex_exit(&(system->mutex));
 
 		return(TRUE);
 	}
-	
+
 	node = UT_LIST_GET_LAST(space->chain);
 
 	fil_node_prepare_for_io(node, system, space);
@@ -3517,7 +3515,7 @@
 				/ (4096 * ((1024 * 1024) / UNIV_PAGE_SIZE));
 		offset_low  = ((start_page_no - file_start_page_no)
 				% (4096 * ((1024 * 1024) / UNIV_PAGE_SIZE)))
-			      * UNIV_PAGE_SIZE;
+			* UNIV_PAGE_SIZE;
 #ifdef UNIV_HOTBACKUP
 		success = os_file_write(node->name, node->handle, buf,
 					offset_low, offset_high,
@@ -3537,7 +3535,7 @@
 		} else {
 			/* Let us measure the size of the file to determine
 			how much we were able to extend it */
-			
+
 			n_pages = ((ulint)
 				(os_file_get_size_as_iblonglong(node->handle)
 				/ UNIV_PAGE_SIZE)) - node->size;
@@ -3570,9 +3568,9 @@
 #endif /* !UNIV_HOTBACKUP */
 
 	/*
-        printf("Extended %s to %lu, actual size %lu pages\n", space->name,
-                                        size_after_extend, *actual_size); */
-	mutex_exit(&(system->mutex));	
+	printf("Extended %s to %lu, actual size %lu pages\n", space->name,
+					size_after_extend, *actual_size); */
+	mutex_exit(&(system->mutex));
 
 	fil_flush(space_id);
 
@@ -3590,7 +3588,7 @@
 fil_extend_tablespaces_to_stored_len(void)
 /*======================================*/
 {
-	fil_system_t*	system 		= fil_system;
+	fil_system_t*	system		= fil_system;
 	fil_space_t*	space;
 	byte*		buf;
 	ulint		actual_size;
@@ -3605,11 +3603,11 @@
 	space = UT_LIST_GET_FIRST(system->space_list);
 
 	while (space) {
-	        ut_a(space->purpose == FIL_TABLESPACE);
+		ut_a(space->purpose == FIL_TABLESPACE);
 
 		mutex_exit(&(system->mutex)); /* no need to protect with a
-					      mutex, because this is a single-
-					      threaded operation */
+					      mutex, because this is a
+					      single-threaded operation */
 		error = fil_read(TRUE, space->id, 0, 0, UNIV_PAGE_SIZE, buf,
 									NULL);
 		ut_a(error == DB_SUCCESS);
@@ -3625,7 +3623,7 @@
 "InnoDB: size after extension %lu pages\n"
 "InnoDB: Check that you have free disk space and retry!\n", space->name,
 					size_in_header, actual_size);
-			exit(1);				
+			exit(1);
 		}
 
 		mutex_enter(&(system->mutex));
@@ -3670,7 +3668,7 @@
 		space->n_reserved_extents += n_to_reserve;
 		success = TRUE;
 	}
-	
+
 	mutex_exit(&(system->mutex));
 
 	return(success);
@@ -3696,9 +3694,9 @@
 
 	ut_a(space);
 	ut_a(space->n_reserved_extents >= n_reserved);
-	
+
 	space->n_reserved_extents -= n_reserved;
-	
+
 	mutex_exit(&(system->mutex));
 }
 
@@ -3720,11 +3718,11 @@
 	mutex_enter(&(system->mutex));
 
 	HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
-	
+
 	ut_a(space);
 
 	n = space->n_reserved_extents;
-	
+
 	mutex_exit(&(system->mutex));
 
 	return(n);
@@ -3751,7 +3749,7 @@
 #ifdef UNIV_SYNC_DEBUG
 	ut_ad(mutex_own(&(system->mutex)));
 #endif /* UNIV_SYNC_DEBUG */
-	
+
 	if (system->n_open > system->max_n_open + 5) {
 		ut_print_timestamp(stderr);
 		fprintf(stderr,
@@ -3768,7 +3766,7 @@
 	}
 
 	if (node->n_pending == 0 && space->purpose == FIL_TABLESPACE
-						      && space->id != 0) {
+		&& space->id != 0) {
 		/* The node is in the LRU list, remove it */
 
 		ut_a(UT_LIST_GET_LEN(system->LRU) > 0);
@@ -3799,7 +3797,7 @@
 #endif /* UNIV_SYNC_DEBUG */
 
 	ut_a(node->n_pending > 0);
-	
+
 	node->n_pending--;
 
 	if (type == OS_FILE_WRITE) {
@@ -3814,7 +3812,7 @@
 					node->space);
 		}
 	}
-	
+
 	if (node->n_pending == 0 && node->space->purpose == FIL_TABLESPACE
 					&& node->space->id != 0) {
 		/* The node must be put back to the LRU list */
@@ -3889,13 +3887,13 @@
 	ibool		ret;
 	ulint		is_log;
 	ulint		wake_later;
-	
+
 	is_log = type & OS_FILE_LOG;
 	type = type & ~OS_FILE_LOG;
 
 	wake_later = type & OS_AIO_SIMULATED_WAKE_LATER;
 	type = type & ~OS_AIO_SIMULATED_WAKE_LATER;
-	
+
 	ut_ad(byte_offset < UNIV_PAGE_SIZE);
 	ut_ad(buf);
 	ut_ad(len > 0);
@@ -3921,17 +3919,17 @@
 		mode = OS_AIO_NORMAL;
 	}
 
-        if (type == OS_FILE_READ) {
-                srv_data_read+= len;
-        } else if (type == OS_FILE_WRITE) {
-                srv_data_written+= len;
-        }
+	if (type == OS_FILE_READ) {
+		srv_data_read+= len;
+	} else if (type == OS_FILE_WRITE) {
+		srv_data_written+= len;
+	}
 
 	/* Reserve the fil_system mutex and make sure that we can open at
 	least one file while holding it, if the file is not already open */
 
 	fil_mutex_enter_and_prepare_for_io(space_id);
-	
+
 	HASH_SEARCH(hash, system->spaces, space_id, space,
 							space->id == space_id);
 	if (!space) {
@@ -3955,7 +3953,7 @@
 		if (node == NULL) {
 			fil_report_invalid_page_access(block_offset, space_id,
 				space->name, byte_offset, len, type);
- 			
+
 			ut_error;
 		}
 
@@ -3973,15 +3971,15 @@
 			block_offset -= node->size;
 			node = UT_LIST_GET_NEXT(chain, node);
 		}
-	}		
-	
+	}
+
 	/* Open file if closed */
 	fil_node_prepare_for_io(node, system, space);
 
 	/* Check that at least the start offset is within the bounds of a
 	single-table tablespace */
 	if (space->purpose == FIL_TABLESPACE && space->id != 0
-	    && node->size <= block_offset) {
+		&& node->size <= block_offset) {
 
 		fil_report_invalid_page_access(block_offset, space_id,
 			space->name, byte_offset, len, type);
@@ -3999,7 +3997,7 @@
 			+ byte_offset;
 
 	ut_a(node->size - block_offset >=
- 		(byte_offset + len + (UNIV_PAGE_SIZE - 1)) / UNIV_PAGE_SIZE);
+		(byte_offset + len + (UNIV_PAGE_SIZE - 1)) / UNIV_PAGE_SIZE);
 
 	/* Do aio */
 
@@ -4025,7 +4023,7 @@
 	if (mode == OS_AIO_SYNC) {
 		/* The i/o operation is already completed when we return from
 		os_aio: */
-		
+
 		mutex_enter(&(system->mutex));
 
 		fil_node_complete_io(node, system, type);
@@ -4104,21 +4102,21 @@
 fil_aio_wait(
 /*=========*/
 	ulint	segment)	/* in: the number of the segment in the aio
-				array to wait for */ 
+				array to wait for */
 {
 	fil_system_t*	system		= fil_system;
-	ibool		ret;		
+	ibool		ret;
 	fil_node_t*	fil_node;
 	void*		message;
 	ulint		type;
-	
+
 	ut_ad(fil_validate());
 
 	if (os_aio_use_native_aio) {
 		srv_set_io_thread_op_info(segment, "native aio handle");
 #ifdef WIN_ASYNC_IO
 		ret = os_aio_windows_handle(segment, 0, &fil_node,
-					    &message, &type);
+			&message, &type);
 #elif defined(POSIX_ASYNC_IO)
 		ret = os_aio_posix_handle(segment, &fil_node, &message);
 #else
@@ -4129,9 +4127,9 @@
 		srv_set_io_thread_op_info(segment, "simulated aio handle");
 
 		ret = os_aio_simulated_handle(segment, &fil_node,
-	                                               &message, &type);
+			&message, &type);
 	}
-	
+
 	ut_a(ret);
 
 	srv_set_io_thread_op_info(segment, "complete io for fil node");
@@ -4176,7 +4174,7 @@
 	ib_longlong	old_mod_counter;
 
 	mutex_enter(&(system->mutex));
-	
+
 	HASH_SEARCH(hash, system->spaces, space_id, space,
 							space->id == space_id);
 	if (!space || space->is_being_deleted) {
@@ -4209,7 +4207,7 @@
 				goto skip_flush;
 			}
 #endif
-retry:			
+retry:
 			if (node->n_pending_flushes > 0) {
 				/* We want to avoid calling os_file_flush() on
 				the file twice at the same time, because we do
@@ -4239,7 +4237,7 @@
 			/* fprintf(stderr, "Flushing to file %s\n",
 				node->name); */
 
-			os_file_flush(file);		
+			os_file_flush(file);
 
 			mutex_enter(&(system->mutex));
 
@@ -4249,7 +4247,7 @@
 				node->flush_counter = old_mod_counter;
 
 				if (space->is_in_unflushed_spaces
-				    && fil_space_is_flushed(space)) {
+					&& fil_space_is_flushed(space)) {
 
 					space->is_in_unflushed_spaces = FALSE;
 
@@ -4267,7 +4265,7 @@
 		}
 
 		node = UT_LIST_GET_NEXT(chain, node);
-	}		
+	}
 
 	space->n_pending_flushes--;
 
@@ -4293,8 +4291,8 @@
 	while (space) {
 		if (space->purpose == purpose && !space->is_being_deleted) {
 
-			space->n_pending_flushes++; /* prevent dropping of the
-						    space while we are
+			space->n_pending_flushes++; /* prevent dropping of
+						    the space while we are
 						    flushing */
 			mutex_exit(&(system->mutex));
 
@@ -4306,7 +4304,7 @@
 		}
 		space = UT_LIST_GET_NEXT(unflushed_spaces, space);
 	}
-	
+
 	mutex_exit(&(system->mutex));
 }
 
@@ -4317,13 +4315,13 @@
 fil_validate(void)
 /*==============*/
 			/* out: TRUE if ok */
-{	
+{
 	fil_system_t*	system		= fil_system;
 	fil_space_t*	space;
 	fil_node_t*	fil_node;
 	ulint		n_open		= 0;
 	ulint		i;
-	
+
 	mutex_enter(&(system->mutex));
 
 	/* Look for spaces in the hash table */
@@ -4331,9 +4329,9 @@
 	for (i = 0; i < hash_get_n_cells(system->spaces); i++) {
 
 		space = HASH_GET_FIRST(system->spaces, i);
-	
+
 		while (space != NULL) {
-			UT_LIST_VALIDATE(chain, fil_node_t, space->chain); 
+			UT_LIST_VALIDATE(chain, fil_node_t, space->chain);
 
 			fil_node = UT_LIST_GET_FIRST(space->chain);
 
@@ -4365,7 +4363,7 @@
 
 		fil_node = UT_LIST_GET_NEXT(LRU, fil_node);
 	}
-	
+
 	mutex_exit(&(system->mutex));
 
 	return(TRUE);
@@ -4408,13 +4406,13 @@
 void
 fil_page_set_type(
 /*==============*/
-	byte* 	page,	/* in: file page */
+	byte*	page,	/* in: file page */
 	ulint	type)	/* in: type */
 {
 	ut_ad(page);
 
 	mach_write_to_2(page + FIL_PAGE_TYPE, type);
-}	
+}
 
 /*************************************************************************
 Gets the file page type. */
@@ -4424,7 +4422,7 @@
 /*==============*/
 			/* out: type; NOTE that if the type has not been
 			written to page, the return value not defined */
-	byte* 	page)	/* in: file page */
+	byte*	page)	/* in: file page */
 {
 	ut_ad(page);
 

--- 1.25.2.1/innobase/fsp/fsp0fsp.c	2006-08-29 13:45:10 +08:00
+++ 1.29/storage/innobase/fsp/fsp0fsp.c	2006-08-29 13:45:10 +08:00
@@ -33,9 +33,9 @@
 
 /* The data structures in files are defined just as byte strings in C */
 typedef	byte	fsp_header_t;
-typedef	byte	xdes_t;		
+typedef	byte	xdes_t;
 
-/*			SPACE HEADER		
+/*			SPACE HEADER
 			============
 
 File space header data structure: this data structure is contained in the
@@ -92,7 +92,7 @@
 #define	FSP_FREE_ADD		4	/* this many free extents are added
 					to the free list from above
 					FSP_FREE_LIMIT at a time */
-					
+
 /*			FILE SEGMENT INODE
 			==================
 
@@ -142,7 +142,7 @@
 				single page */
 
 #define FSEG_MAGIC_N_VALUE	97937874
-					
+
 #define	FSEG_FILLFACTOR		8	/* If this value is x, then if
 					the number of unused but reserved
 					pages in a segment is less than
@@ -152,7 +152,7 @@
 					be added to the segment in
 					fseg_alloc_free_page. Otherwise, we
 					use unused pages of the segment. */
-					
+
 #define FSEG_FRAG_LIMIT		FSEG_FRAG_ARR_N_SLOTS
 					/* If the segment has >= this many
 					used pages, it may be expanded by
@@ -166,7 +166,7 @@
 					list of the extent: at most
 					FSEG_FREE_LIST_MAX_LEN many */
 #define	FSEG_FREE_LIST_MAX_LEN	4
-					
+
 
 /*			EXTENT DESCRIPTOR
 			=================
@@ -186,7 +186,7 @@
 					/* Descriptor bitmap of the pages
 					in the extent */
 /*-------------------------------------*/
-					
+
 #define	XDES_BITS_PER_PAGE	2	/* How many bits are there per page */
 #define	XDES_FREE_BIT		0	/* Index of the bit which tells if
 					the page is free */
@@ -208,7 +208,7 @@
 
 /* Offset of the descriptor array on a descriptor page */
 #define	XDES_ARR_OFFSET		(FSP_HEADER_OFFSET + FSP_HEADER_SIZE)
-					
+
 /**************************************************************************
 Returns an extent to the free list of a space. */
 static
@@ -236,7 +236,7 @@
 fseg_n_reserved_pages_low(
 /*======================*/
 				/* out: number of reserved pages */
-	fseg_inode_t* 	header,	/* in: segment inode */
+	fseg_inode_t*	header,	/* in: segment inode */
 	ulint*		used,	/* out: number of pages used (<= reserved) */
 	mtr_t*		mtr);	/* in: mtr handle */
 /************************************************************************
@@ -290,7 +290,7 @@
 				/* out: the allocated page number, FIL_NULL
 				if no page could be allocated */
 	ulint		space,	/* in: space */
-	fseg_inode_t* 	seg_inode, /* in: segment inode */
+	fseg_inode_t*	seg_inode, /* in: segment inode */
 	ulint		hint,	/* in: hint of which page would be desirable */
 	byte		direction, /* in: if the new page is needed because
 				of an index page split, and records are
@@ -354,17 +354,17 @@
 						MTR_MEMO_PAGE_X_FIX));
 	ut_ad((bit == XDES_FREE_BIT) || (bit == XDES_CLEAN_BIT));
 	ut_ad(offset < FSP_EXTENT_SIZE);
-	
+
 	index = bit + XDES_BITS_PER_PAGE * offset;
 
 	byte_index = index / 8;
 	bit_index = index % 8;
-		
+
 	return(ut_bit_get_nth(
 		   mtr_read_ulint(descr + XDES_BITMAP + byte_index,
 							MLOG_1BYTE, mtr),
-		   bit_index));	  
-}	
+		   bit_index));
+}
 
 /**************************************************************************
 Sets a descriptor bit of a page. */
@@ -383,7 +383,7 @@
 	ulint	byte_index;
 	ulint	bit_index;
 	ulint	descr_byte;
-	
+
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
 							MTR_MEMO_PAGE_X_FIX));
 	ut_ad((bit == XDES_FREE_BIT) || (bit == XDES_CLEAN_BIT));
@@ -400,7 +400,7 @@
 
 	mlog_write_ulint(descr + XDES_BITMAP + byte_index, descr_byte,
 							MLOG_1BYTE, mtr);
-}	
+}
 
 /**************************************************************************
 Looks for a descriptor bit having the desired value. Starts from hint
@@ -419,7 +419,7 @@
 	mtr_t*	mtr)	/* in: mtr */
 {
 	ulint	i;
-	
+
 	ut_ad(descr && mtr);
 	ut_ad(val <= TRUE);
 	ut_ad(hint < FSP_EXTENT_SIZE);
@@ -438,9 +438,9 @@
 			return(i);
 		}
 	}
-	
-	return(ULINT_UNDEFINED);			
-}	
+
+	return(ULINT_UNDEFINED);
+}
 
 /**************************************************************************
 Looks for a descriptor bit having the desired value. Scans the extent in
@@ -458,7 +458,7 @@
 	mtr_t*	mtr)	/* in: mtr */
 {
 	ulint	i;
-	
+
 	ut_ad(descr && mtr);
 	ut_ad(val <= TRUE);
 	ut_ad(hint < FSP_EXTENT_SIZE);
@@ -477,9 +477,9 @@
 			return(i);
 		}
 	}
-	
-	return(ULINT_UNDEFINED);			
-}	
+
+	return(ULINT_UNDEFINED);
+}
 
 /**************************************************************************
 Returns the number of used pages in a descriptor. */
@@ -493,7 +493,7 @@
 {
 	ulint	i;
 	ulint	count	= 0;
-	
+
 	ut_ad(descr && mtr);
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
 							MTR_MEMO_PAGE_X_FIX));
@@ -503,8 +503,8 @@
 		}
 	}
 
-	return(count);		
-}	
+	return(count);
+}
 
 /**************************************************************************
 Returns true if extent contains no used pages. */
@@ -558,7 +558,7 @@
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
 							MTR_MEMO_PAGE_X_FIX));
 
-	mlog_write_ulint(descr + XDES_STATE, state, MLOG_4BYTES, mtr); 
+	mlog_write_ulint(descr + XDES_STATE, state, MLOG_4BYTES, mtr);
 }
 
 /**************************************************************************
@@ -575,7 +575,7 @@
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
 							MTR_MEMO_PAGE_X_FIX));
 
-	return(mtr_read_ulint(descr + XDES_STATE, MLOG_4BYTES, mtr)); 
+	return(mtr_read_ulint(descr + XDES_STATE, MLOG_4BYTES, mtr));
 }
 
 /**************************************************************************
@@ -599,7 +599,7 @@
 	}
 
 	xdes_set_state(descr, XDES_FREE, mtr);
-}	
+}
 
 /************************************************************************
 Calculates the page where the descriptor of a page resides. */
@@ -610,8 +610,10 @@
 				/* out: descriptor page offset */
 	ulint	offset)		/* in: page offset */
 {
-	ut_ad(UNIV_PAGE_SIZE > XDES_ARR_OFFSET
-		+ (XDES_DESCRIBED_PER_PAGE / FSP_EXTENT_SIZE) * XDES_SIZE);
+#if UNIV_PAGE_SIZE <= XDES_ARR_OFFSET \
+		+ (XDES_DESCRIBED_PER_PAGE / FSP_EXTENT_SIZE) * XDES_SIZE
+# error
+#endif
 
 	return(ut_2pow_round(offset, XDES_DESCRIBED_PER_PAGE));
 }
@@ -644,7 +646,7 @@
 				space or if offset > free limit */
 	fsp_header_t*	sp_header,/* in: space header, x-latched */
 	ulint		space,	/* in: space id */
-	ulint		offset,	/* in: page offset; 
+	ulint		offset,	/* in: page offset;
 				if equal to the free limit,
 				we try to add new extents to
 				the space free list */
@@ -687,10 +689,10 @@
 #ifdef UNIV_SYNC_DEBUG
 		buf_page_dbg_add_level(descr_page, SYNC_FSP_PAGE);
 #endif /* UNIV_SYNC_DEBUG */
-	}	
+	}
 
 	return(descr_page + XDES_ARR_OFFSET
-	       + XDES_SIZE * xdes_calc_descriptor_index(offset));
+		+ XDES_SIZE * xdes_calc_descriptor_index(offset));
 }
 
 /************************************************************************
@@ -718,7 +720,7 @@
 				+ buf_page_get(space, 0, RW_X_LATCH, mtr);
 #ifdef UNIV_SYNC_DEBUG
 	buf_page_dbg_add_level(sp_header, SYNC_FSP_PAGE);
-#endif /* UNIV_SYNC_DEBUG */	
+#endif /* UNIV_SYNC_DEBUG */
 	return(xdes_get_descriptor_with_space_hdr(sp_header, space, offset,
 									mtr));
 }
@@ -789,13 +791,13 @@
 static
 void
 fsp_init_file_page_low(
-/*=====================*/
+/*===================*/
 	byte*	ptr)	/* in: pointer to a page */
 {
 	page_t*	page;
 	page = buf_frame_align(ptr);
 
-	buf_block_align(page)->check_index_page_at_flush = FALSE;	
+	buf_block_align(page)->check_index_page_at_flush = FALSE;
 
 #ifdef UNIV_BASIC_LOG_DEBUG
 	memset(page, 0xff, UNIV_PAGE_SIZE);
@@ -807,7 +809,6 @@
 
 /***************************************************************
 Inits a file page whose prior contents should be ignored. */
-
 static
 void
 fsp_init_file_page(
@@ -816,10 +817,10 @@
 	mtr_t*	mtr)	/* in: mtr */
 {
 	fsp_init_file_page_low(page);
-		
+
 	mlog_write_initial_log_record(page, MLOG_INIT_FILE_PAGE, mtr);
 }
-	
+
 /***************************************************************
 Parses a redo log record of a file page init. */
 
@@ -836,7 +837,7 @@
 	if (page) {
 		fsp_init_file_page_low(page);
 	}
-	
+
 	return(ptr);
 }
 
@@ -872,11 +873,11 @@
 /*============*/
 	ulint	space,	/* in: space id */
 	ulint	size,	/* in: current size in blocks */
-	mtr_t*	mtr)	/* in: mini-transaction handle */	
+	mtr_t*	mtr)	/* in: mini-transaction handle */
 {
 	fsp_header_t*	header;
 	page_t*		page;
-	
+
 	ut_ad(mtr);
Thread
bk commit into 5.1 tree (gni:1.2283)gni29 Aug