MDS中的caps和Locker

cephfs是分布式文件系统,所以海量数据和单点是需要考虑的问题。海量数据的情况下,单点MDS无法满足使用性能需求,所以提供了多个active的mds机制,将目录树划分为多个子树分别在多个MDS上进行管理。所以为了保证目录树并发操作能够保持一致性,引入了锁机制。当在一个目录下新建文件,对目标目录来说可以是并行的,所以就要确保目录以上直至根节点,在创建文件的期间不会被其他线程修改,所以MDS中实现的Locker锁机制就是为了保证数据一致性的。

一、目录树结构基本概念

Inode:用来存储文件或目录具体的元信息,比如size、mtime等等。inode具有inode号,可以用来在数据池或元数据池中查找相应的对象。

            作为目录节点时,通过dirfrag管理本节点的目录分片(fragment),通过分片可以将一个大目录或热点目录拆分成多个较小目录,从而管理更大容量目录或在多个MDS之间实现负载均衡,即子树迁移。

Dentry:用来存储文件或目录的名字,连接Inode和Dir。

              在MDS中,Dentry有三种存在形式:

              primary_dn:正常的目录项,已连接inode。

              remote_dn:对应文件系统中的硬链接,其中目录不允许有硬链接。一个inode有一个parent,但可以有多个remote parent,其中parent指向primary_dn,remote_parent指向remote_dn。

              null_dn:中间状态,表示还没有和inode连接。大部分用在新建的dentry。

Dir:其中包含item,item中记录了Dentry。还包含Inode,通Inode能够回溯到上级目录树。

        每个Dir都以<inodenum>.<fragment>为命名形式,存在内存中。当内存被trim掉时,通过fetch到OSD的元数据池中查找,然后填充自己的item,从而在内存中建立起目录树关系。

二、其他基础概念

1、Auth:权威。单个active MDS中,Inode、Dentry、Dir只有一份内存副本,所以都是auth。但存在多个MDS时,就可能存在目录分裂、迁移、备份等情况,所以每种元数据结构就可能发生auth变化,这时就有auth和非auth的概念。一般来说,client发来的修改类请求是必须由auth节点处理的,非修改类的请求可以是auth也可以是非auth。

2、Lease:客户端租期。客户端的Dentry、Inode、Dir比MDS端简单一些,Dentry只有有关联inode和未关联inode两种形态,没有remote形式。所以客户端的Lease一般是dentry lease,指的是dentry在客户端的有效性。通过dentry lease,dentry可以通过inode判断dentry的有效性,比如readdir时,不需要获取dir下各个节点的inode。

3、Loner:独占客户端。指的是在所有客户端中,只有一个客户端在请求写权限,这个客户端就是Loner。只有simplelock sm和filelock sm有Loner的概念,Loner的客户端对元数据具有全部权限(LOCK_EXCL),非Loner客户端不具有任何权限。

4、Cap:Capability。是mds授予Client的许可证,每个client端针对同一inode都有各自独立的caps,通过caps确定是否能够对文件的数据/元数据进行读写。

5、pin:pin表示元数据正在被引用,有pin标记表示不能对当前目录进行分裂、迁移等操作。

6、freeze:在目录进行分裂或迁移前,先对目录置freeze状态,确保目录不能被pin,即freeze期间不能被修改和引用。

7、client range:普通文件被多个客户端同时读写时,锁状态切换至LOCK_MIX状态,这种状态下客户端具有CEPH_CAP_GRD|CEPH_CAP_GWR权限,及允许对文件直读和直写,所以在MDS端,使用client range记录每个client的读写范围,当有其他client改变了文件的size后,相应的client range也需要更新。

三、锁机制

1、锁类型及操作种类

MDS为了保证数据一致性,同时为了保证性能上的高效性,设计了12种分布式锁,每种锁管理一部分元数据信息。同时,每种锁都具有自己的状态。分属于不同的状态机。状态机(locks.c)定义了每种锁存在的状态,以及每种状态下客户端能够进行的操作(caps)。

锁的种类如下所示:

