LockFactory在lucene中用来对索引目录进行加锁,使得同一时间只能有一个IndexWriter对象对索引目录进行操作。
lucene中LockFactory实现类的继承关系如下
LockFactory实现类功能描述
LockFactory实现类 | 功能描述 |
---|---|
SimpleFSLockFactory | 使用File.createNewFile api, 在JVM异常退出时,会在索引目录遗留write.lock文件,在下次使用时,需要手动清除该文件,比较适合NFS文件系统 |
NativeFSLockFactory | 使用java.nio.*进行加锁,FSDirectory默认的锁实现,不适合NFS使用,在JVM异常退出时,由OS负责移除write.lock,OS并不会真正删除该文件,释放该文件上的引用,使得下次可以重新获取锁 |
NoLockFactory | 完全关闭锁机制 |
1. NativeFSLockFactory源码解析
代码语言:javascript复制 @Override
protected Lock obtainFSLock(FSDirectory dir, String lockName) throws IOException {
// 获取索引的目录
Path lockDir = dir.getDirectory();
// Ensure that lockDir exists and is a directory.
// note: this will fail if lockDir is a symlink
// 如果索引目录不存在,创建索引目录
Files.createDirectories(lockDir);
// 获取lock文件的Path
Path lockFile = lockDir.resolve(lockName);
IOException creationException = null;
try {
// 如果索引锁文件不存在,创建锁文件
Files.createFile(lockFile);
} catch (IOException ignore) {
// we must create the file to have a truly canonical path.
// if it's already created, we don't care. if it cant be created, it will fail below.
creationException = ignore;
}
// fails if the lock file does not exist
final Path realPath;
try {
// 如果索引锁文件无法获取到,则会抛出异常
realPath = lockFile.toRealPath();
} catch (IOException e) {
// if we couldn't resolve the lock file, it might be because we couldn't create it.
// so append any exception from createFile as a suppressed exception, in case its useful
if (creationException != null) {
e.addSuppressed(creationException);
}
throw e;
}
// used as a best-effort check, to see if the underlying file has changed
// 获取索引锁文件的创建时间
final FileTime creationTime = Files.readAttributes(realPath, BasicFileAttributes.class).creationTime();
// 如果索引锁文件已经存在LOCK_HELD中,抛出异常,否则添加该对象到LOCK_HELD中
if (LOCK_HELD.add(realPath.toString())) {
FileChannel channel = null;
FileLock lock = null;
try {
channel = FileChannel.open(realPath, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
lock = channel.tryLock();
if (lock != null) {
return new NativeFSLock(lock, channel, realPath, creationTime);
} else {
throw new LockObtainFailedException("Lock held by another program: " realPath);
}
} finally {
if (lock == null) { // not successful - clear up and move out
IOUtils.closeWhileHandlingException(channel); // TODO: addSuppressed
clearLockHeld(realPath); // clear LOCK_HELD last
}
}
} else {
throw new LockObtainFailedException("Lock held by this virtual machine: " realPath);
}
}
lucene的索引锁实现原理比较简单,代码比较简单,这里只是简单的介绍源码实现,感兴趣的读者,可以看lucene的源码实现。