注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

anqiang专栏

不要问细节是怎么搞的,源码说明一切

 
 
 

日志

 
 

FSDirectory源码分析(一)  

2009-11-30 10:51:07|  分类: Lucene |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

import java.io.File;

import java.io.FilenameFilter;

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;

import org.apache.lucene.util.Constants;

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

import org.apache.lucene.index.IndexWriter;

/**

 * <a name="subclasses"/>

 * Base class for Directory implementations that store index

 * files in the file system.  There are currently three core

 * subclasses:

 *

 * <ul>

 *

 *  <li> {@link SimpleFSDirectory} is a straightforward

 *       implementation using java.io.RandomAccessFile.

 *       However, it has poor concurrent performance

 *       (multiple threads will bottleneck) as it

 *       synchronizes when multiple threads read from the

 *       same file.

 *       SimpleFSDirectory是对FSDirectory的简单实现

 *

 *  <li> {@link NIOFSDirectory} uses java.nio's

 *       FileChannel's positional io when reading to avoid

 *       synchronization when reading from the same file.

 *       Unfortunately, due to a Windows-only <a

 *       href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6265734">Sun

 *       JRE bug</a> this is a poor choice for Windows, but

 *       on all other platforms this is the preferred

 *       choice.

 *       NIOFSDirectory对象在windows系统下工作的表现不是很好

 *

 *  <li> {@link MMapDirectory} uses memory-mapped IO when

 *       reading. This is a good choice if you have plenty

 *       of virtual memory relative to your index size, eg

 *       if you are running on a 64 bit JRE, or you are

 *       running on a 32 bit JRE but your index sizes are

 *       small enough to fit into the virtual memory space.

 *       Java has currently the limitation of not being able to

 *       unmap files from user code. The files are unmapped, when GC

 *       releases the byte buffers. Due to

 *       <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4724038">

 *       this bug</a> in Sun's JRE, MMapDirectory's {@link IndexInput#close}

 *       is unable to close the underlying OS file handle. Only when

 *       GC finally collects the underlying objects, which could be

 *       quite some time later, will the file handle be closed.

 *       This will consume additional transient disk usage: on Windows,

 *       attempts to delete or overwrite the files will result in an

 *       exception; on other platforms, which typically have a "delete on

 *       last close" semantics, while such operations will succeed, the bytes

 *       are still consuming space on disk.  For many applications this

 *       limitation is not a problem (e.g. if you have plenty of disk space,

 *       and you don't rely on overwriting files on Windows) but it's still

 *       an important limitation to be aware of. This class supplies a

 *       (possibly dangerous) workaround mentioned in the bug report,

 *       which may fail on non-Sun JVMs.

 *       MMapDirectory的实现原理还没有细看

 * </ul>

 *

 * Unfortunately, because of system peculiarities, there is

 * no single overall best implementation.  Therefore, we've

 * added the {@link #open} method, to allow Lucene to choose

 * the best FSDirectory implementation given your

 * environment, and the known limitations of each

 * implementation.  For users who have no reason to prefer a

 * specific implementation, it's best to simply use {@link

 * #open}.  For all others, you should instantiate the

 * desired implementation directly.

 * 

 * 由于系统的多样性,没有一个FSDirectory子类是可以宣称最好的。

 * 因此,需要针对不同的系统进行特殊的初始化

 * 但是对于一般的情况,可以通过Open()方法可以得到符合当前系统所适合的FSDirectory对象

 * 在windows下是SimpleDirectory对象,在其他系统下是NIOFSDirectory

 *

 * <p>The locking implementation is by default {@link

 * NativeFSLockFactory}, but can be changed by

 * passing in a custom {@link LockFactory} instance.

 * The deprecated <code>getDirectory</code> methods default to use

 * {@link SimpleFSLockFactory} for backwards compatibility.

 * The system properties 

 * <code>org.apache.lucene.store.FSDirectoryLockFactoryClass</code>

 * and <code>org.apache.lucene.FSDirectory.class</code>

 * are deprecated and only used by the deprecated

 * <code>getDirectory</code> methods. The system property

 * <code>org.apache.lucene.lockDir</code> is ignored completely,

 * If you really want to store locks

 * elsewhere, you can create your own {@link

 * SimpleFSLockFactory} (or {@link NativeFSLockFactory},

 * etc.) passing in your preferred lock directory.

 * 对于锁的实现可以在以后加以详细介绍

 * <p><em>In 3.0 this class will become abstract.</em>

 * 

 * 此外由于back compatibility(现在lucene开发社区采用的方式,"向后兼容"),

 * 在3.0版本推出时,FSDirectory将成为一个抽象对象,它的一些废弃方法将不会被支持,

 * 因此我们在代码编写时要注意这一点

 *

 * @see Directory

 */

// TODO: in 3.0 this will become an abstract base class

