DeveelDB  20151217
complete SQL database system, primarly developed for .NET/Mono frameworks
StoreIndex.cs
Go to the documentation of this file.
1 //
2 // Copyright 2010-2015 Deveel
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 using System;
18 using System.Collections.Generic;
19 using System.IO;
20 
21 using Deveel.Data.Store;
22 using Deveel.Data.Util;
23 
24 namespace Deveel.Data.Index {
25  class StoreIndex : BlockIndex<int>, IIndex, IDisposable {
26  private List<IMappedBlock> deletedBlocks;
27 
28  private bool disposed;
29 
30  public StoreIndex(IndexSetStore indexSetStore, int indexNumber, int maxBlockSize, IEnumerable<IIndexBlock<int>> blocks)
31  : base(blocks) {
32  IndexSetStore = indexSetStore;
33  IndexNumber = indexNumber;
34  MaxBlockSize = maxBlockSize;
35 
36  deletedBlocks = new List<IMappedBlock>();
37  }
38 
39 
40  public int IndexNumber { get; private set; }
41 
42  public int MaxBlockSize { get; private set; }
43 
44  public IndexSetStore IndexSetStore { get; private set; }
45 
46  public IEnumerable<IIndexBlock<int>> AllBlocks {
47  get { return Blocks.ToArray(); }
48  }
49 
50  public IEnumerable<IMappedBlock> DeletedBlocks {
51  get { return deletedBlocks.ToArray(); }
52  }
53 
54  private void AssertNotDisposed() {
55  if (disposed)
56  throw new ObjectDisposedException(GetType().FullName);
57  }
58 
59  protected override IIndexBlock<int> NewBlock() {
60  AssertNotDisposed();
61 
62  return new MappedBlock(this);
63  }
64 
65  protected override void OnDeleteBlock(IIndexBlock<int> block) {
66  deletedBlocks.Add((IMappedBlock) block);
67  }
68 
69  public void Dispose() {
70  Dispose(true);
71  GC.SuppressFinalize(this);
72  }
73 
74  private void Dispose(bool disposing) {
75  if (!disposed) {
76  if (disposing) {
77  if (deletedBlocks != null)
78  deletedBlocks.Clear();
79  }
80 
81  IndexSetStore = null;
82  deletedBlocks = null;
83  disposed = true;
84  }
85  }
86 
87  public static IMappedBlock NewMappedBlock(IndexSetStore indexSetStore, long firstEntry, long lastEntry, long blockPointer,
88  int size, byte compactType, int blockSize) {
89  return new MappedBlock(indexSetStore, firstEntry, lastEntry, blockPointer, size, compactType, blockSize);
90  }
91 
92  #region MappedBlock
93 
94  class MappedBlock : Block, IMappedBlock, IDisposable {
95  private readonly int maxBlockSize;
96 
97  private object blockLock = new object();
98  private bool mutableBlock;
99 
100 
101  public IndexSetStore IndexSetStore { get; private set; }
102 
103  private IStore Store {
104  get { return IndexSetStore.Store; }
105  }
106 
107  public MappedBlock(StoreIndex index)
108  : base(index.MaxBlockSize) {
110  maxBlockSize = index.MaxBlockSize;
111  BlockPointer = -1;
112  }
113 
114  public MappedBlock(IndexSetStore indexSetStore, long firstEntry, long lastEntry, long blockPointer, int size, byte compactType, int maxBlockSize) {
115  IndexSetStore = indexSetStore;
116  FirstEntry = firstEntry;
117  LastEntry = lastEntry;
118  BlockPointer = blockPointer;
119  CompactType = compactType;
120 
121  this.maxBlockSize = maxBlockSize;
122  Count = size;
123  BaseArray = null;
124  }
125 
126  public long FirstEntry { get; private set; }
127 
128  public long LastEntry { get; private set; }
129 
130  public long BlockPointer { get; private set; }
131 
132  public byte CompactType { get; private set; }
133 
134  public override int Top {
135  get {
136  if (Count == 0)
137  throw new InvalidOperationException("No first int in block.");
138 
139  lock (blockLock) {
140  return BaseArray == null ? (int)LastEntry : BaseArray[Count - 1];
141  }
142  }
143  }
144 
145  public override int Bottom {
146  get {
147  if (Count == 0)
148  throw new InvalidOperationException("No first int in block.");
149 
150  lock (blockLock) {
151  return BaseArray == null ? (int)FirstEntry : BaseArray[0];
152  }
153  }
154  }
155 
156  protected override int ArrayLength {
157  get { return maxBlockSize; }
158  }
159 
160  private void PrepareMutate(bool readOnly) {
161  // If list is to be mutable
162  if (!readOnly && !mutableBlock) {
163  BaseArray = (int[])BaseArray.Clone();
164  mutableBlock = true;
165  }
166  }
167 
168  public long CopyTo(IStore destStore) {
169  // The number of bytes per entry
170  int entrySize = CompactType;
171  // The total size of the entry.
172  int areaSize = (Count * entrySize);
173 
174  // Allocate the destination area
175  var dest = destStore.CreateArea(areaSize);
176  long destOffset = dest.Id;
177  Store.GetArea(BlockPointer).CopyTo(dest, areaSize);
178  dest.Flush();
179 
180  return destOffset;
181  }
182 
183  public long Flush() {
184  // Convert the int[] array to a byte[] array.
185 
186  // First determine how we compact this int array into a byte array. If
187  // all the values are < 32768 then we store as shorts
188  long largestVal = 0;
189  for (int i = 0; i < Count; ++i) {
190  long v = BaseArray[i];
191  if (System.Math.Abs(v) > System.Math.Abs(largestVal)) {
192  largestVal = v;
193  }
194  }
195 
196  long lv = largestVal;
197  if (lv >> 7 == 0 || lv >> 7 == -1) {
198  CompactType = 1;
199  } else if (lv >> 15 == 0 || lv >> 15 == -1) {
200  CompactType = 2;
201  } else if (lv >> 23 == 0 || lv >> 23 == -1) {
202  CompactType = 3;
203  }
204  // NOTE: in the future we'll want to determine if we are going to store
205  // as an int or long array.
206  else {
207  CompactType = 4;
208  }
209 
210  // The number of bytes per entry
211  int entrySize = CompactType;
212  // The total size of the entry.
213  int areaSize = (Count * entrySize);
214 
215  // Allocate an array to buffer the block to
216  byte[] arr = new byte[areaSize];
217  // Fill the array
218  int p = 0;
219  for (int i = 0; i < Count; ++i) {
220  int v = BaseArray[i];
221  for (int n = entrySize - 1; n >= 0; --n) {
222  //TODO: check this...
223  arr[p] = (byte)(ByteBuffer.URShift(v, (n * 8)) & 0x0FF);
224  ++p;
225  }
226  }
227 
228  // Create an area to store this
229  var a = Store.CreateArea(areaSize);
230  BlockPointer = a.Id;
231 
232  a.Write(arr, 0, areaSize);
233  a.Flush();
234 
235  // Once written, the block is invalidated
236  blockLock = null;
237 
238  return BlockPointer;
239  }
240 
241  protected override int[] GetArray(bool readOnly) {
242  // We must synchronize this entire block because otherwise we could
243  // return a partially loaded array.
244  lock (blockLock) {
245  if (BaseArray != null) {
246  PrepareMutate(readOnly);
247  return BaseArray;
248  }
249 
250  // Create the int array
251  BaseArray = new int[maxBlockSize];
252 
253  // The number of bytes per entry
254  int entrySize = CompactType;
255  // The total size of the entry.
256  int areaSize = (Count * entrySize);
257 
258  // Read in the byte array
259  byte[] buf = new byte[areaSize];
260  try {
261  Store.GetArea(BlockPointer).Read(buf, 0, areaSize);
262  } catch (IOException e) {
263  throw new InvalidOperationException("IO Error: " + e.Message);
264  }
265 
266  // Uncompact it into the int array
267  int p = 0;
268  for (int i = 0; i < Count; ++i) {
269  int v = (((int)buf[p]) << ((entrySize - 1) * 8));
270  ++p;
271  for (int n = entrySize - 2; n >= 0; --n) {
272  v = v | ((((int)buf[p]) & 0x0FF) << (n * 8));
273  ++p;
274  }
275  BaseArray[i] = v;
276  }
277 
278  mutableBlock = false;
279  PrepareMutate(readOnly);
280  return BaseArray;
281  }
282  }
283 
284  public void Dispose() {
285  IndexSetStore = null;
286  }
287  }
288 
289  #endregion
290  }
291 }
override IIndexBlock< int > NewBlock()
Definition: StoreIndex.cs:59
IArea CreateArea(long size)
Allocates a block of memory in the store of the specified size and returns an IArea object that can b...
static IMappedBlock NewMappedBlock(IndexSetStore indexSetStore, long firstEntry, long lastEntry, long blockPointer, int size, byte compactType, int blockSize)
Definition: StoreIndex.cs:87
override int[] GetArray(bool readOnly)
Definition: StoreIndex.cs:241
IndexSetStore IndexSetStore
Definition: StoreIndex.cs:44
override void OnDeleteBlock(IIndexBlock< int > block)
Definition: StoreIndex.cs:65
void Dispose(bool disposing)
Definition: StoreIndex.cs:74
MappedBlock(IndexSetStore indexSetStore, long firstEntry, long lastEntry, long blockPointer, int size, byte compactType, int maxBlockSize)
Definition: StoreIndex.cs:114
static int URShift(int number, int bits)
Operates a shift on the given integer by the number of bits specified.
Definition: ByteBuffer.cs:277
An interface for querying and accessing an index of primitive integers.
Definition: IIndex.cs:37
A wrapper for an array of byte.
Definition: ByteBuffer.cs:27
List< IMappedBlock > deletedBlocks
Definition: StoreIndex.cs:26
An implementation of BlockIndexBase that stores all values in blocks that are entirely stored in m...
Definition: BlockIndex_T.cs:30
long Id
Returns the unique identifier that represents this area.
Definition: IArea.cs:31
A store is a resource where areas can be allocated and freed to store information (a memory allocator...
Definition: IStore.cs:56
StoreIndex(IndexSetStore indexSetStore, int indexNumber, int maxBlockSize, IEnumerable< IIndexBlock< int >> blocks)
Definition: StoreIndex.cs:30