这12种锁中,只有DN和DVERSION锁是dentry使用的,其他全部是inode使用的,dir中没有锁。

对锁的操作有4种:加读锁(rdlock),写锁(wrlock),远程写锁(remote_wrlock),独占锁(xlock)。可以通过状态机去看每种锁会进行哪些操作。

大体上,rdlock用于共享读,xlock用于独占资源,wrlock是专门针对目录的,在某些锁上表现为共享读互斥写,在某些锁上表现为共享读共享写。remote_wrlock也是专门针对目录,但是用于不在同一mds上的目录分片的情况下,例如rename操作,请求处理者与原inode可能不在一个auth上。

2、Inode中每种锁保护的元数据范围

simplelock状态机

DN锁

在Dentry中访问到lock相关内容时会用到DN锁。比如通过lock获取到dentry,或访问dentry的lease相关内容时。

IAUTH锁

ILINK锁

IXATTR锁

ISNAP锁

IFLOCK锁

IPOLICY锁(用在目录上):

scatterlock状态机

IDFT锁

权威:

副本:

INEST锁

权威:

副本:

filelock状态机

IFILE锁

管理目录时:

权威(既管理目录,也普通文件,两者保护的范围有所不同):

副本:

locallock状态机

IVERSION锁

MDS内部使用,用在inode的version管理。

DVERSION锁

MDS内部使用,用在dentry的version管理。

3、mds加锁与放锁的通用流程

mds操作目录树的通用过程都是先确定要锁定的资源(LockType),以及要加那些锁,即做什么操作。基本上都是在rdlock_path_xlock_dentry()流程或rdlock_path_pin_ref()流程中确定资源和操作,然后在acquire_locks()流程中进行状态机判断和加锁动作。经常会出现在acquire_locks()流程中,判断状态机和加锁条件不满足的情况,比如状态机的状态需要转换,就进行相应的转换,转换后成功加锁,或状态机因为客户端持有的权限或客户端某些状态不满足状态机转换要求而无法转换,这种情况下,就会将请求加入waiter队列中等待,同时将计算出的客户端应持有的caps发送给客户端(grant或revoke消息),客户端进行相应的权限修改和操作后,返回给mds正确的权限后,mds再从waiter队列中取出之前的请求,重新走加锁的流程,直至成功加锁。

还有一种通过tick()或log_flush()回调流程也可以触发锁状态转换。

*_start表示对某个锁执行某个类型的锁操作,*_finish表示结束对某个锁执行某个类型的锁操作,*_try表示尝试对某个类型的锁执行锁操作是否能成功。*表示rdlock、wrlock、remote_wrlock和xlock。

变更锁状态只能是auth,非auth只能通过发消息给auth请求转换。MDS之间发送锁消息是通过send_lock_message()流程发送MLock消息。

auth的MDS也会发送MLock消息给replica的MDS要求进行锁状态的转换,转换行为定义为LOCK_AC_*字段,如:

replica转换为相应状态后,回复auth相应的ack:

通常对一个路径加锁时,为了防止其他客户端修改目录结构,最后一个dentry之前的所有dentry都要加rdlock。比如创建目录时,就需要对新创建的dentry加xlock,创建文件时,对ILINK锁加xlock。请求失败或完成后,drop_locks()负责释放锁,释放过程中会处理锁的waiting队列。正常情况下,日志落盘后会触发锁释放,若设置了early_reply,则只要到提交完log的流程就会释放rdlock,但是wrlock和xlock还是要等日志落盘后才会释放。

4、mds日志中锁状态的体现

日志中,通常会有诸如某个inode:

isnap sync r=<NUM> 

之类的打印,这表示当前的inode的ISNAP锁处于LOCK_SYNC状态,且锁上有NUM个读锁操作。SimpleLock.h中有各种状态的打印样式:

也定义了rdlock数、wrlock数、xlock数,以及xlock持有者等等。

print中定义了日志中打印出来的形式:

g表示gather不为0,表示这个inode锁的状态还未成功转换,正在请求客户端修改权限或正在等待副本切换锁状态。

