DeveelDB  20151217
complete SQL database system, primarly developed for .NET/Mono frameworks
FixedRecordList.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 namespace Deveel.Data.Store {
22  public sealed class FixedRecordList {
23  private const int Magic = 0x087131AA;
24 
25  private readonly IStore store;
26  private readonly int elementSize;
27 
28  private long headerAreaId;
29  private IArea headerArea;
30 
31  // Pointers to the blocks in the list block.
32  private readonly long[] blockElements;
33  private readonly IArea[] blockAreas;
34 
35  public FixedRecordList(IStore store, int elementSize) {
36  this.store = store;
37  this.elementSize = elementSize;
38  blockElements = new long[64];
39  blockAreas = new IArea[64];
40  }
41 
42  public int BlockCount { get; private set; }
43 
44  public long NodeCount {
45  get { return BlockFirstPosition(BlockCount); }
46  }
47 
48  private void UpdateListHeaderArea() {
49  headerArea.Position = 4;
50  headerArea.WriteInt4(BlockCount);
51  headerArea.Position = 16;
52  for (int i = 0; i < BlockCount; ++i) {
53  headerArea.WriteInt8(blockElements[i]);
54  }
55  headerArea.Flush();
56  }
57 
58  public long Create() {
59  // Allocate space for the list header (8 + 8 + (64 * 8))
60  IArea writer = store.CreateArea(528);
61  headerAreaId = writer.Id;
62  writer.WriteInt4(Magic);
63  writer.Flush();
64 
65  headerArea = store.GetArea(headerAreaId);
66  BlockCount = 0;
67  UpdateListHeaderArea();
68 
69  return headerAreaId;
70  }
71 
72  public void Open(long listPointer) {
73  headerAreaId = listPointer;
74  headerArea = store.GetArea(headerAreaId);
75 
76  int magic = headerArea.ReadInt4(); // MAGIC
77  if (magic != Magic)
78  throw new IOException("Incorrect magic for list block. [magic=" + magic + "]");
79 
80  BlockCount = headerArea.ReadInt4();
81  headerArea.ReadInt8(); // Delete Chain Head
82  for (int i = 0; i < BlockCount; ++i) {
83  long blockPointer = headerArea.ReadInt8();
84  blockElements[i] = blockPointer;
85  blockAreas[i] = store.GetArea(blockPointer);
86  }
87  }
88 
89  public long ReadDeleteHead() {
90  headerArea.Position = 8;
91  return headerArea.ReadInt8();
92  }
93 
94  public void WriteDeleteHead(long value) {
95  headerArea.Position = 8;
96  headerArea.WriteInt8(value);
97  headerArea.Flush();
98  }
99 
100  public IArea GetRecord(long recordNumber) {
101  // What block is this record in?
102  int bit = 0;
103  long work = recordNumber + 32;
104  while (work != 0) {
105  work = work >> 1;
106  ++bit;
107  }
108 
109  long startOffset = (1 << (bit - 1)) - 32;
110  int blockOffset = bit - 6;
111  long recordOffset = recordNumber - startOffset;
112 
113  // Get the pointer to the block that contains this record status
114  IArea blockArea = blockAreas[blockOffset];
115  blockArea.Position = (int) (recordOffset*elementSize);
116  return blockArea;
117  }
118 
119  public long BlockNodeCount(int blockNumber) {
120  return 32L << blockNumber;
121  }
122 
123  public long BlockFirstPosition(int blockNumber) {
124  // For example, this first node of block 0 is 0, the first node of block 1 is
125  // 32, the first node of block 2 is 96, etc.
126  long startIndex = 0;
127  int i = blockNumber;
128  long diff = 32;
129  while (i > 0) {
130  startIndex = startIndex + diff;
131  diff = diff << 1;
132  --i;
133  }
134  return startIndex;
135  }
136 
137  public void IncreaseSize() {
138  // The size of the block
139  long sizeOfBlock = 32L << BlockCount;
140 
141  // Allocate the new block in the store
142  var area = store.CreateArea(sizeOfBlock * elementSize);
143  var blockId = area.Id;
144  area.Flush();
145 
146  var blockArea = store.GetArea(blockId);
147 
148  // Update the block list
149  blockElements[BlockCount] = blockId;
150  blockAreas[BlockCount] = blockArea;
151  ++BlockCount;
152 
153  // Update the list header,
154  UpdateListHeaderArea();
155  }
156 
157  public void DecreaseSize() {
158  --BlockCount;
159  // Free the top block
160  store.DeleteArea(blockElements[BlockCount]);
161 
162  // Help the GC
163  blockAreas[BlockCount] = null;
164  blockElements[BlockCount] = 0;
165 
166  // Update the list header.
167  UpdateListHeaderArea();
168  }
169 
170  public void GetAreasUsed(IList<long> usedAreas) {
171  usedAreas.Add(headerAreaId);
172  for (int i = 0; i < BlockCount; ++i) {
173  usedAreas.Add(blockElements[i]);
174  }
175  }
176  }
177 }
long BlockFirstPosition(int blockNumber)
long Position
Returns or sets the current position of the pointer within the area.
Definition: IArea.cs:48
void GetAreasUsed(IList< long > usedAreas)
FixedRecordList(IStore store, int elementSize)
An interface for access the contents of an area of a store.
Definition: IArea.cs:23
long BlockNodeCount(int blockNumber)
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
IArea GetRecord(long recordNumber)