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

anqiang专栏

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

 
 
 

日志

 
 

RAMDirectory 源码分析  

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

  下载LOFTER 我的照片书  |

RAMDirectory实际上是一个建立在内存上的Directory对象,所有的操作都是借助于内存来进行

package org.apache.lucene.store;

/**

 * Licensed to the Apache Software Foundation (ASF) under one or more

 * contributor license agreements.  See the NOTICE file distributed with

 * this work for additional information regarding copyright ownership.

 * The ASF licenses this file to You under the Apache License, Version 2.0

 * (the "License"); you may not use this file except in compliance with

 * the License.  You may obtain a copy of the License at

 *

 *     http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */

import java.io.IOException;

import java.io.FileNotFoundException;

import java.io.File;

import java.io.Serializable;

import java.util.HashMap;

import java.util.Iterator;

import java.util.Set;

/**

 * A memory-resident {@link Directory} implementation.  Locking

 * implementation is by default the {@link SingleInstanceLockFactory}

 * but can be changed with {@link #setLockFactory}.

 *

 * @version $Id: RAMDirectory.java 781333 2009-06-03 10:38:57Z mikemccand $

 */

public class RAMDirectory extends Directory implements Serializable {

  private static final long serialVersionUID = 1l;

  /**

   * 存放了一个fileName 和 RAMFile的键值对

   */

  HashMap fileMap = new HashMap();

  long sizeInBytes = 0;

  

  // *****

  // Lock  sequence:  RAMDirectory, then RAMFile

  // *****

  /** Constructs an empty {@link Directory}. */

  public RAMDirectory() {

    setLockFactory(new SingleInstanceLockFactory());

  }

  /**

   * Creates a new <code>RAMDirectory</code> instance from a different

   * <code>Directory</code> implementation.  This can be used to load

   * a disk-based index into memory.

   * <P>

   * This should be used only with indices that can fit into memory.

   * <P>

   * 仅仅当硬盘中的索引能全部放入内存中的时候才能调用此方法

   * 通过这种方法得到的RAMDirectory对象是一个独立于以前的directory对象的新的索引对象

   * 对于以前的Directory对象的任何修改都不会对新的RAMDirectory对象造成影响

   * 因为新的对象中包含所有的已有index的文件信息

   * Note that the resulting <code>RAMDirectory</code> instance is fully

   * independent from the original <code>Directory</code> (it is a

   * complete copy).  Any subsequent changes to the

   * original <code>Directory</code> will not be visible in the

   * <code>RAMDirectory</code> instance.

   *

   * @param dir a <code>Directory</code> value

   * @exception IOException if an error occurs

   */

  public RAMDirectory(Directory dir) throws IOException {

    this(dir, false);

  }

  

  private RAMDirectory(Directory dir, boolean closeDir) throws IOException {

    this();

    Directory.copy(dir, this, closeDir);

  }

  /**

   * Creates a new <code>RAMDirectory</code> instance from the {@link FSDirectory}.

   *

   * @param dir a <code>File</code> specifying the index directory

   *

   * @see #RAMDirectory(Directory)

   * @deprecated Use {@link #RAMDirectory(Directory)} instead

   */

  public RAMDirectory(File dir) throws IOException {

    this(FSDirectory.getDirectory(dir), true);

  }

  /**

   * Creates a new <code>RAMDirectory</code> instance from the {@link FSDirectory}.

   *

   * @param dir a <code>String</code> specifying the full index directory path

   *

   * @see #RAMDirectory(Directory)

   * @deprecated Use {@link #RAMDirectory(Directory)} instead

   */

  public RAMDirectory(String dir) throws IOException {

    this(FSDirectory.getDirectory(dir), true);

  }

  public synchronized final String[] list() {

    return listAll();

  }

  /**

   * 列出内存中所有的文件信息

   */

  public synchronized final String[] listAll() {

    ensureOpen();

    Set fileNames = fileMap.keySet();

    String[] result = new String[fileNames.size()];

    int i = 0;

    Iterator it = fileNames.iterator();

    while (it.hasNext())

      result[i++] = (String)it.next();

    return result;

  }

