最近有个项目要用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
|
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();
}
}
}
|
报错信息:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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的相关源码:
|
1
2
3
4
|
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.
|
两个和锁相关的属性:
|
1
2
|
public
static
final
String WRITE_LOCK_NAME =
"write.lock"
;
private
Lock writeLock;
|
在IndexWriter的构造函数中:
|
1
2
3
4
5
6
7
|
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 );
|
其中Lock是一个抽象类(org.apache.lucene.store.Lock):
锁的获取主要实现是在obtain方法:
|
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
|
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),默认1000ms
2.LOCK_OBTAIN_WAIT_FOREVER 是否无限获取(-1),如果设置为-1,会永不超生
3.LOCK_POLL_INTERVAL 重试间隔时间,默认1000ms
在关闭IndexWriter时调用close方法(实现了Closeable接口的类都会有close方法)即可正常释放锁
更改代码为如下即可:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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方法如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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();
}
|
本文转自菜菜光 51CTO博客,原文链接:http://blog.51cto.com/caiguangguang/1432795,如需转载请自行联系原作者