本文基于MySQL 8.0的源代码总结了MySQL中表级别线程锁的实现机制, 底层仅关注Linux平台, Windows平台的实现可能有差异. 虽然不涉及到某个特定的存储引擎, 但会讨论MySQL的handler(实现plugin的接口) API中与锁相关的部分. 数据结构MySQL的锁实现是基于POSIX的read-lock 锁, 底层使用 mutex 和 conditional variable 等API实现. 为了避免死锁, 每个线程在访问数据前需要调用 thr_multi_lock()一次性获取所有相关表的锁, 一个线程可以持有多个表的锁. 为了便于理解, 需要区分一下 master lock 和 lock instance 两个概念: * master lock 是指每个table share结构中的 THR_LOCK 对象,也就是我们创建的每个表都有且仅有一个对应的 THR_LOCK 对象. * lock instance 是指每个open table handler 中的 THR_LOCK_DATA 对象, 也就是说多个线程并发访问一个表的时候, 每个线程需要有一个 THR_LOCK_DATA 可以这样简单的类比, 如果master lock对应一个磁盘文件, 那么lock instance对应了一个打开该文件的句柄FD. 数据结构定义如下: typedef struct st_thr_lock_info { my_thread_id thread_id; mysql_cond_t *suspend; } THR_LOCK_INFO; typedef struct st_thr_lock_data { THR_LOCK_INFO *owner; struct st_thr_lock_data *next,**prev; struct st_thr_lock *lock; mysql_cond_t *cond; enum thr_lock_type type; void *status_param; /* Param to status functions */ void *debug_print_param; struct PSI_table *m_psi; } THR_LOCK_DATA; struct st_lock_list { THR_LOCK_DATA *data,**last; }; typedef struct st_thr_lock { LIST list; mysql_mutex_t mutex; struct st_lock_list read_wait; struct st_lock_list read; struct st_lock_list write_wait; struct st_lock_list write; ulong write_lock_count; /* incremented for write locks and reset on read locks */ uint read_no_write_count; void (*get_status)(void*, int); /* When one gets a lock */ void (*copy_status)(void*,void*); void (*update_status)(void*); /* Before release of write */ void (*restore_status)(void*); /* Before release of read */ my_bool (*check_status)(void *); } THR_LOCK; THR_LOCK THR_LOCK 是每个表的多个实例共享的结构, 是锁管理的核心结构. 它的成员有:
THR_LOCK_DATA THR_LOCK_DATA 的成员:
锁类型和优先级锁请求的类型定义如下: enum thr_lock_type { TL_IGNORE=-1, TL_UNLOCK, /* UNLOCK ANY LOCK */ /* Parser only! At open_tables() becomes TL_READ or TL_READ_NO_INSERT depending on the binary log format (SBR/RBR) and on the table category (log table). Used for tables that are read by statements which modify tables. */ TL_READ_DEFAULT, TL_READ, /* Read lock */ TL_READ_WITH_SHARED_LOCKS, /* High prior. than TL_WRITE. Allow concurrent insert */ TL_READ_HIGH_PRIORITY, /* READ, Don't allow concurrent insert */ TL_READ_NO_INSERT, /* Write lock, but allow other threads to read / write. Used by BDB tables in MySQL to mark that someone is reading/writing to the table. */ TL_WRITE_ALLOW_WRITE, /* parser only! Late bound low_priority_flag. At open_tables() becomes thd->insert_lock_default. */ TL_WRITE_CONCURRENT_DEFAULT, /* WRITE lock used by concurrent insert. Will allow READ, if one could use concurrent insert on table. */ TL_WRITE_CONCURRENT_INSERT, /* parser only! Late bound low_priority flag. At open_tables() becomes thd->update_lock_default. */ TL_WRITE_DEFAULT, /* WRITE lock that has lower priority than TL_READ */ TL_WRITE_LOW_PRIORITY, /* Normal WRITE lock */ TL_WRITE, /* Abort new lock request with an error */ TL_WRITE_ONLY }; 抛开parser-only类型, 这些类型的优先级从高到底排列如下:
同一类型的锁请求会按照FIFO(first-in-first-out)策略调度. (责任编辑:好模板) |