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

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

Issue 365193004: Move Index and IndexStore implementations into Engine. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 5 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 'package:analysis_server/src/index/b_plus_tree.dart';
11 import 'package:analysis_server/src/index/lru_cache.dart';
12
13
14 /**
15 * A [NodeManager] that caches a specified number of index and leaf nodes.
16 */
17 class CachingNodeManager<K, V, N> implements NodeManager<K, V, N> {
18 final NodeManager<K, V, N> _delegate;
19 LRUCache<N, IndexNodeData<K, N>> _indexCache;
20 LRUCache<N, LeafNodeData<K, V>> _leafCache;
21
22 CachingNodeManager(this._delegate, int indexNodeCacheSize,
23 int leafNodeCacheSize) {
24 _indexCache = new LRUCache<N, IndexNodeData<K, N>>(indexNodeCacheSize,
25 _delegate.writeIndex);
26 _leafCache = new LRUCache<N, LeafNodeData<K, V>>(leafNodeCacheSize,
27 _delegate.writeLeaf);
28 }
29
30 @override
31 int get maxIndexKeys => _delegate.maxIndexKeys;
32
33 @override
34 int get maxLeafKeys => _delegate.maxLeafKeys;
35
36 @override
37 N createIndex() {
38 return _delegate.createIndex();
39 }
40
41 @override
42 N createLeaf() {
43 return _delegate.createLeaf();
44 }
45
46 @override
47 void delete(N id) {
48 _indexCache.remove(id);
49 _leafCache.remove(id);
50 _delegate.delete(id);
51 }
52
53 @override
54 bool isIndex(N id) {
55 return _delegate.isIndex(id);
56 }
57
58 @override
59 IndexNodeData<K, N> readIndex(N id) {
60 IndexNodeData<K, N> data = _indexCache.get(id);
61 if (data == null) {
62 data = _delegate.readIndex(id);
63 _indexCache.put(id, data);
64 }
65 return data;
66 }
67
68 @override
69 LeafNodeData<K, V> readLeaf(N id) {
70 LeafNodeData<K, V> data = _leafCache.get(id);
71 if (data == null) {
72 data = _delegate.readLeaf(id);
73 _leafCache.put(id, data);
74 }
75 return data;
76 }
77
78 @override
79 void writeIndex(N id, IndexNodeData<K, N> data) {
80 _indexCache.put(id, data);
81 }
82
83 @override
84 void writeLeaf(N id, LeafNodeData<K, V> data) {
85 _leafCache.put(id, data);
86 }
87 }
88
89
90 /**
91 * A [Codec] encodes and decodes data.
92 */
93 abstract class Codec<E> {
94 /**
95 * The size of the value in bytes.
96 */
97 int get sizeInBytes;
98
99 /**
100 * Returns the value decoded from [buffer].
101 *
102 * The given [buffer] has exactly [sizeInBytes] bytes length.
103 */
104 E decode(ByteData buffer);
105
106 /**
107 * Encodes [value] into [buffer].
108 *
109 * The given [buffer] has exactly [sizeInBytes] bytes length.
110 */
111 void encode(ByteData buffer, E value);
112 }
113
114
115 /**
116 * A [Codec] for strings with a predefined maximum length.
117 */
118 class FixedStringCodec implements Codec<String> {
119 final int maxLength;
120 final int sizeInBytes;
121
122 const FixedStringCodec(int maxLength)
123 : maxLength = maxLength,
124 sizeInBytes = 2 + 2 * maxLength;
125
126 @override
127 String decode(ByteData buffer) {
128 int length = buffer.getUint16(0);
129 int offset = 2;
130 List<int> codeUnits = new List<int>(length);
131 for (int i = 0; i < length; i++) {
132 codeUnits[i] = buffer.getUint16(offset);
133 offset += 2;
134 }
135 return new String.fromCharCodes(codeUnits);
136 }
137
138 @override
139 void encode(ByteData buffer, String value) {
140 int length = value.length;
141 if (length > maxLength) {
142 throw new ArgumentError(
143 'String $value length=$length is greater than allowed $maxLength');
144 }
145 buffer.setUint16(0, length);
146 int offset = 2;
147 List<int> codeUnits = value.codeUnits;
148 for (int i = 0; i < length; i++) {
149 buffer.setUint16(offset, codeUnits[i]);
150 offset += 2;
151 }
152 }
153 }
154
155
156 /**
157 * A [PageManager] that keeps all [Uint8List] pages in memory.
158 */
159 class MemoryPageManager implements PageManager {
160 final int pageSizeInBytes;
161 int _nextPage = 0;
162 final Map<int, Uint8List> _pages = new HashMap<int, Uint8List>();
163
164 MemoryPageManager(this.pageSizeInBytes);
165
166 @override
167 int alloc() {
168 int id = _nextPage++;
169 Uint8List page = new Uint8List(pageSizeInBytes);
170 _pages[id] = page;
171 return id;
172 }
173
174 @override
175 void free(int id) {
176 Uint8List page = _pages.remove(id);
177 if (page == null) {
178 throw new StateError('Page $id has been already freed.');
179 }
180 }
181
182 @override
183 Uint8List read(int id) {
184 Uint8List page = _pages[id];
185 if (page == null) {
186 throw new StateError('Page $id does not exist.');
187 }
188 return page;
189 }
190
191 @override
192 void write(int id, Uint8List page) {
193 if (!_pages.containsKey(id)) {
194 throw new StateError('Page $id does not exist.');
195 }
196 if (page.length != pageSizeInBytes) {
197 throw new ArgumentError('Page $id has length ${page.length}, '
198 'but $pageSizeInBytes is expected.');
199 }
200 _pages[id] = page;
201 }
202 }
203
204
205 /**
206 * [PageManager] allows to allocate, read, write and free [Uint8List] pages.
207 */
208 abstract class PageManager {
209 /**
210 * The size of pages provided by this [PageManager].
211 */
212 int get pageSizeInBytes;
213
214 /**
215 * Allocates a new page and returns its identifier.
216 */
217 int alloc();
218
219 /**
220 * Frees the page with the given identifier.
221 */
222 void free(int id);
223
224 /**
225 * Reads the page with the given identifier and returns its content.
226 *
227 * An internal representation of the page is returned, any changes made to it
228 * may be accessible to other clients reading the same page.
229 */
230 Uint8List read(int id);
231
232 /**
233 * Writes the given page.
234 */
235 void write(int id, Uint8List page);
236 }
237
238
239 /**
240 * A [NodeManager] that keeps nodes in [PageManager].
241 */
242 class PageNodeManager<K, V> implements NodeManager<K, V, int> {
243 static const int _INDEX_OFFSET_DATA = 4;
244 static const int _INDEX_OFFSET_KEY_COUNT = 0;
245 static const int _LEAF_OFFSET_DATA = 4;
246 static const int _LEAF_OFFSET_KEY_COUNT = 0;
247
248 final Set<int> _indexPages = new HashSet<int>();
249 Codec<K> _keyCodec;
250 final Set<int> _leafPages = new HashSet<int>();
251 PageManager _pageManager;
252 Codec<V> _valueCodec;
253
254 PageNodeManager(this._pageManager, this._keyCodec, this._valueCodec);
255
256 @override
257 int get maxIndexKeys {
258 int keySize = _keyCodec.sizeInBytes;
259 int childSize = 4;
260 int dataSize = _pageManager.pageSizeInBytes - _INDEX_OFFSET_DATA;
261 return (dataSize - childSize) ~/ (keySize + childSize);
262 }
263
264 @override
265 int get maxLeafKeys {
266 int keySize = _keyCodec.sizeInBytes;
267 int valueSize = _valueCodec.sizeInBytes;
268 int dataSize = _pageManager.pageSizeInBytes - _INDEX_OFFSET_DATA;
269 return dataSize ~/ (keySize + valueSize);
270 }
271
272 @override
273 int createIndex() {
274 int id = _pageManager.alloc();
275 _indexPages.add(id);
276 return id;
277 }
278
279 @override
280 int createLeaf() {
281 int id = _pageManager.alloc();
282 _leafPages.add(id);
283 return id;
284 }
285
286 @override
287 void delete(int id) {
288 _pageManager.free(id);
289 _indexPages.remove(id);
290 _leafPages.remove(id);
291 }
292
293 @override
294 bool isIndex(int id) {
295 return _indexPages.contains(id);
296 }
297
298 @override
299 IndexNodeData<K, int> readIndex(int id) {
300 Uint8List page = _pageManager.read(id);
301 // read header
302 int keyCount;
303 {
304 ByteData data = new ByteData.view(page.buffer);
305 keyCount = data.getInt32(_INDEX_OFFSET_KEY_COUNT);
306 }
307 // read keys/children
308 List<K> keys = new List<K>();
309 List<int> children = new List<int>();
310 int keySize = _keyCodec.sizeInBytes;
311 int offset = _INDEX_OFFSET_DATA;
312 for (int i = 0; i < keyCount; i++) {
313 // read child
314 {
315 ByteData byteData = new ByteData.view(page.buffer, offset);
316 int childPage = byteData.getUint32(0);
317 children.add(childPage);
318 offset += 4;
319 }
320 // read key
321 {
322 ByteData byteData = new ByteData.view(page.buffer, offset, keySize);
323 K key = _keyCodec.decode(byteData);
324 keys.add(key);
325 offset += keySize;
326 }
327 }
328 // read last child
329 {
330 ByteData byteData = new ByteData.view(page.buffer, offset);
331 int childPage = byteData.getUint32(0);
332 children.add(childPage);
333 }
334 // done
335 return new IndexNodeData<K, int>(keys, children);
336 }
337
338 @override
339 LeafNodeData<K, V> readLeaf(int id) {
340 Uint8List page = _pageManager.read(id);
341 // read header
342 int keyCount;
343 {
344 ByteData data = new ByteData.view(page.buffer);
345 keyCount = data.getInt32(_LEAF_OFFSET_KEY_COUNT);
346 }
347 // read keys/children
348 List<K> keys = new List<K>();
349 List<V> values = new List<V>();
350 int keySize = _keyCodec.sizeInBytes;
351 int valueSize = _valueCodec.sizeInBytes;
352 int offset = _LEAF_OFFSET_DATA;
353 for (int i = 0; i < keyCount; i++) {
354 // read key
355 {
356 ByteData byteData = new ByteData.view(page.buffer, offset, keySize);
357 K key = _keyCodec.decode(byteData);
358 keys.add(key);
359 offset += keySize;
360 }
361 // read value
362 {
363 ByteData byteData = new ByteData.view(page.buffer, offset);
364 V value = _valueCodec.decode(byteData);
365 values.add(value);
366 offset += valueSize;
367 }
368 }
369 // done
370 return new LeafNodeData<K, V>(keys, values);
371 }
372
373 @override
374 void writeIndex(int id, IndexNodeData<K, int> data) {
375 Uint8List page = new Uint8List(_pageManager.pageSizeInBytes);
376 // write header
377 int keyCount = data.keys.length;
378 {
379 ByteData byteData = new ByteData.view(page.buffer);
380 byteData.setUint32(PageNodeManager._INDEX_OFFSET_KEY_COUNT, keyCount);
381 }
382 // write keys/children
383 int keySize = _keyCodec.sizeInBytes;
384 int offset = PageNodeManager._INDEX_OFFSET_DATA;
385 for (int i = 0; i < keyCount; i++) {
386 // write child
387 {
388 ByteData byteData = new ByteData.view(page.buffer, offset);
389 byteData.setUint32(0, data.children[i]);
390 offset += 4;
391 }
392 // write key
393 {
394 ByteData byteData = new ByteData.view(page.buffer, offset, keySize);
395 _keyCodec.encode(byteData, data.keys[i]);
396 offset += keySize;
397 }
398 }
399 // write last child
400 {
401 ByteData byteData = new ByteData.view(page.buffer, offset);
402 byteData.setUint32(0, data.children.last);
403 }
404 // write page
405 _pageManager.write(id, page);
406 }
407
408 @override
409 void writeLeaf(int id, LeafNodeData<K, V> data) {
410 Uint8List page = new Uint8List(_pageManager.pageSizeInBytes);
411 // write header
412 int keyCount = data.keys.length;
413 {
414 ByteData byteData = new ByteData.view(page.buffer);
415 byteData.setUint32(PageNodeManager._LEAF_OFFSET_KEY_COUNT, keyCount);
416 }
417 // write keys/values
418 int keySize = _keyCodec.sizeInBytes;
419 int valueSize = _valueCodec.sizeInBytes;
420 int offset = PageNodeManager._LEAF_OFFSET_DATA;
421 for (int i = 0; i < keyCount; i++) {
422 // write key
423 {
424 ByteData byteData = new ByteData.view(page.buffer, offset, keySize);
425 _keyCodec.encode(byteData, data.keys[i]);
426 offset += keySize;
427 }
428 // write value
429 {
430 ByteData byteData = new ByteData.view(page.buffer, offset);
431 _valueCodec.encode(byteData, data.values[i]);
432 offset += valueSize;
433 }
434 }
435 // write page
436 _pageManager.write(id, page);
437 }
438 }
439
440
441 /**
442 * A [Codec] for unsigned 32-bit integers.
443 */
444 class Uint32Codec implements Codec<int> {
445 static const Uint32Codec INSTANCE = const Uint32Codec._();
446
447 const Uint32Codec._();
448
449 @override
450 int get sizeInBytes => 4;
451
452 @override
453 int decode(ByteData buffer) {
454 return buffer.getUint32(0);
455 }
456
457 @override
458 void encode(ByteData buffer, int element) {
459 buffer.setUint32(0, element);
460 }
461 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698