/** Setting super_read_only to ON triggers read_only to also be set to ON. */ static Sys_var_bool Sys_super_readonly( "super_read_only", "Make all non-temporary tables read-only, with the exception for " "replication applier threads. Users with the SUPER privilege are " "affected, unlike read_only. Setting super_read_only to ON " "also sets read_only to ON.", GLOBAL_VAR(super_read_only), CMD_LINE(OPT_ARG), DEFAULT(false), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(nullptr), ON_UPDATE(fix_super_read_only));
/* return if no changes: */ if (super_read_only == opt_super_readonly) returnfalse;
/* return immediately if turning super_read_only OFF: */ if (super_read_only == false) { opt_super_readonly = false;
// Do this last as it temporarily releases the global sys-var lock. event_scheduler_restart(thd);
returnfalse; } bool result = true; bool new_super_read_only = super_read_only; /* make a copy before releasing a mutex */
/* set read_only to ON if it is OFF, letting fix_read_only() handle its own locking needs */ if (!opt_readonly) { read_only = true; if ((result = fix_read_only(nullptr, thd, type))) goto end; }
/* if we already have global read lock, set super_read_only and return immediately: */ if (thd->global_read_lock.is_acquired()) { opt_super_readonly = super_read_only; returnfalse; }
/* now we're turning ON super_read_only: */ super_read_only = opt_super_readonly; mysql_mutex_unlock(&LOCK_global_system_variables);
if (thd->global_read_lock.lock_global_read_lock(thd)) // ====> 阻塞位置 goto end_with_mutex_unlock;
if ((result = thd->global_read_lock.make_global_read_lock_block_commit(thd))) goto end_with_read_lock; opt_super_readonly = new_super_read_only; result = false;
/** Take global read lock, wait if there is protection against lock. If the global read lock is already taken by this thread, then nothing is done. See also "Handling of global read locks" above. @param thd Reference to thread. @retval False Success, global read lock set, commits are NOT blocked. @retval True Failure, thread was killed. */
/* Increment static variable first to signal innodb memcached server to release mdl locks held by it */ Global_read_lock::m_atomic_active_requests++; if (thd->mdl_context.acquire_lock(&mdl_request, thd->variables.lock_wait_timeout)) { Global_read_lock::m_atomic_active_requests--; returntrue; }
m_mdl_global_shared_lock = mdl_request.ticket; m_state = GRL_ACQUIRED; } /* We DON'T set global_read_lock_blocks_commit now, it will be set after tables are flushed (as the present function serves for FLUSH TABLES WITH READ LOCK only). Doing things in this order is necessary to avoid deadlocks (we must allow COMMIT until all tables are closed; we should not forbid it before, or we can have a 3-thread deadlock if 2 do SELECT FOR UPDATE and one does FLUSH TABLES WITH READ LOCK). */ returnfalse; }
DBUG_EXECUTE_IF("dbug.enabled_commit", { constchar act[] = "now signal Reached wait_for signal.commit_continue"; assert(!debug_sync_set_action(thd, STRING_WITH_LEN(act))); };); DEBUG_SYNC(thd, "ha_commit_trans_before_acquire_commit_lock"); if (rw_trans && !ignore_global_read_lock) { /* Acquire a metadata lock which will ensure that COMMIT is blocked by an active FLUSH TABLES WITH READ LOCK (and vice versa: COMMIT in progress blocks FTWRL). We allow the owner of FTWRL to COMMIT; we assume that it knows what it does. */ MDL_REQUEST_INIT(&mdl_request, MDL_key::COMMIT, "", "", // ====> 注意此处是 MDL_key::COMMIT,且是意向排他锁 MDL_INTENTION_EXCLUSIVE, MDL_EXPLICIT);
#0 MDL_context::acquire_lock (this=0xaaaab5e21090, mdl_request=0xffffe021c4c0, lock_wait_timeout=31536000) at /home/wslu/work/mysql/cmss-mac-mysql-server/sql/mdl.cc:3383 #10x0000aaaaae48224cin ha_commit_trans(thd=0xaaaab5e20d00, all=true, ignore_global_read_lock=false) at /home/wslu/work/mysql/cmss-mac-mysql-server/sql/handler.cc:1627 #20x0000aaaaae24a3f0 in trans_commit (thd=0xaaaab5e20d00, ignore_global_read_lock=false) at /home/wslu/work/mysql/cmss-mac-mysql-server/sql/transaction.cc:246 #30x0000aaaaae0121c0 in mysql_create_db (thd=0xaaaab5e20d00, db=0xffffb401e8c8"db6", create_info=0xffffe021d030) at /home/wslu/work/mysql/cmss-mac-mysql-server/sql/sql_db.cc:498 #40x0000aaaaae095ccc in mysql_execute_command (thd=0xaaaab5e20d00, first_level=true) at /home/wslu/work/mysql/cmss-mac-mysql-server/sql/sql_parse.cc:3761 #50x0000aaaaae09a1d4 in dispatch_sql_command (thd=0xaaaab5e20d00, parser_state=0xffffe021e308) at /home/wslu/work/mysql/cmss-mac-mysql-server/sql/sql_parse.cc:5278 #60x0000aaaaae0911e4 in dispatch_command (thd=0xaaaab5e20d00, com_data=0xffffe021ec20, command=COM_QUERY) at /home/wslu/work/mysql/cmss-mac-mysql-server/sql/sql_parse.cc:1960 #70x0000aaaaae08f5ec in do_command (thd=0xaaaab5e20d00) at /home/wslu/work/mysql/cmss-mac-mysql-server/sql/sql_parse.cc:1363 #80x0000ffffe9245c4c in threadpool_process_request (thd=0xaaaab5e20d00) at /home/wslu/work/mysql/cmss-mac-mysql-server/plugin/thread_pool/threadpool_common.cc:251 #90x0000ffffe924ba10 in handle_event (connection=0xaaaab5e1b3d0) at /home/wslu/work/mysql/cmss-mac-mysql-server/plugin/thread_pool/threadpool_unix.cc:1528 #100x0000ffffe924be48 in worker_main (param=0xffffe926bd00 <all_groups+512>) at /home/wslu/work/mysql/cmss-mac-mysql-server/plugin/thread_pool/threadpool_unix.cc:1621 #110x0000aaaab01956f0 in pfs_spawn_thread (arg=0xaaaab5e12550) at /home/wslu/work/mysql/cmss-mac-mysql-server/storage/perfschema/pfs.cc:2942 #120x0000fffff767d5c8 in start_thread (arg=0x0) at ./nptl/pthread_create.c:442 #130x0000fffff76e5d1c in thread_start () at ../sysdeps/unix/sysv/linux/aarch64/clone.S:79
/** Object namespaces. Sic: when adding a new member to this enum make sure to update m_namespace_to_wait_state_name array in mdl.cc! Different types of objects exist in different namespaces - GLOBAL is used for the global read lock. - BACKUP_LOCK is to block any operations that could cause inconsistent backup. Such operations are most DDL statements, and some administrative statements. - TABLESPACE is for tablespaces. - SCHEMA is for schemas (aka databases). - TABLE is for tables and views. - FUNCTION is for stored functions. - PROCEDURE is for stored procedures. - TRIGGER is for triggers. - EVENT is for event scheduler events. - COMMIT is for enabling the global read lock to block commits. - USER_LEVEL_LOCK is for user-level locks. - LOCKING_SERVICE is for the name plugin RW-lock service - SRID is for spatial reference systems - ACL_CACHE is for ACL caches - COLUMN_STATISTICS is for column statistics, such as histograms - RESOURCE_GROUPS is for resource groups. - FOREIGN_KEY is for foreign key names. - CHECK_CONSTRAINT is for check constraint names. Note that requests waiting for user-level locks get special treatment - waiting is aborted if connection to client is lost. */ enumenum_mdl_namespace { GLOBAL = 0, BACKUP_LOCK, TABLESPACE, SCHEMA, TABLE, FUNCTION, PROCEDURE, TRIGGER, EVENT, COMMIT, USER_LEVEL_LOCK, LOCKING_SERVICE, SRID, ACL_CACHE, COLUMN_STATISTICS, RESOURCE_GROUPS, FOREIGN_KEY, CHECK_CONSTRAINT, /* This should be the last ! */ NAMESPACE_END };
其中:
GLOBAL is used for the global read lock.
COMMIT is for enabling the global read lock to block commits.
#0open_table (thd=0xaaaab5e633b0, table_list=0xffffd8004c98, ot_ctx=0xffffb0395b60) at /home/wslu/work/mysql/cmss-mac-mysql-server/sql/sql_base.cc:3057 #10x0000aaaaadf826d0in open_and_process_table(thd=0xaaaab5e633b0, lex=0xaaaab5e66710, tables=0xffffd8004c98, counter=0xaaaab5e66768, prelocking_strategy=0xffffb0395be8, has_prelocking_list=false, ot_ctx=0xffffb0395b60) at /home/wslu/work/mysql/cmss-mac-mysql-server/sql/sql_base.cc:5051 #20x0000aaaaadf84060 in open_tables (thd=0xaaaab5e633b0, start=0xffffb0395bd0, counter=0xaaaab5e66768, flags=0, prelocking_strategy=0xffffb0395be8) at /home/wslu/work/mysql/cmss-mac-mysql-server/sql/sql_base.cc:5854 #30x0000aaaaadf85b14 in open_tables_for_query (thd=0xaaaab5e633b0, tables=0xffffd8004c98, flags=0) at /home/wslu/work/mysql/cmss-mac-mysql-server/sql/sql_base.cc:6736 #40x0000aaaaae11c248 in Sql_cmd_dml::prepare (this=0xffffd8005300, thd=0xaaaab5e633b0) at /home/wslu/work/mysql/cmss-mac-mysql-server/sql/sql_select.cc:372 #50x0000aaaaae11cc10 in Sql_cmd_dml::execute (this=0xffffd8005300, thd=0xaaaab5e633b0) at /home/wslu/work/mysql/cmss-mac-mysql-server/sql/sql_select.cc:533 #60x0000aaaaae095404 in mysql_execute_command (thd=0xaaaab5e633b0, first_level=true) at /home/wslu/work/mysql/cmss-mac-mysql-server/sql/sql_parse.cc:3578 #70x0000aaaaae09a1d4 in dispatch_sql_command (thd=0xaaaab5e633b0, parser_state=0xffffb0397308) at /home/wslu/work/mysql/cmss-mac-mysql-server/sql/sql_parse.cc:5278 #80x0000aaaaae0911e4 in dispatch_command (thd=0xaaaab5e633b0, com_data=0xffffb0397c20, command=COM_QUERY) at /home/wslu/work/mysql/cmss-mac-mysql-server/sql/sql_parse.cc:1960 #90x0000aaaaae08f5ec in do_command (thd=0xaaaab5e633b0) at /home/wslu/work/mysql/cmss-mac-mysql-server/sql/sql_parse.cc:1363 #100x0000ffffe9245c4c in threadpool_process_request (thd=0xaaaab5e633b0) at /home/wslu/work/mysql/cmss-mac-mysql-server/plugin/thread_pool/threadpool_common.cc:251 #110x0000ffffe924ba10 in handle_event (connection=0xaaaab5e67df0) at /home/wslu/work/mysql/cmss-mac-mysql-server/plugin/thread_pool/threadpool_unix.cc:1528 #120x0000ffffe924be48 in worker_main (param=0xffffe926bb00 <all_groups>) at /home/wslu/work/mysql/cmss-mac-mysql-server/plugin/thread_pool/threadpool_unix.cc:1621 #130x0000aaaab01956f0 in pfs_spawn_thread (arg=0xaaaab5e69a90) at /home/wslu/work/mysql/cmss-mac-mysql-server/storage/perfschema/pfs.cc:2942 #140x0000fffff767d5c8 in start_thread (arg=0x0) at ./nptl/pthread_create.c:442 #150x0000fffff76e5d1c in thread_start () at ../sysdeps/unix/sysv/linux/aarch64/clone.S:79
在open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx)函数中有申请 IX 模式的 MDL_key::GLOBAL 锁:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
if (thd->global_read_lock.can_acquire_protection()) returntrue;
/* Install error handler which if possible will convert deadlock error into request to back-off and restart process of opening tables. Prefer this context as a victim in a deadlock when such a deadlock can be easily handled by back-off and retry. */ thd->push_internal_handler(&mdl_deadlock_handler); thd->mdl_context.set_force_dml_deadlock_weight(ot_ctx->can_back_off());
bool result = thd->mdl_context.acquire_lock(&protection_request, ot_ctx->get_timeout()); // ====> 加锁