-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Expand file tree
/
Copy pathCollectionPage.cs
More file actions
185 lines (145 loc) · 5.71 KB
/
CollectionPage.cs
File metadata and controls
185 lines (145 loc) · 5.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using static LiteDB.Constants;
namespace LiteDB.Engine
{
internal class CollectionPage : BasePage
{
#region Buffer Field Positions
public const int P_INDEXES = 96; // 96-8192 (64 + 32 header = 96)
public const int P_INDEXES_COUNT = PAGE_SIZE - P_INDEXES; // 8096
#endregion
/// <summary>
/// Free data page linked-list (N lists for different range of FreeBlocks)
/// </summary>
public uint[] FreeDataPageList { get; } = new uint[PAGE_FREE_LIST_SLOTS];
/// <summary>
/// All indexes references for this collection
/// </summary>
private readonly Dictionary<string, CollectionIndex> _indexes = new Dictionary<string, CollectionIndex>();
public CollectionPage(PageBuffer buffer, uint pageID)
: base(buffer, pageID, PageType.Collection)
{
for(var i = 0; i < PAGE_FREE_LIST_SLOTS; i++)
{
this.FreeDataPageList[i] = uint.MaxValue;
}
}
public CollectionPage(PageBuffer buffer)
: base(buffer)
{
ENSURE(this.PageType == PageType.Collection, "page type must be collection page, but it is {0}", PageType);
if (this.PageType != PageType.Collection) throw LiteException.InvalidPageType(PageType.Collection, this);
// create new buffer area to store BsonDocument indexes
var area = _buffer.Slice(PAGE_HEADER_SIZE, PAGE_SIZE - PAGE_HEADER_SIZE);
using (var r = new BufferReader(new[] { area }, false))
{
// read position for FreeDataPage and FreeIndexPage
for(var i = 0; i < PAGE_FREE_LIST_SLOTS; i++)
{
this.FreeDataPageList[i] = r.ReadUInt32();
}
// skip reserved area
r.Skip(P_INDEXES - PAGE_HEADER_SIZE - r.Position);
var count = r.ReadByte(); // 1 byte
for(var i = 0; i < count; i++)
{
var index = new CollectionIndex(r);
_indexes[index.Name] = index;
}
}
}
public override PageBuffer UpdateBuffer()
{
// if page was deleted, do not write in content area (must keep with 0 only)
if (this.PageType == PageType.Empty) return base.UpdateBuffer();
var area = _buffer.Slice(PAGE_HEADER_SIZE, PAGE_SIZE - PAGE_HEADER_SIZE);
using (var w = new BufferWriter(area))
{
// read position for FreeDataPage and FreeIndexPage
for (var i = 0; i < PAGE_FREE_LIST_SLOTS; i++)
{
w.Write(this.FreeDataPageList[i]);
}
// skip reserved area (indexes starts at position 96)
w.Skip(P_INDEXES - PAGE_HEADER_SIZE - w.Position);
w.Write((byte)_indexes.Count); // 1 byte
foreach (var index in _indexes.Values)
{
index.UpdateBuffer(w);
}
}
return base.UpdateBuffer();
}
/// <summary>
/// Get PK index
/// </summary>
public CollectionIndex PK { get { return _indexes["_id"]; } }
/// <summary>
/// Get index from index name (index name is case sensitive) - returns null if not found
/// </summary>
public CollectionIndex GetCollectionIndex(string name)
{
if (_indexes.TryGetValue(name, out var index))
{
return index;
}
return null;
}
/// <summary>
/// Get all indexes in this collection page
/// </summary>
public ICollection<CollectionIndex> GetCollectionIndexes()
{
return _indexes.Values;
}
/// <summary>
/// Get all collections array based on slot number
/// </summary>
public CollectionIndex[] GetCollectionIndexesSlots()
{
var indexes = new CollectionIndex[_indexes.Max(x => x.Value.Slot) + 1];
foreach (var index in _indexes.Values)
{
indexes[index.Slot] = index;
}
return indexes;
}
/// <summary>
/// Insert new index inside this collection page
/// </summary>
public CollectionIndex InsertCollectionIndex(string name, string expr, bool unique)
{
var totalLength = 1 +
_indexes.Sum(x => CollectionIndex.GetLength(x.Value)) +
CollectionIndex.GetLength(name, expr);
// check if has space avaiable
if (_indexes.Count == 255 || totalLength >= P_INDEXES_COUNT) throw new LiteException(0, $"This collection has no more space for new indexes");
var slot = (byte)(_indexes.Count == 0 ? 0 : (_indexes.Max(x => x.Value.Slot) + 1));
var index = new CollectionIndex(slot, 0, name, expr, unique);
_indexes[name] = index;
this.IsDirty = true;
return index;
}
/// <summary>
/// Return index instance and mark as updatable
/// </summary>
public CollectionIndex UpdateCollectionIndex(string name)
{
this.IsDirty = true;
return _indexes[name];
}
/// <summary>
/// Remove index reference in this page
/// </summary>
public void DeleteCollectionIndex(string name)
{
_indexes.Remove(name);
this.IsDirty = true;
}
}
}