diff options
author | jan@hundin.mysql.fi <> | 2004-12-09 11:20:50 +0200 |
---|---|---|
committer | jan@hundin.mysql.fi <> | 2004-12-09 11:20:50 +0200 |
commit | 49c0044a2f6159512e5e40b88104407abcce60de (patch) | |
tree | 465f1cf5128d68051a4742439bf4f69d5975b276 | |
parent | dafb2969c90860676c521edda12377e7b4dd3eb2 (diff) | |
parent | d6effde5d0d727d6f010314cdf422908bee10f98 (diff) | |
download | mariadb-git-49c0044a2f6159512e5e40b88104407abcce60de.tar.gz |
Content merge.
-rw-r--r-- | innobase/include/lock0lock.h | 2 | ||||
-rw-r--r-- | innobase/include/trx0trx.h | 4 | ||||
-rw-r--r-- | innobase/lock/lock0lock.c | 34 | ||||
-rw-r--r-- | innobase/row/row0mysql.c | 12 | ||||
-rw-r--r-- | innobase/trx/trx0roll.c | 7 | ||||
-rw-r--r-- | innobase/trx/trx0trx.c | 13 | ||||
-rw-r--r-- | sql/ha_innodb.cc | 96 | ||||
-rw-r--r-- | sql/ha_innodb.h | 1 | ||||
-rw-r--r-- | sql/handler.h | 1 | ||||
-rw-r--r-- | sql/lock.cc | 62 | ||||
-rw-r--r-- | sql/mysql_priv.h | 1 | ||||
-rw-r--r-- | sql/sql_lex.h | 1 | ||||
-rw-r--r-- | sql/sql_parse.cc | 21 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 13 |
14 files changed, 248 insertions, 20 deletions
diff --git a/innobase/include/lock0lock.h b/innobase/include/lock0lock.h index b99359fe998..0f1fcad563e 100644 --- a/innobase/include/lock0lock.h +++ b/innobase/include/lock0lock.h @@ -585,6 +585,8 @@ extern lock_sys_t* lock_sys; #define LOCK_TABLE 16 /* these type values should be so high that */ #define LOCK_REC 32 /* they can be ORed to the lock mode */ #define LOCK_TABLE_EXP 80 /* explicit table lock (80 = 16 + 64) */ +#define LOCK_TABLE_TRANSACTIONAL 144 + /* transactional table lock (144 = 16 + 128)*/ #define LOCK_TYPE_MASK 0xF0UL /* mask used to extract lock type from the type_mode field in a lock */ /* Waiting lock flag */ diff --git a/innobase/include/trx0trx.h b/innobase/include/trx0trx.h index 8eb71dac763..e305226f9e3 100644 --- a/innobase/include/trx0trx.h +++ b/innobase/include/trx0trx.h @@ -464,6 +464,10 @@ struct trx_struct{ ulint n_lock_table_exp;/* number of explicit table locks (LOCK TABLES) reserved by the transaction, stored in trx_locks */ + ulint n_lock_table_transactional; + /* number of transactional table locks + (LOCK TABLES..WHERE ENGINE) reserved by + the transaction, stored in trx_locks */ UT_LIST_NODE_T(trx_t) trx_list; /* list of transactions */ UT_LIST_NODE_T(trx_t) diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c index d2d16a1ae4e..1ff16bce45a 100644 --- a/innobase/lock/lock0lock.c +++ b/innobase/lock/lock0lock.c @@ -2207,7 +2207,8 @@ lock_grant( release it at the end of the SQL statement */ lock->trx->auto_inc_lock = lock; - } else if (lock_get_type(lock) == LOCK_TABLE_EXP) { + } else if (lock_get_type(lock) == LOCK_TABLE_EXP || + lock_get_type(lock) == LOCK_TABLE_TRANSACTIONAL) { ut_a(lock_get_mode(lock) == LOCK_S || lock_get_mode(lock) == LOCK_X); } @@ -3421,6 +3422,10 @@ lock_table_create( lock->trx->n_lock_table_exp++; } + if (lock_get_type(lock) == LOCK_TABLE_TRANSACTIONAL) { + lock->trx->n_lock_table_transactional++; + } + lock->un_member.tab_lock.table = table; UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); @@ -3458,7 +3463,11 @@ lock_table_remove_low( } if (lock_get_type(lock) == LOCK_TABLE_EXP) { - lock->trx->n_lock_table_exp--; + trx->n_lock_table_exp--; + } + + if (lock_get_type(lock) == LOCK_TABLE_TRANSACTIONAL) { + trx->n_lock_table_transactional--; } UT_LIST_REMOVE(trx_locks, trx->trx_locks, lock); @@ -3592,7 +3601,8 @@ lock_table( DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ ulint flags, /* in: if BTR_NO_LOCKING_FLAG bit is set, does nothing; - if LOCK_TABLE_EXP bits are set, + if LOCK_TABLE_EXP|LOCK_TABLE_TRANSACTIONAL + bits are set, creates an explicit table lock */ dict_table_t* table, /* in: database table in dictionary cache */ ulint mode, /* in: lock mode */ @@ -3608,7 +3618,8 @@ lock_table( return(DB_SUCCESS); } - ut_a(flags == 0 || flags == LOCK_TABLE_EXP); + ut_a(flags == 0 || flags == LOCK_TABLE_EXP || + flags == LOCK_TABLE_TRANSACTIONAL); trx = thr_get_trx(thr); @@ -3722,7 +3733,8 @@ lock_table_dequeue( ut_ad(mutex_own(&kernel_mutex)); #endif /* UNIV_SYNC_DEBUG */ ut_a(lock_get_type(in_lock) == LOCK_TABLE || - lock_get_type(in_lock) == LOCK_TABLE_EXP); + lock_get_type(in_lock) == LOCK_TABLE_EXP || + lock_get_type(in_lock) == LOCK_TABLE_TRANSACTIONAL); lock = UT_LIST_GET_NEXT(un_member.tab_lock.locks, in_lock); @@ -3826,7 +3838,9 @@ lock_release_off_kernel( } lock_table_dequeue(lock); - if (lock_get_type(lock) == LOCK_TABLE_EXP) { + + if (lock_get_type(lock) == LOCK_TABLE_EXP || + lock_get_type(lock) == LOCK_TABLE_TRANSACTIONAL) { ut_a(lock_get_mode(lock) == LOCK_S || lock_get_mode(lock) == LOCK_X); } @@ -3850,6 +3864,7 @@ lock_release_off_kernel( ut_a(trx->auto_inc_lock == NULL); ut_a(trx->n_lock_table_exp == 0); + ut_a(trx->n_lock_table_transactional == 0); } /************************************************************************* @@ -3915,6 +3930,7 @@ lock_release_tables_off_kernel( } ut_a(trx->n_lock_table_exp == 0); + ut_a(trx->n_lock_table_transactional == 0); } /************************************************************************* @@ -4028,11 +4044,15 @@ lock_table_print( ut_ad(mutex_own(&kernel_mutex)); #endif /* UNIV_SYNC_DEBUG */ ut_a(lock_get_type(lock) == LOCK_TABLE || - lock_get_type(lock) == LOCK_TABLE_EXP); + lock_get_type(lock) == LOCK_TABLE_EXP || + lock_get_type(lock) == LOCK_TABLE_TRANSACTIONAL); if (lock_get_type(lock) == LOCK_TABLE_EXP) { fputs("EXPLICIT ", file); + } else if (lock_get_type(lock) == LOCK_TABLE_TRANSACTIONAL) { + fputs("TRANSACTIONAL ", file); } + fputs("TABLE LOCK table ", file); ut_print_name(file, lock->trx, lock->un_member.tab_lock.table->name); fprintf(file, " trx id %lu %lu", diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index fa584df15db..8a3846e046c 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -784,7 +784,7 @@ row_lock_table_for_mysql( table handle */ dict_table_t* table, /* in: table to lock, or NULL if prebuilt->table should be - locked as LOCK_TABLE_EXP | + locked or a prebuilt->select_lock_type */ ulint mode) /* in: lock mode of table */ { @@ -822,8 +822,14 @@ run_again: if (table) { err = lock_table(0, table, mode, thr); } else { - err = lock_table(LOCK_TABLE_EXP, prebuilt->table, - prebuilt->select_lock_type, thr); + if (mode == LOCK_TABLE_TRANSACTIONAL) { + err = lock_table(LOCK_TABLE_TRANSACTIONAL, + prebuilt->table, + prebuilt->select_lock_type, thr); + } else { + err = lock_table(LOCK_TABLE_EXP, prebuilt->table, + prebuilt->select_lock_type, thr); + } } trx->error_state = err; diff --git a/innobase/trx/trx0roll.c b/innobase/trx/trx0roll.c index db5e16c7778..105fa97080f 100644 --- a/innobase/trx/trx0roll.c +++ b/innobase/trx/trx0roll.c @@ -335,8 +335,10 @@ undo log. If the transaction was not yet committed, then we roll it back. Note: this is done in a background thread */ void * -trx_rollback_or_clean_all_without_sess(void *i) -/*========================================*/ +trx_rollback_or_clean_all_without_sess( +/*===================================*/ + /* out: arguments */ + void *i) /* in: arguments (unused) */ { mem_heap_t* heap; que_fork_t* fork; @@ -496,6 +498,7 @@ loop: goto loop; os_thread_exit(i); /* not reached */ + return(i); } /*********************************************************************** diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c index ab8bd898dd6..f676c21934b 100644 --- a/innobase/trx/trx0trx.c +++ b/innobase/trx/trx0trx.c @@ -153,6 +153,7 @@ trx_create( trx->auto_inc_lock = NULL; trx->n_lock_table_exp = 0; + trx->n_lock_table_transactional = 0; trx->read_view_heap = mem_heap_create(256); trx->read_view = NULL; @@ -285,6 +286,7 @@ trx_free( ut_a(!trx->has_search_latch); ut_a(!trx->auto_inc_lock); ut_a(!trx->n_lock_table_exp); + ut_a(!trx->n_lock_table_transactional); ut_a(trx->dict_operation_lock_mode == 0); @@ -1645,10 +1647,15 @@ trx_print( putc('\n', f); if (trx->n_mysql_tables_in_use > 0 || trx->mysql_n_tables_locked > 0) { + fprintf(f, "mysql tables in use %lu, locked %lu\n", + (ulong) trx->n_mysql_tables_in_use, + (ulong) trx->mysql_n_tables_locked); + } - fprintf(f, "mysql tables in use %lu, locked %lu\n", - (ulong) trx->n_mysql_tables_in_use, - (ulong) trx->mysql_n_tables_locked); + if (trx->n_lock_table_transactional > 0 || trx->n_lock_table_exp > 0) { +fprintf(f, "mysql explicit table locks %lu, transactional table locks %lu\n", + (ulong) trx->n_lock_table_exp, + (ulong) trx->n_lock_table_transactional); } newline = TRUE; diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 0c7fc23ee49..6b7f5e05ee2 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -1346,7 +1346,8 @@ innobase_commit( 3. innobase_query_caching_of_table_permitted(), 4. innobase_savepoint(), 5. ::init_table_handle_for_HANDLER(), - 6. innobase_start_trx_and_assign_read_view() + 6. innobase_start_trx_and_assign_read_view(), + 7. ::transactional_table_lock() and it is only set to 0 in a commit or a rollback. If it is 0 we know there cannot be resources to be freed and we could return immediately. @@ -5109,8 +5110,9 @@ ha_innobase::start_stmt( select_lock_type value. The value of stored_select_lock_type was decided in: 1) ::store_lock(), - 2) ::external_lock(), and - 3) ::init_table_handle_for_HANDLER(). */ + 2) ::external_lock(), + 3) ::init_table_handle_for_HANDLER(), and + 4) :.transactional_table_lock(). */ prebuilt->select_lock_type = prebuilt->stored_select_lock_type; @@ -5301,6 +5303,94 @@ ha_innobase::external_lock( DBUG_RETURN(0); } +/********************************************************************** +With this function MySQL request a transactional lock to a table when +user issued query LOCK TABLES..WHERE ENGINE = InnoDB. */ + +int +ha_innobase::transactional_table_lock( +/*==================================*/ + /* out: 0 */ + THD* thd, /* in: handle to the user thread */ + int lock_type) /* in: lock type */ +{ + row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; + trx_t* trx; + + DBUG_ENTER("ha_innobase::transactional_table_lock"); + DBUG_PRINT("enter",("lock_type: %d", lock_type)); + + /* We do not know if MySQL can call this function before calling + external_lock(). To be safe, update the thd of the current table + handle. */ + + update_thd(thd); + + if (prebuilt->table->ibd_file_missing && !current_thd->tablespace_op) { + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB error:\n" +"MySQL is trying to use a table handle but the .ibd file for\n" +"table %s does not exist.\n" +"Have you deleted the .ibd file from the database directory under\n" +"the MySQL datadir, or have you used DISCARD TABLESPACE?\n" +"Look from section 15.1 of http://www.innodb.com/ibman.html\n" +"how you can resolve the problem.\n", + prebuilt->table->name); + DBUG_RETURN(HA_ERR_CRASHED); + } + + trx = prebuilt->trx; + + prebuilt->sql_stat_start = TRUE; + prebuilt->hint_need_to_fetch_extra_cols = 0; + + prebuilt->read_just_key = 0; + prebuilt->keep_other_fields_on_keyread = FALSE; + + if (lock_type == F_WRLCK) { + prebuilt->select_lock_type = LOCK_X; + prebuilt->stored_select_lock_type = LOCK_X; + } else if (lock_type == F_RDLCK) { + prebuilt->select_lock_type = LOCK_X; + prebuilt->stored_select_lock_type = LOCK_X; + } else { + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB error:\n" +"MySQL is trying to set transactional table lock with corrupted lock type\n" +"to table %s, lock type %d does not exist.\n", + prebuilt->table->name, lock_type); + DBUG_RETURN(HA_ERR_CRASHED); + } + + /* MySQL is setting a new transactional table lock */ + + /* Set the MySQL flag to mark that there is an active transaction */ + thd->transaction.all.innodb_active_trans = 1; + + if (thd->in_lock_tables && thd->variables.innodb_table_locks) { + ulint error = DB_SUCCESS; + + error = row_lock_table_for_mysql(prebuilt,NULL, + LOCK_TABLE_TRANSACTIONAL); + + if (error != DB_SUCCESS) { + error = convert_error_code_to_mysql(error, user_thd); + DBUG_RETURN(error); + } + + if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { + + /* Store the current undo_no of the transaction + so that we know where to roll back if we have + to roll back the next SQL statement */ + + trx_mark_sql_stat_end(trx); + } + } + + DBUG_RETURN(0); +} + /**************************************************************************** Here we export InnoDB status variables to MySQL. */ diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index b3b8d1a29e8..214e905a327 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -150,6 +150,7 @@ class ha_innobase: public handler int discard_or_import_tablespace(my_bool discard); int extra(enum ha_extra_function operation); int external_lock(THD *thd, int lock_type); + int transactional_table_lock(THD *thd, int lock_type); int start_stmt(THD *thd); void position(byte *record); diff --git a/sql/handler.h b/sql/handler.h index c9adaefa888..4c6bd1c986b 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -452,6 +452,7 @@ public: { return extra(operation); } virtual int reset() { return extra(HA_EXTRA_RESET); } virtual int external_lock(THD *thd, int lock_type) { return 0; } + virtual int transactional_table_lock(THD *thd, int lock_type) {return 0;} virtual void unlock_row() {} virtual int start_stmt(THD *thd) {return 0;} /* diff --git a/sql/lock.cc b/sql/lock.cc index 8a3619b57dd..1d511fec415 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -695,6 +695,9 @@ static void print_lock_error(int error) case HA_ERR_READ_ONLY_TRANSACTION: textno=ER_READ_ONLY_TRANSACTION; break; + case HA_ERR_LOCK_DEADLOCK: + textno=ER_LOCK_DEADLOCK; + break; default: textno=ER_CANT_LOCK; break; @@ -927,3 +930,62 @@ bool make_global_read_lock_block_commit(THD *thd) thd->exit_cond(old_message); DBUG_RETURN(error); } + +/* + Take transactional table lock for all tables in the list + + SYNOPSIS + transactional_lock_tables + thd Thread THD + tables list of tables + counter number of tables in the list + + NOTES + + RETURN + 0 - OK + -1 - error + +*/ +int transactional_lock_tables(THD *thd, TABLE_LIST *tables, uint counter) +{ + uint i; + int lock_type,error=0; + TABLE_LIST *table; + TABLE **start,**ptr; + + DBUG_ENTER("transactional_lock_tables"); + + if (!(ptr=start=(TABLE**) sql_alloc(sizeof(TABLE*) * counter))) + return -1; + + for (table= tables; table; table= table->next_global) + { + if (!table->placeholder() && !table->schema_table) + *(ptr++)= table->table; + } + + for (i=1 ; i <= counter ; i++, start++) + { + DBUG_ASSERT((*start)->reginfo.lock_type >= TL_READ); + lock_type=F_WRLCK; /* Lock exclusive */ + + if ((*start)->db_stat & HA_READ_ONLY || + ((*start)->reginfo.lock_type >= TL_READ && + (*start)->reginfo.lock_type <= TL_READ_NO_INSERT)) + lock_type=F_RDLCK; + + if ((error=(*start)->file->transactional_table_lock(thd, lock_type))) + { + print_lock_error(error); + DBUG_RETURN(-1); + } + else + { + (*start)->db_stat &= ~ HA_BLOCK_LOCK; + (*start)->current_lock= lock_type; + } + } + + DBUG_RETURN(0); +} diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 91d15dc1125..963ba484cea 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -828,6 +828,7 @@ int open_tables(THD *thd, TABLE_LIST *tables, uint *counter); int simple_open_n_lock_tables(THD *thd,TABLE_LIST *tables); bool open_and_lock_tables(THD *thd,TABLE_LIST *tables); int lock_tables(THD *thd, TABLE_LIST *tables, uint counter); +int transactional_lock_tables(THD *thd, TABLE_LIST *tables, uint counter); TABLE *open_temporary_table(THD *thd, const char *path, const char *db, const char *table_name, bool link_in_list); bool rm_temporary_table(enum db_type base, char *path); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 1c0e3e2e02e..7a4ef0b98e5 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -87,6 +87,7 @@ enum enum_sql_command { SQLCOM_PREPARE, SQLCOM_EXECUTE, SQLCOM_DEALLOCATE_PREPARE, SQLCOM_CREATE_VIEW, SQLCOM_DROP_VIEW, SQLCOM_CREATE_TRIGGER, SQLCOM_DROP_TRIGGER, + SQLCOM_LOCK_TABLES_TRANSACTIONAL, /* This should be the last !!! */ SQLCOM_END }; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 3d4252a2b17..50c346619ee 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3257,6 +3257,27 @@ create_error: thd->options&= ~(ulong) (OPTION_TABLE_LOCK); thd->in_lock_tables=0; break; + case SQLCOM_LOCK_TABLES_TRANSACTIONAL: + { + uint counter = 0; + + if (check_db_used(thd, all_tables)) + 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; + + if (open_tables(thd, all_tables, &counter) == 0 && + transactional_lock_tables(thd, all_tables, counter) == 0) + send_ok(thd); + else + thd->options&= ~(ulong) (OPTION_TABLE_LOCK); + + thd->in_lock_tables=0; + break; + } case SQLCOM_CREATE_DB: { char *alias; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 8b3cdda5d9e..45f0236d0e8 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7387,8 +7387,8 @@ lock: { Lex->sql_command=SQLCOM_LOCK_TABLES; } - table_lock_list - {} + table_lock_list lock_engine_opt + {} ; table_or_tables: @@ -7414,6 +7414,15 @@ lock_option: | READ_SYM LOCAL_SYM { $$= TL_READ; } ; +lock_engine_opt: + /* empty */ + | WHERE + { + Lex->sql_command=SQLCOM_LOCK_TABLES_TRANSACTIONAL; + } + ENGINE_SYM opt_equal storage_engines + ; + unlock: UNLOCK_SYM table_or_tables { Lex->sql_command=SQLCOM_UNLOCK_TABLES; } ; |