LockFactory索引文件锁源码解析

2020-01-20 15:35:19 浏览数 (1)

LockFactory在lucene中用来对索引目录进行加锁,使得同一时间只能有一个IndexWriter对象对索引目录进行操作。

lucene中LockFactory实现类的继承关系如下

LockFactory类继承关系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的源码实现。

0 人点赞