List:Commits« Previous MessageNext Message »
From:ingo Date:November 27 2006 9:58am
Subject:bk commit into 5.1 tree (istruewing:1.2324)
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of istruewing. When istruewing 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-11-27 09:58:26+01:00, istruewing@stripped +10 -0
  WL#3561 - transactional LOCK TABLE
  
  Not to be pushed.
  This is the second prototype.
  Its purpose is to show what I plan to implement.
  
  The main changes over the first prototype are:
  
  - Elimination of the fix_transacltional_lock() function.
  Its work is done in the parser now.
  
  - Added check_transactional_lock(). It warns about converted
  locks or aborts in strict mode. This is not yet fully implemented
  as I am unsure if this is like it should be.
  
  - Elimination of the wrapper handler::ha_lock_table().
  
  The prototype proposes a way to do error handling without
  implementing it in full. This needs additional review.
  
  Still missing is the optional additional cleanup to call
  handler::ha_lock_info() also for non-transactional locks.
  I made an attempt to call this before doing the real locking.
  But the required open_tables() made mysqldump.test fail.
  So I wonder if this can be called after the locking (after
  handler::external_lock().

  sql/handler.h@stripped, 2006-11-27 09:58:23+01:00, istruewing@stripped +8 -0
    WL#3561 - transactional LOCK TABLE
    New handler::lock_table() virtual method definition.

  sql/lex.h@stripped, 2006-11-27 09:58:23+01:00, istruewing@stripped +2 -0
    WL#3561 - transactional LOCK TABLE
    New symbols "EXCLUSIVE" and "NOWAIT".

  sql/lex_symbol.h@stripped, 2006-11-27 09:58:23+01:00, istruewing@stripped +9 -0
    WL#3561 - transactional LOCK TABLE
    Declaration of struct st_table_lock_info for parser internal use.

  sql/lock.cc@stripped, 2006-11-27 09:58:23+01:00, istruewing@stripped +142 -0
    WL#3561 - transactional LOCK TABLE
    Definition of try_transactional_lock() and
    check_transactional_lock() for transactional table locking.

  sql/mysql_priv.h@stripped, 2006-11-27 09:58:23+01:00, istruewing@stripped +2 -0
    WL#3561 - transactional LOCK TABLE
    Declaration of try_transactional_lock() and
    check_transactional_lock() for transactional table locking.

  sql/sql_lex.h@stripped, 2006-11-27 09:58:23+01:00, istruewing@stripped +2 -1
    WL#3561 - transactional LOCK TABLE
    Moved the inclusion of lex_symbol.h to allow parser local
    declaration of struct st_table_lock_info.
    Added lock_transactional to LEX.

  sql/sql_parse.cc@stripped, 2006-11-27 09:58:23+01:00, istruewing@stripped +35 -2
    WL#3561 - transactional LOCK TABLE
    Added calls to the new functions try_transactional_lock() and
    check_transactional_lock() below SQLCOM_LOCK_TABLES.
    Moved check_table_access() before trying to lock/unlock.

  sql/sql_yacc.yy@stripped, 2006-11-27 09:58:23+01:00, istruewing@stripped +88 -12
    WL#3561 - transactional LOCK TABLE
    Added types 'truth' and 'table_lock_info'.
    Added symbols EXCLUSIVE_SYM and NOWAIT_SYM.
    Replaced 'lock_option' by 'table_lock_info'.
    Added new clauses for transactional locking.

  sql/table.h@stripped, 2006-11-27 09:58:23+01:00, istruewing@stripped +3 -0
    WL#3561 - transactional LOCK TABLE
    Added transactional locking variables in TABLE_LIST.

  storage/innobase/handler/ha_innodb.h@stripped, 2006-11-27 09:58:23+01:00,
istruewing@stripped +11 -0
    WL#3561 - transactional LOCK TABLE
    New ha_innodb::lock_table() method, preliminarily calling
    ha_innodb::transactional_table_lock() for transactional locks.

# 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:	istruewing
# Host:	chilla.local
# Root:	/home/mydev/mysql-5.1-wl3561

--- 1.244/sql/handler.h	2006-11-27 09:58:34 +01:00
+++ 1.245/sql/handler.h	2006-11-27 09:58:34 +01:00
@@ -1594,6 +1594,14 @@ public:
   */
   virtual void use_hidden_primary_key();
 
+  virtual int lock_table(THD *thd __attribute__((unused)),
+                         int lock_type __attribute__((unused)),
+                         bool transactional __attribute__((unused)),
+                         bool nowait __attribute__((unused)))
+  {
+    return HA_ERR_WRONG_COMMAND;
+  }
+
 private:
   /*
     Row-level primitives for storage engines.  These should be

--- 1.164/sql/lex.h	2006-11-27 09:58:34 +01:00
+++ 1.165/sql/lex.h	2006-11-27 09:58:34 +01:00
@@ -195,6 +195,7 @@ static SYMBOL symbols[] = {
   { "EVENT",		SYM(EVENT_SYM)},
   { "EVENTS",		SYM(EVENTS_SYM)},
   { "EVERY",		SYM(EVERY_SYM)},
+  { "EXCLUSIVE",        SYM(EXCLUSIVE_SYM)},
   { "EXECUTE",		SYM(EXECUTE_SYM)},
   { "EXISTS",		SYM(EXISTS)},
   { "EXIT",             SYM(EXIT_SYM)},
@@ -362,6 +363,7 @@ static SYMBOL symbols[] = {
   { "NODEGROUP",	SYM(NODEGROUP_SYM)},
   { "NONE",		SYM(NONE_SYM)},
   { "NOT",		SYM(NOT_SYM)},
+  { "NOWAIT",           SYM(NOWAIT_SYM)},
   { "NO_WRITE_TO_BINLOG",  SYM(NO_WRITE_TO_BINLOG)},
   { "NULL",		SYM(NULL_SYM)},
   { "NUMERIC",		SYM(NUMERIC_SYM)},

--- 1.7/sql/lex_symbol.h	2006-11-27 09:58:34 +01:00
+++ 1.8/sql/lex_symbol.h	2006-11-27 09:58:34 +01:00
@@ -20,6 +20,15 @@
 #ifndef _lex_symbol_h
 #define _lex_symbol_h
 
+#include "thr_lock.h"
+/* A helper type for transactional locking. */
+struct st_table_lock_info
+{
+  thr_lock_type lock_type;
+  bool          lock_transactional;
+  bool          lock_nowait;
+};
+
 struct st_sym_group;
 
 typedef struct st_symbol {

--- 1.97/sql/lock.cc	2006-11-27 09:58:34 +01:00
+++ 1.98/sql/lock.cc	2006-11-27 09:58:34 +01:00
@@ -1383,3 +1383,145 @@ void broadcast_refresh(void)
 }
 
 
+/*
+  Try to get transactional table locks for the tables in the list.
+
+  SYNOPSIS
+    try_transactional_lock()
+      thd                       Thread handle
+      table_list                List of tables to lock
+
+  RETURN
+    0                   OK. All tables are transactional locked.
+    1                   Error: must fall back to non-transactional locks.
+    -1                  Error: no recovery possible.
+*/
+
+int try_transactional_lock(THD *thd, TABLE_LIST *table_list)
+{
+  TABLE_LIST    *tlist;
+  uint          dummy_counter;
+  int           error;
+  int           result= 0;
+  DBUG_ENTER("try_transactional_lock");
+  LINT_INIT(error);
+
+  /* Need to open the tables to be able to access engine methods. */
+  if (open_tables(thd, &table_list, &dummy_counter, 0))
+  {
+    DBUG_PRINT("lock_info", ("aborting, open_tables failed"));
+    DBUG_RETURN(-1);
+  }
+
+  for (tlist= table_list; tlist; tlist= tlist->next_global)
+  {
+    int lock_type= ((tlist->lock_type <= TL_READ_NO_INSERT) ?
+                    F_RDLCK : F_WRLCK);
+
+    if (tlist->placeholder() || tlist->schema_table)
+      continue;
+
+    DBUG_PRINT("lock_info", ("table: '%s'  lock_type: %d  nowait: %d",
+                             tlist->alias ? tlist->alias : tlist->table_name,
+                             lock_type, tlist->lock_nowait));
+    DBUG_ASSERT((tlist->lock_type == TL_READ) ||
+                (tlist->lock_type == TL_READ_NO_INSERT) ||
+                (tlist->lock_type == TL_WRITE) ||
+                (tlist->lock_type == TL_WRITE_LOW_PRIORITY));
+
+    if ((error= tlist->table->file->lock_table(thd, lock_type, TRUE,
+                                               tlist->lock_nowait)))
+      break;
+  }
+
+  if (tlist)
+  {
+    /*
+      We broke the loop. Not all transactional locks could be taken. If
+      the error was something else but "unsupported by storage engine",
+      abort the execution of this statement.
+    */
+    if (error != HA_ERR_WRONG_COMMAND)
+    {
+      DBUG_PRINT("lock_info", ("aborting, lock_table failed"));
+      tlist->table->file->print_error(error, MYF(0));
+
+      /*
+        TODO: ha_rollback[_stmt]() for some errors?
+        If yes: What error should ha_rollback_stmt(), and what
+        errors should ha_rollback()?
+      */
+
+      result= -1;
+      goto err;
+    }
+    /*
+      Fall back to non-transactional locks because transactional locks
+      are unsupported by a storage engine. No need to unlock the
+      successfully taken transactional locks. They go away at end of
+      transaction anyway.
+    */
+    DBUG_PRINT("lock_info", ("fall back to non-trans lock: no SE support"));
+    result= 1;
+  }
+
+ err:
+  /* Close the tables. The locks (if taken) persist in the storage engines. */
+  close_tables_for_reopen(thd, &table_list);
+  DBUG_PRINT("lock_info", ("result: %d", result));
+  DBUG_RETURN(result);
+}
+
+
+/*
+  Check if transactional locks are converted to non-transactional.
+
+  SYNOPSIS
+    check_transactional_lock()
+      thd                       Thread handle
+      table_list                List of tables to lock
+
+  RETURN
+    0                   OK. Proceed with non-transactional locks.
+    -1                  Error: Lock conversion is prohibited.
+*/
+
+int check_transactional_lock(THD *thd, TABLE_LIST *table_list)
+{
+  TABLE_LIST    *tlist;
+  int           result= 0;
+  DBUG_ENTER("check_transactional_lock");
+
+  for (tlist= table_list; tlist; tlist= tlist->next_global)
+  {
+    if (tlist->placeholder() || tlist->schema_table ||
+        !tlist->lock_transactional)
+      continue;
+
+    /* We must not convert the lock method in strict mode. */
+    if (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES |
+                                   MODE_STRICT_ALL_TABLES))
+    {
+      /*
+        my_error(ER_NO_AUTO_CONVERT_LOCK, MYF(0),
+                 tlist->alias ? tlist->alias : tlist->table_name);
+      */
+      result= -1;
+      goto err;
+    }
+    /* Warn about the conversion. */
+    /*
+      char warn_buff[MYSQL_ERRMSG_SIZE];
+      my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_WARN_AUTO_CONVERT_LOCK),
+                  tlist->alias ? tlist->alias : tlist->table_name);
+      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                   ER_WARN_AUTO_CONVERT_LOCK, warn_buff);
+    */
+  }
+
+ err:
+  DBUG_PRINT("lock_info", ("result: %d", result));
+  DBUG_RETURN(result);
+}
+
+

