【转载保存】索引文件锁LockFactory
索引文件鎖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的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【使用注意】文件内容突然消失
- 下一篇: 【技巧】Chrome应用技巧