lucene indexwriterロックメカニズム


最近solrを使用するプロジェクトがあります.solrはluceneベースです.今日indexwriterをテストするときにlockの問題に遭遇しました.
テストコード:
import java.io.File;
import java.io.IOException;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
public class TestLock {
    private Directory dir;
    public static TestLock ttt;
    public static IndexWriter writer2;
    private Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_48);
    private IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_48, analyzer);
    public void init() throws Exception {
        String pathFile = "D://luceneindex";
        try{
               dir = FSDirectory. open(new File(pathFile));
        } catch (IOException e) {        
            throw new RuntimeException(e);
        }
        IndexWriter writer = getWriter();             
        System. out.println("init ok,test IndexWriter lock" );
        LockTest( writer);      
        //writer.close();
    }
    public IndexWriter getWriter() throws Exception {
        //analyzer.close();
        return new IndexWriter(dir, iwc);
    }
    public void LockTest(IndexWriter w1) {
       try{
               if(w1.isLocked (dir )){
                     System. out.println("write1 locked" );
                     IndexWriterConfig iwc1 = new IndexWriterConfig(Version.LUCENE_48 , analyzer );
                      writer2 = new IndexWriter(dir, iwc1); 
              } else{
                     System. out.println("write1 not locked" );                      
              }      
       } catch(Exception e){
              e.printStackTrace();
       }       
    }  
    public static void main(String[] args){
       ttt = new TestLock();
       try{
               ttt.init();
       } catch(Exception e){
              e. printStackTrace();              
       }      
    }
}

エラーメッセージ:
org.apache.lucene.store.LockObtainFailedException : Lock obtain timed out: NativeFSLock@D:\luceneindex\write.lock: java.nio.channels.OverlappingFileLockException
       at org.apache.lucene.store.Lock.obtain( Lock.java:89)
       at org.apache.lucene.index.IndexWriter.<init>( IndexWriter.java:710)
       at TestLock.LockTest( TestLock.java:38)
       at TestLock.init( TestLock.java:26)
       at TestLock.main( TestLock.java:51)
Caused by: java.nio.channels.OverlappingFileLockException
       at sun.nio.ch.SharedFileLockTable.checkList(Unknown Source)
       at sun.nio.ch.SharedFileLockTable.add(Unknown Source)
       at sun.nio.ch.FileChannelImpl.tryLock(Unknown Source)
       at java.nio.channels.FileChannel.tryLock(Unknown Source)
       at org.apache.lucene.store.NativeFSLock.obtain(NativeFSLockFactory.java:148)
       at org.apache.lucene.store.Lock.obtain( Lock.java:100)
       ... 4 more

エラーメッセージからはIndexWriterがロックを取得するエラーが発生していることがわかり、スタック情報からはIndexWriterの構築方法を実行する際にロックの操作に関与していることがわかります.
IndexWriterの関連ソースを表示します.
doc:
Opening an IndexWriter creates a lock file for the directory in use. Trying to open another IndexWriter  on the same directory will lead to a
LockObtainFailedException. The  LockObtainFailedException is also thrown if an IndexReader on the same directory is used to delete documents
from the index.

ロックに関連する2つのプロパティ:
  public static final String WRITE_LOCK_NAME = "write.lock" ;
  private Lock writeLock;

IndexWriterのコンストラクション関数:
  public IndexWriter(Directory d, IndexWriterConfig conf) throws IOException
....
     directory = d;
.....
    writeLock = directory.makeLock(WRITE_LOCK_NAME);
    if (! writeLock.obtain(config .getWriteLockTimeout())) // obtain write lock( )
      throw new LockObtainFailedException("Index locked for write: " + writeLock );

ロックは抽象クラス(org.apache.lucene.store.Lock):
ロックの取得の主な実装はobtainメソッドです.
  public static long LOCK_POLL_INTERVAL = 1000;
  public static final long LOCK_OBTAIN_WAIT_FOREVER = -1;
  public final boolean obtain(long lockWaitTimeout) throws IOException {
    failureReason = null;
    boolean locked = obtain();
    if (lockWaitTimeout < 0 && lockWaitTimeout != LOCK_OBTAIN_WAIT_FOREVER )
      throw new IllegalArgumentException("lockWaitTimeout should be LOCK_OBTAIN_WAIT_FOREVER or a non-negative number (got " + lockWaitTimeout + ")");
    long maxSleepCount = lockWaitTimeout / LOCK_POLL_INTERVAL;
    long sleepCount = 0;
    while (!locked) {
      if (lockWaitTimeout != LOCK_OBTAIN_WAIT_FOREVER && sleepCount++ >= maxSleepCount) {
        String reason = "Lock obtain timed out: " + this .toString();
        if (failureReason != null) {
          reason += ": " + failureReason ;
        }
        LockObtainFailedException e = new LockObtainFailedException(reason);
        if (failureReason != null) {
          e.initCause( failureReason);
        }
        throw e;
      }
      try {
        Thread. sleep(LOCK_POLL_INTERVAL);
      } catch (InterruptedException ie) {
        throw new ThreadInterruptedException(ie);
      }
      locked = obtain();
    }
    return locked;
  }

次の要素によって決定されます.
1.lockWaitTimeoutタイムアウト時間(合計時間、この時間を超えるとtimeout)、デフォルト1000 ms
2.LOCK_OBTAIN_WAIT_FOREVERが無限に取得されているか(-1)、-1に設定されている場合は、常に超生しません
3.LOCK_POLL_INTERVAL再試行間隔時間、デフォルト1000 ms
IndexWriterを閉じるときにcloseメソッド(Closeableインタフェースを実装したクラスにはcloseメソッドがある)を呼び出すと、ロックが正常に解除されます.
コードを次のように変更します.
  public void LockTest(IndexWriter w1) {
       try{
               if(w1.isLocked (dir )){
                     System. out.println("write1 locked" );
                     w1.close();
                     IndexWriterConfig iwc1 = new IndexWriterConfig(Version.LUCENE_48 , analyzer );
                      writer2 = new IndexWriter(dir, iwc1); 
              } else{
                     System. out.println("write1 not locked" );                      
              }      
       } catch(Exception e){
              e.printStackTrace();
       }       
    }

またlockについての判断とunlockの方法は以下の通りである.
 public static boolean isLocked(Directory directory) throws IOException {  //  lock
    return directory.makeLock( WRITE_LOCK_NAME).isLocked();
  }
  /**
   * Forcibly unlocks the index in the named directory.
   * <P>
   * Caution: this should only be used by failure recovery code,
   * when it is known that no other process nor thread is in fact
   * currently accessing this index.
   */
  public static void unlock(Directory directory) throws IOException { //  
    directory.makeLock(IndexWriter. WRITE_LOCK_NAME).close();
  }