Maison base de données tutoriel mysql MySQL源代码:如何对读写锁进行处理_MySQL

MySQL源代码:如何对读写锁进行处理_MySQL

Jun 01, 2016 pm 01:43 PM
如何 源代码

bitsCN.com 转载请署名:印风
-----------------------------------------------------------
最近碰到一个问题,线上一台机器在等待信号量时间过长,mysql的监控线程认为此时mysqld已经hang住了,于是自杀重启。这里涉及到一个有趣的问题,也就是mysql如何对读写锁进行处理。
主要包括三个部分:
1. 建锁
2. 加锁
3. 解锁
4. 监控锁
 以下内容基于Percona5.5.18进行分析
 
1.创建锁
锁的创建实际上就是初始化一个RW结构体(rw_lock_t),实际调用函数如下:
 
# define rw_lock_create(K, L, level)                                 / 
         rw_lock_create_func((L),#L) 
 
在rw_lock_create上有三个参数,在实际场景锁时只用到第2个参数
其中K表示mysql_pfs_key_t,level显示当前的操作类型(起码看起来是的,在文件sync0sync.h中定义),看起来k是为performance schema准备的,而k代表了当前操作所在的层次。
例如:purge线程的读写锁创建:
 
rw_lock_create(trx_purge_latch_key, 
                 &purge_sys->latch,SYNC_PURGE_LATCH); 
 
我们进去rw_lock_create_func看看到底是怎么创建的。
可以看到这个函数的逻辑其实很简单:
lock->lock_word =X_LOCK_DECR;    //关键字段
用于限制读写锁的最大并发数,代码里的注释如下:
 
/* We decrement lock_word by this amountfor each x_lock. It is also the
start value for the lock_word, meaning thatit limits the maximum number
of concurrent read locks before the rw_lockbreaks. The current value of
0x00100000 allows 1,048,575 concurrentreaders and 2047 recursive writers.*/ 
 
在尝试加锁时会调用rw_lock_lock_word_decr减少lock_word
 在初始化一系列变量后,执行:
 
lock->event = os_event_create(NULL); 
lock->wait_ex_event = os_event_create(NULL); 
os_event_create用于创建一个系统信号,实际上最终创建的还是互斥量(os_fast_mutex_init(&(event->os_mutex));以及条件变量(os_cond_init(&(event->cond_var));)
最后将lock加入到全局链表rw_lock_list中
 
2.加锁
加锁函数由宏定义,实际调用函数为:
1)写锁
 
# define rw_lock_x_lock(M)                                          / 
         rw_lock_x_lock_func((M),0, __FILE__, __LINE__) 
 
当申请写锁时,执行如下步骤:
(1).调用rw_lock_x_lock_low函数去获取锁,如果得到锁,则rw_x_spin_round_count += i后直接返回,如果得不到锁,继续执行
(2).loop过程中只执行一次rw_x_spin_wait_count++
(3).在毫秒级别的loop多次等待
 
while (i                           && lock->lock_word                             if(srv_spin_wait_delay) { 
                                     ut_delay(ut_rnd_interval(0, 
                                                                  srv_spin_wait_delay)); 
                            } 
                            i++; 
                   } 
 
这里涉及到两个系统变量:
innodb_sync_spin_loops(SYNC_SPIN_ROUNDS)
innodb_spin_wait_delay(srv_spin_wait_delay)
 
在SYNC_SPIN_ROUNDS循环里调用函数ut_delay,这个函数很简单,就是做了delay*50次空循环
 
Ut_delay(uint delay): 
         for(i = 0; i                    j+= i; 
                   UT_RELAX_CPU(); 
         } 
其中,UT_RELAX_CPU()会调用汇编指令来独占CPU,以防止线程切换
(4).如果loop的次数等于SYNC_SPIN_ROUNDS,调用os_thread_yield(实际调用pthread_yield,导致调用线程放弃CPU的占用)将线程挂起;否则挑到1继续loop
(5).在sync_primary_wait_array里获取一个cell(占个坑?)。调用sync_array_reserve_cell,看起来有1000个坑位(sync_primary_wait_array->n_cells)
(6).再次调用rw_lock_x_lock_low函数尝试获取锁,若成功获得,则返回
(7).调用sync_array_wait_event等待条件变量,然后返回1继续loop
具体的加锁函数(rw_lock_x_lock_low)稍后分析
 
2)读锁
 
