/*
 * 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.
 */
package org.apache.lucene.store;


import java.io.EOFException;
import java.io.IOException;

import static org.apache.lucene.store.RAMOutputStream.BUFFER_SIZE;

A memory-resident IndexInput implementation.
@lucene.internal
Deprecated:This class uses inefficient synchronization and is discouraged in favor of MMapDirectory. It will be removed in future versions of Lucene.
/** * A memory-resident {@link IndexInput} implementation. * * @lucene.internal * @deprecated This class uses inefficient synchronization and is discouraged * in favor of {@link MMapDirectory}. It will be removed in future versions * of Lucene. */
@Deprecated public class RAMInputStream extends IndexInput implements Cloneable { private final RAMFile file; private final long length; private byte[] currentBuffer; private int currentBufferIndex; private int bufferPosition; private int bufferLength; public RAMInputStream(String name, RAMFile f) throws IOException { this(name, f, f.length); } RAMInputStream(String name, RAMFile f, long length) throws IOException { super("RAMInputStream(name=" + name + ")"); this.file = f; this.length = length; if (length/BUFFER_SIZE >= Integer.MAX_VALUE) { throw new IOException("RAMInputStream too large length=" + length + ": " + name); } setCurrentBuffer(); } @Override public void close() { // nothing to do here } @Override public long length() { return length; } @Override public byte readByte() throws IOException { if (bufferPosition == bufferLength) { nextBuffer(); } if (currentBuffer == null) { throw new EOFException(); } else { return currentBuffer[bufferPosition++]; } } @Override public void readBytes(byte[] b, int offset, int len) throws IOException { while (len > 0) { if (bufferPosition == bufferLength) { nextBuffer(); } if (currentBuffer == null) { throw new EOFException(); } int remainInBuffer = bufferLength - bufferPosition; int bytesToCopy = len < remainInBuffer ? len : remainInBuffer; System.arraycopy(currentBuffer, bufferPosition, b, offset, bytesToCopy); offset += bytesToCopy; len -= bytesToCopy; bufferPosition += bytesToCopy; } } @Override public long getFilePointer() { return (long) currentBufferIndex * BUFFER_SIZE + bufferPosition; } @Override public void seek(long pos) throws IOException { int newBufferIndex = (int) (pos / BUFFER_SIZE); if (newBufferIndex != currentBufferIndex) { // we seek'd to a different buffer: currentBufferIndex = newBufferIndex; setCurrentBuffer(); } bufferPosition = (int) (pos % BUFFER_SIZE); // This is not >= because seeking to exact end of file is OK: this is where // you'd also be if you did a readBytes of all bytes in the file if (getFilePointer() > length()) { throw new EOFException("seek beyond EOF: pos=" + getFilePointer() + " vs length=" + length() + ": " + this); } } private void nextBuffer() throws IOException { // This is >= because we are called when there is at least 1 more byte to read: if (getFilePointer() >= length()) { throw new EOFException("cannot read another byte at EOF: pos=" + getFilePointer() + " vs length=" + length() + ": " + this); } currentBufferIndex++; setCurrentBuffer(); assert currentBuffer != null; bufferPosition = 0; } private final void setCurrentBuffer() throws IOException { if (currentBufferIndex < file.numBuffers()) { currentBuffer = file.getBuffer(currentBufferIndex); assert currentBuffer != null; long bufferStart = (long) BUFFER_SIZE * (long) currentBufferIndex; bufferLength = (int) Math.min(BUFFER_SIZE, length - bufferStart); } else { currentBuffer = null; } } @Override public IndexInput slice(String sliceDescription, final long offset, final long sliceLength) throws IOException { if (offset < 0 || sliceLength < 0 || offset + sliceLength > this.length) { throw new IllegalArgumentException("slice() " + sliceDescription + " out of bounds: " + this); } return new RAMInputStream(getFullSliceDescription(sliceDescription), file, offset + sliceLength) { { seek(0L); } @Override public void seek(long pos) throws IOException { if (pos < 0L) { throw new IllegalArgumentException("Seeking to negative position: " + this); } super.seek(pos + offset); } @Override public long getFilePointer() { return super.getFilePointer() - offset; } @Override public long length() { return sliceLength; } @Override public IndexInput slice(String sliceDescription, long ofs, long len) throws IOException { return super.slice(sliceDescription, offset + ofs, len); } }; } }