directory即lucene中对索引目录的一个抽象,体现到api上,它被设计为一个抽象类,类里面定义了一些抽象方法,如listall列出目录下所有文件,deletefile(string name) 根据文件名称删除索引文件,这个都是文件的基本操作,其中比较重要的一个接口方法是makelock,为什么要为索引目录加锁?其实就跟你上厕所为什么要锁门是一样一样滴?我没拉完你就给我乖乖等着。
basedirectory是directory的一个子类,它默认实现了makelock方法,

@override
public final lock makelock(string name) {
return lockfactory.makelock(this, name);
}
这里的lockfactory仍然是一个抽象类,由子类传入传入具体的lockfactory工厂实现来创建不同的lock实例fsdirectory是针对文件系统的一个directory实现,即使用这个directory就可以把索引文件存储到我们的文件系统里了。fsdirectory下面又有3个子类,分别是simplefsdirectory,niofsdirectory,mmapdirectory,
simplefsdirectory:它是基于文件系统的索引目录的一个简单实现,它在多线程环境下性能表现很差,不支持并发读写索引文件。
niofsdirectory:顾名思义,它就是使用nio里的filechannel文件通道来解决并发读写索引文件的,但它在windows平台下有个致命的bug,官方建议在windows平台下使用rafdirectory来代替niofsdirectory。
mmapdirectory:即基于内存映射的方式把文件load到内存来减少与io的交互次数,从而提高io性能,但这部分内存也存在隐患,因为jdk存在一个bug,就是当indexinput.close()时并不能有效的交还文件系统里索引文件的文件句柄,这就直接导致索引lock无法释放,一直直到gc回收这部分内存中潜在的对象时该句柄才会释放。由于文件句柄不能有效的立即释放,可能会导致你的硬盘空间得不到立即的释放,所以如果你的应用对于硬盘状况很敏感,这将是一个致命的定时炸蛋(连个zha弹都不让写,iteye这是怎么了?),放在心里就行,反正暂时这个bug未解决。(现在硬盘这么廉价,多浪费点硬盘空间也没啥)不过在linux系统上,即使句柄没有释放,当你删除索引文件时会提示是否在delete on last close,当你close时候还是会删除成功的,但索引文件还是会文件系统上占硬盘空间,而在windows平台上你只会得到一个error,所以又是windows,你懂的。
上面简单说了下各种fsdirectory的作用,下面简单说下各个directory中比较重要的一些接口方法:

/** just like {@link #open(path)}, but allows you to
* also specify a custom {@link lockfactory}. */
public static fsdirectory open(path path, lockfactory lockfactory) throws ioexception {
if (constants.jre_is_64bit && mmapdirectory.unmap_supported) {
return new mmapdirectory(path, lockfactory);
} else if (constants.windows) {
return new simplefsdirectory(path, lockfactory);
} else {
return new niofsdirectory(path, lockfactory);
}
fsdirectory类里的open方法是使用比较频繁的方法之一,其实内部就是根据用户的操作系统环境和使用的jdk来选择合适的directory,
constants.jre_is_64bit即表示是否是64位的jdk,
mmapdirectory.unmap_supported即表示是否支持direct buffer,什么叫direct buffer?其实direct buffer并不是直接分配在堆上的,direct buffer不受gc管理,即direct buffer是有操作系统来销毁的,但direct buffer上对象是由gc负责回收的,direct buffer读写之所以快,是因为减少数据拷贝到内核缓冲区的操作,但direct buffer是由操作系统负责销毁,所以代价也是很高的。那我们看看lucene是如何判断是否支持direct buffer的?

/**
* <code>true</code>, if this platform supports unmapping mmapped files.
*/
public static final boolean unmap_supported;
static {
boolean v;
try {
class.forname("sun.misc.cleaner");
class.forname("java.nio.directbytebuffer")
.getmethod("cleaner");
v = true;
} catch (exception e) {
v = false;
unmap_supported = v;
这两个类都是用于direct buffer里对象清理工作的。
oracle/sun jdk 6中的hotspot vm只会在年老代gc(full gc/major gc或者concurrent gc都算)的时候才会做reference processing,而在young gc/minor gc时不做。 也就是说,做full gc的话会做reference processing,进而能触发cleaner对已死的directbytebuffer对象做清理工作。而如果很长一段时间里没做过gc或者只做了young gc的话则不会触发cleaner的工作,那么就可能让本来已经死了的directbytebuffer关联的native memory得不到及时释放。
之所以要保证有上述两个类,就是确保directbytebuffer里的内存能得到释放以保证性能,这样你使用mmapdirectory才能体现它的优势又能避免它潜在的隐患。
另外一个比较重要的directory就是fileswitchdirectory,它就是集niodirectory与mmapdirectory优点与一身的directory,niodirectory是直接把文件放入heap buffer中,而mmapdirectory是把文件直接映射到direct buffer,由于heap buffer可使用量大而direct buffer虽然读写速度快,但它受操作系统调度,开辟和销毁的代价太高,不宜过多使用,所以一般我们需要使用niodirectory来读写比较大的索引文件,而用mmapdirectory来读写相对比较小的文件,两者结合互补你懂的。
同理lock也有对应的3种实现,就不赘述了。
一般我们使用fsdirectory.open由api自动帮我们来选择合适的directory即可,特殊情况下可以使用fileswitchdirectory结合下两种directory的优点。关于directory就说这么多了,如果有哪里说的不正确,还望你提出来,谢谢!
如果你还有什么问题请加我Q-q:7-3-6-0-3-1-3-0-5,
或者加裙
一起交流学习!
转载:http://iamyida.iteye.com/blog/2194394