Add TL_FIRST_WRITE in SQL layer for determining R/W

Use < TL_FIRST_WRITE for determining a READ transaction.

Use TL_FIRST_WRITE as the relative operator replacing TL_WRITE_ALLOW_WRITE
as the minimium WRITE lock type.
This commit is contained in:
Daniel Black 2021-03-24 15:41:10 +11:00
parent cf552f5886
commit 058484687a
18 changed files with 57 additions and 56 deletions

View File

@ -72,6 +72,15 @@ enum thr_lock_type { TL_IGNORE=-1,
/* Abort new lock request with an error */
TL_WRITE_ONLY};
/*
TL_FIRST_WRITE is here to impose some consistency in the sql
layer on determining read/write transactions and to
provide some API compatibility if additional transactions
are added. Above or equal to TL_FIRST_WRITE is a write transaction
while < TL_FIRST_WRITE is a read transaction.
*/
#define TL_FIRST_WRITE TL_WRITE_ALLOW_WRITE
enum enum_thr_lock_result { THR_LOCK_SUCCESS= 0, THR_LOCK_ABORTED= 1,
THR_LOCK_WAIT_TIMEOUT= 2, THR_LOCK_DEADLOCK= 3 };

View File

@ -216,8 +216,8 @@ static int check_lock(struct st_lock_list *list, const char* lock_type,
lock_type, where);
return 1;
}
if ((read_lock && data->type > TL_READ_NO_INSERT) ||
(!read_lock && data->type <= TL_READ_NO_INSERT))
if ((read_lock && data->type >= TL_FIRST_WRITE) ||
(!read_lock && data->type < TL_FIRST_WRITE))
{
fprintf(stderr,
"Warning: Found %s lock in %s queue at %s: %s\n",
@ -765,9 +765,9 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout)
DBUG_PRINT("lock",("data:%p thread:%lu lock:%p type: %d",
data, (ulong) data->owner->thread_id,
lock, (int) lock_type));
check_locks(lock,(uint) lock_type <= (uint) TL_READ_NO_INSERT ?
check_locks(lock,(uint) lock_type < (uint) TL_FIRST_WRITE ?
"enter read_lock" : "enter write_lock", lock_type, 0);
if ((int) lock_type <= (int) TL_READ_NO_INSERT)
if ((int) lock_type < (int) TL_FIRST_WRITE)
{
/* Request for READ lock */
if (lock->write.data)

View File

@ -4244,15 +4244,8 @@ int ha_partition::start_stmt(THD *thd, thr_lock_type lock_type)
/* Add partition to be called in reset(). */
bitmap_set_bit(&m_partitions_to_reset, i);
}
switch (lock_type)
if (lock_type >= TL_FIRST_WRITE)
{
case TL_WRITE_ALLOW_WRITE:
case TL_WRITE_CONCURRENT_INSERT:
case TL_WRITE_DELAYED:
case TL_WRITE_DEFAULT:
case TL_WRITE_LOW_PRIORITY:
case TL_WRITE:
case TL_WRITE_ONLY:
if (m_part_info->part_expr)
m_part_info->part_expr->walk(&Item::register_field_in_read_map, 1, 0);
if (m_part_info->part_type == VERSIONING_PARTITION &&
@ -4260,7 +4253,6 @@ int ha_partition::start_stmt(THD *thd, thr_lock_type lock_type)
thd->lex->sql_command != SQLCOM_SELECT &&
thd->lex->sql_command != SQLCOM_INSERT_SELECT)
m_part_info->vers_set_hist_part(thd);
default:;
}
DBUG_RETURN(error);
}

View File

@ -140,7 +140,7 @@ lock_tables_check(THD *thd, TABLE **tables, uint count, uint flags)
or hold any type of lock in a session,
since this would be a DOS attack.
*/
if ((t->reginfo.lock_type >= TL_READ_NO_INSERT)
if ((t->reginfo.lock_type >= TL_FIRST_WRITE)
|| (thd->lex->sql_command == SQLCOM_LOCK_TABLES))
{
my_error(ER_CANT_LOCK_LOG_TABLE, MYF(0));
@ -148,7 +148,7 @@ lock_tables_check(THD *thd, TABLE **tables, uint count, uint flags)
}
}
if (t->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE)
if (t->reginfo.lock_type >= TL_FIRST_WRITE)
{
if (t->s->table_category == TABLE_CATEGORY_SYSTEM)
system_count++;
@ -170,7 +170,7 @@ lock_tables_check(THD *thd, TABLE **tables, uint count, uint flags)
DBUG_ASSERT(t->s->tmp_table ||
thd->mdl_context.is_lock_owner(MDL_key::TABLE,
t->s->db.str, t->s->table_name.str,
t->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE ?
t->reginfo.lock_type >= TL_FIRST_WRITE ?
MDL_SHARED_WRITE : MDL_SHARED_READ));
/*
@ -179,7 +179,7 @@ lock_tables_check(THD *thd, TABLE **tables, uint count, uint flags)
*/
if (!(flags & MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY) && !t->s->tmp_table)
{
if (t->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE &&
if (t->reginfo.lock_type >= TL_FIRST_WRITE &&
!ignore_read_only && opt_readonly && !thd->slave_thread)
{
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
@ -387,7 +387,7 @@ static int lock_external(THD *thd, TABLE **tables, uint count)
lock_type=F_WRLCK; /* Lock exclusive */
if ((*tables)->db_stat & HA_READ_ONLY ||
((*tables)->reginfo.lock_type >= TL_READ &&
(*tables)->reginfo.lock_type <= TL_READ_NO_INSERT))
(*tables)->reginfo.lock_type < TL_FIRST_WRITE))
lock_type=F_RDLCK;
if (unlikely((error=(*tables)->file->ha_external_lock(thd,lock_type))))
@ -481,7 +481,7 @@ int mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock)
for (i=found=0 ; i < sql_lock->table_count ; i++)
{
DBUG_ASSERT(sql_lock->table[i]->lock_position == i);
if ((uint) sql_lock->table[i]->reginfo.lock_type > TL_WRITE_ALLOW_WRITE)
if ((uint) sql_lock->table[i]->reginfo.lock_type >= TL_FIRST_WRITE)
{
swap_variables(TABLE *, *table, sql_lock->table[i]);
table++;
@ -501,7 +501,7 @@ int mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock)
THR_LOCK_DATA **lock=sql_lock->locks;
for (i=found=0 ; i < sql_lock->lock_count ; i++)
{
if (sql_lock->locks[i]->type >= TL_WRITE_ALLOW_WRITE)
if (sql_lock->locks[i]->type >= TL_FIRST_WRITE)
{
swap_variables(THR_LOCK_DATA *, *lock, sql_lock->locks[i]);
lock++;

View File

@ -255,7 +255,7 @@ bool init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
thd->variables.read_rnd_buff_size &&
!(table->file->ha_table_flags() & HA_FAST_KEY_READ) &&
(table->db_stat & HA_READ_ONLY ||
table->reginfo.lock_type <= TL_READ_NO_INSERT) &&
table->reginfo.lock_type < TL_FIRST_WRITE) &&
(ulonglong) table->s->reclength* (table->file->stats.records+
table->file->stats.deleted) >
(ulonglong) MIN_FILE_LENGTH_TO_USE_ROW_CACHE &&

View File

@ -996,7 +996,7 @@ enum_tx_state Transaction_state_tracker::calc_trx_state(THD *thd,
bool has_trx)
{
enum_tx_state s;
bool read= (l <= TL_READ_NO_INSERT);
bool read= (l < TL_FIRST_WRITE);
if (read)
s= has_trx ? TX_READ_TRX : TX_READ_UNSAFE;

View File

@ -1942,7 +1942,7 @@ class Grant_tables
We can read privilege tables even when !initialized.
This can be acl_load() - server startup or FLUSH PRIVILEGES
*/
if (lock_type >= TL_WRITE_ALLOW_WRITE && !initialized)
if (lock_type >= TL_FIRST_WRITE && !initialized)
{
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
DBUG_RETURN(-1);
@ -1957,7 +1957,7 @@ class Grant_tables
NULL, lock_type);
tl->open_type= OT_BASE_ONLY;
tl->i_s_requested_object= OPEN_TABLE_ONLY;
tl->updating= lock_type >= TL_WRITE_ALLOW_WRITE;
tl->updating= lock_type >= TL_FIRST_WRITE;
if (i >= FIRST_OPTIONAL_TABLE)
tl->open_strategy= TABLE_LIST::OPEN_IF_EXISTS;
tl->next_global= tl->next_local= first;
@ -1982,7 +1982,7 @@ class Grant_tables
NULL, lock_type);
tl->open_type= OT_BASE_ONLY;
tl->i_s_requested_object= OPEN_TABLE_ONLY;
tl->updating= lock_type >= TL_WRITE_ALLOW_WRITE;
tl->updating= lock_type >= TL_FIRST_WRITE;
p_user_table= &m_user_table_tabular;
counter++;
res= really_open(thd, tl, &unused);
@ -2049,7 +2049,7 @@ class Grant_tables
{
DBUG_ENTER("Grant_tables::really_open:");
#ifdef HAVE_REPLICATION
if (tables->lock_type >= TL_WRITE_ALLOW_WRITE &&
if (tables->lock_type >= TL_FIRST_WRITE &&
thd->slave_thread && !thd->spcont)
{
/*
@ -8116,7 +8116,7 @@ bool check_grant(THD *thd, privilege_t want_access, TABLE_LIST *tables,
We want to have either SELECT or INSERT rights to sequences depending
on how they are accessed
*/
orig_want_access= ((t_ref->lock_type == TL_WRITE_ALLOW_WRITE) ?
orig_want_access= ((t_ref->lock_type >= TL_FIRST_WRITE) ?
INSERT_ACL : SELECT_ACL);
}

View File

@ -570,7 +570,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
*/
table->mdl_request.set_type(lex->sql_command == SQLCOM_REPAIR
? MDL_SHARED_NO_READ_WRITE
: lock_type >= TL_WRITE_ALLOW_WRITE
: lock_type >= TL_FIRST_WRITE
? MDL_SHARED_WRITE : MDL_SHARED_READ);
/* open only one table from local list of command */

View File

@ -2724,7 +2724,7 @@ bool Locked_tables_list::restore_lock(THD *thd, TABLE_LIST *dst_table_list,
add_back_last_deleted_lock(dst_table_list);
table->mdl_ticket->downgrade_lock(table->reginfo.lock_type >=
TL_WRITE_ALLOW_WRITE ?
TL_FIRST_WRITE ?
MDL_SHARED_NO_READ_WRITE :
MDL_SHARED_READ);
@ -3518,7 +3518,7 @@ bool extend_table_list(THD *thd, TABLE_LIST *tables,
bool error= false;
LEX *lex= thd->lex;
bool maybe_need_prelocking=
(tables->updating && tables->lock_type >= TL_WRITE_ALLOW_WRITE)
(tables->updating && tables->lock_type >= TL_FIRST_WRITE)
|| thd->lex->default_used;
if (thd->locked_tables_mode <= LTM_LOCK_TABLES &&
@ -4709,7 +4709,7 @@ handle_table(THD *thd, Query_tables_list *prelocking_ctx,
DBUG_ENTER("handle_table");
TABLE *table= table_list->table;
/* We rely on a caller to check that table is going to be changed. */
DBUG_ASSERT(table_list->lock_type >= TL_WRITE_ALLOW_WRITE ||
DBUG_ASSERT(table_list->lock_type >= TL_FIRST_WRITE ||
thd->lex->default_used);
if (table_list->trg_event_map)
@ -4891,7 +4891,7 @@ handle_table(THD *thd, Query_tables_list *prelocking_ctx,
tl->open_strategy= TABLE_LIST::OPEN_NORMAL;
/* We rely on a caller to check that table is going to be changed. */
DBUG_ASSERT(table_list->lock_type >= TL_WRITE_ALLOW_WRITE);
DBUG_ASSERT(table_list->lock_type >= TL_FIRST_WRITE);
return FALSE;
}
@ -4998,8 +4998,8 @@ static bool check_lock_and_start_stmt(THD *thd,
else
lock_type= table_list->lock_type;
if ((int) lock_type >= (int) TL_WRITE_ALLOW_WRITE &&
(int) table_list->table->reginfo.lock_type < (int) TL_WRITE_ALLOW_WRITE)
if ((int) lock_type >= (int) TL_FIRST_WRITE &&
(int) table_list->table->reginfo.lock_type < (int) TL_FIRST_WRITE)
{
my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0),
table_list->table->alias.c_ptr());
@ -5436,7 +5436,7 @@ static bool fix_all_session_vcol_exprs(THD *thd, TABLE_LIST *tables)
{
TABLE *t= table->table;
if (!table->placeholder() && t->s->vcols_need_refixing &&
table->lock_type >= TL_WRITE_ALLOW_WRITE)
table->lock_type >= TL_FIRST_WRITE)
{
Query_arena *stmt_backup= thd->stmt_arena;
if (thd->stmt_arena->is_conventional())
@ -5594,7 +5594,7 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count, uint flags)
a table that is already used by the calling statement.
*/
if (thd->locked_tables_mode >= LTM_PRELOCKED &&
table->lock_type >= TL_WRITE_ALLOW_WRITE)
table->lock_type >= TL_FIRST_WRITE)
{
for (TABLE* opentab= thd->open_tables; opentab; opentab= opentab->next)
{
@ -9043,7 +9043,7 @@ open_system_tables_for_read(THD *thd, TABLE_LIST *table_list)
if (open_and_lock_tables(thd, table_list, FALSE,
(MYSQL_OPEN_IGNORE_FLUSH |
MYSQL_OPEN_IGNORE_LOGGING_FORMAT |
(table_list->lock_type < TL_WRITE_ALLOW_WRITE ?
(table_list->lock_type < TL_FIRST_WRITE ?
MYSQL_LOCK_IGNORE_TIMEOUT : 0))))
{
lex->restore_backup_query_tables_list(&query_tables_list_backup);

View File

@ -2291,7 +2291,7 @@ void Query_cache::invalidate_locked_for_write(THD *thd,
for (; tables_used; tables_used= tables_used->next_local)
{
THD_STAGE_INFO(thd, stage_invalidating_query_cache_entries_table);
if (tables_used->lock_type >= TL_WRITE_ALLOW_WRITE &&
if (tables_used->lock_type >= TL_FIRST_WRITE &&
tables_used->table)
{
invalidate_table(thd, tables_used->table);

View File

@ -6237,7 +6237,7 @@ int THD::decide_logging_format(TABLE_LIST *tables)
*/
lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_TABLE);
if (tbl->lock_type >= TL_WRITE_ALLOW_WRITE)
if (tbl->lock_type >= TL_FIRST_WRITE)
{
non_replicated_tables_count++;
continue;
@ -6250,10 +6250,10 @@ int THD::decide_logging_format(TABLE_LIST *tables)
if (tbl->prelocking_placeholder != TABLE_LIST::PRELOCK_FK)
{
if (tbl->lock_type <= TL_READ_NO_INSERT)
if (tbl->lock_type < TL_FIRST_WRITE)
has_read_tables= true;
else if (table->found_next_number_field &&
(tbl->lock_type >= TL_WRITE_ALLOW_WRITE))
(tbl->lock_type >= TL_FIRST_WRITE))
{
has_auto_increment_write_tables= true;
has_auto_increment_write_tables_not_first= found_first_not_own_table;
@ -6262,7 +6262,7 @@ int THD::decide_logging_format(TABLE_LIST *tables)
}
}
if (tbl->lock_type >= TL_WRITE_ALLOW_WRITE)
if (tbl->lock_type >= TL_FIRST_WRITE)
{
bool trans;
if (prev_write_table && prev_write_table->file->ht !=
@ -6532,7 +6532,7 @@ int THD::decide_logging_format(TABLE_LIST *tables)
if (table->placeholder())
continue;
if (table->table->file->ht->db_type == DB_TYPE_BLACKHOLE_DB &&
table->lock_type >= TL_WRITE_ALLOW_WRITE)
table->lock_type >= TL_FIRST_WRITE)
{
table_names.append(&table->table_name);
table_names.append(",");

View File

@ -4369,7 +4369,7 @@ void LEX::set_trg_event_type_for_tables()
parsing.
*/
if (static_cast<int>(tables->lock_type) >=
static_cast<int>(TL_WRITE_ALLOW_WRITE))
static_cast<int>(TL_FIRST_WRITE))
tables->trg_event_map= new_trg_event_map;
tables= tables->next_local;
}

View File

@ -3648,7 +3648,7 @@ mysql_execute_command(THD *thd)
{
for (TABLE_LIST *table= all_tables; table; table= table->next_global)
{
if (table->lock_type >= TL_WRITE_ALLOW_WRITE)
if (table->lock_type >= TL_FIRST_WRITE)
{
lex->sql_command= SQLCOM_BEGIN;
thd->wsrep_converted_lock_session= true;
@ -7096,7 +7096,7 @@ check_table_access(THD *thd, privilege_t requirements, TABLE_LIST *tables,
/* We want to have either SELECT or INSERT rights to sequences depending
on how they are accessed
*/
want_access= ((table_ref->lock_type == TL_WRITE_ALLOW_WRITE) ?
want_access= ((table_ref->lock_type >= TL_FIRST_WRITE) ?
INSERT_ACL : SELECT_ACL);
}
@ -8894,7 +8894,7 @@ void st_select_lex::set_lock_for_tables(thr_lock_type lock_type, bool for_update
{
tables->lock_type= lock_type;
tables->updating= for_update;
tables->mdl_request.set_type((lock_type >= TL_WRITE_ALLOW_WRITE) ?
tables->mdl_request.set_type((lock_type >= TL_FIRST_WRITE) ?
MDL_SHARED_WRITE : MDL_SHARED_READ);
}
DBUG_VOID_RETURN;
@ -9687,7 +9687,7 @@ bool multi_delete_set_locks_and_link_aux_tables(LEX *lex)
walk->updating= target_tbl->updating;
walk->lock_type= target_tbl->lock_type;
/* We can assume that tables to be deleted from are locked for write. */
DBUG_ASSERT(walk->lock_type >= TL_WRITE_ALLOW_WRITE);
DBUG_ASSERT(walk->lock_type >= TL_FIRST_WRITE);
walk->mdl_request.set_type(MDL_SHARED_WRITE);
target_tbl->correspondent_table= walk; // Remember corresponding table
}

View File

@ -1049,7 +1049,7 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables)
if (vers_conditions.is_set())
{
if (vers_conditions.was_set() &&
table->lock_type > TL_READ_NO_INSERT &&
table->lock_type >= TL_FIRST_WRITE &&
!vers_conditions.delete_history)
{
my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table->alias.str);

View File

@ -2270,7 +2270,7 @@ add_tables_and_routines_for_triggers(THD *thd,
TABLE_LIST *table_list)
{
DBUG_ASSERT(static_cast<int>(table_list->lock_type) >=
static_cast<int>(TL_WRITE_ALLOW_WRITE));
static_cast<int>(TL_FIRST_WRITE));
for (int i= 0; i < (int)TRG_EVENT_MAX; i++)
{

View File

@ -16704,7 +16704,7 @@ table_lock:
table_ident opt_table_alias_clause lock_option
{
thr_lock_type lock_type= (thr_lock_type) $3;
bool lock_for_write= (lock_type >= TL_WRITE_ALLOW_WRITE);
bool lock_for_write= (lock_type >= TL_FIRST_WRITE);
ulong table_options= lock_for_write ? TL_OPTION_UPDATING : 0;
enum_mdl_type mdl_type= !lock_for_write
? MDL_SHARED_READ

View File

@ -3616,7 +3616,7 @@ bool fix_session_vcol_expr_for_read(THD *thd, Field *field,
{
DBUG_ENTER("fix_session_vcol_expr_for_read");
TABLE_LIST *tl= field->table->pos_in_table_list;
if (!tl || tl->lock_type >= TL_WRITE_ALLOW_WRITE)
if (!tl || tl->lock_type >= TL_FIRST_WRITE)
DBUG_RETURN(0);
Security_context *save_security_ctx= thd->security_ctx;
if (tl->security_ctx)
@ -8494,7 +8494,7 @@ void init_mdl_requests(TABLE_LIST *table_list)
for ( ; table_list ; table_list= table_list->next_global)
MDL_REQUEST_INIT(&table_list->mdl_request, MDL_key::TABLE,
table_list->db.str, table_list->table_name.str,
table_list->lock_type >= TL_WRITE_ALLOW_WRITE
table_list->lock_type >= TL_FIRST_WRITE
? MDL_SHARED_WRITE : MDL_SHARED_READ, MDL_TRANSACTION);
}

View File

@ -2135,7 +2135,7 @@ struct TABLE_LIST
enum thr_lock_type lock_type_arg)
{
enum enum_mdl_type mdl_type;
if (lock_type_arg >= TL_WRITE_ALLOW_WRITE)
if (lock_type_arg >= TL_FIRST_WRITE)
mdl_type= MDL_SHARED_WRITE;
else if (lock_type_arg == TL_READ_NO_INSERT)
mdl_type= MDL_SHARED_NO_WRITE;
@ -2150,7 +2150,7 @@ struct TABLE_LIST
table_name= *table_name_arg;
alias= (alias_arg ? *alias_arg : *table_name_arg);
lock_type= lock_type_arg;
updating= lock_type >= TL_WRITE_ALLOW_WRITE;
updating= lock_type >= TL_FIRST_WRITE;
MDL_REQUEST_INIT(&mdl_request, MDL_key::TABLE, db.str, table_name.str,
mdl_type, MDL_TRANSACTION);
}
@ -2184,7 +2184,7 @@ struct TABLE_LIST
belong_to_view= belong_to_view_arg;
trg_event_map= trg_event_map_arg;
/* MDL is enough for read-only FK checks, we don't need the table */
if (prelocking_type == PRELOCK_FK && lock_type < TL_WRITE_ALLOW_WRITE)
if (prelocking_type == PRELOCK_FK && lock_type < TL_FIRST_WRITE)
open_strategy= OPEN_STUB;
**last_ptr= this;