| /* |
| * 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.backward_codecs.lucene84; |
| |
| import java.io.IOException; |
| import java.util.Arrays; |
| import org.apache.lucene.codecs.MultiLevelSkipListReader; |
| import org.apache.lucene.store.IndexInput; |
| |
| /** |
| * Implements the skip list reader for block postings format that stores positions and payloads. |
| * |
| * <p>Although this skipper uses MultiLevelSkipListReader as an interface, its definition of skip |
| * position will be a little different. |
| * |
| * <p>For example, when skipInterval = blockSize = 3, df = 2*skipInterval = 6, |
| * |
| * <pre> |
| * 0 1 2 3 4 5 |
| * d d d d d d (posting list) |
| * ^ ^ (skip point in MultiLeveSkipWriter) |
| * ^ (skip point in Lucene84SkipWriter) |
| * </pre> |
| * |
| * <p>In this case, MultiLevelSkipListReader will use the last document as a skip point, while |
| * Lucene84SkipReader should assume no skip point will comes. |
| * |
| * <p>If we use the interface directly in Lucene84SkipReader, it may silly try to read another skip |
| * data after the only skip point is loaded. |
| * |
| * <p>To illustrate this, we can call skipTo(d[5]), since skip point d[3] has smaller docId, and |
| * numSkipped+blockSize== df, the MultiLevelSkipListReader will assume the skip list isn't exhausted |
| * yet, and try to load a non-existed skip point |
| * |
| * <p>Therefore, we'll trim df before passing it to the interface. see trim(int) |
| */ |
| class Lucene84SkipReader extends MultiLevelSkipListReader { |
| private long docPointer[]; |
| private long posPointer[]; |
| private long payPointer[]; |
| private int posBufferUpto[]; |
| private int payloadByteUpto[]; |
| |
| private long lastPosPointer; |
| private long lastPayPointer; |
| private int lastPayloadByteUpto; |
| private long lastDocPointer; |
| private int lastPosBufferUpto; |
| |
| public Lucene84SkipReader( |
| IndexInput skipStream, |
| int maxSkipLevels, |
| boolean hasPos, |
| boolean hasOffsets, |
| boolean hasPayloads) { |
| super(skipStream, maxSkipLevels, ForUtil.BLOCK_SIZE, 8); |
| docPointer = new long[maxSkipLevels]; |
| if (hasPos) { |
| posPointer = new long[maxSkipLevels]; |
| posBufferUpto = new int[maxSkipLevels]; |
| if (hasPayloads) { |
| payloadByteUpto = new int[maxSkipLevels]; |
| } else { |
| payloadByteUpto = null; |
| } |
| if (hasOffsets || hasPayloads) { |
| payPointer = new long[maxSkipLevels]; |
| } else { |
| payPointer = null; |
| } |
| } else { |
| posPointer = null; |
| } |
| } |
| |
| /** |
| * Trim original docFreq to tell skipReader read proper number of skip points. |
| * |
| * <p>Since our definition in Lucene84Skip* is a little different from MultiLevelSkip* This |
| * trimmed docFreq will prevent skipReader from: 1. silly reading a non-existed skip point after |
| * the last block boundary 2. moving into the vInt block |
| */ |
| protected int trim(int df) { |
| return df % ForUtil.BLOCK_SIZE == 0 ? df - 1 : df; |
| } |
| |
| public void init( |
| long skipPointer, long docBasePointer, long posBasePointer, long payBasePointer, int df) |
| throws IOException { |
| super.init(skipPointer, trim(df)); |
| lastDocPointer = docBasePointer; |
| lastPosPointer = posBasePointer; |
| lastPayPointer = payBasePointer; |
| |
| Arrays.fill(docPointer, docBasePointer); |
| if (posPointer != null) { |
| Arrays.fill(posPointer, posBasePointer); |
| if (payPointer != null) { |
| Arrays.fill(payPointer, payBasePointer); |
| } |
| } else { |
| assert posBasePointer == 0; |
| } |
| } |
| |
| /** |
| * Returns the doc pointer of the doc to which the last call of {@link |
| * MultiLevelSkipListReader#skipTo(int)} has skipped. |
| */ |
| public long getDocPointer() { |
| return lastDocPointer; |
| } |
| |
| public long getPosPointer() { |
| return lastPosPointer; |
| } |
| |
| public int getPosBufferUpto() { |
| return lastPosBufferUpto; |
| } |
| |
| public long getPayPointer() { |
| return lastPayPointer; |
| } |
| |
| public int getPayloadByteUpto() { |
| return lastPayloadByteUpto; |
| } |
| |
| public int getNextSkipDoc() { |
| return skipDoc[0]; |
| } |
| |
| @Override |
| protected void seekChild(int level) throws IOException { |
| super.seekChild(level); |
| docPointer[level] = lastDocPointer; |
| if (posPointer != null) { |
| posPointer[level] = lastPosPointer; |
| posBufferUpto[level] = lastPosBufferUpto; |
| if (payloadByteUpto != null) { |
| payloadByteUpto[level] = lastPayloadByteUpto; |
| } |
| if (payPointer != null) { |
| payPointer[level] = lastPayPointer; |
| } |
| } |
| } |
| |
| @Override |
| protected void setLastSkipData(int level) { |
| super.setLastSkipData(level); |
| lastDocPointer = docPointer[level]; |
| |
| if (posPointer != null) { |
| lastPosPointer = posPointer[level]; |
| lastPosBufferUpto = posBufferUpto[level]; |
| if (payPointer != null) { |
| lastPayPointer = payPointer[level]; |
| } |
| if (payloadByteUpto != null) { |
| lastPayloadByteUpto = payloadByteUpto[level]; |
| } |
| } |
| } |
| |
| @Override |
| protected int readSkipData(int level, IndexInput skipStream) throws IOException { |
| int delta = skipStream.readVInt(); |
| docPointer[level] += skipStream.readVLong(); |
| |
| if (posPointer != null) { |
| posPointer[level] += skipStream.readVLong(); |
| posBufferUpto[level] = skipStream.readVInt(); |
| |
| if (payloadByteUpto != null) { |
| payloadByteUpto[level] = skipStream.readVInt(); |
| } |
| |
| if (payPointer != null) { |
| payPointer[level] += skipStream.readVLong(); |
| } |
| } |
| readImpacts(level, skipStream); |
| return delta; |
| } |
| |
| // The default impl skips impacts |
| protected void readImpacts(int level, IndexInput skipStream) throws IOException { |
| skipStream.skipBytes(skipStream.readVInt()); |
| } |
| } |