# define rw_lock_s_lock(M)                                          / 
         rw_lock_s_lock_func((M),0, __FILE__, __LINE__) 
 
这个函数定义在sync0rw.ic里,函数也很简单,如下:
 
   if (rw_lock_s_lock_low(lock, pass, file_name, line)) { 
       return; /* Success */ 
    }else { 
       /* Did not succeed, try spin wait */ 
       rw_lock_s_lock_spin(lock, pass, file_name, line); 
       return; 
}   
 
这里首先调用rw_lock_s_lock_low进行加锁,如果加锁不成功,则调用rw_lock_s_lock_spin进行等待,rw_lock_s_lock_spin的代码逻辑与rw_lock_x_lock_func有些相似,这里不再赘述。
在rw_lock_s_lock_spin里会递归的调用到rw_lock_s_lock_low函数;
 
看起来实际的加锁和解锁操作是通过对计数器来控制的,
(1)在函数rw_lock_s_lock_low中
rw_lock_lock_word_decr (lock, 1),对lock->lock_word减去1
减数成功返回true,否则返回false
这部分的逻辑还是很简单的。
 
(2)在函数rw_lock_x_lock_low中,调用:
rw_lock_lock_word_decr(lock, X_LOCK_DECR),对lock->lock_word减去X_LOCK_DECR
减数成功后,执行:
 
rw_lock_set_writer_id_and_recursion_flag(lock,pass ? FALSE : TRUE)来设置: 
lock->writer_thread = s_thread_get_curr_id() 
lock->recursive = TRUE 
 
然后调用rw_lock_x_lock_wait函数等待lock->lock_word=0,也就是说等待所有的读锁退出。
 
看到一个比较有意思的现象,在.ic的代码里看到使用了宏
INNODB_RW_LOCKS_USE_ATOMICS,这是跟gcc的版本相关的,通过使用gcc的内建函数来实现原子操作。
 
3.解锁
解锁操作包括解除读锁(#define rw_lock_s_unlock(L) rw_lock_s_unlock_gen(L, 0))和解除写锁操作(#definerw_lock_x_unlock(L) rw_lock_x_unlock_gen(L, 0))
实际调用函数为rw_lock_s_unlock_func和rw_lock_x_unlock_func
 
1)解除读锁(rw_lock_s_unlock_func)
增加计数rw_lock_lock_word_incr(lock, 1)
 
2)解除写锁(rw_lock_x_unlock_func)
执行如下操作
(1)如果是最后一个递归调用锁的线程,设置lock->recursive= FALSE; 代码里的注释如下:
 
/* lock->recursive flag also indicatesif lock->writer_thread is
   valid or stale. If we are the last of the recursive callers
   then we must unset lock->recursive flag to indicate that the
   lock->writer_thread is now stale.
   Note that since we still hold the x-lock we can safely read the
   lock_word. */ 
 
(2)增加计数rw_lock_lock_word_incr(lock,X_LOCK_DECR) == X_LOCK_DECR,这时候需要向等待锁的线程发送信号:
 