l表示客户端具有当前inode的lease。

r表示当前inode上了rdlock,且上面的rdlock数量有NUM个。

w表示当前inode上了wrlock,且上面的wrlock数量有NUM个。

x表示当前的inode上了xlock,且上面的xlock数量有NUM个。并可以打印出xlock的持有者。

四、状态机(state machine——sm)

1、状态机介绍

通过前面锁机制的内容,可以得知MDS中一共有四种状态机,每一种状态机都包含一种或多种具体的锁,这四种状态机分别是:

simplelock_sm

scatterlock_sm

filelock_sm

locallock_sm

并且锁机制中给出的LockType类,看得出:

simplelock_sm包含:

DN锁、IAUTH锁、ILINK锁、ISNAP锁、IXAAR锁、IFLOCK锁、IPOLICY锁。

scatterlock_sm包含:

IDFT锁、INEST锁。

filelock_sm包含:

IFILE锁。

locallock_sm包含:

IVERSION锁、DVERSION锁。

2、各状态机加锁通用原则

simplelock_sm状态机下所有的锁大多数情况下只有rdlock和xlock操作,且rdlock和xlock符合共享读/互斥写的原则。LOCK_EXCL状态下,即独占状态可以加wrlock。

filelock_sm状态机下只有IFILE一种锁,但却比较复杂。如前面锁机制保护范围所述,它能够管理目录,也能够管理文件。当管理的是目录时,主要管理的是目录的统计信息,与scatterlock_sm中的INEST不同在于INEST管理的是目录递归信息。filelock_sm的IFILE在管理目录时,可以加rdlock、wrlock、remote_wrlock三种锁,提供共享读/共享写的功能。但在IFILE管理文件时,它主要管理每个客户端的client_range以及其他atime、mtime等等的属性,这种情况可以加rdlock和xlock锁,提供共享读/互斥写的功能。

scatterlock_sm状态机包含的两个锁,IDFT用于目录分片的管理,INEST用于目录递归信息管理。可进行的加锁操作一般是rdlock和wrlock,提供共享读/共享写的功能。INEST还可以加remote_wrlock操作。只有LOCK_LOCK状态可以加xlock锁。

locallock_sm状态机包含IVERSION和DVERSION两种锁,这两个锁只用于保护inode或dentry version的一致性,其他三个状态机都是为了保证inode或dentry的资源一致性。locallock_sm可以加rdlock和xlock,提供共享读/互斥写功能。

3、状态机中的caps含义

(1)、caps类型

caps主要有以下五类:

类型功能
PIN主要是告知客户端MDS将inode pin在缓存中,表示该inode正在使用,MDS缓存中有此inode
AUTH主要是客户端能否访问文件/目录权限相关的一些元数据,即IAUTH锁保护的内容,owner、group、mode等
LINK主要是客户端能否访问到inode被引用的次数,即ILINK锁保护的inode.nlink
XATTR主要是客户端是否具有访问或操作xattr扩展属性的能力。有些文件权限存放在acl中,acl存储在xattr中,此时就需要访问XATTR
FILE最重要的类型,客户端能否访问文件数据以及与文件数据相关的一些元数据,即IFILE保护的那些项

在代码中,定义了以上caps类型以及caps相关的权限宏:

CEPH_CAP_PIN就是PIN权限,日志中打印为p

CEPH_CAP_SAUTH就是AUTH权限,日志中打印为A

CEPH_CAP_SLINK就是LINK权限,日志中打印为L

CEPH_CAP_SXATTR就是XATTR权限,日志中打印为X

CEPH_CAP_SFILE就是FILE权限,日志中打印为F

(2)、caps权限

MDS定义了8种权限,分别是:

