/** * 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.IndexInput; import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.IntsRef; import org.sindice.siren.index.codecs.block.BlockDecompressor; import org.sindice.siren.index.codecs.block.BlockIndexInput; import org.sindice.siren.util.ArrayUtils; /** * Implementation of the {@link BlockIndexInput} for the .pos file of the SIREn * postings format. */ public class PosBlockIndexInput extends BlockIndexInput { protected BlockDecompressor posDecompressor; public PosBlockIndexInput(final IndexInput in, final BlockDecompressor posDecompressor) throws IOException { super(in); this.posDecompressor = posDecompressor; } @Override public PosBlockReader getBlockReader() { // Clone index input. A cloned index input does not need to be closed // by the block reader, as the underlying stream will be closed by the // input it was cloned from return new PosBlockReader(in.clone()); } /** * Implementation of the {@link BlockReader} for the .pos file. * * <p> * * Read and decode blocks containing the the term positions. */ protected class PosBlockReader extends BlockReader { int posBlockSize; IntsRef posBuffer = new IntsRef(); boolean posReadPending = true; int posCompressedBufferLength; BytesRef posCompressedBuffer = new BytesRef(); private int currentPos = 0; private PosBlockReader(final IndexInput in) { super(in); // ensure that the output buffers has the minimum size required posBuffer = ArrayUtils.grow(posBuffer, posDecompressor.getWindowSize()); } @Override protected void readHeader() throws IOException { // logger.debug("Decode Pos header: {}", this.hashCode()); // logger.debug("Pos header start at {}", in.getFilePointer()); // read blockSize and check buffer size posBlockSize = in.readVInt(); // ensure that the output buffer has the minimum size required final int posLength = this.getMinimumBufferSize(posBlockSize, posDecompressor.getWindowSize()); posBuffer = ArrayUtils.grow(posBuffer, posLength); // logger.debug("Read Pos block size: {}", posBlockSize); // read size of each compressed data block and check buffer size posCompressedBufferLength = in.readVInt(); posCompressedBuffer = ArrayUtils.grow(posCompressedBuffer, posCompressedBufferLength); posReadPending = true; } @Override protected void skipData() throws IOException { long size = 0; if (posReadPending) { size += posCompressedBufferLength; } this.seek(in.getFilePointer() + size); // logger.debug("Skip Pos data: {}", in.getFilePointer() + size); } /** * Decode and return the next position of the current block. */ public int nextPosition() throws IOException { if (posReadPending) { this.decodePositions(); } assert posBuffer.offset <= posBuffer.length; return currentPos = posBuffer.ints[posBuffer.offset++] + currentPos; } private void decodePositions() throws IOException { // logger.debug("Decode Pos: {}", this.hashCode()); in.readBytes(posCompressedBuffer.bytes, 0, posCompressedBufferLength); posCompressedBuffer.offset = 0; posCompressedBuffer.length = posCompressedBufferLength; posDecompressor.decompress(posCompressedBuffer, posBuffer); // set length limit based on block size, as certain decompressor with // large window size can set it larger than the blockSize, e.g., AFor posBuffer.length = posBlockSize; posReadPending = false; } @Override public boolean isExhausted() { return posBuffer.offset >= posBuffer.length; } @Override protected void initBlock() { posBuffer.offset = posBuffer.length = 0; this.resetCurrentPosition(); posReadPending = true; posCompressedBufferLength = 0; } public void resetCurrentPosition() { currentPos = 0; } } }