| using Lucene.Net.Support; |
| using System; |
| using ArrayUtil = Lucene.Net.Util.ArrayUtil; |
| |
| namespace Lucene.Net.Codecs.Compressing |
| { |
| /* |
| * 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. |
| */ |
| |
| using CorruptIndexException = Lucene.Net.Index.CorruptIndexException; |
| using IndexInput = Lucene.Net.Store.IndexInput; |
| using PackedInt32s = Lucene.Net.Util.Packed.PackedInt32s; |
| using RamUsageEstimator = Lucene.Net.Util.RamUsageEstimator; |
| using SegmentInfo = Lucene.Net.Index.SegmentInfo; |
| |
| /// <summary> |
| /// Random-access reader for <see cref="CompressingStoredFieldsIndexWriter"/>. |
| /// <para/> |
| /// @lucene.internal |
| /// </summary> |
| public sealed class CompressingStoredFieldsIndexReader |
| #if FEATURE_CLONEABLE |
| : System.ICloneable |
| #endif |
| { |
| internal static long MoveLowOrderBitToSign(long n) |
| { |
| return (((long)((ulong)n >> 1)) ^ -(n & 1)); |
| } |
| |
| internal readonly int maxDoc; |
| internal readonly int[] docBases; |
| internal readonly long[] startPointers; |
| internal readonly int[] avgChunkDocs; |
| internal readonly long[] avgChunkSizes; |
| internal readonly PackedInt32s.Reader[] docBasesDeltas; // delta from the avg |
| internal readonly PackedInt32s.Reader[] startPointersDeltas; // delta from the avg |
| |
| // It is the responsibility of the caller to close fieldsIndexIn after this constructor |
| // has been called |
| internal CompressingStoredFieldsIndexReader(IndexInput fieldsIndexIn, SegmentInfo si) |
| { |
| maxDoc = si.DocCount; |
| int[] docBases = new int[16]; |
| long[] startPointers = new long[16]; |
| int[] avgChunkDocs = new int[16]; |
| long[] avgChunkSizes = new long[16]; |
| PackedInt32s.Reader[] docBasesDeltas = new PackedInt32s.Reader[16]; |
| PackedInt32s.Reader[] startPointersDeltas = new PackedInt32s.Reader[16]; |
| |
| int packedIntsVersion = fieldsIndexIn.ReadVInt32(); |
| |
| int blockCount = 0; |
| |
| for (; ; ) |
| { |
| int numChunks = fieldsIndexIn.ReadVInt32(); |
| if (numChunks == 0) |
| { |
| break; |
| } |
| if (blockCount == docBases.Length) |
| { |
| int newSize = ArrayUtil.Oversize(blockCount + 1, 8); |
| docBases = Arrays.CopyOf(docBases, newSize); |
| startPointers = Arrays.CopyOf(startPointers, newSize); |
| avgChunkDocs = Arrays.CopyOf(avgChunkDocs, newSize); |
| avgChunkSizes = Arrays.CopyOf(avgChunkSizes, newSize); |
| docBasesDeltas = Arrays.CopyOf(docBasesDeltas, newSize); |
| startPointersDeltas = Arrays.CopyOf(startPointersDeltas, newSize); |
| } |
| |
| // doc bases |
| docBases[blockCount] = fieldsIndexIn.ReadVInt32(); |
| avgChunkDocs[blockCount] = fieldsIndexIn.ReadVInt32(); |
| int bitsPerDocBase = fieldsIndexIn.ReadVInt32(); |
| if (bitsPerDocBase > 32) |
| { |
| throw new CorruptIndexException("Corrupted bitsPerDocBase (resource=" + fieldsIndexIn + ")"); |
| } |
| docBasesDeltas[blockCount] = PackedInt32s.GetReaderNoHeader(fieldsIndexIn, PackedInt32s.Format.PACKED, packedIntsVersion, numChunks, bitsPerDocBase); |
| |
| // start pointers |
| startPointers[blockCount] = fieldsIndexIn.ReadVInt64(); |
| avgChunkSizes[blockCount] = fieldsIndexIn.ReadVInt64(); |
| int bitsPerStartPointer = fieldsIndexIn.ReadVInt32(); |
| if (bitsPerStartPointer > 64) |
| { |
| throw new CorruptIndexException("Corrupted bitsPerStartPointer (resource=" + fieldsIndexIn + ")"); |
| } |
| startPointersDeltas[blockCount] = PackedInt32s.GetReaderNoHeader(fieldsIndexIn, PackedInt32s.Format.PACKED, packedIntsVersion, numChunks, bitsPerStartPointer); |
| |
| ++blockCount; |
| } |
| |
| this.docBases = Arrays.CopyOf(docBases, blockCount); |
| this.startPointers = Arrays.CopyOf(startPointers, blockCount); |
| this.avgChunkDocs = Arrays.CopyOf(avgChunkDocs, blockCount); |
| this.avgChunkSizes = Arrays.CopyOf(avgChunkSizes, blockCount); |
| this.docBasesDeltas = Arrays.CopyOf(docBasesDeltas, blockCount); |
| this.startPointersDeltas = Arrays.CopyOf(startPointersDeltas, blockCount); |
| } |
| |
| private int Block(int docID) |
| { |
| int lo = 0, hi = docBases.Length - 1; |
| while (lo <= hi) |
| { |
| int mid = (int)((uint)(lo + hi) >> 1); |
| int midValue = docBases[mid]; |
| if (midValue == docID) |
| { |
| return mid; |
| } |
| else if (midValue < docID) |
| { |
| lo = mid + 1; |
| } |
| else |
| { |
| hi = mid - 1; |
| } |
| } |
| return hi; |
| } |
| |
| private int RelativeDocBase(int block, int relativeChunk) |
| { |
| int expected = avgChunkDocs[block] * relativeChunk; |
| long delta = MoveLowOrderBitToSign(docBasesDeltas[block].Get(relativeChunk)); |
| return expected + (int)delta; |
| } |
| |
| private long RelativeStartPointer(int block, int relativeChunk) |
| { |
| long expected = avgChunkSizes[block] * relativeChunk; |
| long delta = MoveLowOrderBitToSign(startPointersDeltas[block].Get(relativeChunk)); |
| return expected + delta; |
| } |
| |
| private int RelativeChunk(int block, int relativeDoc) |
| { |
| int lo = 0, hi = docBasesDeltas[block].Count - 1; |
| while (lo <= hi) |
| { |
| int mid = (int)((uint)(lo + hi) >> 1); |
| int midValue = RelativeDocBase(block, mid); |
| if (midValue == relativeDoc) |
| { |
| return mid; |
| } |
| else if (midValue < relativeDoc) |
| { |
| lo = mid + 1; |
| } |
| else |
| { |
| hi = mid - 1; |
| } |
| } |
| return hi; |
| } |
| |
| internal long GetStartPointer(int docID) |
| { |
| if (docID < 0 || docID >= maxDoc) |
| { |
| throw new ArgumentException("docID out of range [0-" + maxDoc + "]: " + docID); |
| } |
| int block = Block(docID); |
| int relativeChunk = RelativeChunk(block, docID - docBases[block]); |
| return startPointers[block] + RelativeStartPointer(block, relativeChunk); |
| } |
| |
| public object Clone() |
| { |
| return this; |
| } |
| |
| internal long RamBytesUsed() |
| { |
| long res = 0; |
| |
| foreach (PackedInt32s.Reader r in docBasesDeltas) |
| { |
| res += r.RamBytesUsed(); |
| } |
| foreach (PackedInt32s.Reader r in startPointersDeltas) |
| { |
| res += r.RamBytesUsed(); |
| } |
| |
| res += RamUsageEstimator.SizeOf(docBases); |
| res += RamUsageEstimator.SizeOf(startPointers); |
| res += RamUsageEstimator.SizeOf(avgChunkDocs); |
| res += RamUsageEstimator.SizeOf(avgChunkSizes); |
| |
| return res; |
| } |
| } |
| } |