如果多个进程对网络文件系统中的同一个文件进行写入操作会有什么结果呢?(势必造成文件的损坏)
Lease(租约)可以认为是一个文件写锁,当客户端需要写文件的时候,它需要申请一个Lease,那其他对该文件的写入进程就会因为获得租约失败而不能进行写入操作,NameNode负责记录每个正在处于写入状态文件的Lease,Lease的属主是谁,超时时间(分布式处理的一种常用技术)等,所有这些工作由下面3个类完成
Lease
租约,用户需要对文件进行写操作时,都需要首先申请一个租约。
该类主要相关属性如下:
//租约的所有者,holder客户端程序一次应用名称,每次构建DFSClient这个对象都会生成一个clientName
private StringBytesWritable holder;
//最新更新时间
private long lastUpdate;
//租约相关联的路径列表。
private Collection<StringBytesWritable> paths = new TreeSet<StringBytesWritable>();
LeaseManager
租约管理器
// Used for handling lock-leases
// Mapping: leaseHolder -> Lease
//按照租约所有者索引查找的租约列表
private SortedMap<StringBytesWritable, Lease> leases = new TreeMap<StringBytesWritable, Lease>();
// Set of: Lease
//所有租约列表
private SortedSet<Lease> sortedLeases = new TreeSet<Lease>();
// 按照路径进行索引查找的租约列表
// Map path names to leases. It is protected by the sortedLeases lock.
// The map stores pathnames in lexicographical order.
private SortedMap<String, Lease> sortedLeasesByPath = new TreeMap<String, Lease>();
一个租约由一个holder(客户端名),lastUpdate(上次更新时间)和paths(该客户端操作的文件集合)构成。
客户端名取得方式:DFSClient在进行构造的时候通过如下方式构建clientName
if (taskId != null)
{
this.clientName = "DFSClient_" + taskId;
}
else
{
this.clientName = "DFSClient_" + r.nextInt();
}
可以认为一台客户端机器的某次应用链接对应一个clientName.
LeaseManager的方法就是对Lease进行操作。注意,LeaseManager的addLease并没有检查文件上是否已经有Lease,这个是由LeaseManager的调用者来保证的,这使LeaseManager比较简单。内部类Monitor通过对Lease的最后更新时间来检测Lease是否过期,如果过期,简单调用FSNamesystem的internalReleaseLease方法。主要是大部分的一致性逻辑都存在于LeaseManager的使用者。
每个客户端通过一次应用对应的clientName只能在namenode上存在一个租约,每个租约都可以包含多个路径。租约的主要目的就是客户端创建文件并填充文件内容过程中,其他客户端不能打开这个文件进行写操作。
如下是与租约相关的创建文件的流程。