权限含义日志打印
CEPH_CAP_GSHARED表示客户端具有读取元数据的权限s
CEPH_CAP_GEXCL表示客户端具有读取和更新(修改)元数据的权限x
CEPH_CAP_GCACHE针对文件数据,表示客户端具有从cache(缓存)中读取数据的权限c
CEPH_CAP_GRD针对文件数据,表示客户端具有从OSD读取数据的权限r
CEPH_CAP_GWR针对文件数据,表示客户端具有向OSD写入数据的权限w
CEPH_CAP_GBUFFER针对文件数据,表示客户端具有向buffer(缓存)中写入数据的权限b
CEPH_CAP_GWREXTEND针对文件数据,表示客户端具有扩展文件结束符的权限a
CEPH_CAP_GLAZYIO针对文件数据,表示客户端具有可以使用lazyio的权限l

将caps类型和caps权限结合起来,可以组合出某个caps类型具有什么样的caps,如:

组合权限日志打印
#define CEPH_CAP_AUTH_SHARED  (CEPH_CAP_GSHARED  << CEPH_CAP_SAUTH)As
#define CEPH_CAP_AUTH_EXCL     (CEPH_CAP_GEXCL     << CEPH_CAP_SAUTH)Ax
#define CEPH_CAP_LINK_SHARED  (CEPH_CAP_GSHARED  << CEPH_CAP_SLINK)Ls
#define CEPH_CAP_LINK_EXCL     (CEPH_CAP_GEXCL     << CEPH_CAP_SLINK)Lx
#define CEPH_CAP_XATTR_SHARED (CEPH_CAP_GSHARED  << CEPH_CAP_SXATTR)Xs
#define CEPH_CAP_XATTR_EXCL    (CEPH_CAP_GEXCL     << CEPH_CAP_SXATTR)Xx
#define CEPH_CAP_FILE_SHARED   (CEPH_CAP_GSHARED   << CEPH_CAP_SFILE)Fs
#define CEPH_CAP_FILE_EXCL     (CEPH_CAP_GEXCL     << CEPH_CAP_SFILE)Fx
#define CEPH_CAP_FILE_CACHE    (CEPH_CAP_GCACHE    << CEPH_CAP_SFILE)Fc
#define CEPH_CAP_FILE_RD       (CEPH_CAP_GRD       << CEPH_CAP_SFILE)Fr
#define CEPH_CAP_FILE_WR       (CEPH_CAP_GWR       << CEPH_CAP_SFILE)Fw
#define CEPH_CAP_FILE_BUFFER   (CEPH_CAP_GBUFFER   << CEPH_CAP_SFILE)Fb
#define CEPH_CAP_FILE_WREXTEND (CEPH_CAP_GWREXTEND << CEPH_CAP_SFILE)Fa
#define CEPH_CAP_FILE_LAZYIO   (CEPH_CAP_GLAZYIO   << CEPH_CAP_SFILE)Fl

所以,在日志中经常看到某客户端对某个文件权限:pAsxLsxXsxFsxrwcb,就可以看懂其意义了。

另外,日志有时会打印上面的组合偏移值的十进制数,例如,打印权限是16384,可以使用指令:

ceph mds caps 16384

输出:the caps of 16384 is Fa   也可以得知具体的权限情况。

4、结合状态机、锁机制、caps查locks.c

以上了解了状态机、锁机制、caps相关的概念和意义后,在实际分析代码的过程中,需要查看当前状态允许什么样的权限,可以加什么样的锁操作,可以通过locks.c中定义的内容进行确认。

locks.c中状态机表头如下:

