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

anqiang专栏

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

 
 
 

日志

 
 

RAMOutputStream源码分析  

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

  下载LOFTER 我的照片书  |

RAMOutputStream也是在内存上进行操作,将一块儿内存的内容输出到RAMFile对象的Buffers中去,感觉这有点像搬家,只不过没搬很远而已,仅仅在中国这个圈儿里面转悠,对于BufferedIndexOutput,它是对硬件存储介质进行操作,所以它会搬得比较远一点,可能是搬到美国或者非洲去了(相信有一天我会把自己搬到美国或者欧洲什么地方,人生这么长,可能性会很大)。

言归正传,先展示一下源码:

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;

/**

 * A memory-resident {@link IndexOutput} implementation.

 * 

 * @version $Id: RAMOutputStream.java 691694 2008-09-03 17:34:29Z mikemccand $

 * Andrew Wang

 */

public class RAMOutputStream extends IndexOutput {

/**

 * 一小块的内存bulk的大小为1KB

 */

  static final int BUFFER_SIZE = 1024;

  private RAMFile file;

  /**

   * 这个是当前RAMFile的bulk,它是一个byte的数组

   */

  private byte[] currentBuffer;

  /**

   * 当前RAMFile的bulk的Index,在这里起名叫bufferIndex有点不妥

   */

  private int currentBufferIndex;

  

  /**

   * 这个bufferPosition是当前currentBuffer的指针位置

   */

  private int bufferPosition;

  private long bufferStart;

  private int bufferLength;

  /** Construct an empty output buffer. */

  public RAMOutputStream() {

    this(new RAMFile());

  }

  RAMOutputStream(RAMFile f) {

    file = f;

    // make sure that we switch to the

    // first needed buffer lazily

    currentBufferIndex = -1;

    currentBuffer = null;

  }

  /** Copy the current contents of this buffer to the named output. */

  /**

   * 将内存文件RAMFile中的内容全部写入到其它介质中去

   * 由于RAMFile每个bulk的大小为1KB,所以每次写入的大小为1KB

   */

  public void writeTo(IndexOutput out) throws IOException {

    flush();

    final long end = file.length;

    long pos = 0;

    int buffer = 0;

    /**

     * 写入的原理如下:

     * 当写入的大小大于BUFFER_SIZE时,每次写入的大小为1KB

     * 当写入的大小小于BUFFER_SIZE时,写入当前大小数量的bytes

     */

    while (pos < end) {

      int length = BUFFER_SIZE;

      long nextPos = pos + length;

      if (nextPos > end) {                        // at the last buffer

        length = (int)(end - pos);

      }

      out.writeBytes((byte[])file.getBuffer(buffer++), length);

      pos = nextPos;

    }

  }

  /** Resets this to an empty buffer. */

  public void reset() {

    try {

      seek(0);

    } catch (IOException e) {                     // should never happen

      throw new RuntimeException(e.toString());

    }

    file.setLength(0);

  }

  public void close() throws IOException {

    flush();

  }

  public void seek(long pos) throws IOException {

    // set the file length in case we seek back

    // and flush() has not been called yet

    setFileLength();

    if (pos < bufferStart || pos >= bufferStart + bufferLength) {

      currentBufferIndex = (int) (pos / BUFFER_SIZE);

      switchCurrentBuffer();

    }

    bufferPosition = (int) (pos % BUFFER_SIZE);

  }

  public long length() {

    return file.length;

  }

  /**

   * 写入一个byte到当前文件中RAMFile

   * 处理方式和writeBytes(byte[], int offset, int length)

   */

  public void writeByte(byte b) throws IOException {

    if (bufferPosition == bufferLength) {

      currentBufferIndex++;

      switchCurrentBuffer();

    }

    currentBuffer[bufferPosition++] = b;

  }

  /**

   * 流程如下:

   * 1.判断是否还有信息需要写入;

   * 2.如果有,判断当前bufferPosition的位置是否已经到了RAMFile当前bulk的末尾

   * 3.如果已经到了末尾,则将当前RAMFile的bulkIndex加1,切换到下一个块

   * 4.如果没有到末尾,则将信息写入RAMFile的当前块中;

   * 5.判断是否所有信息全部写入

   */

  public void writeBytes(byte[] b, int offset, int len) throws IOException {

    assert b != null;

    while (len > 0) {

     /**

      * 如果当前buffer已满,则转换到下一个buffer

      */

      if (bufferPosition ==  bufferLength) {

        currentBufferIndex++;

        switchCurrentBuffer();

      }

      /**

       * 查看剩余当前buffer的大小

       */

      int remainInBuffer = currentBuffer.length - bufferPosition;

      /**

       * 得到当前需要读入的byte的数量

       */

      int bytesToCopy = len < remainInBuffer ? len : remainInBuffer;

      System.arraycopy(b, offset, currentBufferbufferPosition, bytesToCopy);

      offset += bytesToCopy;

      len -= bytesToCopy;

      bufferPosition += bytesToCopy;

    }

  }

  /**

   * 跳转到当前的buffer块

   * 流程如下:

   * 1.先判断是否已经到了RAMFile所有块队列的末尾;

   * 2.如果到了队列末尾,则加入一个新的块;

   * 3.如果没有,则将当前currentBufferIndex指向该块;将currentBuffer指向该块内存地址;

   * 

   * @throws IOException

   */

  private final void switchCurrentBuffer() throws IOException {

    /**

     * 如果当前已经file的Buffer[]数组已经使用完,则创建一个新的块

     */

  if (currentBufferIndex == file.numBuffers()) {

  /**

   * 从这里可以知道RAMFile每个块的大小为BUFFER_SIZE = 1KB

   */

      currentBuffer = file.addBuffer(BUFFER_SIZE);

    } else {

     /**

      * 否则到达当前块

      */

      currentBuffer = (byte[]) file.getBuffer(currentBufferIndex);

    }

  /**

   * 初始化当前buffer的指针位置和buffer的长度

   */

    bufferPosition = 0;

    bufferStart = (longBUFFER_SIZE * (longcurrentBufferIndex;

    bufferLength = currentBuffer.length;

  }

  private void setFileLength() {

    long pointer = bufferStart + bufferPosition;

    if (pointer > file.length) {

      file.setLength(pointer);

    }

  }

  public void flush() throws IOException {

    file.setLastModified(System.currentTimeMillis());

    setFileLength();

  }

  public long getFilePointer() {

    return currentBufferIndex < 0 ? 0 : bufferStart + bufferPosition;

  }

  /** Returns byte usage of all buffers. */

  public long sizeInBytes() {

    return file.numBuffers() * BUFFER_SIZE;

  }

}

public void writeTo(IndexOutput out) throws IOException

这个函数是将当前RAMFile中所用的信息都写入到IndexOutput对象中去。每次写入的大小为1KB,以后我们会看到BufferedIndexOutputbuffer大小为16KB,这样就避免了频繁的硬盘操作

public void seek(long pos) throws IOException

这个函数的流程如下:

1.先定位到pos所在的块

2.跳转到目的块

3.将当前块的position设置为 pos%BUFFER_SIZE

public void writeBytes(byte[] b, int offset, int len) throws IOException

这个函数写入一个bytes数组的内容到当前RAMFile

private final void switchCurrentBuffer() throws IOException

这个函数实现了切换块儿的操作

总的来说,在RAMOutputStream中没有buffer的概念,每次都是对RAMFile当前bulk的操作,在这里我以为代码编写者将bulk写成buffer是不妥的,可能会误导代码维护者,错误的以为它们是buffer。这个需要引起大家的注意。

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

历史上的今天

评论

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

页脚

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