Lucene-同步机制

  Lucene是一个优秀的开源搜索引擎library,其价值已经在众多的应用中体现出来。对于lucene的相关研究的文章每天都层出不穷的出现在各大论坛中。为初学者的学习之路打开了方便之门。本文仅针对Lucene中有关Directory同步机制做相关的论述。同步机制是保证索引的完备性、一致性的重要的一种方式,保持进程间的同步。

  在使用Lucene 进行索引的过程中,首先我们需要创建或指定一个操作、存储索引数据的场景。因此,Directory以及与其相关的便承担了这个责任。

  •  Directory在Lucene中被定义为一个抽象类public abstract class Directory implements Closeable {...},其具体的实现类主要有FileSwitchDirectory、RAMDirectory、 FSDirectory,SimpleFSDirectory等(其次还有NIOFSDirectory--主要针对linux系统,MMapDirectory)。而通常我们在创建Directory 实例过程中的directory类型实际上是SimpleFSDirectory,它是FSDirectory的一个子类。 

    Directory directory=FSDirectory.open(new File(indexDirectory));在FSDirectory的open方法中首先会判断当前系统的类型如果是window则创建SimpleFSDirectory类型对象,如果是其他平台则创建NIOFSDirectory类型的对象。因此,实际上,对象的初始化过程是由 SimpleFSDirectory调用FSDirectory来完成的。

        if (Constants.WINDOWS) {
            return new SimpleFSDirectory(path, lockFactory);
        } else {
            return new NIOFSDirectory(path, lockFactory);
        }

      public SimpleFSDirectory(File path, LockFactory lockFactory) throws IOException {
          super(path, lockFactory);
       } 

  • FSDirecotry 中有一个LockFactory的对象lockFacotry,该对象主要用来生成Lock对象实例,Lock writeLock = directory.makeLock(WRITE_LOCK_NAME),由Directory对象发起,调用makeLock(object)方法,传入一个String类型的参数作为Lock对象的名称,通常该名称为一个固定的常量,public static final String WRITE_LOCK_NAME = "write.lock",这个文件在生成索引的时候可以直接在索引目录下,其中lockFactory实际类型为NativeFSLockFactory,makeLock方法返回一个 NativeFSLock对象实例因此,NativeFSLock是实际执行同步机制的Lock执行类,NativeFSLock是NativeFSLockFactory的内部类。参照如下代码及类图

 //FSDirectory构造函数,对应Lucene3.0FSDirectory类中的144-170

protected FSDirectory(File path, LockFactory lockFactory) throws IOException {

  //索引目录的路径

    path = getCanonicalPath(path);
    // 使用NativeFSLockFactory 作为默认的工厂类

    if (lockFactory == null) {

    //建立一个Lock Facotry

      lockFactory = new NativeFSLockFactory();
    }
    directory = path;

    if (directory.exists() && !directory.isDirectory())

      throw new NoSuchDirectoryException("file '" + directory + "' exists but is not a directory");

  //为FSDirectory属性lockFactory赋值

    setLockFactory(lockFactory);

   

//设置LockFactory对象对应的目录 以及名称的前缀

    if (lockFactory instanceof FSLockFactory) {
      final FSLockFactory lf = (FSLockFactory) lockFactory;
      final File dir = lf.getLockDir();
      // if the lock factory has no lockDir set, use the this directory as lockDir
      if (dir == null) {
        lf.setLockDir(this.directory);
        lf.setLockPrefix(null);
      } else if (dir.getCanonicalPath().equals(this.directory.getCanonicalPath())) {
        lf.setLockPrefix(null);
      }
    }

  }

//NNativeFSLockFactory 中的makeLock()方法,生成一个NativeFSLock对象,用于后面的进程同步。

@ lockName,对应要生成锁文件的名字

 public synchronized Lock makeLock(String lockName) {
    acquireTestLock();
    if (lockPrefix != null)
      lockName = lockPrefix + "-" + lockName;
    return new NativeFSLock(lockDir, lockName);
  } 

 // NativeFSLock类中对应的obtain()方法,真正同步策略的执行体,在IndexWriter对象创建过程中被调用

//来探查是否已经存在相关进程进行索引目录的操作

public synchronized boolean obtain() throws IOException {

    if (lockExists()) {
      // Our instance is already locked:
      return false;
    }

    // Ensure that lockDir exists and is a directory.
    if (!lockDir.exists()) {
      if (!lockDir.mkdirs())
        throw new IOException("Cannot create directory: " +
                              lockDir.getAbsolutePath());
    } else if (!lockDir.isDirectory()) {
      throw new IOException("Found regular file where directory expected: " +
                            lockDir.getAbsolutePath());
    }

    String canonicalPath = path.getCanonicalPath();

    boolean markedHeld = false;

    try {

      // Make sure nobody else in-process has this lock held
      // already, and, mark it held if not:
  //确保没有其他进程在使用该LOCK_HELD,一个HashSet<String>对象用来保存当前创建的所有Lock实例
      synchronized(LOCK_HELD) {
        if (LOCK_HELD.contains(canonicalPath)) {
          //该锁已经存在
          return false;
        } else {
    //添加一个实例
          LOCK_HELD.add(canonicalPath);
          markedHeld = true;
        }
      }

      try {
        f = new RandomAccessFile(path, "rw");
      } catch (IOException e) {
        failureReason = e;
        f = null;
      }

      if (f != null) {
        try {//类似指针
          channel = f.getChannel();
          try {
            lock = channel.tryLock();
          } catch (IOException e) {
            failureReason = e;
          } finally {
            if (lock == null) {
              try {
                channel.close();
              } finally {
                channel = null;
              }
            }
          }
        } finally {
          if (channel == null) {
            try {
              f.close();
            } finally {
              f = null;
            }
          }
        }
      }

    } finally {
      if (markedHeld && !lockExists()) {
        synchronized(LOCK_HELD) {
          if (LOCK_HELD.contains(canonicalPath)) {//清楚异常操作
            LOCK_HELD.remove(canonicalPath);
          }
        }
      }
    }
    return lockExists();
  } 

posted on 2010-09-16 14:34  Creative Common  阅读(582)  评论(0编辑  收藏  举报

导航