天天看点

lucene indexwriter锁机制

最近有个项目要用solr,solr是基于lucene的,今天在测试indexwriter时遇到了lock的问题:

测试代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

<code>import</code> <code>java.io.File;</code>

<code>import</code> <code>java.io.IOException;</code>

<code>import</code> <code>org.apache.lucene.analysis.Analyzer;</code>

<code>import</code> <code>org.apache.lucene.analysis.standard.StandardAnalyzer;</code>

<code>import</code> <code>org.apache.lucene.index.IndexWriter;</code>

<code>import</code> <code>org.apache.lucene.index.IndexWriterConfig;</code>

<code>import</code> <code>org.apache.lucene.store.Directory;</code>

<code>import</code> <code>org.apache.lucene.store.FSDirectory;</code>

<code>import</code> <code>org.apache.lucene.util.Version;</code>

<code>public</code> <code>class</code> <code>TestLock {</code>

<code>    </code><code>private</code> <code>Directory dir;</code>

<code>    </code><code>public</code> <code>static</code> <code>TestLock ttt;</code>

<code>    </code><code>public</code> <code>static</code> <code>IndexWriter writer2;</code>

<code>    </code><code>private</code> <code>Analyzer analyzer = </code><code>new</code> <code>StandardAnalyzer(Version.LUCENE_48);</code>

<code>    </code><code>private</code> <code>IndexWriterConfig iwc = </code><code>new</code> <code>IndexWriterConfig(Version.LUCENE_48, analyzer);</code>

<code>    </code><code>public</code> <code>void</code> <code>init() </code><code>throws</code> <code>Exception {</code>

<code>        </code><code>String pathFile = </code><code>"D://luceneindex"</code><code>;</code>

<code>        </code><code>try</code><code>{</code>

<code>               </code><code>dir = FSDirectory. open(</code><code>new</code> <code>File(pathFile));</code>

<code>        </code><code>} </code><code>catch</code> <code>(IOException e) {        </code>

<code>            </code><code>throw</code> <code>new</code> <code>RuntimeException(e);</code>

<code>        </code><code>}</code>

<code>        </code><code>IndexWriter writer = getWriter();             </code>

<code>        </code><code>System. out.println(</code><code>"init ok,test IndexWriter lock"</code> <code>);</code>

<code>        </code><code>LockTest( writer);      </code>

<code>        </code><code>//writer.close();</code>

<code>    </code><code>}</code>

<code>    </code><code>public</code> <code>IndexWriter getWriter() </code><code>throws</code> <code>Exception {</code>

<code>        </code><code>//analyzer.close();</code>

<code>        </code><code>return</code> <code>new</code> <code>IndexWriter(dir, iwc);</code>

<code>    </code><code>public</code> <code>void</code> <code>LockTest(IndexWriter w1) {</code>

<code>       </code><code>try</code><code>{</code>

<code>               </code><code>if</code><code>(w1.isLocked (dir )){</code>

<code>                     </code><code>System. out.println(</code><code>"write1 locked"</code> <code>);</code>

<code>                     </code><code>IndexWriterConfig iwc1 = </code><code>new</code> <code>IndexWriterConfig(Version.LUCENE_48 , analyzer );</code>

<code>                      </code><code>writer2 = </code><code>new</code> <code>IndexWriter(dir, iwc1); </code>

<code>              </code><code>} </code><code>else</code><code>{</code>

<code>                     </code><code>System. out.println(</code><code>"write1 not locked"</code> <code>);                      </code>

<code>              </code><code>}      </code>

<code>       </code><code>} </code><code>catch</code><code>(Exception e){</code>

<code>              </code><code>e.printStackTrace();</code>

<code>       </code><code>}       </code>

<code>    </code><code>}  </code>

<code>    </code><code>public</code> <code>static</code> <code>void</code> <code>main(String[] args){</code>

<code>       </code><code>ttt = </code><code>new</code> <code>TestLock();</code>

<code>               </code><code>ttt.init();</code>

<code>              </code><code>e. printStackTrace();              </code>

<code>       </code><code>}      </code>

<code>}</code>

报错信息:

<code>org.apache.lucene.store.LockObtainFailedException : Lock obtain timed out: NativeFSLock</code><code>@D</code><code>:\luceneindex\write.lock: java.nio.channels.OverlappingFileLockException</code>

<code>       </code><code>at org.apache.lucene.store.Lock.obtain( Lock.java:</code><code>89</code><code>)</code>

<code>       </code><code>at org.apache.lucene.index.IndexWriter.&lt;init&gt;( IndexWriter.java:</code><code>710</code><code>)</code>

<code>       </code><code>at TestLock.LockTest( TestLock.java:</code><code>38</code><code>)</code>

<code>       </code><code>at TestLock.init( TestLock.java:</code><code>26</code><code>)</code>

<code>       </code><code>at TestLock.main( TestLock.java:</code><code>51</code><code>)</code>

<code>Caused by: java.nio.channels.OverlappingFileLockException</code>

<code>       </code><code>at sun.nio.ch.SharedFileLockTable.checkList(Unknown Source)</code>

<code>       </code><code>at sun.nio.ch.SharedFileLockTable.add(Unknown Source)</code>

<code>       </code><code>at sun.nio.ch.FileChannelImpl.tryLock(Unknown Source)</code>

<code>       </code><code>at java.nio.channels.FileChannel.tryLock(Unknown Source)</code>

<code>       </code><code>at org.apache.lucene.store.NativeFSLock.obtain(NativeFSLockFactory.java:</code><code>148</code><code>)</code>

<code>       </code><code>at org.apache.lucene.store.Lock.obtain( Lock.java:</code><code>100</code><code>)</code>

<code>       </code><code>... </code><code>4</code> <code>more</code>

从错误信息可以看到是IndexWriter获取锁出错导致,从堆栈信息可以看到,是在运行IndexWriter的构造方法时,涉及到锁的操作。

查看IndexWriter的相关源码:

<code>doc:</code>

<code>Opening an IndexWriter creates a lock </code><code>file</code> <code>for</code> <code>the directory </code><code>in</code> <code>use. Trying to </code><code>open</code> <code>another IndexWriter  on the same directory will lead to a</code>

<code>LockObtainFailedException. The  LockObtainFailedException is also thrown </code><code>if</code> <code>an IndexReader on the same directory is used to delete documents</code>

<code>from the index.</code>

两个和锁相关的属性:

<code>  </code><code>public</code> <code>static</code> <code>final</code> <code>String WRITE_LOCK_NAME = </code><code>"write.lock"</code> <code>;</code>

<code>  </code><code>private</code> <code>Lock writeLock;</code>

在IndexWriter的构造函数中:

<code>  </code><code>public</code> <code>IndexWriter(Directory d, IndexWriterConfig conf) </code><code>throws</code> <code>IOException</code>

<code>....</code>

<code>     </code><code>directory = d;</code>

<code>.....</code>

<code>    </code><code>writeLock = directory.makeLock(WRITE_LOCK_NAME);</code>

<code>    </code><code>if</code> <code>(! writeLock.obtain(config .getWriteLockTimeout())) </code><code>// obtain write lock(尝试获取锁)</code>

<code>      </code><code>throw</code> <code>new</code> <code>LockObtainFailedException(</code><code>"Index locked for write: "</code> <code>+ writeLock );</code>

其中Lock是一个抽象类(org.apache.lucene.store.Lock):   

锁的获取主要实现是在obtain方法:

<code>  </code><code>public</code> <code>static</code> <code>long</code> <code>LOCK_POLL_INTERVAL = </code><code>1000</code><code>;</code>

<code>  </code><code>public</code> <code>static</code> <code>final</code> <code>long</code> <code>LOCK_OBTAIN_WAIT_FOREVER = -</code><code>1</code><code>;</code>

<code>  </code><code>public</code> <code>final</code> <code>boolean</code> <code>obtain(</code><code>long</code> <code>lockWaitTimeout) </code><code>throws</code> <code>IOException {</code>

<code>    </code><code>failureReason = </code><code>null</code><code>;</code>

<code>    </code><code>boolean</code> <code>locked = obtain();</code>

<code>    </code><code>if</code> <code>(lockWaitTimeout &lt; </code><code>0</code> <code>&amp;&amp; lockWaitTimeout != LOCK_OBTAIN_WAIT_FOREVER )</code>

<code>      </code><code>throw</code> <code>new</code> <code>IllegalArgumentException(</code><code>"lockWaitTimeout should be LOCK_OBTAIN_WAIT_FOREVER or a non-negative number (got "</code> <code>+ lockWaitTimeout + </code><code>")"</code><code>);</code>

<code>    </code><code>long</code> <code>maxSleepCount = lockWaitTimeout / LOCK_POLL_INTERVAL;</code>

<code>    </code><code>long</code> <code>sleepCount = </code><code>0</code><code>;</code>

<code>    </code><code>while</code> <code>(!locked) {</code>

<code>      </code><code>if</code> <code>(lockWaitTimeout != LOCK_OBTAIN_WAIT_FOREVER &amp;&amp; sleepCount++ &gt;= maxSleepCount) {</code>

<code>        </code><code>String reason = </code><code>"Lock obtain timed out: "</code> <code>+ </code><code>this</code> <code>.toString();</code>

<code>        </code><code>if</code> <code>(failureReason != </code><code>null</code><code>) {</code>

<code>          </code><code>reason += </code><code>": "</code> <code>+ failureReason ;</code>

<code>        </code><code>LockObtainFailedException e = </code><code>new</code> <code>LockObtainFailedException(reason);</code>

<code>          </code><code>e.initCause( failureReason);</code>

<code>        </code><code>throw</code> <code>e;</code>

<code>      </code><code>}</code>

<code>      </code><code>try</code> <code>{</code>

<code>        </code><code>Thread. sleep(LOCK_POLL_INTERVAL);</code>

<code>      </code><code>} </code><code>catch</code> <code>(InterruptedException ie) {</code>

<code>        </code><code>throw</code> <code>new</code> <code>ThreadInterruptedException(ie);</code>

<code>      </code><code>locked = obtain();</code>

<code>    </code><code>return</code> <code>locked;</code>

<code>  </code><code>}</code>

可以看到有由下面几个因素决定:

1.lockWaitTimeout 超时时间(总时间,超过这个时间即timeout),默认1000ms

2.LOCK_OBTAIN_WAIT_FOREVER  是否无限获取(-1),如果设置为-1,会永不超生

3.LOCK_POLL_INTERVAL  重试间隔时间,默认1000ms

在关闭IndexWriter时调用close方法(实现了Closeable接口的类都会有close方法)即可正常释放锁

更改代码为如下即可:

<code>  </code><code>public</code> <code>void</code> <code>LockTest(IndexWriter w1) {</code>

<code>                     </code><code>w1.close();</code>

另外关于lock的判断和unlock方法如下:

<code> </code><code>public</code> <code>static</code> <code>boolean</code> <code>isLocked(Directory directory) </code><code>throws</code> <code>IOException {  </code><code>// 判断写目录是否被lock</code>

<code>    </code><code>return</code> <code>directory.makeLock( WRITE_LOCK_NAME).isLocked();</code>

<code>  </code><code>/**</code>

<code>   </code><code>* Forcibly unlocks the index in the named directory.</code>

<code>   </code><code>* &lt;P&gt;</code>

<code>   </code><code>* Caution: this should only be used by failure recovery code,</code>

<code>   </code><code>* when it is known that no other process nor thread is in fact</code>

<code>   </code><code>* currently accessing this index.</code>

<code>   </code><code>*/</code>

<code>  </code><code>public</code> <code>static</code> <code>void</code> <code>unlock(Directory directory) </code><code>throws</code> <code>IOException { </code><code>// 解锁</code>

<code>    </code><code>directory.makeLock(IndexWriter. WRITE_LOCK_NAME).close();</code>

本文转自菜菜光 51CTO博客,原文链接:http://blog.51cto.com/caiguangguang/1432795,如需转载请自行联系原作者