--- 1.453/sql/mysql_priv.h	2006-11-27 09:58:34 +01:00
+++ 1.454/sql/mysql_priv.h	2006-11-27 09:58:34 +01:00
@@ -1702,6 +1702,8 @@ bool make_global_read_lock_block_commit(
 bool set_protect_against_global_read_lock(void);
 void unset_protect_against_global_read_lock(void);
 void broadcast_refresh(void);
+int  try_transactional_lock(THD *thd, TABLE_LIST *table_list);
+int  check_transactional_lock(THD *thd, TABLE_LIST *table_list);
 
 /* Lock based on name */
 int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list);

--- 1.246/sql/sql_lex.h	2006-11-27 09:58:34 +01:00
+++ 1.247/sql/sql_lex.h	2006-11-27 09:58:34 +01:00
@@ -40,8 +40,8 @@ class Event_parse_data;
 #ifdef MYSQL_YACC
 #define LEX_YYSTYPE void *
 #else
-#include "lex_symbol.h"
 #if MYSQL_LEX
+#include "lex_symbol.h"
 #include "sql_yacc.h"
 #define LEX_YYSTYPE YYSTYPE *
 #else
@@ -981,6 +981,7 @@ typedef struct st_lex : public Query_tab
   union {
     enum ha_rkey_function ha_rkey_mode;
     enum xa_option_words xa_opt;
+    bool lock_transactional;            /* For LOCK TABLE ... IN ... MODE */
   };
   enum enum_var_type option_type;
   enum enum_view_create_mode create_view_mode;