其中,[]内的内容表示锁状态,{}中:

  • stable表示当前锁状态是否是稳态(is_stable),为0表示是稳态,为其他锁状态,表示当前是非稳态,进入下一个(next)稳态应当的锁状态。非稳态表示一种中间状态,是用来转变为另一个稳态前提前做权限与资源回收或分配的状态,到达非稳态后,需要满足下一步稳态的条件,才能转变为下一步稳态。一般LOCK_SYNC、LOCK_LOCK、LOCK_MIX、LOCK_EXCL、LOCK_XSYN、LOCK_TSYN这种都是稳态。代码中通过is_stable()判断。

  • loner表示当前锁状态,是否要求有loner,也就是是否允许有独占客户端(is_loner)。scatterlock_sm状态机中任何状态下都不允许有独占客户端。其他状态机中,基本上是LOCK_EXCL和LOCK_XSYN状态允许有独占,另外就是向这两个状态转或从这两个状态转的非稳态状态允许有独占。代码中通过is_loner()判断。

  • rep state表示auth在当前锁状态下,副本应该是什么样的锁状态(replicate state)。当权威进行锁状态转换时,有的状态需要副本也应当处于某个锁状态下,auth就会发送MLock锁消息给副本,附上要求副本转换到某个锁状态的标志LOCK_AC_*,副本mds收到后进行副本锁状态的转换,转换成功回复LOCK_AC_*ACK。

  • r表示当前锁状态下,谁可以读(can_read)。这里的谁分为ANY、AUTH、XCL、REQ:

            ANY:指的任何拥有Object副本的MDS

            AUTH:指的是权威MDS

            XCL:指的是权威MDS或者独占客户端

            REQ:指的是副本MDS需要请求权威MDS改变状态

  • rp表示read_projected,也是指谁可以读(can_read_projected),与普通判断谁可以read是一样的。但不同的是,它判断的对象是临时的,新建dentry或删除dentry或rename流程,会将还未关联inode的dentry linkage放在projected中,rp判断的就是这种对象是否可读。

  • rd表示当前锁状态下,谁可以加读锁(can_rdlock)。一般来说,LOCK_SYNC状态基本上都是任何MDS都可以加读锁(ANY),其他稳态要么是只有权威MDS可以加,要么是副本需要请求权威MDS转换状态后可加。非稳态介于转换的中间状态,根据locks.c的规定决定。

  • wr表示当前锁状态下,谁可以加写锁(can_wrlock)。一般来说,wrlock涉及到修改,所以LOCK_SYNC状态不需要申请wrlock。LOCK_MIX、LOCK_EXCL等涉及混合读写或独占客户端操作这种可能设计修改操作的,才会需要wrlock。

  • fwr表示当前锁状态下,谁可以加强制写锁(can_force_wrlock)。这个情况使用的场景不算多,一般用在revoke caps中,客户端释放权限后,修改文件的maxsize中,基本都用在LOCK_EXCL向LOCK_SYNC或LOCK_LOCK转换的非稳态状态中。

  • l表示当前锁状态下,谁允许客户端拥有lease(can_lease)。使用在caps消息中,给客户端分配lease或回收lease的判断中。LOCK_SYNC状态这种不设计修改的状态可以允许客户端有lease。

  • x表示当前锁状态下,谁可以加独占锁(can_xlock)。用在加xlock流程的判断中,如rdlock_path_xlock_dentry中给dentry加锁时,需要先判断当前状态是否可加xlock,不可以加则转换到LOCK_PREXLOCK。

  • caps就是具体客户端的权限,分为四个部分,any、loner、xlocker、replica。any指任意客户端具有的权限,loner指loner客户端具有的权限,xlocker指对某资源加了xlock锁的客户端具有的权限,replica指副本具有的权限。0表示没有权限,其他的就按上面给出的caps表示具体的权限,比如simplelock_sm状态机的LOCK_SYNC状态,这个状态就是无对数据和元数据的修改或写入的操作,只有读取操作,所以any客户端具有CEPH_CAP_GSHARD|CEPH_GCACHE|CEPH_CAP_GRD权限(scr),即任何客户端都具有读对象元数据的权限,也具有从cache中读对象数据缓存的权限,也具有从OSD中读对象数据的权限,但没有任何写的权限。且该状态不允许有loner,所以没有loner权限,也不允许加独占锁做任何修改,所以没有xlocker权限。同时副本也和权威一样可允许有scr的权限。

代码中判断以上can_*条件的方式:

上锁、放锁与判断锁:

5、状态机稳定状态的含义

(1)、simplelock_sm中的状态

该状态机管理的锁均为文件/目录元数据,不涉及数据:

LOCK_SYNC

