Lucene(2.4.1)技术研究(5)--IndexWrite类源代码解析(三)FSDirectory介绍

其中常用的就是FSDirectory:表示对文件系统目录的操作。RAMDirectory :内存中的目录操作。


首先我们看看类FSDirectory的源代码

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.RandomAccessFile;

import java.security.MessageDigest;

import java.security.NoSuchAlgorithmException;

import java.util.HashMap;

import java.util.Map;


import org.apache.lucene.index.IndexFileNameFilter;


// Used only for WRITE_LOCK_NAME in deprecated create=true case:

import org.apache.lucene.index.IndexWriter;

public class FSDirectory extends Directory {

//主要是用来缓存FilePath与FSDirectory,主要是保证针对统一目录,只能有一个FSDirectory实例

private static final Map DIRECTORIES = new HashMap();

//主要判断是否给目录上锁

private static boolean disableLocks = false;

//设置是否给目录上锁,一般只能用户只读目录。

//They should only be disabled if the index

// is on a read-only medium like a CD-ROM

public static void setDisableLocks(boolean doDisableLocks) {

FSDirectory.disableLocks = doDisableLocks;

}

//f返回是否给目录上锁

public static boolean getDisableLocks() {

return FSDirectory.disableLocks;

}

public static final String LOCK_DIR = System.getProperty("org.apache.lucene.lockDir",

System.getProperty("java.io.tmpdir"));

private static Class IMPL; //主要是获取FSDirectory的实例

static {

try {

String name =System.getProperty("org.apache.lucene.FSDirectory.class",

FSDirectory.class.getName());

IMPL = Class.forName(name); //首先获取该类的名称,然后在获取该类的Class实例

} catch (ClassNotFoundException e) {

throw new RuntimeException("cannot load FSDirectory class: " + e.toString(), e);

} catch (SecurityException se) {

try {

IMPL = Class.forName(FSDirectory.class.getName()); //直接使用JAVA反射获取该类Class实例

} catch (ClassNotFoundException e) {

throw new RuntimeException("cannot load default FSDirectory class: " + e.toString(), e);

}

}

}

private static MessageDigest DIGESTER; //获取加密

static {

try {

DIGESTER = MessageDigest.getInstance("MD5"); //使用MD5加密

} catch (NoSuchAlgorithmException e) {

throw new RuntimeException(e.toString(), e);

}

}

private byte[] buffer = null;

/**静态方法,根据基于指定目录,返回该目录中对应的一个FSDirectory实例 */

public static FSDirectory getDirectory(String path) throws IOException {

return getDirectory(new File(path), null);

}

/** 静态方法,根据指定的路径path以及锁工厂LockFactory参数,返回该路径的一个FSDirectiry实例 */

public static FSDirectory getDirectory(String path, LockFactory lockFactory) throws IOException {

return getDirectory(new File(path), lockFactory);

}

/**静态方法,根据指定的File对象,返回该路径的一个FSDirectiry实例 */

public static FSDirectory getDirectory(File file) throws IOException {

return getDirectory(file, null);

}

/**静态方法,根据指定File对象以及锁工厂LockFactory参数,返回该路径的一个FSDirectiry实例

其他方法,都最终转化为该方法来实现 */

public static FSDirectory getDirectory(File file, LockFactory lockFactory) throws IOException

{

file = new File(file.getCanonicalPath()); //定义一个File对象,以传递的参数作为目录

if (file.exists() && !file.isDirectory()) //首先判断文件存在时,是否是目录

throw new IOException(file + " not a directory");

if (!file.exists()) //如果文件不存在。则创建

if (!file.mkdirs()) throw new IOException("Cannot create directory: " + file); //创建所有目录

FSDirectory dir; //定义一个类 FSDirectory

synchronized (DIRECTORIES) {

dir = (FSDirectory)DIRECTORIES.get(file); //首先从Map查找是否存在该实例,

if (dir == null) {

try {

dir = (FSDirectory)IMPL.newInstance(); //调用静态内部类IMPL获取一个与文件系统目录有关的Directory类,并加载该类

} catch (Exception e) {

throw new RuntimeException("cannot load FSDirectory class: " + e.toString(), e);

}

dir.init(file, lockFactory); // 根据指定的file和lockFactory,调用该类Directory的init方法,进行FSDirectory的初始化初始化工作

DIRECTORIES.put(file, dir); //将该实例放置到HashMap中

} else {

//如果该目录dir管理所用的锁工厂实例为空,或者不是同一个锁工厂实例,抛出异常

if (lockFactory != null && lockFactory != dir.getLockFactory()) {

throw new IOException("Directory was previously created with a different LockFactory instance; please pass null as the lockFactory instance and use setLockFactory to change it");

}

}

}

synchronized (dir) {

dir.refCount++; //用于记录该目录dir被引用的计数增加1

}

return dir;

}

/** 废弃的方法 */

public static FSDirectory getDirectory(String path, boolean create) throws IOException {

return getDirectory(new File(path), create);

}

/** 废弃的方法 */

public static FSDirectory getDirectory(File file, boolean create) throws IOException

{

FSDirectory dir = getDirectory(file, null);

if (create) {

dir.create();

}

return dir;

}


private void create() throws IOException {

if (directory.exists()) {

String[] files = directory.list(IndexFileNameFilter.getFilter()); // clear old files

if (files == null)

throw new IOException("cannot read directory " + directory.getAbsolutePath() + ": list() returned null");

for (int i = 0; i < files.length; i++) {

File file = new File(directory, files[i]);

if (!file.delete())

throw new IOException("Cannot delete " + file);

}

}

lockFactory.clearLock(IndexWriter.WRITE_LOCK_NAME);

}


private File directory = null; //File directory是FSDirectory类的一个成员

private int refCount; //用于记录该目录dir被引用的计数增加1


protected FSDirectory() {}; // permit subclassing


private void init(File path, LockFactory lockFactory) throws IOException {

//根据指定的file和lockFactory,调用该类Directory的init方法,进行FSDirectory的初始化初始化工作

directory = path;

boolean doClearLockID = false;

if (lockFactory == null) { //锁工厂实例为null

if (disableLocks) { //如果锁不可以使用

lockFactory = NoLockFactory.getNoLockFactory(); //调用NoLockFactory类,获取NoLockFactory实例,为当前的锁工厂实例。其实NoLockFactory是一个单态(singleton)模式的工厂类,应用中只能有一个锁实例,不需要进行同步

} else { //如果锁可以使用,获取锁工厂类名称的字符串描述

String lockClassName = System.getProperty("org.apache.lucene.store.FSDirectoryLockFactoryClass");

if (lockClassName != null && !lockClassName.equals("")) {//如果获取的锁工厂类名称的字符串描述不为null,而且者不为空

Class c;

try {

c = Class.forName(lockClassName); //创建一个Class对象,加载该锁工厂类

} catch (ClassNotFoundException e) {

throw new IOException("unable to find LockClass " + lockClassName);

}

try {

lockFactory = (LockFactory) c.newInstance(); //获取一个锁工厂的实例

} catch (IllegalAccessException e) {

throw new IOException("IllegalAccessException when instantiating LockClass " + lockClassName);

} catch (InstantiationException e) {

throw new IOException("InstantiationException when instantiating LockClass " + lockClassName);

} catch (ClassCastException e) {

throw new IOException("unable to cast LockClass " + lockClassName + " instance to a LockFactory");

}

// 根据获取的锁工厂实例的类型来设置对文件File path加锁的方式

if (lockFactory instanceof NativeFSLockFactory) {

((NativeFSLockFactory) lockFactory).setLockDir(path);

} else if (lockFactory instanceof SimpleFSLockFactory) {

((SimpleFSLockFactory) lockFactory).setLockDir(path);

}

} else {

// 没有其他的锁工厂类可用,则使用默认的锁工厂类创建一个锁工厂实例

lockFactory = new SimpleFSLockFactory(path);

doClearLockID = true;

}

}

}

// 设置当前FSDirectory相关锁工厂实例

setLockFactory(lockFactory);

if (doClearLockID) {

// Clear the prefix because write.lock will be

// stored in our directory:

lockFactory.setLockPrefix(null);

}

}

/** 返回所有的在当前目录下的Lucene索引文件名,并且保存在数组中*/

public String[] list() {

ensureOpen();

return directory.list(IndexFileNameFilter.getFilter());

}

/**检查指定名称的文件是否存在 */

public boolean fileExists(String name) {

ensureOpen();

File file = new File(directory, name);

return file.exists();

}

/** 返回指定文件最后修改的时间*/

public long fileModified(String name) {

ensureOpen();

File file = new File(directory, name);

return file.lastModified();

}

/** 返回指定目录和文件名的文件最后修改的时间*/

public static long fileModified(File directory, String name) {

File file = new File(directory, name);

return file.lastModified();

}

/**设置指定文件最后修改的时间为当前时间*/

public void touchFile(String name) {

ensureOpen();

File file = new File(directory, name);

file.setLastModified(System.currentTimeMillis());

}

/**返回指定文件的长度*/

public long fileLength(String name) {

ensureOpen();

File file = new File(directory, name);

return file.length();

}

/**删除当前目录中指定文件名的文件*/

public void deleteFile(String name) throws IOException {

ensureOpen();

File file = new File(directory, name);

if (!file.delete())

throw new IOException("Cannot delete " + file);

}

/** 创建一个名称为name的文件,返回一个输出流,以便对该文件进行写入操作 */

public IndexOutput createOutput(String name) throws IOException {

ensureOpen();

File file = new File(directory, name);

if (file.exists() && !file.delete()) //如果文件存在,则将文件删除

throw new IOException("Cannot overwrite: " + file);


return new FSIndexOutput(file); // 返回文件File file的一个输出流

}

// Lucene使用该方法确保所有的针对该文件的写操作都会存储到Index。并且阻止machine/OS发生故障 破坏该index。

public void sync(String name) throws IOException {

ensureOpen();

File fullFile = new File(directory, name);

boolean success = false;

int retryCount = 0;

IOException exc = null;

while(!success && retryCount < 5) {

retryCount++;

RandomAccessFile file = null;

try {

try {

file = new RandomAccessFile(fullFile, "rw");

file.getFD().sync();

success = true;

} finally {

if (file != null)

file.close();

}

} catch (IOException ioe) {

if (exc == null)

exc = ioe;

try {

// Pause 5 msec

Thread.sleep(5);

} catch (InterruptedException ie) {

Thread.currentThread().interrupt();

}

}

}

if (!success)

// Throw original exception

throw exc;

}

//读取名称为name的文件,返回一个输出流,以便定义对读取出来的内容进行操作

public IndexInput openInput(String name) throws IOException {

ensureOpen();

return openInput(name, BufferedIndexInput.BUFFER_SIZE);

}

// 打开指定名称为name的文件,指定大小为缓冲区大小bufferSize,返回一个输入流

public IndexInput openInput(String name, int bufferSize) throws IOException {

ensureOpen();

return new FSIndexInput(new File(directory, name), bufferSize);

}

// 一个字符缓冲区,将字节转换为十六进制

private static final char[] HEX_DIGITS =

{'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};

//获取锁的标识ID

public String getLockID() {

ensureOpen();

String dirName; // name to be hashed

try {

dirName = directory.getCanonicalPath();

} catch (IOException e) {

throw new RuntimeException(e.toString(), e);

}


byte digest[];

synchronized (DIGESTER) {

digest = DIGESTER.digest(dirName.getBytes());

}

StringBuffer buf = new StringBuffer();

buf.append("lucene-");

for (int i = 0; i < digest.length; i++) {

int b = digest[i];

buf.append(HEX_DIGITS[(b >> 4) & 0xf]);

buf.append(HEX_DIGITS[b & 0xf]);

}


return buf.toString();

}


/** 关闭当前目录. */

public synchronized void close() {

if (isOpen && --refCount <= 0) {

isOpen = false;

synchronized (DIRECTORIES) {

DIRECTORIES.remove(directory);

}

}

}

//获取当前目录File类

public File getFile() {

ensureOpen();

return directory;

}


/** For debug output. */

public String toString() {

return this.getClass().getName() + "@" + directory;

}

//FSIndexInput是一个静态内部类,用于管理文件系统中的索引文件输入流

protected static class FSIndexInput extends BufferedIndexInput {

protected static class Descriptor extends RandomAccessFile {

// 用于记录文件打开状态的boolean型变量isOpen

protected volatile boolean isOpen;

long position;

final long length; // 文件长度

//构造函数for类Descriptor

public Descriptor(File file, String mode) throws IOException {

super(file, mode);

isOpen=true;

length=length();

}

//关闭

public void close() throws IOException {

if (isOpen) {

isOpen=false;

super.close();

}

}



protected void finalize() throws Throwable {

try {

close();

} finally {

super.finalize();

}

}

}



protected final Descriptor file;

boolean isClone;



public FSIndexInput(File path) throws IOException {

this(path, BufferedIndexInput.BUFFER_SIZE);

}



public FSIndexInput(File path, int bufferSize) throws IOException {

super(bufferSize);

file = new Descriptor(path, "r");

}

/** 比较底层的读取操作,主要是对字节操作 */

protected void readInternal(byte[] b, int offset, int len)

throws IOException {

synchronized (file) {

long position = getFilePointer();

if (position != file.position) {

file.seek(position);

file.position = position;

}

int total = 0;

do {

int i = file.read(b, offset+total, len-total);

if (i == -1)

throw new IOException("read past EOF");

file.position += i;

total += i;

} while (total < len);

}

}

//仅当不是拷贝的时间关闭

public void close() throws IOException {

// only close the file if this is not a clone

if (!isClone) file.close();

}

protected void seekInternal(long position) {

}

//返回文件的长度

public long length() {

return file.length;

}

//创建一个拷贝

public Object clone() {

FSIndexInput clone = (FSIndexInput)super.clone();

clone.isClone = true;

return clone;

}



/** Method used for testing. Returns true if the underlying

* file descriptor is valid.

*/

boolean isFDValid() throws IOException {

return file.getFD().valid();

}

}

// FSIndexOutput是一个静态内部类,用于管理文件系统中的索引文件输出流,与FSIndexInput实现类似

protected static class FSIndexOutput extends BufferedIndexOutput {

RandomAccessFile file = null; //定一个随机读写文件

private volatile boolean isOpen;

//构造函数,根据文件定一个一个可以读写

public FSIndexOutput(File path) throws IOException {

file = new RandomAccessFile(path, "rw");

isOpen = true;

}

//输入内容

public void flushBuffer(byte[] b, int offset, int size) throws IOException {

file.write(b, offset, size);

}

//关闭该对象。仅当该对象被打开,从来没有被关闭过

public void close() throws IOException {

if (isOpen) {

boolean success = false;

try {

super.close();

success = true;

} finally {

isOpen = false;

if (!success) {

try {

file.close();

} catch (Throwable t) {

// Suppress so we don't mask original exception

}

} else

file.close();

}

}

}

// 随机访问的方法实现

public void seek(long pos) throws IOException {

super.seek(pos);

file.seek(pos);

}

public long length() throws IOException {

return file.length();

}

public void setLength(long length) throws IOException {

file.setLength(length);

}

}

}

由具体构造函数实现方法以及dir.init()方法,可以看出来,针对每一个目录只能有一个FSDirectory实例,

由此我们可以看看FSDirectory的主要功能:

1、针对同一个目录进行维护

2、对于锁工厂的获取以及管理

3、对文件系统目录下索引文件的输入流和输出流的管理

4、FSDirectory类中实现了很多静态内部类,这使得只能在FSDirectory类内部访问这些静态类,对外部透明。

因此该类主要Directory抽象类的操作本地文件的实现。具体操作我们在以后索引的处理详细讲解


<------------------我是快乐的转载符----------------------->
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值