Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(118)

Side by Side Diff: pkg/analysis_server/lib/src/index/page_node_manager.dart

Issue 324743003: A NodeManager implementation with encoding/decoding keys/values into pages. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Tweak and include index tests Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 library index.page_node_manager;
6
7 import 'dart:collection';
8 import 'dart:typed_data';
9
10 import 'b_plus_tree.dart';
11
12
13 /**
14 * A [Codec] encodes and decodes data.
15 */
16 abstract class Codec<E> {
17 /**
18 * The size of the value in bytes.
19 */
20 int get sizeInBytes;
21
22 /**
23 * Returns the value decoded from [buffer].
24 *
25 * The given [buffer] has exactly [sizeInBytes] bytes length.
26 */
27 E decode(ByteData buffer);
28
29 /**
30 * Encodes [value] into [buffer].
31 *
32 * The given [buffer] has exactly [sizeInBytes] bytes length.
33 */
34 void encode(ByteData buffer, E value);
35 }
36
37
38 /**
39 * A [Codec] for strings with a predefined maximum length.
40 */
41 class FixedStringCodec implements Codec<String> {
42 final int maxLength;
43 final int sizeInBytes;
44
45 const FixedStringCodec(int maxLength)
46 : maxLength = maxLength,
47 sizeInBytes = 2 + 2 * maxLength;
48
49 @override
50 String decode(ByteData buffer) {
51 int length = buffer.getUint16(0);
52 int offset = 2;
53 List<int> codeUnits = new List<int>(length);
54 for (int i = 0; i < length; i++) {
55 codeUnits[i] = buffer.getUint16(offset);
56 offset += 2;
57 }
58 return new String.fromCharCodes(codeUnits);
59 }
60
61 @override
62 void encode(ByteData buffer, String value) {
63 int length = value.length;
64 if (length > maxLength) {
65 throw new ArgumentError(
66 'String $value length=$length is greater than allowed $maxLength');
67 }
68 buffer.setUint16(0, length);
69 int offset = 2;
70 for (int codeUnit in value.codeUnits) {
71 buffer.setUint16(offset, codeUnit);
72 offset += 2;
73 }
74 }
75 }
76
77
78 /**
79 * A [PageManager] that keeps all [Uint8List] pages in memory.
80 */
81 class MemoryPageManager implements PageManager {
82 final int pageSizeInBytes;
83 int _nextPage = 0;
84 final Map<int, Uint8List> _pages = new HashMap<int, Uint8List>();
Paul Berry 2014/06/10 18:39:08 Kind of surprised that you're using a Map here, si
scheglov 2014/06/10 20:12:12 I don't observe any performance difference with on
85
86 MemoryPageManager(this.pageSizeInBytes);
87
88 @override
89 int alloc() {
90 int id = _nextPage++;
91 Uint8List page = new Uint8List(pageSizeInBytes);
92 _pages[id] = page;
93 return id;
94 }
95
96 @override
97 void free(int id) {
98 Uint8List page = _pages.remove(id);
99 if (page == null) {
100 throw new StateError('Page $id has been already freed.');
101 }
102 }
103
104 @override
105 Uint8List read(int id) {
106 Uint8List page = _pages[id];
107 if (page == null) {
108 throw new StateError('Page $id does not exist.');
109 }
110 return page;
111 }
112
113 @override
114 void write(int id, Uint8List page) {
115 if (!_pages.containsKey(id)) {
Paul Berry 2014/06/10 18:39:08 Might want to add a check here to verify that page
scheglov 2014/06/10 20:12:12 Done.
116 throw new StateError('Page $id does not exist.');
117 }
118 _pages[id] = page;
119 }
120 }
121
122
123 /**
124 * [PageManager] allows to allocate, read, write and free [Uint8List] pages.
125 */
126 abstract class PageManager {
127 /**
128 * The size of pages provided by this [PageManager].
129 */
130 int get pageSizeInBytes;
131
132 /**
133 * Allocates a new page and returns its identifier.
134 */
135 int alloc();
136
137 /**
138 * Frees the page with the given identifier.
139 */
140 void free(int id);
141
142 /**
143 * Reads the page with the given identifier and returns its content.
Paul Berry 2014/06/10 18:39:08 Is the caller allowed to modify the contents of th
scheglov 2014/06/10 20:12:12 Done.
144 */
145 Uint8List read(int id);
146
147 /**
148 * Writes the given page.
149 */
150 void write(int id, Uint8List page);
151 }
152
153
154 /**
155 * A [NodeManager] that keeps nodes in [PageManager].
156 */
157 class PageNodeManager<K, V> implements NodeManager<K, V, int> {
Paul Berry 2014/06/10 18:39:08 To make it easier to understand (and use) this cla
scheglov 2014/06/10 20:12:12 Yes, already done in one of the subsequent CLs. I'
158 static const int INDEX_OFFSET_DATA = 4;
159 static const int INDEX_OFFSET_KEY_COUNT = 0;
160 static const int LEAF_OFFSET_DATA = 4;
161 static const int LEAF_OFFSET_KEY_COUNT = 0;
162
163 final Set<int> indexPages = new HashSet<int>();
164 Codec<K> keyCodec;
165 final Set<int> leafPages = new HashSet<int>();
166 PageManager pageManager;
167 Codec<V> valueCodec;
168
169 PageNodeManager(this.pageManager, this.keyCodec, this.valueCodec);
170
171 @override
172 int createIndex() {
173 int id = pageManager.alloc();
174 indexPages.add(id);
175 return id;
176 }
177
178 @override
179 int createLeaf() {
180 int id = pageManager.alloc();
181 leafPages.add(id);
182 return id;
183 }
184
185 @override
186 void delete(int id) {
187 pageManager.free(id);
188 indexPages.remove(id);
189 leafPages.remove(id);
190 }
191
192 @override
193 bool isIndex(int id) {
194 return indexPages.contains(id);
195 }
196
197 @override
198 IndexNodeData<K, int> readIndex(int id) {
199 Uint8List page = pageManager.read(id);
200 // read header
201 int keyCount;
202 {
203 ByteData data = new ByteData.view(page.buffer);
204 keyCount = data.getInt32(INDEX_OFFSET_KEY_COUNT);
205 }
206 // read keys/children
207 List<K> keys = new List<K>();
208 List<int> children = new List<int>();
209 int keySize = keyCodec.sizeInBytes;
210 int offset = INDEX_OFFSET_DATA;
211 for (int i = 0; i < keyCount; i++) {
212 // read child
213 {
214 ByteData byteData = new ByteData.view(page.buffer, offset);
Paul Berry 2014/06/10 18:39:08 I'm a little worried that creating all of these vi
215 int childPage = byteData.getUint32(0);
216 children.add(childPage);
217 offset += 4;
218 }
219 // read key
220 {
221 ByteData byteData = new ByteData.view(page.buffer, offset, keySize);
222 K key = keyCodec.decode(byteData);
223 keys.add(key);
224 offset += keySize;
225 }
226 }
227 // read last child
228 {
229 ByteData byteData = new ByteData.view(page.buffer, offset);
230 int childPage = byteData.getUint32(0);
231 children.add(childPage);
232 }
233 // done
234 return new IndexNodeData<K, int>(keys, children);
235 }
236
237 @override
238 LeafNodeData<K, V> readLeaf(int id) {
239 Uint8List page = pageManager.read(id);
240 // read header
241 int keyCount;
242 {
243 ByteData data = new ByteData.view(page.buffer);
244 keyCount = data.getInt32(LEAF_OFFSET_KEY_COUNT);
245 }
246 // read keys/children
247 List<K> keys = new List<K>();
248 List<V> values = new List<V>();
249 int keySize = keyCodec.sizeInBytes;
250 int valueSize = valueCodec.sizeInBytes;
251 int offset = LEAF_OFFSET_DATA;
252 for (int i = 0; i < keyCount; i++) {
253 // read key
254 {
255 ByteData byteData = new ByteData.view(page.buffer, offset, keySize);
256 K key = keyCodec.decode(byteData);
257 keys.add(key);
258 offset += keySize;
259 }
260 // read value
261 {
262 ByteData byteData = new ByteData.view(page.buffer, offset);
263 V value = valueCodec.decode(byteData);
264 values.add(value);
265 offset += valueSize;
266 }
267 }
268 // done
269 return new LeafNodeData<K, V>(keys, values);
270 }
271
272 @override
273 void writeIndex(int id, IndexNodeData<K, int> data) {
274 Uint8List page = new Uint8List(pageManager.pageSizeInBytes);
275 // write header
276 int keyCount = data.keys.length;
277 {
278 ByteData byteData = new ByteData.view(page.buffer);
279 byteData.setUint32(INDEX_OFFSET_KEY_COUNT, keyCount);
280 }
281 // write keys/children
282 int keySize = keyCodec.sizeInBytes;
283 int offset = INDEX_OFFSET_DATA;
284 for (int i = 0; i < keyCount; i++) {
285 // write child
286 {
287 ByteData byteData = new ByteData.view(page.buffer, offset);
288 byteData.setUint32(0, data.children[i]);
289 offset += 4;
290 }
291 // write key
292 {
293 ByteData byteData = new ByteData.view(page.buffer, offset, keySize);
294 keyCodec.encode(byteData, data.keys[i]);
295 offset += keySize;
296 }
297 }
298 // write last child
299 {
300 ByteData byteData = new ByteData.view(page.buffer, offset);
301 byteData.setUint32(0, data.children.last);
302 }
303 // write page
304 pageManager.write(id, page);
305 }
306
307 @override
308 void writeLeaf(int id, LeafNodeData<K, V> data) {
309 Uint8List page = new Uint8List(pageManager.pageSizeInBytes);
310 // write header
311 int keyCount = data.keys.length;
312 {
313 ByteData byteData = new ByteData.view(page.buffer);
314 byteData.setUint32(LEAF_OFFSET_KEY_COUNT, keyCount);
315 }
316 // write keys/values
317 int keySize = keyCodec.sizeInBytes;
318 int valueSize = valueCodec.sizeInBytes;
319 int offset = LEAF_OFFSET_DATA;
320 for (int i = 0; i < keyCount; i++) {
321 // write key
322 {
323 ByteData byteData = new ByteData.view(page.buffer, offset, keySize);
324 keyCodec.encode(byteData, data.keys[i]);
325 offset += keySize;
326 }
327 // write value
328 {
329 ByteData byteData = new ByteData.view(page.buffer, offset);
330 valueCodec.encode(byteData, data.values[i]);
331 offset += valueSize;
332 }
333 }
334 // write page
335 pageManager.write(id, page);
336 }
337 }
338
339
340 /**
341 * A [Codec] for unsigned 32-bit integers.
342 */
343 class Uint32Codec implements Codec<int> {
344 static const Uint32Codec INSTANCE = const Uint32Codec._();
345
346 const Uint32Codec._();
347
348 @override
349 int get sizeInBytes => 4;
350
351 @override
352 int decode(ByteData buffer) {
353 return buffer.getUint32(0);
354 }
355
356 @override
357 void encode(ByteData buffer, int element) {
358 buffer.setUint32(0, element);
359 }
360 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698