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

anqiang专栏

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

 
 
 

日志

 
 

FSDirectory源码分析(二)  

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

  下载LOFTER 我的照片书  |

 /* will move to ctor, when reflection is removed in 3.0 */

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

    // Set up lockFactory with cascaded defaults: if an instance was passed in,

    // use that; else if locks are disabled, use NoLockFactory; else if the

    // system property org.apache.lucene.store.FSDirectoryLockFactoryClass is set,

    // instantiate that; else, use SimpleFSLockFactory:

    directory = path;

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

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

    if (lockFactory == null) {

      if (disableLocks) {

        // Locks are disabled:

        lockFactory = NoLockFactory.getNoLockFactory();

      } else {

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

        if (lockClassName != null && !lockClassName.equals("")) {

          Class c;

          try {

            c = Class.forName(lockClassName);

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

          }

        } else {

          // Our default lock is SimpleFSLockFactory;

          // default lockDir is our index directory:

          lockFactory = new SimpleFSLockFactory();

        }

      }

    }

    setLockFactory(lockFactory);

    

    // for filesystem based LockFactory, delete the lockPrefix, if the locks are placed

    // in index dir. If no index dir is given, set ourselves

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

      }

    }

  }

  /** Lists all files (not subdirectories) in the

   *  directory.  This method never returns null (throws

   *  {@link IOException} instead).

   *

   *  @throws NoSuchDirectoryException if the directory

   *   does not exist, or does exist but is not a

   *   directory.

   *  @throws IOException if list() returns null */

  /**

   * FSDirectory下面的所有Index文件

   */

  public static String[] listAll(File dir) throws IOException {

    if (!dir.exists())

      throw new NoSuchDirectoryException("directory '" + dir + "' does not exist");

    else if (!dir.isDirectory())

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

    // Exclude subdirs

    String[] result = dir.list(new FilenameFilter() {

        public boolean accept(File dir, String file) {

          return !new File(dir, file).isDirectory();

        }

      });

    if (result == null)

      throw new IOException("directory '" + dir + "' exists and is a directory, but cannot be listed: list() returned null");

    return result;

  }

  public String[] list() {

    ensureOpen();

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

  }

  /** Lists all files (not subdirectories) in the

   * directory.

   * @see #listAll(File) */

  public String[] listAll() throws IOException {

    ensureOpen();

    return listAll(directory);

  }

  /** Returns true iff a file with the given name exists. */

  public boolean fileExists(String name) {

    ensureOpen();

    File file = new File(directory, name);

    return file.exists();

  }

  /** Returns the time the named file was last modified. */

  public long fileModified(String name) {

    ensureOpen();

    File file = new File(directory, name);

    return file.lastModified();

  }

  /** Returns the time the named file was last modified. */

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

    File file = new File(directory, name);

    return file.lastModified();

  }

  /** Set the modified time of an existing file to now. */

  public void touchFile(String name) {

    ensureOpen();

    File file = new File(directory, name);

    file.setLastModified(System.currentTimeMillis());

  }

  /** Returns the length in bytes of a file in the directory. */

  public long fileLength(String name) {

    ensureOpen();

    File file = new File(directory, name);

    return file.length();

  }

  /** Removes an existing file in the directory. */

  public void deleteFile(String name) throws IOException {

    ensureOpen();

    File file = new File(directory, name);

    if (!file.delete())

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

  }

  /** Renames an existing file in the directory. 

   * Warning: This is not atomic.

   * @deprecated 

   */

  public synchronized void renameFile(String from, String to)

      throws IOException {

    ensureOpen();

    File old = new File(directory, from);

    File nu = new File(directory, to);

    /* This is not atomic.  If the program crashes between the call to

       delete() and the call to renameTo() then we're screwed, but I've

       been unable to figure out how else to do this... */

    if (nu.exists())

      if (!nu.delete())

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

    // Rename the old file to the new one. Unfortunately, the renameTo()

    // method does not work reliably under some JVMs.  Therefore, if the

    // rename fails, we manually rename by copying the old file to the new one

    if (!old.renameTo(nu)) {

      java.io.InputStream in = null;

      java.io.OutputStream out = null;

      try {

        in = new FileInputStream(old);

        out = new FileOutputStream(nu);

        // see if the buffer needs to be initialized. Initialization is

        // only done on-demand since many VM's will never run into the renameTo

        // bug and hence shouldn't waste 1K of mem for no reason.

        if (buffer == null) {

          buffer = new byte[1024];

        }

        int len;

        while ((len = in.read(buffer)) >= 0) {

          out.write(buffer, 0, len);

        }

        // delete the old file.

        old.delete();

      }

      catch (IOException ioe) {

        IOException newExc = new IOException("Cannot rename " + old + " to " + nu);

        newExc.initCause(ioe);

        throw newExc;

      }

      finally {

        try {

          if (in != null) {

            try {

              in.close();

            } catch (IOException e) {

              throw new RuntimeException("Cannot close input stream: " + e.toString(), e);

            }

          }

        } finally {

          if (out != null) {

            try {

              out.close();

            } catch (IOException e) {

              throw new RuntimeException("Cannot close output stream: " + e.toString(), e);

            }

          }

        }

      }

    }

  }

  /** Creates an IndexOutput for the file with the given name.

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

  public IndexOutput createOutput(String name) throws IOException {

    initOutput(name);

    return new FSIndexOutput(new File(directory, name));

  }

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

          // In 3.0 we will change this to throw

          // InterruptedException instead

          Thread.currentThread().interrupt();

          throw new RuntimeException(ie);

        }

      }

    }

    if (!success)

      // Throw original exception

      throw exc;

  }

  // Inherit javadoc

  public IndexInput openInput(String name) throws IOException {

    ensureOpen();

    //使用默认的bufferSize = 1KB

    return openInput(name, BufferedIndexInput.BUFFER_SIZE);

  }

  /** Creates an IndexInput for the file with the given name.

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

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

    ensureOpen();

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

  }

  /**

   * So we can do some byte-to-hexchar conversion below

   */

  private static final char[] HEX_DIGITS =

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

  

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

  }

  /** Closes the store to future operations. */

  public synchronized void close() {

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

      isOpen = false;

      synchronized (DIRECTORIES) {

        DIRECTORIES.remove(directory);

      }

    }

  }

  public File getFile() {

    ensureOpen();

    return directory;

  }

  /** For debug output. */

  public String toString() {

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

  }

  /**

   * Default read chunk size.  This is a conditional

   * default: on 32bit JVMs, it defaults to 100 MB.  On

   * 64bit JVMs, it's <code>Integer.MAX_VALUE</code>.

   * 对于32位的JVM, 默认读入的chunk大小为100MB

   * 对于64位的JVM, 默认读入的chunk大小为Integer.MAX_VALUE 大概是2G

   * @see #setReadChunkSize

   */

  public static final int DEFAULT_READ_CHUNK_SIZE = Constants.JRE_IS_64BIT ? Integer.MAX_VALUE: 100 * 1024 * 1024;

  // LUCENE-1566

  private int chunkSize = DEFAULT_READ_CHUNK_SIZE;

  /**

   * Sets the maximum number of bytes read at once from the

   * underlying file during {@link IndexInput#readBytes}.

   * The default value is {@link #DEFAULT_READ_CHUNK_SIZE};

   *

   * <p> This was introduced due to <a

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

   * JVM Bug 6478546</a>, which throws an incorrect

   * OutOfMemoryError when attempting to read too many bytes

   * at once.  It only happens on 32bit JVMs with a large

   * maximum heap size.</p>

   *

   * <p>Changes to this value will not impact any

   * already-opened {@link IndexInput}s.  You should call

   * this before attempting to open an index on the

   * directory.</p>

   *

   * <p> <b>NOTE</b>: This value should be as large as

   * possible to reduce any possible performance impact.  If

   * you still encounter an incorrect OutOfMemoryError,

   * trying lowering the chunk size.</p>

   */

  public final void setReadChunkSize(int chunkSize) {

    // LUCENE-1566

    if (chunkSize <= 0) {

      throw new IllegalArgumentException("chunkSize must be positive");

    }

    if (!Constants.JRE_IS_64BIT) {

      this.chunkSize = chunkSize;

    }

  }

  /**

   * The maximum number of bytes to read at once from the

   * underlying file during {@link IndexInput#readBytes}.

   * @see #setReadChunkSize

   */

  public final int getReadChunkSize() {

    // LUCENE-1566

    return chunkSize;

  }

  /** @deprecated Use SimpleFSDirectory.SimpleFSIndexInput instead */

  protected static class FSIndexInput extends SimpleFSDirectory.SimpleFSIndexInput {

  

    /** @deprecated */

    protected static class Descriptor extends SimpleFSDirectory.SimpleFSIndexInput.Descriptor {

      /** @deprecated */

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

        super(file, mode);

      }

    }

  

    /** @deprecated */

    public FSIndexInput(File path) throws IOException {

      super(path);

    }

  

    /** @deprecated */

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

      super(path, bufferSize);

    }

  

  }

  /** @deprecated Use SimpleFSDirectory.SimpleFSIndexOutput instead */

  protected static class FSIndexOutput extends SimpleFSDirectory.SimpleFSIndexOutput {

    /** @deprecated */

    public FSIndexOutput(File path) throws IOException {

      super(path);

    }

  }

}

FSDirectory创建的默认DirectorySimpleFSDirectory对象。

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

历史上的今天

评论

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

页脚

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