public class FSDirectory extends Directory {

    

  /** This cache of directories ensures that there is a unique Directory

   * instance per path, so that synchronization on the Directory can be used to

   * synchronize access between readers and writers.  We use

   * refcounts to ensure when the last use of an FSDirectory

   * instance for a given canonical path is closed, we remove the

   * instance from the cache.  See LUCENE-776

   * for some relevant discussion.

   * @deprecated Not used by any non-deprecated methods anymore

   */

  private static final Map DIRECTORIES = new HashMap();

  private static boolean disableLocks = false;

  // TODO: should this move up to the Directory base class?  Also: should we

  // make a per-instance (in addition to the static "default") version?

  /**

   * Set whether Lucene's use of lock files is disabled. By default, 

   * lock files are enabled. They should only be disabled if the index

   * is on a read-only medium like a CD-ROM.

   * @deprecated Use a {@link #open(File, LockFactory)} or a constructor

   * that takes a {@link LockFactory} and supply

   * {@link NoLockFactory#getNoLockFactory}. This setting does not work

   * with {@link #open(File)} only the deprecated <code>getDirectory</code>

   * respect this setting.   

   */

  public static void setDisableLocks(boolean doDisableLocks) {

    FSDirectory.disableLocks = doDisableLocks;

  }

  /**

   * Returns whether Lucene's use of lock files is disabled.

   * @return true if locks are disabled, false if locks are enabled.

   * @see #setDisableLocks

   * @deprecated Use a constructor that takes a {@link LockFactory} and

   * supply {@link NoLockFactory#getNoLockFactory}.

  */

  public static boolean getDisableLocks() {

    return FSDirectory.disableLocks;

  }

  /**

   * Directory specified by <code>org.apache.lucene.lockDir</code>

   * or <code>java.io.tmpdir</code> system property.

   * @deprecated As of 2.1, <code>LOCK_DIR</code> is unused

   * because the write.lock is now stored by default in the

   * index directory.  If you really want to store locks

   * elsewhere, you can create your own {@link

   * SimpleFSLockFactory} (or {@link NativeFSLockFactory},

   * etc.) passing in your preferred lock directory.  Then,

   * pass this <code>LockFactory</code> instance to one of

   * the <code>open</code> methods that take a

   * <code>lockFactory</code> (for example, {@link #open(File, LockFactory)}).

   */

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

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

  /** The default class which implements filesystem-based directories. */

  // deprecated

  /**

   * 这一段也将被废弃掉

   */

  private static Class IMPL;

  static {

    try {

      String name =

        System.getProperty("org.apache.lucene.FSDirectory.class",

                           SimpleFSDirectory.class.getName());

      if (FSDirectory.class.getName().equals(name)) {

        // FSDirectory will be abstract, so we replace it by the correct class

        IMPL = SimpleFSDirectory.class;

      } else {

        IMPL = Class.forName(name);

      }

    } catch (ClassNotFoundException e) {

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

    } catch (SecurityException se) {

      IMPL = SimpleFSDirectory.class;

    }

  }

  private static MessageDigest DIGESTER;

  static {

    try {

      DIGESTER = MessageDigest.getInstance("MD5");

    } catch (NoSuchAlgorithmException e) {

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

    }

  }

  /** A buffer optionally used in renameTo method */

  private byte[] buffer = null;

  /** Returns the directory instance for the named location.

   *

   * @deprecated Use {@link #open(File)}

   *

   * @param path the path to the directory.

   * @return the FSDirectory for the named file.  */

  public static FSDirectory getDirectory(String path)

      throws IOException {

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

  }

  /** Returns the directory instance for the named location.

   *

   * @deprecated Use {@link #open(File, LockFactory)}

   *

   * @param path the path to the directory.

   * @param lockFactory instance of {@link LockFactory} providing the

   *        locking implementation.

   * @return the FSDirectory for the named file.  */

  public static FSDirectory getDirectory(String path, LockFactory lockFactory)

      throws IOException {

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

  }

  /** Returns the directory instance for the named location.

   *

   * @deprecated Use {@link #open(File)}

   *

   * @param file the path to the directory.

   * @return the FSDirectory for the named file.  */

  public static FSDirectory getDirectory(File file)

    throws IOException {

    return getDirectory(file, null);

  }

  /** Returns the directory instance for the named location.

   *

   * @deprecated Use {@link #open(File, LockFactory)}

   *

   * @param file the path to the directory.

   * @param lockFactory instance of {@link LockFactory} providing the

   *        locking implementation.

   * @return the FSDirectory for the named file.  */

  public static FSDirectory getDirectory(File file, LockFactory lockFactory)

    throws IOException

