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

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

Issue 351453004: Move split_store.dart to the store/ folder and extract collections/codecs. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: 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
« no previous file with comments | « no previous file | pkg/analysis_server/lib/src/index/store/codec.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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.split.store;
6
7 import 'dart:async';
8 import 'dart:collection';
9 import 'dart:io';
10 import 'dart:typed_data';
11
12 import 'package:analyzer/src/generated/element.dart';
13 import 'package:analyzer/src/generated/engine.dart';
14 import 'package:analyzer/src/generated/index.dart';
15 import 'package:analyzer/src/generated/java_engine.dart';
16 import 'package:analyzer/src/generated/source.dart';
17
18
19 /**
20 * A helper that encodes/decodes [AnalysisContext]s from/to integers.
21 *
22 * TODO(scheglov) add API to remove [AnalysisContext]s.
23 */
24 class ContextCodec {
25 /**
26 * A table mapping contexts to their unique indices.
27 */
28 Map<AnalysisContext, int> _contextToIndex = new HashMap<AnalysisContext, int>(
29 );
30
31 /**
32 * A table mapping indices to the corresponding contexts.
33 */
34 Map<int, AnalysisContext> _indexToContext = new HashMap<int, AnalysisContext>(
35 );
36
37 /**
38 * The next id to assign.
39 */
40 int _nextId = 0;
41
42 /**
43 * Returns the [AnalysisContext] that corresponds to the given index.
44 */
45 AnalysisContext decode(int index) => _indexToContext[index];
46
47 /**
48 * Returns an unique index for the given [AnalysisContext].
49 */
50 int encode(AnalysisContext context) {
51 int index = _contextToIndex[context];
52 if (index == null) {
53 index = _nextId++;
54 _contextToIndex[context] = index;
55 _indexToContext[index] = context;
56 }
57 return index;
58 }
59
60 /**
61 * Removes the given [context].
62 */
63 void remove(AnalysisContext context) {
64 int id = _contextToIndex.remove(context);
65 if (id != null) {
66 _indexToContext.remove(id);
67 }
68 }
69 }
70
71
72 /**
73 * A helper that encodes/decodes [Element]s to/from integers.
74 */
75 class ElementCodec {
76 /**
77 * A list that works as a mapping of integers to element encodings (in form of integer arrays).
78 */
79 List<List<int>> _indexToPath = [];
80
81 /**
82 * A table mapping element locations (in form of integer arrays) into a single integer.
83 */
84 IntArrayToIntMap _pathToIndex = new IntArrayToIntMap(10000, 0.75);
85
86 final StringCodec _stringCodec;
87
88 ElementCodec(this._stringCodec);
89
90 /**
91 * Returns an [Element] that corresponds to the given location.
92 *
93 * @param context the [AnalysisContext] to find [Element] in
94 * @param index an integer corresponding to the [Element]
95 * @return the [Element] or `null`
96 */
97 Element decode(AnalysisContext context, int index) {
98 List<int> path = _indexToPath[index];
99 List<String> components = _getLocationComponents(path);
100 ElementLocation location = new ElementLocationImpl.con3(components);
101 return context.getElement(location);
102 }
103
104 /**
105 * Returns a unique integer that corresponds to the given [Element].
106 */
107 int encode(Element element) {
108 List<int> path = _getLocationPath(element);
109 int index = _pathToIndex.get(path, -1);
110 if (index == -1) {
111 index = _indexToPath.length;
112 _pathToIndex.put(path, index);
113 _indexToPath.add(path);
114 }
115 return index;
116 }
117
118 List<String> _getLocationComponents(List<int> path) {
119 int length = path.length;
120 List<String> components = new List<String>();
121 for (int i = 0; i < length; i++) {
122 int componentId = path[i];
123 String component = _stringCodec.decode(componentId);
124 if (i < length - 1 && path[i + 1] < 0) {
125 component += '@${(-path[i + 1])}';
126 i++;
127 }
128 components.add(component);
129 }
130 return components;
131 }
132
133 List<int> _getLocationPath(Element element) {
134 List<String> components = element.location.components;
135 int length = components.length;
136 if (_hasLocalOffset(components)) {
137 List<int> path = new List<int>();
138 for (String component in components) {
139 int atOffset = component.indexOf('@');
140 if (atOffset == -1) {
141 path.add(_stringCodec.encode(component));
142 } else {
143 String preAtString = component.substring(0, atOffset);
144 String atString = component.substring(atOffset + 1);
145 path.add(_stringCodec.encode(preAtString));
146 path.add(-1 * int.parse(atString));
147 }
148 }
149 return path;
150 } else {
151 List<int> path = new List<int>.filled(length, 0);
152 for (int i = 0; i < length; i++) {
153 String component = components[i];
154 path[i] = _stringCodec.encode(component);
155 }
156 return path;
157 }
158 }
159
160 bool _hasLocalOffset(List<String> components) {
161 for (String component in components) {
162 if (component.indexOf('@') != -1) {
163 return true;
164 }
165 }
166 return false;
167 }
168 }
169
170
171 /**
172 * A manager for files content.
173 */
174 abstract class FileManager {
175 /**
176 * Removes all files.
177 */
178 void clear();
179
180 /**
181 * Deletes the file with the given name.
182 */
183 void delete(String name);
184
185 /**
186 * Read the entire file contents as a list of bytes.
187 */
188 Future<List<int>> read(String name);
189
190 /**
191 * Write a list of bytes to a file.
192 */
193 Future write(String name, Uint8List bytes);
194 }
195
196
197 /**
198 * A [FileManager] based [NodeManager].
199 */
200 class FileNodeManager implements NodeManager {
201 static int _VERSION = 1;
202
203 final ContextCodec contextCodec;
204
205 final ElementCodec elementCodec;
206
207 final StringCodec stringCodec;
208
209 final FileManager _fileManager;
210
211 int _locationCount = 0;
212
213 final Logger _logger;
214
215 Map<String, int> _nodeLocationCounts = {};
216
217 final RelationshipCodec _relationshipCodec;
218
219 FileNodeManager(this._fileManager, this._logger, this.stringCodec,
220 this.contextCodec, this.elementCodec, this._relationshipCodec);
221
222 @override
223 int get locationCount => _locationCount;
224
225 @override
226 void clear() {
227 _fileManager.clear();
228 }
229
230 @override
231 Future<IndexNode> getNode(String name) {
232 return _fileManager.read(name).then((List<int> bytes) {
233 if (bytes == null) {
234 return null;
235 }
236 _DataInputStream stream = new _DataInputStream(bytes);
237 return _readNode(stream);
238 }).catchError((e, stackTrace) {
239 _logger.logError2('Exception during reading index file ${name}',
240 new CaughtException(e, stackTrace));
241 });
242 }
243
244 @override
245 IndexNode newNode(AnalysisContext context) => new IndexNode(context,
246 elementCodec, _relationshipCodec);
247
248 @override
249 Future putNode(String name, IndexNode node) {
250 // update location count
251 {
252 _locationCount -= _getLocationCount(name);
253 int nodeLocationCount = node.locationCount;
254 _nodeLocationCounts[name] = nodeLocationCount;
255 _locationCount += nodeLocationCount;
256 }
257 // write the node
258 return new Future.microtask(() {
259 _DataOutputStream stream = new _DataOutputStream();
260 _writeNode(node, stream);
261 var bytes = stream.getBytes();
262 return _fileManager.write(name, bytes);
263 }).catchError((e, stackTrace) {
264 _logger.logError2('Exception during reading index file ${name}',
265 new CaughtException(e, stackTrace));
266 });
267 }
268
269 @override
270 void removeNode(String name) {
271 // update location count
272 _locationCount -= _getLocationCount(name);
273 _nodeLocationCounts.remove(name);
274 // remove node
275 _fileManager.delete(name);
276 }
277
278 int _getLocationCount(String name) {
279 int locationCount = _nodeLocationCounts[name];
280 return locationCount != null ? locationCount : 0;
281 }
282
283 RelationKeyData _readElementRelationKey(_DataInputStream stream) {
284 int elementId = stream.readInt();
285 int relationshipId = stream.readInt();
286 return new RelationKeyData.forData(elementId, relationshipId);
287 }
288
289 LocationData _readLocationData(_DataInputStream stream) {
290 int elementId = stream.readInt();
291 int offset = stream.readInt();
292 int length = stream.readInt();
293 return new LocationData.forData(elementId, offset, length);
294 }
295
296 IndexNode _readNode(_DataInputStream stream) {
297 // check version
298 {
299 int version = stream.readInt();
300 if (version != _VERSION) {
301 throw new StateError(
302 'Version ${_VERSION} expected, but ${version} found.');
303 }
304 }
305 // context
306 int contextId = stream.readInt();
307 AnalysisContext context = contextCodec.decode(contextId);
308 if (context == null) {
309 return null;
310 }
311 // relations
312 Map<RelationKeyData, List<LocationData>> relations = {};
313 int numRelations = stream.readInt();
314 for (int i = 0; i < numRelations; i++) {
315 RelationKeyData key = _readElementRelationKey(stream);
316 int numLocations = stream.readInt();
317 List<LocationData> locations = new List<LocationData>();
318 for (int j = 0; j < numLocations; j++) {
319 locations.add(_readLocationData(stream));
320 }
321 relations[key] = locations;
322 }
323 // create IndexNode
324 IndexNode node = new IndexNode(context, elementCodec, _relationshipCodec);
325 node.relations = relations;
326 return node;
327 }
328
329 void _writeElementRelationKey(_DataOutputStream stream, RelationKeyData key) {
330 stream.writeInt(key.elementId);
331 stream.writeInt(key.relationshipId);
332 }
333
334 void _writeNode(IndexNode node, _DataOutputStream stream) {
335 // version
336 stream.writeInt(_VERSION);
337 // context
338 {
339 AnalysisContext context = node.context;
340 int contextId = contextCodec.encode(context);
341 stream.writeInt(contextId);
342 }
343 // relations
344 Map<RelationKeyData, List<LocationData>> relations = node.relations;
345 stream.writeInt(relations.length);
346 relations.forEach((key, locations) {
347 _writeElementRelationKey(stream, key);
348 stream.writeInt(locations.length);
349 for (LocationData location in locations) {
350 stream.writeInt(location.elementId);
351 stream.writeInt(location.offset);
352 stream.writeInt(location.length);
353 }
354 });
355 }
356 }
357
358
359 /**
360 * A single index file in-memory presentation.
361 */
362 class IndexNode {
363 final AnalysisContext context;
364
365 final ElementCodec _elementCodec;
366
367 Map<RelationKeyData, List<LocationData>> _relations =
368 new HashMap<RelationKeyData, List<LocationData>>();
369
370 final RelationshipCodec _relationshipCodec;
371
372 IndexNode(this.context, this._elementCodec, this._relationshipCodec);
373
374 /**
375 * Returns number of locations in this node.
376 */
377 int get locationCount {
378 int locationCount = 0;
379 for (List<LocationData> locations in _relations.values) {
380 locationCount += locations.length;
381 }
382 return locationCount;
383 }
384
385 /**
386 * Returns the recorded relations.
387 */
388 Map<RelationKeyData, List<LocationData>> get relations => _relations;
389
390 /**
391 * Sets relations data. This method is used during loading data from a storage .
392 */
393 void set relations(Map<RelationKeyData, List<LocationData>> relations) {
394 this._relations.clear();
395 this._relations.addAll(relations);
396 }
397
398 /**
399 * Return the locations of the elements that have the given relationship with the given element.
400 *
401 * @param element the the element that has the relationship with the locations to be returned
402 * @param relationship the [Relationship] between the given element and the lo cations to be
403 * returned
404 */
405 List<Location> getRelationships(Element element, Relationship relationship) {
406 // prepare key
407 RelationKeyData key = new RelationKeyData.forObject(_elementCodec,
408 _relationshipCodec, element, relationship);
409 // find LocationData(s)
410 List<LocationData> locationDatas = _relations[key];
411 if (locationDatas == null) {
412 return Location.EMPTY_ARRAY;
413 }
414 // convert to Location(s)
415 List<Location> locations = [];
416 for (LocationData locationData in locationDatas) {
417 Location location = locationData.getLocation(context, _elementCodec);
418 if (location != null) {
419 locations.add(location);
420 }
421 }
422 return locations;
423 }
424
425 /**
426 * Records that the given element and location have the given relationship.
427 *
428 * @param element the element that is related to the location
429 * @param relationship the [Relationship] between the element and the location
430 * @param location the [Location] where relationship happens
431 */
432 void recordRelationship(Element element, Relationship relationship,
433 Location location) {
434 RelationKeyData key = new RelationKeyData.forObject(_elementCodec,
435 _relationshipCodec, element, relationship);
436 // prepare LocationData(s)
437 List<LocationData> locationDatas = _relations[key];
438 if (locationDatas == null) {
439 locationDatas = [];
440 _relations[key] = locationDatas;
441 }
442 // add new LocationData
443 locationDatas.add(new LocationData.forObject(_elementCodec, location));
444 }
445 }
446
447
448 class IntArrayToIntMap {
449 // TODO(scheglov) consider using Int32List
450 final Map<List<int>, int> map = new HashMap<List<int>, int>(equals:
451 _intArrayEquals, hashCode: _intArrayHashCode);
452
453 IntArrayToIntMap(int initialCapacity, double loadFactor);
454
455 int get(List<int> key, int defaultValue) {
456 int value = map[key];
457 if (value == null) {
458 return defaultValue;
459 }
460 return value;
461 }
462
463 void put(List<int> key, int value) {
464 map[key] = value;
465 }
466
467 static bool _intArrayEquals(List<int> a, List<int> b) {
468 int length = a.length;
469 if (length != b.length) {
470 return false;
471 }
472 for (int i = 0; i < length; i++) {
473 if (a[i] != b[i]) {
474 return false;
475 }
476 }
477 return true;
478 }
479
480 static int _intArrayHashCode(List<int> key) {
481 return key.fold(0, (int result, int item) {
482 return 31 * result + item;
483 });
484 }
485 }
486
487
488 class IntToIntSetMap {
489 // TODO(scheglov) consider using Int32List
490 final Map<int, List<int>> _map = new HashMap<int, List<int>>();
491 int _size = 0;
492
493 IntToIntSetMap(int initialCapacity, double loadFactor);
494
495 int get length => _size;
496
497 void add(int key, int value) {
498 List<int> values = _map[key];
499 if (values == null) {
500 values = new List<int>();
501 _map[key] = values;
502 }
503 if (values.indexOf(value) == -1) {
504 values.add(value);
505 _size++;
506 }
507 }
508
509 void clear() {
510 _map.clear();
511 _size = 0;
512 }
513
514 List<int> get(int key) {
515 List<int> values = _map[key];
516 if (values == null) {
517 values = <int>[];
518 }
519 return values;
520 }
521 }
522
523
524 /**
525 * A container with information about a [Location].
526 */
527 class LocationData {
528 final int elementId;
529 final int length;
530 final int offset;
531
532 LocationData.forData(this.elementId, this.offset, this.length);
533
534 LocationData.forObject(ElementCodec elementCodec, Location location)
535 : elementId = elementCodec.encode(location.element),
536 offset = location.offset,
537 length = location.length;
538
539 @override
540 int get hashCode {
541 return 31 * (31 * elementId + offset) + length;
542 }
543
544 @override
545 bool operator ==(Object obj) {
546 if (obj is! LocationData) {
547 return false;
548 }
549 LocationData other = obj;
550 return other.elementId == elementId && other.offset == offset &&
551 other.length == length;
552 }
553
554 /**
555 * Returns a {@link Location} that is represented by this {@link LocationData} .
556 */
557 Location getLocation(AnalysisContext context, ElementCodec elementCodec) {
558 Element element = elementCodec.decode(context, elementId);
559 if (element == null) {
560 return null;
561 }
562 return new Location(element, offset, length);
563 }
564 }
565
566
567 /**
568 * A manager for [IndexNode]s.
569 */
570 abstract class NodeManager {
571 /**
572 * The shared {@link ContextCodec} instance.
573 */
574 ContextCodec get contextCodec;
575
576 /**
577 * The shared {@link ElementCodec} instance.
578 */
579 ElementCodec get elementCodec;
580
581 /**
582 * A number of locations in all nodes.
583 */
584 int get locationCount;
585
586 /**
587 * The shared {@link StringCodec} instance.
588 */
589 StringCodec get stringCodec;
590
591 /**
592 * Removes all nodes.
593 */
594 void clear();
595
596 /**
597 * Returns the {@link IndexNode} with the given name, {@code null} if not foun d.
598 */
599 Future<IndexNode> getNode(String name);
600
601 /**
602 * Returns a new {@link IndexNode}.
603 */
604 IndexNode newNode(AnalysisContext context);
605
606 /**
607 * Associates the given {@link IndexNode} with the given name.
608 */
609 void putNode(String name, IndexNode node);
610
611 /**
612 * Removes the {@link IndexNode} with the given name.
613 */
614 void removeNode(String name);
615 }
616
617
618 /**
619 * An [Element] to [Location] relation key.
620 */
621 class RelationKeyData {
622 final int elementId;
623 final int relationshipId;
624
625 RelationKeyData.forData(this.elementId, this.relationshipId);
626
627 RelationKeyData.forObject(ElementCodec elementCodec,
628 RelationshipCodec relationshipCodec, Element element, Relationship relatio nship)
629 : elementId = elementCodec.encode(element),
630 relationshipId = relationshipCodec.encode(relationship);
631
632 @override
633 int get hashCode {
634 return 31 * elementId + relationshipId;
635 }
636
637 @override
638 bool operator ==(Object obj) {
639 if (obj is! RelationKeyData) {
640 return false;
641 }
642 RelationKeyData other = obj;
643 return other.elementId == elementId && other.relationshipId ==
644 relationshipId;
645 }
646 }
647
648
649 /**
650 * A helper that encodes/decodes [Relationship]s to/from integers.
651 */
652 class RelationshipCodec {
653 final StringCodec _stringCodec;
654
655 RelationshipCodec(this._stringCodec);
656
657 Relationship decode(int idIndex) {
658 String id = _stringCodec.decode(idIndex);
659 return Relationship.getRelationship(id);
660 }
661
662 int encode(Relationship relationship) {
663 String id = relationship.identifier;
664 return _stringCodec.encode(id);
665 }
666 }
667
668
669 /**
670 * An [IndexStore] which keeps index information in separate nodes for each unit .
671 */
672 class SplitIndexStore implements IndexStore {
673 /**
674 * The [ContextCodec] to encode/decode [AnalysisContext]s.
675 */
676 ContextCodec _contextCodec;
677
678 /**
679 * Information about "universe" elements.
680 * We need to keep them together to avoid loading of all index nodes.
681 *
682 * Order of keys: contextId, nodeId, Relationship.
683 */
684 Map<int, Map<int, Map<Relationship, List<LocationData>>>>
685 _contextNodeRelations = new HashMap<int, Map<int, Map<Relationship,
686 List<LocationData>>>>();
687
688 /**
689 * The mapping of library [Source] to the [Source]s of part units.
690 */
691 Map<AnalysisContext, Map<Source, Set<Source>>> _contextToLibraryToUnits =
692 new HashMap<AnalysisContext, Map<Source, Set<Source>>>();
693
694 /**
695 * The mapping of unit [Source] to the [Source]s of libraries it is used in.
696 */
697 Map<AnalysisContext, Map<Source, Set<Source>>> _contextToUnitToLibraries =
698 new HashMap<AnalysisContext, Map<Source, Set<Source>>>();
699
700 int _currentContextId = 0;
701
702 IndexNode _currentNode;
703
704 String _currentNodeName;
705
706 int _currentNodeNameId = 0;
707
708 /**
709 * The [ElementCodec] to encode/decode [Element]s.
710 */
711 ElementCodec _elementCodec;
712
713 /**
714 * A table mapping element names to the node names that may have relations wit h elements with
715 * these names.
716 */
717 IntToIntSetMap _nameToNodeNames = new IntToIntSetMap(10000, 0.75);
718
719 /**
720 * The [NodeManager] to get/put [IndexNode]s.
721 */
722 final NodeManager _nodeManager;
723
724 /**
725 * The set of known [Source]s.
726 */
727 Set<Source> _sources = new HashSet<Source>();
728
729 /**
730 * The [StringCodec] to encode/decode [String]s.
731 */
732 StringCodec _stringCodec;
733
734 SplitIndexStore(this._nodeManager) {
735 this._contextCodec = _nodeManager.contextCodec;
736 this._elementCodec = _nodeManager.elementCodec;
737 this._stringCodec = _nodeManager.stringCodec;
738 }
739
740 @override
741 String get statistics =>
742 '[${_nodeManager.locationCount} locations, ${_sources.length} sources, ${_ nameToNodeNames.length} names]';
743
744 @override
745 bool aboutToIndexDart(AnalysisContext context,
746 CompilationUnitElement unitElement) {
747 context = _unwrapContext(context);
748 // may be already disposed in other thread
749 if (context.isDisposed) {
750 return false;
751 }
752 // validate unit
753 if (unitElement == null) {
754 return false;
755 }
756 LibraryElement libraryElement = unitElement.library;
757 if (libraryElement == null) {
758 return false;
759 }
760 CompilationUnitElement definingUnitElement =
761 libraryElement.definingCompilationUnit;
762 if (definingUnitElement == null) {
763 return false;
764 }
765 // prepare sources
766 Source library = definingUnitElement.source;
767 Source unit = unitElement.source;
768 // special handling for the defining library unit
769 if (unit == library) {
770 // prepare new parts
771 Set<Source> newParts = new Set();
772 for (CompilationUnitElement part in libraryElement.parts) {
773 newParts.add(part.source);
774 }
775 // prepare old parts
776 Map<Source, Set<Source>> libraryToUnits =
777 _contextToLibraryToUnits[context];
778 if (libraryToUnits == null) {
779 libraryToUnits = {};
780 _contextToLibraryToUnits[context] = libraryToUnits;
781 }
782 Set<Source> oldParts = libraryToUnits[library];
783 // check if some parts are not in the library now
784 if (oldParts != null) {
785 Set<Source> noParts = oldParts.difference(newParts);
786 for (Source noPart in noParts) {
787 _removeLocations(context, library, noPart);
788 }
789 }
790 // remember new parts
791 libraryToUnits[library] = newParts;
792 }
793 // remember library/unit relations
794 _recordUnitInLibrary(context, library, unit);
795 _recordLibraryWithUnit(context, library, unit);
796 _sources.add(library);
797 _sources.add(unit);
798 // prepare node
799 String libraryName = library.fullName;
800 String unitName = unit.fullName;
801 int libraryNameIndex = _stringCodec.encode(libraryName);
802 int unitNameIndex = _stringCodec.encode(unitName);
803 _currentNodeName = '${libraryNameIndex}_${unitNameIndex}.index';
804 _currentNodeNameId = _stringCodec.encode(_currentNodeName);
805 _currentNode = _nodeManager.newNode(context);
806 _currentContextId = _contextCodec.encode(context);
807 // remove Universe information for the current node
808 for (Map<int, dynamic> nodeRelations in _contextNodeRelations.values) {
809 nodeRelations.remove(_currentNodeNameId);
810 }
811 // done
812 return true;
813 }
814
815 @override
816 bool aboutToIndexHtml(AnalysisContext context, HtmlElement htmlElement) {
817 context = _unwrapContext(context);
818 // may be already disposed in other thread
819 if (context.isDisposed) {
820 return false;
821 }
822 // remove locations
823 Source source = htmlElement.source;
824 _removeLocations(context, null, source);
825 // remember library/unit relations
826 _recordUnitInLibrary(context, null, source);
827 // prepare node
828 String sourceName = source.fullName;
829 int sourceNameIndex = _stringCodec.encode(sourceName);
830 _currentNodeName = '${sourceNameIndex}.index';
831 _currentNodeNameId = _stringCodec.encode(_currentNodeName);
832 _currentNode = _nodeManager.newNode(context);
833 return true;
834 }
835
836 @override
837 void clear() {
838 _nodeManager.clear();
839 _nameToNodeNames.clear();
840 }
841
842 @override
843 void doneIndex() {
844 if (_currentNode != null) {
845 _nodeManager.putNode(_currentNodeName, _currentNode);
846 _currentNodeName = null;
847 _currentNodeNameId = -1;
848 _currentNode = null;
849 _currentContextId = -1;
850 }
851 }
852
853 @override
854 List<Location> getRelationships(Element element, Relationship relationship) {
855 // TODO(scheglov) make IndexStore interface async
856 return <Location>[];
857 }
858
859 Future<List<Location>> getRelationshipsAsync(Element element,
860 Relationship relationship) {
861 // special support for UniverseElement
862 if (identical(element, UniverseElement.INSTANCE)) {
863 List<Location> locations = _getRelationshipsUniverse(relationship);
864 return new Future.value(locations);
865 }
866 // prepare node names
867 String name = _getElementName(element);
868 int nameId = _stringCodec.encode(name);
869 List<int> nodeNameIds = _nameToNodeNames.get(nameId);
870 // prepare Future(s) for reading each IndexNode
871 List<Future<List<Location>>> nodeFutures = <Future<List<Location>>>[];
872 for (int nodeNameId in nodeNameIds) {
873 String nodeName = _stringCodec.decode(nodeNameId);
874 Future<IndexNode> nodeFuture = _nodeManager.getNode(nodeName);
875 Future<List<Location>> locationsFuture = nodeFuture.then((node) {
876 if (node == null) {
877 // TODO(scheglov) remove node
878 return Location.EMPTY_ARRAY;
879 }
880 return node.getRelationships(element, relationship);
881 });
882 nodeFutures.add(locationsFuture);
883 }
884 // return Future that merges separate IndexNode Location(s)
885 return Future.wait(nodeFutures).then((List<List<Location>> locationsList) {
886 List<Location> allLocations = <Location>[];
887 for (List<Location> locations in locationsList) {
888 allLocations.addAll(locations);
889 }
890 return allLocations;
891 });
892 }
893
894 @override
895 void recordRelationship(Element element, Relationship relationship,
896 Location location) {
897 if (element == null || location == null) {
898 return;
899 }
900 // special support for UniverseElement
901 if (identical(element, UniverseElement.INSTANCE)) {
902 _recordRelationshipUniverse(relationship, location);
903 return;
904 }
905 // other elements
906 _recordNodeNameForElement(element);
907 _currentNode.recordRelationship(element, relationship, location);
908 }
909
910 @override
911 void removeContext(AnalysisContext context) {
912 context = _unwrapContext(context);
913 if (context == null) {
914 return;
915 }
916 // remove sources
917 removeSources(context, null);
918 // remove context information
919 _contextToLibraryToUnits.remove(context);
920 _contextToUnitToLibraries.remove(context);
921 _contextNodeRelations.remove(_contextCodec.encode(context));
922 // remove context from codec
923 _contextCodec.remove(context);
924 }
925
926 @override
927 void removeSource(AnalysisContext context, Source source) {
928 context = _unwrapContext(context);
929 if (context == null) {
930 return;
931 }
932 // remove nodes for unit/library pairs
933 Map<Source, Set<Source>> unitToLibraries =
934 _contextToUnitToLibraries[context];
935 if (unitToLibraries != null) {
936 Set<Source> libraries = unitToLibraries.remove(source);
937 if (libraries != null) {
938 for (Source library in libraries) {
939 _removeLocations(context, library, source);
940 }
941 }
942 }
943 // remove nodes for library/unit pairs
944 Map<Source, Set<Source>> libraryToUnits = _contextToLibraryToUnits[context];
945 if (libraryToUnits != null) {
946 Set<Source> units = libraryToUnits.remove(source);
947 if (units != null) {
948 for (Source unit in units) {
949 _removeLocations(context, source, unit);
950 }
951 }
952 }
953 }
954
955 @override
956 void removeSources(AnalysisContext context, SourceContainer container) {
957 context = _unwrapContext(context);
958 if (context == null) {
959 return;
960 }
961 // remove nodes for unit/library pairs
962 Map<Source, Set<Source>> unitToLibraries =
963 _contextToUnitToLibraries[context];
964 if (unitToLibraries != null) {
965 List<Source> units = new List<Source>.from(unitToLibraries.keys);
966 for (Source source in units) {
967 if (container == null || container.contains(source)) {
968 removeSource(context, source);
969 }
970 }
971 }
972 // remove nodes for library/unit pairs
973 Map<Source, Set<Source>> libraryToUnits = _contextToLibraryToUnits[context];
974 if (libraryToUnits != null) {
975 List<Source> libraries = new List<Source>.from(libraryToUnits.keys);
976 for (Source source in libraries) {
977 if (container == null || container.contains(source)) {
978 removeSource(context, source);
979 }
980 }
981 }
982 }
983
984 String _getElementName(Element element) => element.name;
985
986 List<Location> _getRelationshipsUniverse(Relationship relationship) {
987 List<Location> locations = [];
988 _contextNodeRelations.forEach((contextId, contextRelations) {
989 AnalysisContext context = _contextCodec.decode(contextId);
990 if (context != null) {
991 for (Map<Relationship, List<LocationData>> nodeRelations in
992 contextRelations.values) {
993 List<LocationData> nodeLocations = nodeRelations[relationship];
994 if (nodeLocations != null) {
995 for (LocationData locationData in nodeLocations) {
996 Location location = locationData.getLocation(context,
997 _elementCodec);
998 if (location != null) {
999 locations.add(location);
1000 }
1001 }
1002 }
1003 }
1004 }
1005 });
1006 return locations;
1007 }
1008
1009 void _recordLibraryWithUnit(AnalysisContext context, Source library,
1010 Source unit) {
1011 Map<Source, Set<Source>> libraryToUnits = _contextToLibraryToUnits[context];
1012 if (libraryToUnits == null) {
1013 libraryToUnits = {};
1014 _contextToLibraryToUnits[context] = libraryToUnits;
1015 }
1016 Set<Source> units = libraryToUnits[library];
1017 if (units == null) {
1018 units = new Set();
1019 libraryToUnits[library] = units;
1020 }
1021 units.add(unit);
1022 }
1023
1024 void _recordNodeNameForElement(Element element) {
1025 String name = _getElementName(element);
1026 int nameId = _stringCodec.encode(name);
1027 _nameToNodeNames.add(nameId, _currentNodeNameId);
1028 }
1029
1030 void _recordRelationshipUniverse(Relationship relationship,
1031 Location location) {
1032 // in current context
1033 Map<int, Map<Relationship, List<LocationData>>> nodeRelations =
1034 _contextNodeRelations[_currentContextId];
1035 if (nodeRelations == null) {
1036 nodeRelations = {};
1037 _contextNodeRelations[_currentContextId] = nodeRelations;
1038 }
1039 // in current node
1040 Map<Relationship, List<LocationData>> relations =
1041 nodeRelations[_currentNodeNameId];
1042 if (relations == null) {
1043 relations = {};
1044 nodeRelations[_currentNodeNameId] = relations;
1045 }
1046 // for the given relationship
1047 List<LocationData> locations = relations[relationship];
1048 if (locations == null) {
1049 locations = [];
1050 relations[relationship] = locations;
1051 }
1052 // record LocationData
1053 locations.add(new LocationData.forObject(_elementCodec, location));
1054 }
1055
1056 void _recordUnitInLibrary(AnalysisContext context, Source library,
1057 Source unit) {
1058 Map<Source, Set<Source>> unitToLibraries =
1059 _contextToUnitToLibraries[context];
1060 if (unitToLibraries == null) {
1061 unitToLibraries = {};
1062 _contextToUnitToLibraries[context] = unitToLibraries;
1063 }
1064 Set<Source> libraries = unitToLibraries[unit];
1065 if (libraries == null) {
1066 libraries = new Set();
1067 unitToLibraries[unit] = libraries;
1068 }
1069 libraries.add(library);
1070 }
1071
1072 /**
1073 * Removes locations recorded in the given library/unit pair.
1074 */
1075 void _removeLocations(AnalysisContext context, Source library, Source unit) {
1076 // remove node
1077 String libraryName = library != null ? library.fullName : null;
1078 String unitName = unit.fullName;
1079 int libraryNameIndex = _stringCodec.encode(libraryName);
1080 int unitNameIndex = _stringCodec.encode(unitName);
1081 String nodeName = '${libraryNameIndex}_${unitNameIndex}.index';
1082 _nodeManager.removeNode(nodeName);
1083 // remove source
1084 _sources.remove(library);
1085 _sources.remove(unit);
1086 }
1087
1088 /**
1089 * When logging is on, [AnalysisEngine] actually creates
1090 * [InstrumentedAnalysisContextImpl], which wraps [AnalysisContextImpl] used t o create
1091 * actual [Element]s. So, in index we have to unwrap [InstrumentedAnalysisCont extImpl]
1092 * when perform any operation.
1093 */
1094 AnalysisContext _unwrapContext(AnalysisContext context) {
1095 if (context is InstrumentedAnalysisContextImpl) {
1096 context = (context as InstrumentedAnalysisContextImpl).basis;
1097 }
1098 return context;
1099 }
1100 }
1101
1102
1103 /**
1104 * A helper that encodes/decodes [String]s from/to integers.
1105 */
1106 class StringCodec {
1107 /**
1108 * A table mapping names to their unique indices.
1109 */
1110 final Map<String, int> nameToIndex = {};
1111
1112 /**
1113 * A table mapping indices to the corresponding strings.
1114 */
1115 List<String> _indexToName = [];
1116
1117 /**
1118 * Returns the [String] that corresponds to the given index.
1119 */
1120 String decode(int index) => _indexToName[index];
1121
1122 /**
1123 * Returns an unique index for the given [String].
1124 */
1125 int encode(String name) {
1126 int index = nameToIndex[name];
1127 if (index == null) {
1128 index = _indexToName.length;
1129 nameToIndex[name] = index;
1130 _indexToName.add(name);
1131 }
1132 return index;
1133 }
1134 }
1135
1136
1137 class _DataInputStream {
1138 ByteData _byteData;
1139 int _byteOffset = 0;
1140
1141 _DataInputStream(List<int> bytes) {
1142 ByteBuffer buffer = new Uint8List.fromList(bytes).buffer;
1143 _byteData = new ByteData.view(buffer);
1144 }
1145
1146 int readInt() {
1147 int result = _byteData.getInt32(_byteOffset);
1148 _byteOffset += 4;
1149 return result;
1150 }
1151 }
1152
1153
1154 class _DataOutputStream {
1155 BytesBuilder _buffer = new BytesBuilder();
1156
1157 Uint8List getBytes() {
1158 return new Uint8List.fromList(_buffer.takeBytes());
1159 }
1160
1161 void writeInt(int value) {
1162 _buffer.addByte((value & 0xFF000000) >> 24);
1163 _buffer.addByte((value & 0x00FF0000) >> 16);
1164 _buffer.addByte((value & 0x0000FF00) >> 8);
1165 _buffer.addByte(value & 0xFF);
1166 }
1167 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analysis_server/lib/src/index/store/codec.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698