-
Notifications
You must be signed in to change notification settings - Fork 552
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
(#622)Add file lock design doc
- Loading branch information
Showing
1 changed file
with
31 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
|
||
|
||
# 文件锁支持方案 | ||
|
||
## 背景 | ||
|
||
为保证对同一文件元数据操作的正确性,需要将对元数据的操作串行化,所以需要文件锁的支持 | ||
|
||
## 方案 | ||
|
||
在`NameServer`中,设置一个`FileLockManager`,用来负责保证单个文件元数据操作的原子性,`FileLockManager`为每个正在进行元信息修改的文件或目录维护一个内存结构`LockEntry`,该结构中包含一个引用计数`ref_`和一个读写锁`rw_lock_` | ||
|
||
- 加锁的整体过程为:为最后一级文件加写锁,前面所有目录加读锁。加锁时,从根目录开始,不断尝试对下级目录进行加锁。同时,加读写锁时,写锁优先,可以防止写目录操作的饥饿现象 | ||
|
||
|
||
- 在对某一级目录或文件进行加锁时,首先在`FileLockManager`查找其对应的`LockEntry`, | ||
1. 如果没有找到,则说明并没有其它线程对该条链路进行操作,则构造一个新的`LockEntry`,将其引用计数加1,并对该`LockEntry`中的读写锁进行加锁 | ||
2. 如果找到,则说明有其它线程正在对该条链路进行操作,则首先将其引用计数加1将其对应的`LockEntry`引用计数加1,然后再去尝试加读锁或写锁,如果加锁不成功,则会被阻塞直到加锁成功 | ||
|
||
|
||
- 在对某一级目录或文件操作完成后,对锁进行释放时,需要按照加锁的相反顺序进行释放。释放时,先释放读写锁,然后将`LockEntry`的引用计数减1,如果引用计数减至0,则触发`LockEntry`的析构 | ||
|
||
## rename时预防死锁 | ||
|
||
由于在rename时涉及到两个不同的路径,为防止死锁,rename操作时,都遵循按照路径的字典序进行加锁 | ||
|
||
## 可能需要的优化 | ||
|
||
1. 考虑到每个文件的锁相对比较独立,可以对`FileLockManager`中的映射信息进行分桶 | ||
2. 绝大部分情况下,并不会出现同时操作同一个文件的元数据的情况,因此次加锁、释放锁的时候,会造成`LockEntry`结构的构造和析构,或者可以辅以`cache`,将需要释放的`LockEntry`先缓存起来,让缓存去负责最终释放,当需要新申请`LockEntry`时,直接从缓存中召回一个即可,类似内核中`slab`的做法 | ||
|