  /** Returns true iff the named file exists in this directory. */

  public final boolean fileExists(String name) {

    ensureOpen();

    RAMFile file;

    synchronized (this) {

      file = (RAMFile)fileMap.get(name);

    }

    return file != null;

  }

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

   * 获得当前name文件的最后修改时间

   * @throws IOException if the file does not exist

   */

  public final long fileModified(String name) throws IOException {

    ensureOpen();

    RAMFile file;

    synchronized (this) {

      file = (RAMFile)fileMap.get(name);

    }

    if (file==null)

      throw new FileNotFoundException(name);

    return file.getLastModified();

  }

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

   * 

   * @throws IOException if the file does not exist

   */

  public void touchFile(String name) throws IOException {

    ensureOpen();

    RAMFile file;

    synchronized (this) {

      file = (RAMFile)fileMap.get(name);

    }

    if (file==null)

      throw new FileNotFoundException(name);

    

    

    /**

     * 下面一段是什么意思还没有搞明白

     */

    long ts2, ts1 = System.currentTimeMillis();

    do {

      try {

        Thread.sleep(0, 1);

      } catch (InterruptedException ie) {

        // In 3.0 we will change this to throw

        // InterruptedException instead

        Thread.currentThread().interrupt();

        throw new RuntimeException(ie);

      }

      ts2 = System.currentTimeMillis();

    } while(ts1 == ts2);

    

    file.setLastModified(ts2);

  }

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

   * @throws IOException if the file does not exist

   */

  public final long fileLength(String name) throws IOException {

    ensureOpen();

    RAMFile file;

    synchronized (this) {

      file = (RAMFile)fileMap.get(name);

    }

    if (file==null)

      throw new FileNotFoundException(name);

    return file.getLength();

  }

  

  /** Return total size in bytes of all files in this

   * directory.  This is currently quantized to

   * RAMOutputStream.BUFFER_SIZE. */

  public synchronized final long sizeInBytes() {

    ensureOpen();

    return sizeInBytes;

  }

  

  /** Removes an existing file in the directory.

   * 从当前集合中删除名为name的文件

   * @throws IOException if the file does not exist

   */

  public synchronized void deleteFile(String name) throws IOException {

    ensureOpen();

    RAMFile file = (RAMFile)fileMap.get(name);

    if (file!=null) {

        fileMap.remove(name);

        file.directory = null;

        sizeInBytes -= file.sizeInBytes;       // updates to RAMFile.sizeInBytes synchronized on directory

    } else

      throw new FileNotFoundException(name);

  }

  /** Renames an existing file in the directory.

   * @throws FileNotFoundException if from does not exist

   * @deprecated

   */

  public synchronized final void renameFile(String from, String to) throws IOException {

    ensureOpen();

    RAMFile fromFile = (RAMFile)fileMap.get(from);

    if (fromFile==null)

      throw new FileNotFoundException(from);

    RAMFile toFile = (RAMFile)fileMap.get(to);

    if (toFile!=null) {

      sizeInBytes -= toFile.sizeInBytes;       // updates to RAMFile.sizeInBytes synchronized on directory

      toFile.directory = null;

    }

    fileMap.remove(from);

    fileMap.put(to, fromFile);

  }

  /** Creates a new, empty file in the directory with the given name. Returns a stream writing this file. */

  /**

   * 创建一个新的文件RAMFile 

   * 如果Directory中已经存在一个当前Name的File,

   * 则删除现有的这个File,将新的File加入到Directory中来

   */

  public IndexOutput createOutput(String name) throws IOException {

    ensureOpen();

    RAMFile file = new RAMFile(this);

    synchronized (this) {

      RAMFile existing = (RAMFile)fileMap.get(name);

      /**

       * 加入一个File对象已经存在,需要将原有的那个从集合中排除掉

       * 但是它所对应的相关信息没有消失

       * 由于没有其它对象引用这个排除掉的File对象,因此它很快会被GC回收掉

       */

      if (existing!=null) {

        sizeInBytes -= existing.sizeInBytes;

        /**

         * 这个地方需要将existing中引用的directory对象置为空

         */

        existing.directory = null;

      }

      fileMap.put(name, file);

    }

    return new RAMOutputStream(file);

  }

