/**
* Copyright 2014 National University of Ireland, Galway.
*
* This file is part of the SIREn project. Project and contact information:
*
* https://github.com/rdelbru/SIREn
*
* 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.sindice.siren.index.codecs.siren10;
import java.io.IOException;
import org.apache.lucene.store.IndexOutput;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.IntsRef;
import org.sindice.siren.index.codecs.block.BlockCompressor;
import org.sindice.siren.index.codecs.block.BlockIndexOutput;
import org.sindice.siren.util.ArrayUtils;
/**
* Implementation of the {@link BlockIndexOutput} for the .pos file of the SIREn
* postings format.
*/
public class PosBlockIndexOutput extends BlockIndexOutput {
private final int maxBlockSize;
private final BlockCompressor posCompressor;
public PosBlockIndexOutput(final IndexOutput out, final int maxBlockSize,
final BlockCompressor posCompressor)
throws IOException {
super(out);
this.posCompressor = posCompressor;
this.maxBlockSize = maxBlockSize;
}
@Override
public PosBlockWriter getBlockWriter() {
return new PosBlockWriter();
}
/**
* Implementation of the {@link BlockWriter} for the .pos file.
*
* <p>
*
* Encode and write blocks containing the term positions.
*/
protected class PosBlockWriter extends BlockWriter {
IntsRef posBuffer;
BytesRef posCompressedBuffer;
private int currentPos = 0;
public PosBlockWriter() {
// ensure that the input buffers has the minimum size required
// maxBlockSize is just use as a minimum initial capacity for the buffers
posBuffer = new IntsRef(this.getMinimumBufferSize(maxBlockSize, posCompressor.getWindowSize()));
}
@Override
protected void writeHeader() throws IOException {
// logger.debug("Write Pos header: {}", this.hashCode());
// logger.debug("Pos header start at {}", out.getFilePointer());
// write block sizes
out.writeVInt(posBuffer.length);
// write size of compressed data block
out.writeVInt(posCompressedBuffer.length);
}
@Override
protected void compress() {
// Flip buffer before compression
posBuffer.length = posBuffer.offset;
posBuffer.offset = 0;
// determine max size of compressed buffer to avoid overflow
final int size = posCompressor.maxCompressedSize(posBuffer.length);
posCompressedBuffer = new BytesRef(size);
posCompressor.compress(posBuffer, posCompressedBuffer);
}
@Override
protected void writeData() throws IOException {
// logger.debug("Write Pos data: {}", this.hashCode());
out.writeBytes(posCompressedBuffer.bytes, posCompressedBuffer.length);
}
/**
* Add the term position to the buffer
*/
public void write(final int pos) {
if (posBuffer.offset >= posBuffer.ints.length) {
// Take the max to ensure that buffer will be large enough
int newLength = Math.max(posBuffer.offset + 1, posBuffer.ints.length * 3/2);
// ensure that the buffer is large enough to accomodate the window size
newLength = this.getMinimumBufferSize(newLength, posCompressor.getWindowSize());
ArrayUtils.growAndCopy(posBuffer, newLength);
}
posBuffer.ints[posBuffer.offset++] = pos - currentPos;
currentPos = pos;
}
@Override
protected void initBlock() {
posBuffer.offset = posBuffer.length = 0;
this.resetCurrentPosition();
}
public void resetCurrentPosition() {
currentPos = 0;
}
@Override
public boolean isEmpty() {
return posBuffer.offset == 0;
}
@Override
public boolean isFull() {
// this implementation is never full as it is synchronised with doc block
// and grows on demand
return false;
}
}
}