--- 1.585/sql/sql_parse.cc	2006-11-27 09:58:34 +01:00
+++ 1.586/sql/sql_parse.cc	2006-11-27 09:58:34 +01:00
@@ -3702,11 +3702,43 @@ end_with_restore_list:
     send_ok(thd);
     break;
   case SQLCOM_LOCK_TABLES:
+  {
+    if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, 0))
+      goto error;
+    if (lex->lock_transactional)
+    {
+      /*
+        All requested locks are transactional and no non-transactional
+        locks exist.
+      */
+      switch (try_transactional_lock(thd, all_tables)) {
+      case -1:
+        goto error;
+      case 0:
+        send_ok(thd);
+        goto end;
+      default:
+        /*
+          Non-transactional locking has been requested or
+          non-transactional locks exist already or transactional locks are
+          not supported by all storage engines. Take non-transactional
+          locks.
+        */
+        break;
+      }
+    }
+    /*
+      One or more requested locks are non-transactional and/or
+      non-transactional locks exist or a storage engine does not support
+      transactional locks. Check if at least one transactional lock is
+      requested. If yes, warn about the conversion to non-transactional
+      locks or abort in strict mode.
+    */
+    if (check_transactional_lock(thd, all_tables))
+      goto error;
     unlock_locked_tables(thd);
     if (end_active_trans(thd))
       goto error;