  /** Returns a stream reading an existing file. */

  /**

   * 打开一个input对象

   */

  public IndexInput openInput(String name) throws IOException {

    ensureOpen();

    RAMFile file;

    synchronized (this) {

      file = (RAMFile)fileMap.get(name);

    }

    if (file == null)

      throw new FileNotFoundException(name);

    return new RAMInputStream(file);

  }

  /** Closes the store to future operations, releasing associated memory. */

  /**

   * 关闭操作

   */

  public void close() {

    isOpen = false;

    fileMap = null;

  }

}

public RAMDirectory(Directory dir) throws IOException

这个函数是通过其它的Directory对象来构造当前的RAMDirectory对象,值得注意的是,我们要保证构造函数里的Directory对象,它所代表的索引大小一定要能够放在内存才行。否则得话将会发生OOM的异常。因为在前面我们也介绍了Directory拷贝的操作,它会将所有的现有Index放入到内存中来。

public IndexOutput createOutput(String name) throws IOException

这个函数是创建一个名称为name的输出流。这里牵扯到一个RAMFile对象和RAMOutputStream对象。

RAMFile对象就是在内存中维护一个当前file信息的对象

package org.apache.lucene.store;

/**

 * Licensed to the Apache Software Foundation (ASF) under one or more

 * contributor license agreements.  See the NOTICE file distributed with

 * this work for additional information regarding copyright ownership.

 * The ASF licenses this file to You under the Apache License, Version 2.0

 * (the "License"); you may not use this file except in compliance with

 * the License.  You may obtain a copy of the License at

 *

 *     http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */

import java.util.ArrayList;

import java.io.Serializable;

/**

 * 内存中组织的一个File对象 

 * 实际上是一个byte[]的数组链表

 * @author Andrew.Wang

 *

 */

class RAMFile implements Serializable {

  private static final long serialVersionUID = 1l;

  private ArrayList buffers = new ArrayList();

  long length;

  RAMDirectory directory;

  long sizeInBytes;                  // Only maintained if in a directory; updates synchronized on directory

  // This is publicly modifiable via Directory.touchFile(), so direct access not supported

  private long lastModified = System.currentTimeMillis();

  // File used as buffer, in no RAMDirectory

  RAMFile() {}

  

  RAMFile(RAMDirectory directory) {

    this.directory = directory;

  }

  // For non-stream access from thread that might be concurrent with writing

  synchronized long getLength() {

    return length;

  }

  synchronized void setLength(long length) {

    this.length = length;

  }

  // For non-stream access from thread that might be concurrent with writing

  synchronized long getLastModified() {

    return lastModified;

  }

  synchronized void setLastModified(long lastModified) {

    this.lastModified = lastModified;

  }

  /**

   * 同步的关键字synchronized的使用方式是什么样的??

   * @param size

   * @return

   */

  final synchronized byte[] addBuffer(int size) {

    byte[] buffer = newBuffer(size);

    if (directory!=null)

      synchronized (directory) {             // Ensure addition of buffer and adjustment to directory size are atomic wrt directory

        buffers.add(buffer);

        directory.sizeInBytes += size;

        sizeInBytes += size;

      }

    else

      buffers.add(buffer);

    return buffer;

  }

  final synchronized byte[] getBuffer(int index) {

    return (byte[]) buffers.get(index);

  }

  final synchronized int numBuffers() {

    return buffers.size();

  }

  /**

   * Expert: allocate a new buffer. 

   * Subclasses can allocate differently. 

   * @param size size of allocated buffer.

   * @return allocated buffer.

   */

  byte[] newBuffer(int size) {

    return new byte[size];

  }

  // Only valid if in a directory

  long getSizeInBytes() {

    synchronized (directory) {

      return sizeInBytes;

    }

  }

  

}

 private ArrayList buffers = new ArrayList();

这个buffers对象是最重要的,它保存了File对象中的所有数据信息。RAMOutputStreamRAMInputStream都是对这个buffers对象进行操作。

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

历史上的今天

评论

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

页脚

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