blob: 5b2053365a09de2feb969edcd52a55af8752be0d [file] [log] [blame]
/*
* 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.geode.cache.lucene.internal.filesystem;
import java.io.EOFException;
import java.io.IOException;
/**
* An input stream that reads chunks from a File saved in the region. This input stream will keep
* going back to the region to look for chunks until nothing is found.
*/
class FileInputStream extends SeekableInputStream {
private final File file;
private byte[] chunk = null;
private int chunkPosition = 0;
private int chunkId = 0;
private boolean open = true;
public FileInputStream(File file) {
this.file = file;
nextChunk();
}
public FileInputStream(FileInputStream other) {
this.file = other.file;
this.chunk = other.chunk;
this.chunkId = other.chunkId;
this.chunkPosition = other.chunkPosition;
this.open = other.open;
}
@Override
public int read() throws IOException {
assertOpen();
checkAndFetchNextChunk();
if (null == chunk) {
return -1;
}
return chunk[chunkPosition++] & 0xff;
}
@Override
public void seek(long position) throws IOException {
if (position > file.length) {
throw new EOFException();
}
int targetChunk = (int) (position / file.getChunkSize());
int targetPosition = (int) (position % file.getChunkSize());
if (targetChunk != (this.chunkId - 1)) {
chunk = file.getFileSystem().getChunk(this.file, targetChunk);
chunkId = targetChunk + 1;
chunkPosition = targetPosition;
} else {
chunkPosition = targetPosition;
}
}
@Override
public long skip(long n) throws IOException {
int currentPosition = (chunkId - 1) * file.getChunkSize() + chunkPosition;
seek(currentPosition + n);
return n;
}
@Override
public void reset() throws IOException {
seek(0);
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
assertOpen();
checkAndFetchNextChunk();
if (null == chunk) {
return -1;
}
int read = 0;
while (len > 0) {
final int min = Math.min(remaining(), len);
System.arraycopy(chunk, chunkPosition, b, off, min);
off += min;
len -= min;
chunkPosition += min;
read += min;
if (len > 0) {
// we read to the end of the chunk, fetch another.
nextChunk();
if (null == chunk) {
break;
}
}
}
return read;
}
@Override
public int available() throws IOException {
assertOpen();
return remaining();
}
@Override
public void close() throws IOException {
if (open) {
open = false;
}
}
private int remaining() {
return chunk.length - chunkPosition;
}
private void checkAndFetchNextChunk() {
if (null != chunk && remaining() <= 0) {
nextChunk();
}
}
private void nextChunk() {
chunk = file.getFileSystem().getChunk(this.file, chunkId++);
chunkPosition = 0;
}
private void assertOpen() throws IOException {
if (!open) {
throw new IOException("Closed");
}
}
@Override
public FileInputStream clone() {
return new FileInputStream(this);
}
}