索引文件锁LockFactory

  LockFactory在Lucene中用来对索引文件所在的目录进行加锁,使得同一时间总是只有一个IndexWriter对象可以更改索引文件,即保证单进程内(single in-process)多个不同IndexWriter对象互斥更改(多线程持有相同引用的IndexWriter对象视为一个IndexWriter不会受制于LockFactory,而是受制于对象锁(synchronized(this))、多进程内(multi-processes)多个对象互斥更改。

LockFactory的具体实现类

  LockFactory是一个抽象类,提供了以下几种子类,即NoLockFactory、SingleInstanceLockFactory、SimpleFSLockFactory、NativeFSLockFactory、VerifyingLockFactory,下面一一介绍。

图1:

NoLockFactory

  该类的功能同类名一样,即不会对索引文件进行加锁,如果使用者有把握(certain)使得IndexWriter对象总是能互斥更改索引文件,那么可以不对索引文件所在的目录进行加锁。

SingleInstanceLockFactory

  该类是RAMDirectory默认使用的索引文件锁,RAMDirectory属于Directory类的子类,Directory类描述了索引文件所在目录的一些信息,以后会有文章介绍Directory类。

  对于拥有相同RAMDirectory对象的多个IndexWriter对象,实现不同IndexWriter之间对索引文件的互斥更改。

获得索引文件锁

  该过程十分的简单,故给出完整的代码:

  final HashSet<String> locks = new HashSet<>();
  // 尝试获得索引文件锁,如果已经占用则抛出异常
  public Lock obtainLock(Directory dir, String lockName) throws IOException {
    synchronized (locks) {
      if (locks.add(lockName)) {
        return new SingleInstanceLock(lockName);
      } else {
        throw new LockObtainFailedException("lock instance already obtained: (dir=" + dir + ", lockName=" + lockName + ")");
      }
    }
  }

  在IndexWriter类中,定义了一个不可更改的lockName,使得无论哪个线程通过IndexWriter来获得索引文件锁时,lockName的值都是相同的,这样就能通过判断该lockName是否在locks容器中来实现互斥,lockName在IndexWriter类中的定义如下:

图2:

释放索引文件锁

  释放锁的过程即从locks容器(HashSet对象)中移除键值为write.lock的元素。

FSLockFactory

  FSLockFactory是一个抽象类,它有两个子类分别是SimpleFSLockFactory,NativeFSLockFactory,用来专门指定给FSDirectory类提供索引文件锁(can only be used with FSDirectory subclasses)。

SimpleFSLockFactory

  该类只能用于FSDirectory,FSDirectory跟RAMDirectory一样是Directory的子类。

  该类通过在索引文件所在目录创建一个名为write.lock文件的方式来实现索引文件锁,该方法的缺点在于如果JVM异常退出,那么索引文件锁可能无法被释放,即没有删除write.lock文件。

  解决的方法只能是通过手动删除write.lock文件,注意是,手动删除前用户得自己保证(certain)目前没有IndexWriter正在写入,否则非常容易破坏(corrupt)索引文件,比如说由于删除了write.lock文件,使得多个IndexWriter对象同时更改了索引文件。

获得索引文件锁

  在索引文件所在目录生成一个write.lock文件,并且记录该文件的创建时间,目的是在任意阶段可以检查该文件是否被外在力量(external force)篡改了,从而判定该锁的合法性(valid),在该类中,如果发现被篡改,那么就抛出异常。

  比如每次添加一篇文档(Document)后,将该Document的信息写入索引文件之前会做检查(调用该类的ensureValid( )方法),如果此时发现write.lock被篡改了(比如说被删除了),那么这次写入就会失败,后续的处理会在以后介绍IndexWriter时详细介绍。

释放索引文件锁

  释放锁的过程即删除write.lock文件,如果发现write.lock文件的创建时间跟获得该锁的时间不同,那么就抛出异常来让用户决定如何处理这种情况,使用Files.delete(Path path)的方法来尝试删除write.lock文件,如果出错了,那么同样地抛出异常让用户决定如何处理这种情况。

NativeFSLockFactory

  NativeFSLockFactory同SimpleFSLockFactory一样,只能用于FSDirectory,它是Directory默认使用的LockFactory的,同样的通过在索引文件所在目录生成一个write.lock文件,但是该类还使用了FileChannel来管理write.lock文件。

获得索引文件锁

  NativeFSLockFactory获得索引文件锁的过程分为两步:

  • 第一步:判断write.lock文件是否已经被进程内(in-process)的其他线程的不同IndexWriter对象占有,通过一个线程安全的同步Set容器(Collection.synchronizedSet())实现,最先到的(first come)的线程会将write.lock文件的绝对路径写入到同步Set容器中,后来的线程尝试添加路径时会抛出异常
  • 第二步:使用FileChannel来尝试获得进程间(inter-process)级别的文件锁FileLock,即判断write.lock文件是否被其他进程占用,如果占用则直接抛出异常。

  另外也会记录write.lock文件的创建时间,用法跟SimpleFSLockFactory一样。

  同SimpleFSLockFactory一样,在运行过程中,当更改索引文件时(添加文档、更新、commit、flush等变更索引文件的操作),依次判断下面的条件,任意一个条件不满足时说明当前索引文件锁是不合法的:

  • 条件1:进程内的某个线程调用了close(),如果该线程继续执行更改索引操作,会抛出异常
  • 条件2:如果同步Set容器不包含write.lock文件的绝对路径,会抛出异常
  • 条件3:FileChannel的锁FileLock是不合法的状态,这种情况是未知的外部力量(external force)导致的, 会抛出异常
  • 条件4:FileChannel中的channel的值不是0,Lucene不会对write.lock文件写入任何数据,所以如果发现该文件中被添加了数据则抛出异常
  • 条件5:当前write.lock文件的创建时间跟获得锁时的创建时间不一致,说明被未知的(external force)修改了,会抛出异常

释放索引文件锁

  该类释放锁的过程分两步走:

  • 释放write.lock文件的FileLock
  • 清空同步Set容器中的内容

SimpleFSLockFactory与NativeFSLockFactory各自的特点

  尽管NativeFSLockFactory是默认的FSDirectory的索引文件锁,但基于实际场景,有时候使用SimpleFSLockFactory能更好的工作(work perfectly)。

  • NativeFSLockFactory基于 java.nio.*来获得FileLock,但在某些文件系统下可能会受限,比如说在NFS下可能无法获得FileLock(the lock can incorrectly be double acquired),此时使用SimpleFSLockFactory就不会有这个问题
  • 当JVM异常退出时,残留的(leftover)write.lock文件无法删除,如果使用SimpleFSLockFactory需要手动的去删除该文件,否则尝试获得索引文件锁时就直接抛出异常,而使用NativeFSLockFactory时,不用关心当前write.lock文件是否被正确删除,因为它只关心write.lock是否被其他进程占用,而JVM异常退出后,会自动释放FileLock(操作系统会释放FileLock),所以不能通过判断write.lock文件在索引文件的目录中就认为索引文件被锁定了(locked),Lucene从不会因为异常去删除write.lock文件

VerifyingLockFactory

  该类不同于上面提到的NoLockFactory、SingleInstanceLockFactory、SimpleFSLockFactory、NativeFSLockFactory,如果上述这些索引文件锁在实际业务还是无法正确的工作(not working properly),那么可以使用VerifyingLockFactory封装上述的LockFactory,通过一个开启一个LockVerifyServer(单独的服务)来实现认证(verify),保证不会发生同一时间两个进程同时获得锁的情况。

认证方法

  Lucene7.5.0中通过Socket向LockVerifyServer发送特定的字节来尝试获得锁,同样的通过发送特定字节来释放锁,由于源码中的实现过于简单,一般不会直接使用,故不详细介绍。

结语

  本文介绍了实现互斥访问索引文件的索引文件锁LockFactory。

转载:https://www.codercto.com/a/84611.html

【转载保存】索引文件锁LockFactory相关推荐

  1. Lucene 的索引文件锁原理

    Lucene 的索引文件锁原理 2016/11/24 · IT技术 · lucene 环境 Lucene 6.0.0 Java "1.8.0_111" OS Windows 7 U ...

  2. 【转载保存】B+树索引原理以及应用案例

    地址:https://www.jianshu.com/p/486a514b0ded 利用c/c++实现基于b+树小型关系型数据库:https://github.com/enpeizhao/duck_d ...

  3. 【转载】索引的一些总结

    作者:黄钧航(JK_Rush)   原文链接:http://www.cnblogs.com/rush/archive/2012/04/22/2465683.html 1.1.1 摘要 如果说要对数据库 ...

  4. 【转载保存】推荐ApacheCN开源的一个机器学习路线图

    转载:https://mp.weixin.qq.com/s/EMWFFPsaKaGc8FO1g-htzg 推荐ApacheCN开源的一个机器学习路线图 原创: 机器学习初学者 机器学习初学者 今天 推 ...

  5. [转载]oracle索引的简单总结

    原文地址:oracle索引的简单总结作者:kindle 一.索引的概念: 数据库的索引类似于书籍的索引.在书籍中,索引允许用户不必翻阅完整个书就能迅速地找到所需要的信息.在数据库中,索引也允许数据库程 ...

  6. MySQL聚簇索引:叶子保存主键或unique字段+data 非聚簇保存索引字段

    非聚簇索引:索引与真实数据文件不在一个文件中 myisam的一个数据表table中,它是有table.frm.table.myd以及table.myi组成. table.myd记录了数据,table. ...

  7. [转载] mysql 索引中的USING BTREE 的意义

    索引是在存储引擎中实现的,因此每种存储引擎的索引都不一定完全相同,并且每种存储引擎也不一定支持所有索引类型. 根据存储引擎定义每个表的最大索引数和最大索引长度.所有存储引擎支持每个表至少16个索引,总 ...

  8. 【转载保存】lucene优秀文章整理

    Lucene解析 - 基本概念:   https://www.jianshu.com/p/fbb171e73721?from=timeline&isappinstalled=0       L ...

  9. 【转载保存】mysql不设置主键使用自增长ID方法

    MySQL 每张表只能有1个自动增长字段,这个自动增长字段即可作为主键,也可以用作非主键使用,但是请注意将自动增长字段当做非主键使用时必须必须为其添加唯一索引,否则系统将会报错.例如: 1.将自动增长 ...

最新文章

  1. 《中国大数据产业白皮书及百强榜单》:一览中国大数据产业发展全局
  2. Java-自定义注解
  3. 7 补充业务_哪些情况可以补充申报?金关账册报核要申报哪些数据?
  4. fafu oj 1266 数数
  5. jQuery 源码系列(四)Tokens 词法分析
  6. 【转】linux内核态和用户态的区别
  7. 放心了!邮政、顺丰和京东基本全部复工
  8. 【Java】字符串substring方法在jkd6,7,8中的差异
  9. Maven : maven异常记录-must be unique maven duplicate declaration of version
  10. matlab数据分类与识别,Matlab图像识别/检索系列(3)—10行代码完成caltech图象集分类和识别...
  11. [转载] python数学计算模块之math常用函数学习使用
  12. 基于ExoPlayer的ExoPlayerVideoView
  13. Python入门深度学习完整指南
  14. 【解题报告】表达式求值(栈,表达式树)
  15. pgadmin3简单使用
  16. 工程课系列-Level3-Web应用课
  17. 用prototype 方法$A() uncheck radio button
  18. SAP ABAP 解析 excel 文件的函数 TEXT_CONVERT_XLS_TO_SAP 单步执行分析
  19. 计算机组成原理大题速成,计算机组成原理大题
  20. 新版CSDN怎么改博客背景

热门文章

  1. MD5算法原理与常用实现
  2. XCode的控制台调试命令
  3. loss下降auc下降_梯度下降算法 线性回归拟合(附Python/Matlab/Julia源代码)
  4. hbase java api最新版本_HBase基本命令与新版本Java API
  5. 青岛旅游学校计算机证书,【我和我的旅校】青岛旅游学校优秀毕业生郭千瑜
  6. python电脑编程求圆的面积案例_学Python划重点七 网络编程(UPD Socket编程、上传文件实例、计算圆的面积实例)...
  7. python目标检测答案_入门指南:用Python实现实时目标检测(内附代码)
  8. java泰拉轴距_Java面向对象
  9. 【LeetCode笔记】152. 乘积最大子数组(Java、动态规划)
  10. python条件循环叠加_Python基础:条件判断与循环的两个要点