/*
* Copyright 2004-2009 the original author or authors.
*
* Licensed 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.compass.needle.coherence;
import java.io.IOException;
import org.apache.lucene.store.IndexInput;
/**
* @author kimchy
*/
class CoherenceIndexInput extends IndexInput {
private CoherenceDirectory dir;
private FileHeaderKey fileHeaderKey;
private FileHeaderValue fileHeaderValue;
private long position;
private FileBucketKey fileBucketKey;
private FileBucketValue fileBucketValue;
private int currentBucketPosition;
public CoherenceIndexInput(CoherenceDirectory dir, FileHeaderKey fileHeaderKey, FileHeaderValue fileHeaderValue) {
this.dir = dir;
this.fileHeaderKey = fileHeaderKey;
this.fileHeaderValue = fileHeaderValue;
this.fileBucketKey = new FileBucketKey(fileHeaderKey.getIndexName(), fileHeaderKey.getFileName(), -1);
}
public void close() throws IOException {
}
/**
* Returns the current position in this file, where the next read will
* occur.
*
* @see #seek(long)
*/
public long getFilePointer() {
return this.position;
}
/**
* The number of bytes in the file.
*/
public long length() {
return fileHeaderValue.getSize();
}
/**
* Reads and returns a single byte.
*
* @see org.apache.lucene.store.IndexOutput#writeByte(byte)
*/
public byte readByte() throws IOException {
loadBucketIfNeeded();
position++;
return fileBucketValue.getData()[currentBucketPosition++];
}
/**
* Reads a specified number of bytes into an array at the specified
* offset.
*
* @param b the array to read bytes into
* @param offset the offset in the array to start storing bytes
* @param len the number of bytes to read
* @see org.apache.lucene.store.IndexOutput#writeBytes(byte[],int)
*/
public void readBytes(byte[] b, int offset, int len) throws IOException {
loadBucketIfNeeded();
// if there is enough place to load at once
if (len <= (dir.getBucketSize() - currentBucketPosition)) {
if (len > 0) {
System.arraycopy(fileBucketValue.getData(), currentBucketPosition, b, offset, len);
}
currentBucketPosition += len;
position += len;
return;
}
// cycle through the reads
while (true) {
int available = dir.getBucketSize() - currentBucketPosition;
int sizeToRead = (len <= available) ? len : available;
System.arraycopy(fileBucketValue.getData(), currentBucketPosition, b, offset, sizeToRead);
len -= sizeToRead;
offset += sizeToRead;
position += sizeToRead;
currentBucketPosition += sizeToRead;
// check if we read enough, if we did, bail
if (len <= 0) {
break;
}
loadBucketIfNeeded();
}
}
/**
* Sets current position in this file, where the next read will occur.
*
* @see #getFilePointer()
*/
public void seek(long pos) throws IOException {
position = pos;
}
private void loadBucketIfNeeded() throws IOException {
currentBucketPosition = (int) position % dir.getBucketSize();
long bucketIndex = position / dir.getBucketSize();
// check if we need to load the bucket
if (bucketIndex == fileBucketKey.getBucketIndex()) {
return;
}
fileBucketKey = new FileBucketKey(fileHeaderKey.getIndexName(), fileHeaderKey.getFileName(), bucketIndex);
try {
fileBucketValue = (FileBucketValue) dir.getCache().get(fileBucketKey);
} catch (Exception e) {
throw new CoherenceDirectoryException(fileBucketKey.getIndexName(), fileBucketKey.getFileName(),
"Failed to read bucket [" + bucketIndex + "]", e);
}
if (fileBucketValue == null) {
throw new CoherenceDirectoryException(fileBucketKey.getIndexName(), fileBucketKey.getFileName(), "Bucket [" + bucketIndex
+ "] not found");
}
}
public Object clone() {
CoherenceIndexInput indexInput = (CoherenceIndexInput) super.clone();
indexInput.fileBucketKey = new FileBucketKey(fileHeaderKey.getIndexName(), fileHeaderKey.getFileName(), -1);
return indexInput;
}
}