该状态是在多个客户端均没有修改/写simplelock下保护的文件/目录元数据的操作,只涉及查询/读取文件/目录simplelock保护元数据的场景,所以这时没有loner,任何mds均可上rdlock,但不可以上与写有关的任何锁,比如wrlock和xlock,也允许客户端有lease,且客户端具有读取这些元数据的s权限。

LOCK_LOCK

该状态是不允许客户端进行对simplelock下保护的文件/目录的元数据进行任何读写操作,在该状态下,权威不允许加rdlock、wrlock、xlock,也不允许客户端有lease,客户端不具有任何元数据操作权限。

LOCK_PREXLOCK

该状态不算稳态,但是它是simplelock下唯一可以允许任意mds上xlock的状态。该状态可以由LOCK_LOCK转为LOCK_LOCK_XLOCK,再由LOCK_LOCK_XLOCK转来。比如在mkdir流程中,需要对新建的目录dn加xlock锁,就需要将状态转为LOCK_PREXLOCK状态。

LOCK_EXCL

该状态用于仅有loner的情形。loner客户端在该状态下,具有全部的读写权限,所以对于simplelock来说,在这个状态下,loner具有读/写simplelock保护下所有元数据的权限sx。

其余非稳态,均是从一个稳态转到另一个稳态过程中的临时状态,权限以及允许的操作,介于两个稳态之间。转换后比转换前权限更多了的,就发mds授予client新权限GRANT消息,更少了的,就发mds回收client全新的REVOKE消息。

(2)、scatterlock_sm中的状态

该状态机管理的锁只涉及目录分片和目录递归方面的信息,这些信息只有mds内部会使用,客户端不会用,且不体现在客户端的权限上,所以没有loner概念,也就不可能有EXCL状态。所以也不涉及数据,不涉及文件。

LOCK_SYNC

与simplelock一样,是在多个客户端均没有修改/写元数据的操作,只涉及查询/读取目录元数据的场景,行为和权限都一样。

LOCK_LOCK

由于scatterlock保护内容仅限mds内部使用,所以客户端的caps不需要任何关于这方面内容的权限。该状态允许权威加wrlock进行修改,允许任何MDS加独占锁xlock进行修改,是scatterlock中唯一允许加xlock的状态。

LOCK_TSYN

该状态本意是等于临时LOCK_SYNC的状态,但是该状态目前未实际使用。

LOCK_MIX

该状态是在多个客户端有读有写的情形下的一种状态。这个状态同样因为客户端不涉及访问scatterlock的内容,所以客户端不具有任何这方面的权限。但在该状态下,任何mds均可加wrlock进行修改,且支持共享写。

(3)、filelock_sm中的状态

该状态机管理的锁既涉及文件/目录的部分元数据,也涉及文件的数据。

LOCK_SYNC

与simplelock一样,是在多个客户端均没有修改/写文件/目录元数据/数据的操作,只涉及查询/读取文件/目录数据/元数据的场景。所以该状态下,没有loner,任何mds均可上rdlock,但不可以上与写有关的任何锁,比如wrlock和xlock,也允许客户端有lease,且客户端对于文件/目录元数据具有s权限,对于文件数据有Fc和Fr即读cache和读osd的权限。

LOCK_LOCK

与simplelock含义基本一样。在这个状态下,不允许客户端对filelock下保护的文件/目录的元数据进行任何读写操作,对文件数据保留缓存权限。在该状态下,不允许加读锁rdlock和独占锁xlock,针对目录时只有权威可以加wrlock修改目录统计dirstat,所以客户端不具有任何元数据相关的权限,仅允许Fc和Fb即读cache和写buffer的权限,不可以直接向OSD中进行读写。

LOCK_PREXLOCK

与simplelock含义基本一样,该状态不算稳态,但是是filelock下唯一允许任意mds上xlock的状态。它也是由LOCK_LOCK转来,所以对于客户端,还是保持与LOCK_LOCK状态一样的针对文件数据具有Fcb权限。

LOCK_MIX

