2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
20 using BufferedIndexInput = Mono.Lucene.Net.Store.BufferedIndexInput;
21 using IndexInput = Mono.Lucene.Net.Store.IndexInput;
23 namespace Mono.Lucene.Net.Index
26 /// <summary> This abstract class reads skip lists with multiple levels.
28 /// See {@link MultiLevelSkipListWriter} for the information about the encoding
29 /// of the multi level skip lists.
31 /// Subclasses must implement the abstract method {@link #ReadSkipData(int, IndexInput)}
32 /// which defines the actual format of the skip data.
34 abstract class MultiLevelSkipListReader
36 // the maximum number of skip levels possible for this index
37 private int maxNumberOfSkipLevels;
39 // number of levels in this skip list
40 private int numberOfSkipLevels;
42 // Expert: defines the number of top skip levels to buffer in memory.
43 // Reducing this number results in less memory usage, but possibly
44 // slower performance due to more random I/Os.
45 // Please notice that the space each level occupies is limited by
46 // the skipInterval. The top level can not contain more than
47 // skipLevel entries, the second top level can not contain more
48 // than skipLevel^2 entries and so forth.
49 private int numberOfLevelsToBuffer = 1;
52 private bool haveSkipped;
54 private IndexInput[] skipStream; // skipStream for each level
55 private long[] skipPointer; // the start pointer of each skip level
56 private int[] skipInterval; // skipInterval of each level
57 private int[] numSkipped; // number of docs skipped per level
59 private int[] skipDoc; // doc id of current skip entry per level
60 private int lastDoc; // doc id of last read skip entry with docId <= target
61 private long[] childPointer; // child pointer of current skip entry per level
62 private long lastChildPointer; // childPointer of last read skip entry with docId <= target
64 private bool inputIsBuffered;
66 public MultiLevelSkipListReader(IndexInput skipStream, int maxSkipLevels, int skipInterval)
68 this.skipStream = new IndexInput[maxSkipLevels];
69 this.skipPointer = new long[maxSkipLevels];
70 this.childPointer = new long[maxSkipLevels];
71 this.numSkipped = new int[maxSkipLevels];
72 this.maxNumberOfSkipLevels = maxSkipLevels;
73 this.skipInterval = new int[maxSkipLevels];
74 this.skipStream[0] = skipStream;
75 this.inputIsBuffered = (skipStream is BufferedIndexInput);
76 this.skipInterval[0] = skipInterval;
77 for (int i = 1; i < maxSkipLevels; i++)
79 // cache skip intervals
80 this.skipInterval[i] = this.skipInterval[i - 1] * skipInterval;
82 skipDoc = new int[maxSkipLevels];
86 /// <summary>Returns the id of the doc to which the last call of {@link #SkipTo(int)}
89 internal virtual int GetDoc()
95 /// <summary>Skips entries to the first beyond the current whose document number is
96 /// greater than or equal to <i>target</i>. Returns the current doc count.
98 internal virtual int SkipTo(int target)
102 // first time, load skip levels
107 // walk up the levels until highest level is found that has a skip
110 while (level < numberOfSkipLevels - 1 && target > skipDoc[level + 1])
117 if (target > skipDoc[level])
119 if (!LoadNextSkip(level))
126 // no more skips on this level, go down one level
127 if (level > 0 && lastChildPointer > skipStream[level - 1].GetFilePointer())
129 SeekChild(level - 1);
135 return numSkipped[0] - skipInterval[0] - 1;
138 private bool LoadNextSkip(int level)
140 // we have to skip, the target document is greater than the current
142 SetLastSkipData(level);
144 numSkipped[level] += skipInterval[level];
146 if (numSkipped[level] > docCount)
148 // this skip list is exhausted
149 skipDoc[level] = System.Int32.MaxValue;
150 if (numberOfSkipLevels > level)
151 numberOfSkipLevels = level;
155 // read next skip entry
156 skipDoc[level] += ReadSkipData(level, skipStream[level]);
160 // read the child pointer if we are not on the leaf level
161 childPointer[level] = skipStream[level].ReadVLong() + skipPointer[level - 1];
167 /// <summary>Seeks the skip entry on the given level </summary>
168 protected internal virtual void SeekChild(int level)
170 skipStream[level].Seek(lastChildPointer);
171 numSkipped[level] = numSkipped[level + 1] - skipInterval[level + 1];
172 skipDoc[level] = lastDoc;
175 childPointer[level] = skipStream[level].ReadVLong() + skipPointer[level - 1];
179 internal virtual void Close()
181 for (int i = 1; i < skipStream.Length; i++)
183 if (skipStream[i] != null)
185 skipStream[i].Close();
190 /// <summary>initializes the reader </summary>
191 internal virtual void Init(long skipPointer, int df)
193 this.skipPointer[0] = skipPointer;
195 System.Array.Clear(skipDoc, 0, skipDoc.Length);
196 System.Array.Clear(numSkipped, 0, numSkipped.Length);
197 System.Array.Clear(childPointer, 0, childPointer.Length);
200 for (int i = 1; i < numberOfSkipLevels; i++)
202 skipStream[i] = null;
206 /// <summary>Loads the skip levels </summary>
207 private void LoadSkipLevels()
209 numberOfSkipLevels = docCount == 0?0:(int) System.Math.Floor(System.Math.Log(docCount) / System.Math.Log(skipInterval[0]));
210 if (numberOfSkipLevels > maxNumberOfSkipLevels)
212 numberOfSkipLevels = maxNumberOfSkipLevels;
215 skipStream[0].Seek(skipPointer[0]);
217 int toBuffer = numberOfLevelsToBuffer;
219 for (int i = numberOfSkipLevels - 1; i > 0; i--)
221 // the length of the current level
222 long length = skipStream[0].ReadVLong();
224 // the start pointer of the current level
225 skipPointer[i] = skipStream[0].GetFilePointer();
229 skipStream[i] = new SkipBuffer(skipStream[0], (int) length);
234 // clone this stream, it is already at the start of the current level
235 skipStream[i] = (IndexInput) skipStream[0].Clone();
236 if (inputIsBuffered && length < BufferedIndexInput.BUFFER_SIZE)
238 ((BufferedIndexInput) skipStream[i]).SetBufferSize((int) length);
241 // move base stream beyond the current level
242 skipStream[0].Seek(skipStream[0].GetFilePointer() + length);
246 // use base stream for the lowest level
247 skipPointer[0] = skipStream[0].GetFilePointer();
250 /// <summary> Subclasses must implement the actual skip data encoding in this method.
253 /// <param name="level">the level skip data shall be read from
255 /// <param name="skipStream">the skip stream to read from
257 protected internal abstract int ReadSkipData(int level, IndexInput skipStream);
259 /// <summary>Copies the values of the last read skip entry on this level </summary>
260 protected internal virtual void SetLastSkipData(int level)
262 lastDoc = skipDoc[level];
263 lastChildPointer = childPointer[level];
267 /// <summary>used to buffer the top skip levels </summary>
268 private sealed class SkipBuffer:IndexInput
271 private long pointer;
274 internal SkipBuffer(IndexInput input, int length)
276 data = new byte[length];
277 pointer = input.GetFilePointer();
278 input.ReadBytes(data, 0, length);
281 public override void Close()
286 public override long GetFilePointer()
288 return pointer + pos;
291 public override long Length()
296 public override byte ReadByte()
301 public override void ReadBytes(byte[] b, int offset, int len)
303 Array.Copy(data, pos, b, offset, len);
307 public override void Seek(long pos)
309 this.pos = (int) (pos - pointer);
312 override public System.Object Clone()
314 System.Diagnostics.Debug.Fail("Port issue:", "Lets see if we need this FilterIndexReader.Clone()"); // {{Aroush-2.9}}