  {

    file = getCanonicalPath(file);

    FSDirectory dir;

    synchronized (DIRECTORIES) {

      dir = (FSDirectory)DIRECTORIES.get(file);

      if (dir == null) {

        try {

          dir = (FSDirectory)IMPL.newInstance();

        } catch (Exception e) {

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

        }

        dir.init(file, lockFactory);

        DIRECTORIES.put(file, dir);

      } else {

        // Catch the case where a Directory is pulled from the cache, but has a

        // different LockFactory instance.

        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");

        }

        dir.checked = false;

      }

    }

    synchronized (dir) {

      dir.refCount++;

    }

    return dir;

  }

  /** Returns the directory instance for the named location.

   *

   * @deprecated Use IndexWriter's create flag, instead, to

   * create a new index.

   *

   * @param path the path to the directory.

   * @param create if true, create, or erase any existing contents.

   * @return the FSDirectory for the named file.  */

  public static FSDirectory getDirectory(String path, boolean create)

      throws IOException {

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

  }

  /** Returns the directory instance for the named location.

   *

   * @deprecated Use IndexWriter's create flag, instead, to

   * create a new index.

   *

   * @param file the path to the directory.

   * @param create if true, create, or erase any existing contents.

   * @return the FSDirectory for the named file.  */

  public static FSDirectory getDirectory(File file, boolean create)

    throws IOException

  {

    FSDirectory dir = getDirectory(file, null);

    // This is now deprecated (creation should only be done

    // by IndexWriter):

    if (create) {

      dir.create();

    }

    return dir;

  }

  /** @deprecated */

  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);

  }

  // returns the canonical version of the directory, creating it if it doesn't exist.

  private static File getCanonicalPath(File file) throws IOException {

    return new File(file.getCanonicalPath());

  }

  private boolean checked;

  final void createDir() throws IOException {

    if (!checked) {

      if (!directory.exists())

        if (!directory.mkdirs())

          throw new IOException("Cannot create directory: " + directory);

      checked = true;

    }

  }

  /** Initializes the directory to create a new file with the given name.

   * This method should be used in {@link #createOutput}. */

  protected final void initOutput(String name) throws IOException {

    ensureOpen();

    createDir();

    File file = new File(directory, name);

    if (file.exists() && !file.delete())          // delete existing, if any

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

  }

  /** The underlying filesystem directory */

  protected File directory = null;

  

  /** @deprecated */

  private int refCount = 0;

  /** @deprecated */

  protected FSDirectory() {}; // permit subclassing

  /** Create a new FSDirectory for the named location (ctor for subclasses).

   * @param path the path of the directory

   * @param lockFactory the lock factory to use, or null for the default

   * ({@link NativeFSLockFactory});

   * @throws IOException

   */

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

    path = getCanonicalPath(path);

    // new ctors use always NativeFSLockFactory as default:

    if (lockFactory == null) {

      lockFactory = new NativeFSLockFactory();

    }

    init(path, lockFactory);

    refCount = 1;

  }

  /** Creates an FSDirectory instance, trying to pick the

   *  best implementation given the current environment.

   *  The directory returned uses the {@link NativeFSLockFactory}.

   *

   *  <p>Currently this returns {@link NIOFSDirectory}

   *  on non-Windows JREs and {@link SimpleFSDirectory}

   *  on Windows.

   *

   * <p><b>NOTE</b>: this method may suddenly change which

   * implementation is returned from release to release, in

   * the event that higher performance defaults become

   * possible; if the precise implementation is important to

   * your application, please instantiate it directly,

   * instead. On 64 bit systems, it may also good to

   * return {@link MMapDirectory}, but this is disabled

   * because of officially missing unmap support in Java.

   * For optimal performance you should consider using

   * this implementation on 64 bit JVMs.

   * 

   * 这个方法中的代码可能会在以后的迭代版本中发生变化,因为最好的默认实现方式可能在将来出现。

   * 在64位 JVM的条件下,推荐使用MMapDirectory

   * 有特殊要求的用户可以选择创建符合自己系统特点的对象

   *

   * <p>See <a href="#subclasses">above</a> */

  public static FSDirectory open(File path) throws IOException {

    return open(path, null);

  }

  /** Just like {@link #open(File)}, but allows you to

   *  also specify a custom {@link LockFactory}. */

  public static FSDirectory open(File path, LockFactory lockFactory) throws IOException {

    /* For testing:

    MMapDirectory dir=new MMapDirectory(path, lockFactory);

    dir.setUseUnmap(true);

    return dir;

    */

  /**

   * 在FSDirectory中使用open方法时,对于windows,我们使用SimpleFSDirectory

   * 对于其它类型的操作系统使用NIOFSDirectory

   */

    if (Constants.WINDOWS) {

      return new SimpleFSDirectory(path, lockFactory);

    } else {

      return new NIOFSDirectory(path, lockFactory);

    }

  }

  

 

  评论这张
 
阅读(972)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017