该状态是在多个客户端有读有写的场景下。在该状态下,不可以加rdlock和xlock,但任意mds都可以加wrlock,记录目录统计dirstat以及client range。因为多个客户端有读有写,所以为保持数据一致性,只允许客户端对OSD进行直读直写或lazyio,即Frwl权限,不能使用缓存。

LOCK_EXCL

该状态用于仅有loner的情形。loner客户端在该状态下,具有全部的读写权限,所以对于loner客户端来说,该状态下无论对filelock下的元数据还是数据,具有全部的权限:Fsxcbrwl。

LOCK_XSYN

该状态用于原先有loner,但新增了一个需要进行一些读操作的客户端的场景。这种状态都是从LOCK_EXCL状态转为LOCK_EXCL_XSYN再转来的。所以这种状态下,为防止请求读操作客户端读到的数据不一致,要回收原先EXCL状态下loner的操作元数据和直读直写数据的权限,只允许写buffer和读cache即Fcb权限。

LOCK_SCAN

该状态不算稳态。这个状态只用于做file recovery。

(4)、locallock_sm中的状态

该状态机管理的锁只用于mds内部,不涉及文件数据,所以客户端也不涉及。

LOCK_LOCK

locallock只有这一种状态,所以该状态下允许上rdlock,用于读取version信息,权威可以上xlock修改version信息。因为不涉及客户端这部分权限,所以不需要给客户端分配任何权限。

五、代码中的状态机转换与加锁过程

在代码中,主要是Simplelock.h中的SimpleLock类定义了大部分锁操作,Scatterlock.h中的Scatterlock类和Locallock.h中的Locallock均继承于Simplelock类,Filelock由Scatterlock实现。这是因为根据上面的状态机所示,锁的状态判断和操作很多都是通用的。所以对于每种状态机,操作状态转变一般都是几个通用流程。如下的转换过程锁类型可以是simplelock,也可以是scatterlock,也可以是filelock,只要它具有转换所列的状态。

1、调用栈

如下的simple_excl、simple_sync、simple_lock、simple_xlock、scatter_mix、file_excl、file_xsync与file_recover:

(1)、一部分由直接由之前说明过的正常OP进行acquire_locks,然后走到相应的*_start中直接调用:

wrlock_start拿wrlock:

其他rdlock_start、xlock_start类似。

(2)、另一部分是放锁*_finish流程,走try_eval,然后再走到eval中,分发出simple_eval、scatter_eval、file_eval调用下去的;如果是非稳态,走eval_gather流程。

(3)、还有一部分是比如处理caps消息handle_client_caps或其他诸如迁移、recover等流程直接调用eval分发出simple_eval、scatter_eval、file_eval调用下去,如果是非稳态,走eval_gather流程。

eval_gather流程做的事情非常多,它包含了对各种非稳态状态情况的处理,包括发送锁消息给其他MDS要求副本转换锁状态、根据当前的情况做log下刷操作、做recover操作等,直到满足能够转为next稳态的条件,然后转为稳态,再从waiter中取出之前不满足转换条件的请求,重新调用OP,走acquire_locks重新加锁,已经加锁成功的不会重新加锁。