if (lock->waiters) { 
     rw_lock_reset_waiter_flag(lock); 
     os_event_set(lock->event);    
     sync_array_object_signalled(sync_primary_wait_array); 

 
os_event_set函数会发送一个pthread_cond_broadcast给等待的线程
 
4.监控读写锁
为了防止mysqld被hang住导致的长时间等待rw锁,error监控线程会对长时间等待的线程进行监控。这个线程每1秒loop一次
(os_event_wait_time_low(srv_error_event, 1000000, sig_count);)
函数入口:srv_error_monitor_thread
函数sync_array_print_long_waits()用于处理长时间等待信号量的线程,流程如下:
1. 查看sync_primary_wait_array数组中的所有等待线程。
->大于240秒时,向错误日志中输出警告,设置noticed = TRUE;
->大于600秒时,设置fatal =TRUE;
2.当noticed为true时,打印出innodb监控信息,然后sleep30秒
3. 返回fatal值
 
当函数sync_primary_wait_array返回true时,对于同一个等待线程还会有十次机会,也就是300 + 1*10(监控线程每次loop sleep 1s)秒的时间;如果挺不过去,监控线程就会执行一个断言失败:
 
if (fatal_cnt > 10) { 
                   fprintf(stderr, 
                            "InnoDB:Error: semaphore wait has lasted" 
                            "> %lu seconds/n" 
                            "InnoDB:We intentionally crash the server," 
                            "because it appears to be hung./n", 
                             (ulong) srv_fatal_semaphore_wait_threshold); 
  
                            ut_error; 
                   } 
 
ut_error是一个宏:
 
#define ut_error      assert(0) 
断言失败导致mysqld crash
 在函数srv_error_monitor_thread里发现一个比较有意思的参数srv_kill_idle_transaction,对应的系统变量为innodb_kill_idle_transaction,用于清理在一段时间内的空闲事务。这个变量指定了空闲事务的最长时间。具体实现分析,且听下回分解

作者 记录成长之路 bitsCN.com

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Article chaud

R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
2 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Repo: Comment relancer ses coéquipiers
4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: Comment obtenir des graines géantes
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Combien de temps faut-il pour battre Split Fiction?
3 Il y a quelques semaines By DDD

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Tutoriel sur la mise à jour de la version curl sous Linux ! Tutoriel sur la mise à jour de la version curl sous Linux ! Mar 07, 2024 am 08:30 AM

Pour mettre à jour la version curl sous Linux, vous pouvez suivre les étapes ci-dessous : Vérifiez la version actuelle de curl : Tout d'abord, vous devez déterminer la version de curl installée dans le système actuel. Ouvrez un terminal et exécutez la commande suivante : curl --version Cette commande affichera les informations sur la version actuelle de curl. Confirmer la version curl disponible : Avant de mettre à jour curl, vous devez confirmer la dernière version disponible. Vous pouvez visiter le site officiel de curl (curl.haxx.se) ou des sources de logiciels associées pour trouver la dernière version de curl. Téléchargez le code source de curl : à l'aide de curl ou d'un navigateur, téléchargez le fichier de code source pour la version curl de votre choix (généralement .tar.gz ou .tar.bz2).

Comment afficher le code source Java Comment afficher le code source Java Dec 27, 2023 pm 04:41 PM

Afficher les étapes : 1. Recherchez le répertoire d'installation ou affichez-le en ligne ; 2. Décompressez le code source ; 3. Utilisez un éditeur de texte ou un environnement de développement intégré. 4. Naviguez et affichez le code source ; Introduction détaillée : 1. Recherchez le répertoire d'installation ou affichez-le en ligne : Si JDK est installé, vous pouvez trouver le code source Java dans le répertoire d'installation de JDK. Dans le répertoire d'installation du JDK, il existe généralement un fichier compressé src.zip ou similaire, qui contient le code source de la bibliothèque de classes Java Core. Il est également possible de visualiser le code source Java en ligne, etc.

Analyse du chemin de stockage du code source du noyau Linux Analyse du chemin de stockage du code source du noyau Linux Mar 14, 2024 am 11:45 AM

Le noyau Linux est un noyau de système d'exploitation open source dont le code source est stocké dans un référentiel de code dédié. Dans cet article, nous analyserons en détail le chemin de stockage du code source du noyau Linux et utiliserons des exemples de code spécifiques pour aider les lecteurs à mieux comprendre. 1. Chemin de stockage du code source du noyau Linux Le code source du noyau Linux est stocké dans un référentiel Git appelé Linux, hébergé sur [https://github.com/torvalds/linux](http

Comment afficher le code source de Tomcat Comment afficher le code source de Tomcat Jan 25, 2024 pm 01:56 PM

Étapes pour afficher le code source de Tomcat : 1. Téléchargez le code source de Tomcat ; 2. Importez le code source de Tomcat dans IDEA ; 3. Affichez le code source ; 4. Comprendre le principe de fonctionnement de Tomcat ; 5. Participez à la communauté et contribuez ; ; 6. Précautions ; 7. Apprendre et mettre à jour en permanence ; 8. Utiliser des outils et des plug-ins. Introduction détaillée : 1. Pour télécharger le code source de Tomcat, vous devez d'abord obtenir le code source de Tomcat. Vous pouvez télécharger le package de code source depuis le site officiel d'Apache Tomcat, etc.

Comment pouvez-vous comprendre les principes et les objectifs de conception derrière la dernière spécification de code PHP en lisant son code source ? Comment pouvez-vous comprendre les principes et les objectifs de conception derrière la dernière spécification de code PHP en lisant son code source ? Sep 05, 2023 pm 02:46 PM

Comment pouvez-vous comprendre les principes et les objectifs de conception derrière la dernière spécification de code PHP en lisant son code source ? Introduction : lors de l'écriture de code PHP de haute qualité, il est très important de suivre certaines normes de codage. Grâce aux spécifications du code, la lisibilité, la maintenabilité et l’évolutivité du code peuvent être améliorées. Pour le langage PHP, il existe une spécification de code largement adoptée, à savoir PSR (PHPStandardsRecommendations). Cet article explique comment lire le code source de la dernière spécification de code PHP.

Une exploration approfondie de la distribution du code source du noyau Linux Une exploration approfondie de la distribution du code source du noyau Linux Mar 15, 2024 am 10:21 AM

Il s'agit d'un article de 1 500 mots qui explore en profondeur la distribution du code source du noyau Linux. En raison de l'espace limité, nous nous concentrerons sur la structure organisationnelle du code source du noyau Linux et fournirons quelques exemples de code spécifiques pour aider les lecteurs à mieux comprendre. Le noyau Linux est un noyau de système d'exploitation open source dont le code source est hébergé sur GitHub. La distribution entière du code source du noyau Linux est très vaste, contenant des centaines de milliers de lignes de code, impliquant plusieurs sous-systèmes et modules différents. Pour mieux comprendre le code source du noyau Linux

Quel est le suffixe du code source Java ? Quel est le suffixe du code source Java ? Dec 27, 2023 pm 04:31 PM

En Java, le suffixe des fichiers de code source est généralement .java. Lors de l'écriture d'un programme Java, un fichier de code source avec un suffixe .java est créé, qui contient le code source Java. Par exemple, un simple fichier de code source Java pourrait être nommé MyClass.java, où MyClass est le nom de la classe et .java est le suffixe du fichier.

Existe-t-il un avenir pour l'emploi en pharmacie clinique à l'Université médicale de Harbin ? (Quelles sont les perspectives d'emploi pour la pharmacie clinique à l'Université médicale de Harbin ?) Existe-t-il un avenir pour l'emploi en pharmacie clinique à l'Université médicale de Harbin ? (Quelles sont les perspectives d'emploi pour la pharmacie clinique à l'Université médicale de Harbin ?) Jan 02, 2024 pm 08:54 PM

Quelles sont les perspectives d'emploi de la pharmacie clinique à l'Université médicale de Harbin ? Bien que la situation nationale de l'emploi ne soit pas optimiste, les diplômés en pharmacie ont toujours de bonnes perspectives d'emploi. Dans l'ensemble, l'offre de diplômés en pharmacie est inférieure à la demande. Les sociétés pharmaceutiques et les usines pharmaceutiques sont les principaux canaux d'absorption de ces diplômés. La demande de talents dans l'industrie pharmaceutique augmente également de manière constante. Selon les rapports, ces dernières années, le rapport offre-demande pour les étudiants diplômés dans des domaines tels que les préparations pharmaceutiques et la chimie médicinale naturelle a même atteint 1:10. Direction d'emploi de la majeure en pharmacie clinique : Après l'obtention de leur diplôme, les étudiants se spécialisant en médecine clinique peuvent s'engager dans le traitement médical, la prévention, la recherche médicale, etc. dans les unités médicales et sanitaires, la recherche médicale et d'autres départements. Postes d'emploi : Représentant médical, représentant commercial pharmaceutique, représentant commercial, directeur commercial, directeur régional des ventes, responsable des investissements, chef de produit, spécialiste produit, infirmière

See all articles