-    if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, 0))
-      goto error;
     thd->in_lock_tables=1;
     thd->options|= OPTION_TABLE_LOCK;
 
@@ -3724,6 +3756,7 @@ end_with_restore_list:
       thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
     thd->in_lock_tables=0;
     break;
+  }
   case SQLCOM_CREATE_DB:
   {
     if (end_active_trans(thd))

--- 1.508/sql/sql_yacc.yy	2006-11-27 09:58:34 +01:00
+++ 1.509/sql/sql_yacc.yy	2006-11-27 09:58:34 +01:00
@@ -94,6 +94,7 @@ void turn_parser_debug_on()
 
 %}
 %union {
+  bool truth;
   int  num;
   ulong ulong_num;
   ulonglong ulonglong_number;
@@ -124,6 +125,7 @@ void turn_parser_debug_on()
   enum Item_udftype udf_type;
   CHARSET_INFO *charset;
   thr_lock_type lock_type;
+  struct st_table_lock_info table_lock_info;
   interval_type interval, interval_time_st;
   timestamp_type date_time_type;
   st_select_lex *select_lex;
@@ -298,6 +300,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
 %token  EVENT_SYM
 %token  EVENTS_SYM
 %token  EVERY_SYM
+%token  EXCLUSIVE_SYM
 %token  EXECUTE_SYM
 %token  EXISTS
 %token  EXIT_SYM
@@ -489,6 +492,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
 %token  NOT2_SYM
 %token  NOT_SYM
 %token  NOW_SYM
+%token  NOWAIT_SYM
 %token  NO_SYM
 %token  NO_WAIT_SYM
 %token  NO_WRITE_TO_BINLOG
@@ -767,7 +771,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
 	text_string opt_gconcat_separator
 
 %type <num>
-	type int_type real_type order_dir lock_option
+	type int_type real_type order_dir
 	udf_type if_exists opt_local opt_table_options table_options
         table_option opt_if_not_exists opt_no_write_to_binlog
         delete_option opt_temporary all_or_any opt_distinct
@@ -789,6 +793,13 @@ bool my_yyoverflow(short **a, YYSTYPE **
 
 %type <lock_type>
 	replace_lock_option opt_low_priority insert_lock_option load_data_lock
+        transactional_lock_mode
+
+%type <truth>
+        opt_transactional_lock_nowait
+
+%type <table_lock_info>
+        table_lock_info
 
 %type <item>
 	literal text_literal insert_ident order_ident
@@ -9393,6 +9404,7 @@ keyword_sp:
 	| EVENT_SYM		{}
 	| EVENTS_SYM		{}
 	| EVERY_SYM             {}
+        | EXCLUSIVE_SYM         {}
 	| EXPANSION_SYM         {}
 	| EXTENDED_SYM		{}
 	| EXTENT_SIZE_SYM       {}
@@ -9478,6 +9490,7 @@ keyword_sp:
 	| NO_WAIT_SYM           {}
 	| NODEGROUP_SYM         {}
 	| NONE_SYM		{}
+	| NOWAIT_SYM            {}
 	| NVARCHAR_SYM		{}
 	| OFFSET_SYM		{}
 	| OLD_PASSWORD		{}
@@ -10002,7 +10015,23 @@ set_expr_or_default:
 /* Lock function */
 
 lock:
-	LOCK_SYM table_or_tables
+	LOCK_SYM
+        {
+          /*
+            transactional locks can be taken only if there are no
+            existing non-transactional locks and all requested locks
+            are transactional. Initialize lex->lock_transactional
+            from the first condition before parsing the table locks.
+            Any non-transactional lock request turns this to FALSE.
+            Table specific variables keep track of the locking method
+            requested for the table. This is used to warn about a
+            changed locking method later.
+          */
+          Lex->lock_transactional= !Lex->thd->locked_tables;
+          DBUG_PRINT("lock_info", ("Initialized lock_transactional: %d",
+                                   Lex->lock_transactional));
+        }
+        table_or_tables
 	{
 	  LEX *lex= Lex;
 
@@ -10026,18 +10055,65 @@ table_lock_list:
 	| table_lock_list ',' table_lock;
 
 table_lock:
-	table_ident opt_table_alias lock_option
-	{
-	  if (!Select->add_table_to_list(YYTHD, $1, $2, 0, (thr_lock_type) $3))
-	   YYABORT;
-	}
+        table_ident opt_table_alias table_lock_info
+        {
+          TABLE_LIST *tlist;
+          if (!(tlist= Select->add_table_to_list(YYTHD, $1, $2, 0,
+                                                 $3.lock_type)))
+            YYABORT;
+          /* Store the requested lock method for later warning. */
+          tlist->lock_transactional= $3.lock_transactional;
+          tlist->lock_nowait=        $3.lock_nowait;
+          /* Compute the resulting lock method for all tables. */
+          if (!$3.lock_transactional)
+            Lex->lock_transactional= FALSE;
+          DBUG_PRINT("lock_info", ("Now  have   lock_transactional: %d",
+                                   Lex->lock_transactional));
+        }
+        ;
+
+table_lock_info:
+        READ_SYM
+        {
+          $$.lock_type=          TL_READ_NO_INSERT;
+          $$.lock_transactional= FALSE;
+          $$.lock_nowait=        FALSE;
+        }
+        | WRITE_SYM
+        {
+          $$.lock_type=          YYTHD->update_lock_default;
+          $$.lock_transactional= FALSE;
+          $$.lock_nowait=        FALSE;
+        }
+        | LOW_PRIORITY WRITE_SYM
+        {
+          $$.lock_type=          TL_WRITE_LOW_PRIORITY;
+          $$.lock_transactional= FALSE;
+          $$.lock_nowait=        FALSE;
+        }
+        | READ_SYM LOCAL_SYM
+        {
+          $$.lock_type=          TL_READ;
+          $$.lock_transactional= FALSE;
+          $$.lock_nowait=        FALSE;
+        }
+        | IN_SYM transactional_lock_mode MODE_SYM opt_transactional_lock_nowait
+        {
+          $$.lock_type=          $2;
+          $$.lock_transactional= TRUE;
+          $$.lock_nowait=        $4;
+        }
+        ;
+
+/* Use thr_lock_type here for easier fallback to non-trans locking. */
+transactional_lock_mode:
+        SHARE_SYM       { $$= TL_READ_NO_INSERT; }
+        | EXCLUSIVE_SYM { $$= YYTHD->update_lock_default; }
         ;
 
-lock_option:
-	READ_SYM	{ $$=TL_READ_NO_INSERT; }
-	| WRITE_SYM     { $$=YYTHD->update_lock_default; }
-	| LOW_PRIORITY WRITE_SYM { $$=TL_WRITE_LOW_PRIORITY; }
-	| READ_SYM LOCAL_SYM { $$= TL_READ; }
+opt_transactional_lock_nowait:
+        /* empty */     { $$= FALSE; }
+        | NOWAIT_SYM    { $$= TRUE; }
         ;
 
 unlock:

--- 1.153/sql/table.h	2006-11-27 09:58:34 +01:00
+++ 1.154/sql/table.h	2006-11-27 09:58:34 +01:00
@@ -815,6 +815,9 @@ typedef struct st_table_list
     used for implicit LOCK TABLES only and won't be used in real statement.
   */
   bool          prelocking_placeholder;
+  /* For transactional locking. */
+  bool          lock_transactional;     /* If transactional lock requested. */
+  bool          lock_nowait;            /* If NOWAIT requested.             */
 
   void calc_md5(char *buffer);
   void set_underlying_merge();

--- 1.129/storage/innobase/handler/ha_innodb.h	2006-11-27 09:58:34 +01:00
+++ 1.130/storage/innobase/handler/ha_innodb.h	2006-11-27 09:58:34 +01:00
@@ -149,6 +149,17 @@ class ha_innobase: public handler
 	int discard_or_import_tablespace(my_bool discard);
 	int extra(enum ha_extra_function operation);
         int reset();
+        int lock_table(THD *thd, int lock_type, bool transactional,
+                       bool nowait __attribute__((unused)))
+        {
+          /*
+            Preliminarily call the pre-existing internal method for
+            transactional locking and ignore non-transactional locks.
+          */
+          if (transactional || thd->variables.innodb_table_locks)
+            return transactional_table_lock(thd, lock_type);
+          return 0;
+        }
 	int external_lock(THD *thd, int lock_type);
 	int transactional_table_lock(THD *thd, int lock_type);
 	int start_stmt(THD *thd, thr_lock_type lock_type);
Thread
bk commit into 5.1 tree (istruewing:1.2324)ingo27 Nov