2、实施函数

  • simple_excl() 该流程可以实现锁状态从某状态转为EXCL状态,simplelock专用:

                      LOCK_LOCK -> LOCK_LOCK_EXCL -> !gather -> LOCK_EXCL

                      LOCK_SYNC -> LOCK_SYNC_EXCL -> !gather -> LOCK_EXCL

                      LOCK_XSYN -> LOCK_XSYN_EXCL -> !gather -> LOCK_EXCL

            !gather的条件,是根据locks.c中规定的对应的状态机所在状态下,能够持有的锁情况决定。在该场景下,不能有rdlock,不能有wrlock,副本需要是LOCK_LOCK状态,mds记录的client权限必须符合要求,只要这几个条件有一个不满足,gather就不为0,该状态转换过程就会加入add_waiter中,等相应条件满足后再取出重新转换和加锁。

  • simple_sync() 该流程可以实现锁状态从某状态转为SYNC状态,simplelock、scatterlock和filelock都可以用:

                     LOCK_MIX -> LOCK_MIX_SYNC -> !gather -> LOCK_SYNC

                     LOCK_LOCK -> LOCK_LOCK_SYNC -> !gather -> LOCK_SYNC

                     LOCK_XSYN -> LOCK_XSYN_SYNC -> !gather -> LOCK_SYNC

                     LOCK_EXCL -> LOCK_EXCL_SYNC -> !gather -> LOCK_SYNC

            !gather的条件,在该场景下,不能有wrlock,副本需要是LOCK_SYNC状态,mds记录的client权限必须符合要求,如果是IFILE类型,所操作的inode不能是recovery状态。

  • simple_lock() 该流程可以实现锁状态从某状态转为LOCK状态,simplelock、scatterlock和filelock都可以用:

                     LOCK_SYNC -> LOCK_SYNC_LOCK -> !gather -> LOCK_LOCK

                     LOCK_XSYN -> LOCK_XSYN_LOCK -> !gather -> LOCK_LOCK

                     LOCK_EXCL -> LOCK_EXCL_LOCK -> !gather -> LOCK_LOCK

                     LOCK_MIX -> LOCK_MIX_LOCK -> !gather -> LOCK_LOCK

            !gather的条件,在该场景下,不能有lease,不能有rdlock,副本需要是LOCK_LOCK状态,mds记录的client权限必须符合要求,如果是IFILE类型,所操作的inode不能是recovery状态。

  • simple_xlock() 该流程可以实现锁状态从某状态转为XLOCK状态,simplelock和filelock使用:

                     LOCK_LOCK -> LOCK_LOCK_XLOCK -> !gather -> LOCK_PREXLOCK

                     LOCK_XLOCKDONE -> LOCK_LOCK_XLOCK -> !gather -> LOCK_LOCK

            !gather的条件,在该场景下,不能有rdlock和wrlock,mds记录的client权限必须符合要求。

  • scatter_mix() 该流程可以实现锁状态从某状态转为MIX状态,scatterlock以及filelock都可以使用:

                     LOCK_SYNC -> LOCK_SYNC_MIX -> !gather -> LOCK_MIX

                     LOCK_EXCL -> LOCK_EXCL_MIX -> !gather -> LOCK_MIX

                     LOCK_XSYN -> LOCK_XSYN_MIX -> !gather -> LOCK_MIX

                     LOCK_TSYN -> LOCK_TSYN_MIX -> !gather -> LOCK_MIX

            !gather的条件,在该场景下,不能有rdlock,不允许有lease,副本需要是LOCK_MIX状态,mds记录的client权限必须符合要求,所操作的inode不能是recovery状态。

  • file_excl() 该流程可以实现锁状态从某状态转为EXCL状态,filelock专用:

                     LOCK_SYNC -> LOCK_SYNC_EXCL -> !gather -> LOCK_EXCL

                     LOCK_MIX -> LOCK_MIX_EXCL -> !gather -> LOCK_EXCL

                     LOCK_XSYN -> LOCK_XSYN_EXCL -> !gather -> LOCK_EXCL

                     LOCK_LOCK -> LOCK_LOCK_EXCL -> !gather -> LOCK_EXCL

            !gather的条件,在该场景下,不能有rdlock和wrlock,不允许有lease,副本需要是LOCK_LOCK状态,mds记录的client权限必须符合要求,所操作的inode不能是recovery状态。

  • file_xsync() 该流程可以实现锁状态从某状态转为XSYN状态,filelock专用:

                     LOCK_EXCL -> LOCK_EXCL_XSYN -> !gather -> LOCK_XSYN

            !gather的条件,在该场景下,不能有wrlock,mds记录的client权限必须符合要求。

  • file_recover() 该流程可以实现锁状态从某状态转为SCAN状态,IFILE锁专用:

                     LOCK_PRE_SCAN -> !gather -> LOCK_SCAN

            !gather的条件,在该场景下,mds记录的client权限必须符合要求。

以上,就是MDS中caps和Locker相关的内容。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值