Lucene.Net  3.0.3
Lucene.Net is a .NET port of the Java Lucene Indexing Library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties
ByteBlockPool.cs
Go to the documentation of this file.
1 /*
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
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17 
18 
19 /* Class that Posting and PostingVector use to write byte
20 * streams into shared fixed-size byte[] arrays. The idea
21 * is to allocate slices of increasing lengths For
22 * example, the first slice is 5 bytes, the next slice is
23 * 14, etc. We start by writing our bytes into the first
24 * 5 bytes. When we hit the end of the slice, we allocate
25 * the next slice and then write the address of the new
26 * slice into the last 4 bytes of the previous slice (the
27 * "forwarding address").
28 *
29 * Each slice is filled with 0's initially, and we mark
30 * the end with a non-zero byte. This way the methods
31 * that are writing into the slice don't need to record
32 * its length and instead allocate a new slice once they
33 * hit a non-zero byte. */
34 
35 using System;
36 using System.Collections.Generic;
37 using Lucene.Net.Support;
38 
39 namespace Lucene.Net.Index
40 {
41 
42  sealed public class ByteBlockPool
43  {
44  private void InitBlock()
45  {
46  byteUpto = DocumentsWriter.BYTE_BLOCK_SIZE;
47  }
48 
49  public /*internal*/ abstract class Allocator
50  {
51  public /*internal*/ abstract void RecycleByteBlocks(byte[][] blocks, int start, int end);
52  public /*internal*/ abstract void RecycleByteBlocks(IList<byte[]> blocks);
53  public /*internal*/ abstract byte[] GetByteBlock(bool trackAllocations);
54  }
55 
56  public byte[][] buffers = new byte[10][];
57 
58  internal int bufferUpto = - 1; // Which buffer we are upto
59  public int byteUpto; // Where we are in head buffer
60 
61  public byte[] buffer; // Current head buffer
62  public int byteOffset = - DocumentsWriter.BYTE_BLOCK_SIZE; // Current head offset
63 
64  private readonly bool trackAllocations;
65  private readonly Allocator allocator;
66 
67  public ByteBlockPool(Allocator allocator, bool trackAllocations)
68  {
69  InitBlock();
70  this.allocator = allocator;
71  this.trackAllocations = trackAllocations;
72  }
73 
74  public void Reset()
75  {
76  if (bufferUpto != - 1)
77  {
78  // We allocated at least one buffer
79 
80  for (int i = 0; i < bufferUpto; i++)
81  // Fully zero fill buffers that we fully used
82  System.Array.Clear(buffers[i], 0, buffers[i].Length);
83 
84  // Partial zero fill the final buffer
85  System.Array.Clear(buffers[bufferUpto], 0, byteUpto);
86 
87  if (bufferUpto > 0)
88  // Recycle all but the first buffer
89  allocator.RecycleByteBlocks(buffers, 1, 1 + bufferUpto);
90 
91  // Re-use the first buffer
92  bufferUpto = 0;
93  byteUpto = 0;
94  byteOffset = 0;
95  buffer = buffers[0];
96  }
97  }
98 
99  public void NextBuffer()
100  {
101  if (1 + bufferUpto == buffers.Length)
102  {
103  var newBuffers = new byte[(int) (buffers.Length * 1.5)][];
104  Array.Copy(buffers, 0, newBuffers, 0, buffers.Length);
105  buffers = newBuffers;
106  }
107  buffer = buffers[1 + bufferUpto] = allocator.GetByteBlock(trackAllocations);
108  bufferUpto++;
109 
110  byteUpto = 0;
111  byteOffset += DocumentsWriter.BYTE_BLOCK_SIZE;
112  }
113 
114  public int NewSlice(int size)
115  {
116  if (byteUpto > DocumentsWriter.BYTE_BLOCK_SIZE - size)
117  NextBuffer();
118  int upto = byteUpto;
119  byteUpto += size;
120  buffer[byteUpto - 1] = 16;
121  return upto;
122  }
123 
124  // Size of each slice. These arrays should be at most 16
125  // elements (index is encoded with 4 bits). First array
126  // is just a compact way to encode X+1 with a max. Second
127  // array is the length of each slice, ie first slice is 5
128  // bytes, next slice is 14 bytes, etc.
129  internal static readonly int[] nextLevelArray = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 9};
130  internal static readonly int[] levelSizeArray = new int[]{5, 14, 20, 30, 40, 40, 80, 80, 120, 200};
131  internal static readonly int FIRST_LEVEL_SIZE = levelSizeArray[0];
132  public readonly static int FIRST_LEVEL_SIZE_For_NUnit_Test = levelSizeArray[0];
133 
134  public int AllocSlice(byte[] slice, int upto)
135  {
136 
137  int level = slice[upto] & 15;
138  int newLevel = nextLevelArray[level];
139  int newSize = levelSizeArray[newLevel];
140 
141  // Maybe allocate another block
142  if (byteUpto > DocumentsWriter.BYTE_BLOCK_SIZE - newSize)
143  NextBuffer();
144 
145  int newUpto = byteUpto;
146  int offset = newUpto + byteOffset;
147  byteUpto += newSize;
148 
149  // Copy forward the past 3 bytes (which we are about
150  // to overwrite with the forwarding address):
151  buffer[newUpto] = slice[upto - 3];
152  buffer[newUpto + 1] = slice[upto - 2];
153  buffer[newUpto + 2] = slice[upto - 1];
154 
155  // Write forwarding address at end of last slice:
156  slice[upto - 3] = (byte) (Number.URShift(offset, 24));
157  slice[upto - 2] = (byte) (Number.URShift(offset, 16));
158  slice[upto - 1] = (byte) (Number.URShift(offset, 8));
159  slice[upto] = (byte) offset;
160 
161  // Write new level:
162  buffer[byteUpto - 1] = (byte) (16 | newLevel);
163 
164  return newUpto + 3;
165  }
166 
167  public static int FIRST_LEVEL_SIZE_ForNUnit
168  {
169  get { return FIRST_LEVEL_SIZE; }
170  }
171  }
172 }