Index: dart/editor/tools/plugins/com.google.dart.engine/src/com/google/dart/engine/internal/index/file/SplitIndexStoreImpl.java |
=================================================================== |
--- dart/editor/tools/plugins/com.google.dart.engine/src/com/google/dart/engine/internal/index/file/SplitIndexStoreImpl.java (revision 0) |
+++ dart/editor/tools/plugins/com.google.dart.engine/src/com/google/dart/engine/internal/index/file/SplitIndexStoreImpl.java (revision 0) |
@@ -0,0 +1,451 @@ |
+/* |
+ * Copyright (c) 2014, the Dart project authors. |
+ * |
+ * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except |
+ * in compliance with the License. You may obtain a copy of the License at |
+ * |
+ * http://www.eclipse.org/legal/epl-v10.html |
+ * |
+ * Unless required by applicable law or agreed to in writing, software distributed under the License |
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
+ * or implied. See the License for the specific language governing permissions and limitations under |
+ * the License. |
+ */ |
+ |
+package com.google.dart.engine.internal.index.file; |
+ |
+import com.google.common.collect.Lists; |
+import com.google.common.collect.Maps; |
+import com.google.common.collect.Sets; |
+import com.google.dart.engine.AnalysisEngine; |
+import com.google.dart.engine.context.AnalysisContext; |
+import com.google.dart.engine.element.CompilationUnitElement; |
+import com.google.dart.engine.element.Element; |
+import com.google.dart.engine.element.ElementKind; |
+import com.google.dart.engine.element.HtmlElement; |
+import com.google.dart.engine.element.LibraryElement; |
+import com.google.dart.engine.index.IndexStore; |
+import com.google.dart.engine.index.Location; |
+import com.google.dart.engine.index.Relationship; |
+import com.google.dart.engine.index.UniverseElement; |
+import com.google.dart.engine.internal.context.AnalysisContextImpl; |
+import com.google.dart.engine.internal.context.InstrumentedAnalysisContextImpl; |
+import com.google.dart.engine.source.Source; |
+import com.google.dart.engine.source.SourceContainer; |
+ |
+import org.apache.commons.lang3.ArrayUtils; |
+ |
+import java.util.Collections; |
+import java.util.List; |
+import java.util.Map; |
+import java.util.Map.Entry; |
+import java.util.Set; |
+ |
+/** |
+ * An {@link IndexStore} which keeps index information in separate nodes for each unit. |
+ * |
+ * @coverage dart.engine.index |
+ */ |
+public class SplitIndexStoreImpl implements IndexStore { |
+ /** |
+ * The {@link NodeManager} to get/put {@link IndexNode}s. |
+ */ |
+ private final NodeManager nodeManager; |
+ |
+ /** |
+ * The {@link ContextCodec} to encode/decode {@link AnalysisContext}s. |
+ */ |
+ private final ContextCodec contextCodec; |
+ |
+ /** |
+ * The {@link ElementCodec} to encode/decode {@link Element}s. |
+ */ |
+ private final ElementCodec elementCodec; |
+ |
+ /** |
+ * The {@link StringCodec} to encode/decode {@link String}s. |
+ */ |
+ private final StringCodec stringCodec; |
+ |
+ /** |
+ * A table mapping element names to the node names that may have relations with elements with |
+ * these names. |
+ */ |
+ private final IntToIntSetMap nameToNodeNames = new IntToIntSetMap(10000, 0.75f); |
+ |
+ /** |
+ * Information about "universe" elements. We need to keep them together to avoid loading of all |
+ * index nodes. |
+ * <p> |
+ * Order of keys: contextId, nodeId, Relationship. |
+ */ |
+ private final Map<Integer, Map<Integer, Map<Relationship, List<LocationData>>>> contextNodeRelations = Maps.newHashMap(); |
+ |
+ /** |
+ * The mapping of library {@link Source} to the {@link Source}s of part units. |
+ */ |
+ final Map<AnalysisContext, Map<Source, Set<Source>>> contextToLibraryToUnits = Maps.newHashMap(); |
+ |
+ /** |
+ * The mapping of unit {@link Source} to the {@link Source}s of libraries it is used in. |
+ */ |
+ final Map<AnalysisContext, Map<Source, Set<Source>>> contextToUnitToLibraries = Maps.newHashMap(); |
+ |
+ /** |
+ * The set of known {@link Source}s. |
+ */ |
+ private final Set<Source> sources = Sets.newHashSet(); |
+ |
+ private int currentContextId; |
+ private String currentNodeName; |
+ private int currentNodeNameId; |
+ private IndexNode currentNode; |
+ |
+ public SplitIndexStoreImpl(NodeManager nodeManager) { |
+ this.nodeManager = nodeManager; |
+ this.contextCodec = nodeManager.getContextCodec(); |
+ this.elementCodec = nodeManager.getElementCodec(); |
+ this.stringCodec = nodeManager.getStringCodec(); |
+ } |
+ |
+ @Override |
+ public boolean aboutToIndexDart(AnalysisContext context, CompilationUnitElement unitElement) { |
+ context = unwrapContext(context); |
+ // may be already disposed in other thread |
+ if (context.isDisposed()) { |
+ return false; |
+ } |
+ // validate unit |
+ if (unitElement == null) { |
+ return false; |
+ } |
+ LibraryElement libraryElement = unitElement.getLibrary(); |
+ if (libraryElement == null) { |
+ return false; |
+ } |
+ CompilationUnitElement definingUnitElement = libraryElement.getDefiningCompilationUnit(); |
+ if (definingUnitElement == null) { |
+ return false; |
+ } |
+ // prepare sources |
+ Source library = definingUnitElement.getSource(); |
+ Source unit = unitElement.getSource(); |
+ // special handling for the defining library unit |
+ if (unit.equals(library)) { |
+ // prepare new parts |
+ Set<Source> newParts = Sets.newHashSet(); |
+ for (CompilationUnitElement part : libraryElement.getParts()) { |
+ newParts.add(part.getSource()); |
+ } |
+ // prepare old parts |
+ Map<Source, Set<Source>> libraryToUnits = contextToLibraryToUnits.get(context); |
+ if (libraryToUnits == null) { |
+ libraryToUnits = Maps.newHashMap(); |
+ contextToLibraryToUnits.put(context, libraryToUnits); |
+ } |
+ Set<Source> oldParts = libraryToUnits.get(library); |
+ // check if some parts are not in the library now |
+ if (oldParts != null) { |
+ Set<Source> noParts = Sets.difference(oldParts, newParts); |
+ for (Source noPart : noParts) { |
+ removeLocations(context, library, noPart); |
+ } |
+ } |
+ // remember new parts |
+ libraryToUnits.put(library, newParts); |
+ } |
+ // remember library/unit relations |
+ recordUnitInLibrary(context, library, unit); |
+ recordLibraryWithUnit(context, library, unit); |
+ sources.add(library); |
+ sources.add(unit); |
+ // prepare node |
+ String libraryName = library.getFullName(); |
+ String unitName = unit.getFullName(); |
+ int libraryNameIndex = stringCodec.encode(libraryName); |
+ int unitNameIndex = stringCodec.encode(unitName); |
+ currentNodeName = libraryNameIndex + "_" + unitNameIndex + ".index"; |
+ currentNodeNameId = stringCodec.encode(currentNodeName); |
+ currentNode = nodeManager.newNode(context); |
+ currentContextId = contextCodec.encode(context); |
+ // remove Universe information for the current node |
+ for (Map<Integer, ?> nodeRelations : contextNodeRelations.values()) { |
+ nodeRelations.remove(currentNodeNameId); |
+ } |
+ // done |
+ return true; |
+ } |
+ |
+ @Override |
+ public boolean aboutToIndexHtml(AnalysisContext context, HtmlElement htmlElement) { |
+ context = unwrapContext(context); |
+ // may be already disposed in other thread |
+ if (context.isDisposed()) { |
+ return false; |
+ } |
+ // remove locations |
+ Source source = htmlElement.getSource(); |
+ removeLocations(context, null, source); |
+ // remember library/unit relations |
+ recordUnitInLibrary(context, null, source); |
+ // prepare node |
+ String sourceName = source.getFullName(); |
+ int sourceNameIndex = stringCodec.encode(sourceName); |
+ currentNodeName = sourceNameIndex + ".index"; |
+ currentNodeNameId = stringCodec.encode(currentNodeName); |
+ currentNode = nodeManager.newNode(context); |
+ return true; |
+ } |
+ |
+ @Override |
+ public void clear() { |
+ nodeManager.clear(); |
+ nameToNodeNames.clear(); |
+ } |
+ |
+ @Override |
+ public void doneIndex() { |
+ if (currentNode != null) { |
+ nodeManager.putNode(currentNodeName, currentNode); |
+ currentNodeName = null; |
+ currentNodeNameId = -1; |
+ currentNode = null; |
+ currentContextId = -1; |
+ } |
+ } |
+ |
+ @Override |
+ public Location[] getRelationships(Element element, Relationship relationship) { |
+ // special support for UniverseElement |
+ if (element == UniverseElement.INSTANCE) { |
+ return getRelationshipsUniverse(relationship); |
+ } |
+ // prepare node names |
+ String name = getElementName(element); |
+ int nameId = stringCodec.encode(name); |
+ int[] nodeNameIds = nameToNodeNames.get(nameId); |
+ // check each node |
+ List<Location> locations = Lists.newArrayList(); |
+ for (int i = 0; i < nodeNameIds.length; i++) { |
+ int nodeNameId = nodeNameIds[i]; |
+ String nodeName = stringCodec.decode(nodeNameId); |
+ IndexNode node = nodeManager.getNode(nodeName); |
+ if (node != null) { |
+ Collections.addAll(locations, node.getRelationships(element, relationship)); |
+ } else { |
+ nodeNameIds = ArrayUtils.removeElement(nodeNameIds, nodeNameId); |
+ i--; |
+ } |
+ } |
+ // done |
+ return locations.toArray(new Location[locations.size()]); |
+ } |
+ |
+ @Override |
+ public String getStatistics() { |
+ return "[" + nodeManager.getLocationCount() + " locations, " + sources.size() + " sources, " |
+ + nameToNodeNames.size() + " names]"; |
+ } |
+ |
+ @Override |
+ public void recordRelationship(Element element, Relationship relationship, Location location) { |
+ if (element == null || element.getKind() == ElementKind.ERROR) { |
+ return; |
+ } |
+ if (location == null) { |
+ return; |
+ } |
+ // special support for UniverseElement |
+ if (element == UniverseElement.INSTANCE) { |
+ recordRelationshipUniverse(relationship, location); |
+ return; |
+ } |
+ // other elements |
+ recordNodeNameForElement(element); |
+ currentNode.recordRelationship(element, relationship, location); |
+ } |
+ |
+ @Override |
+ public void removeContext(AnalysisContext context) { |
+ context = unwrapContext(context); |
+ if (context == null) { |
+ return; |
+ } |
+ // remove sources |
+ removeSources(context, null); |
+ // remove context information |
+ contextToLibraryToUnits.remove(context); |
+ contextToUnitToLibraries.remove(context); |
+ contextNodeRelations.remove(contextCodec.encode(context)); |
+ // remove context from codec |
+ contextCodec.removeContext(context); |
+ } |
+ |
+ @Override |
+ public void removeSource(AnalysisContext context, Source source) { |
+ context = unwrapContext(context); |
+ if (context == null) { |
+ return; |
+ } |
+ // remove nodes for unit/library pairs |
+ Map<Source, Set<Source>> unitToLibraries = contextToUnitToLibraries.get(context); |
+ if (unitToLibraries != null) { |
+ Set<Source> libraries = unitToLibraries.remove(source); |
+ if (libraries != null) { |
+ for (Source library : libraries) { |
+ removeLocations(context, library, source); |
+ } |
+ } |
+ } |
+ // remove nodes for library/unit pairs |
+ Map<Source, Set<Source>> libraryToUnits = contextToLibraryToUnits.get(context); |
+ if (libraryToUnits != null) { |
+ Set<Source> units = libraryToUnits.remove(source); |
+ if (units != null) { |
+ for (Source unit : units) { |
+ removeLocations(context, source, unit); |
+ } |
+ } |
+ } |
+ } |
+ |
+ @Override |
+ public void removeSources(AnalysisContext context, SourceContainer container) { |
+ context = unwrapContext(context); |
+ if (context == null) { |
+ return; |
+ } |
+ // remove nodes for unit/library pairs |
+ Map<Source, Set<Source>> unitToLibraries = contextToUnitToLibraries.get(context); |
+ if (unitToLibraries != null) { |
+ List<Source> units = Lists.newArrayList(unitToLibraries.keySet()); |
+ for (Source source : units) { |
+ if (container == null || container.contains(source)) { |
+ removeSource(context, source); |
+ } |
+ } |
+ } |
+ // remove nodes for library/unit pairs |
+ Map<Source, Set<Source>> libraryToUnits = contextToLibraryToUnits.get(context); |
+ if (libraryToUnits != null) { |
+ List<Source> libraries = Lists.newArrayList(libraryToUnits.keySet()); |
+ for (Source source : libraries) { |
+ if (container == null || container.contains(source)) { |
+ removeSource(context, source); |
+ } |
+ } |
+ } |
+ } |
+ |
+ private String getElementName(Element element) { |
+ return element.getName(); |
+ } |
+ |
+ private Location[] getRelationshipsUniverse(Relationship relationship) { |
+ List<Location> locations = Lists.newArrayList(); |
+ for (Entry<Integer, Map<Integer, Map<Relationship, List<LocationData>>>> contextEntry : contextNodeRelations.entrySet()) { |
+ int contextId = contextEntry.getKey(); |
+ AnalysisContext context = contextCodec.decode(contextId); |
+ if (context != null) { |
+ for (Map<Relationship, List<LocationData>> nodeRelations : contextEntry.getValue().values()) { |
+ List<LocationData> nodeLocations = nodeRelations.get(relationship); |
+ if (nodeLocations != null) { |
+ for (LocationData locationData : nodeLocations) { |
+ Location location = locationData.getLocation(context, elementCodec); |
+ if (location != null) { |
+ locations.add(location); |
+ } |
+ } |
+ } |
+ } |
+ } |
+ } |
+ return locations.toArray(new Location[locations.size()]); |
+ } |
+ |
+ private void recordLibraryWithUnit(AnalysisContext context, Source library, Source unit) { |
+ Map<Source, Set<Source>> libraryToUnits = contextToLibraryToUnits.get(context); |
+ if (libraryToUnits == null) { |
+ libraryToUnits = Maps.newHashMap(); |
+ contextToLibraryToUnits.put(context, libraryToUnits); |
+ } |
+ Set<Source> units = libraryToUnits.get(library); |
+ if (units == null) { |
+ units = Sets.newHashSet(); |
+ libraryToUnits.put(library, units); |
+ } |
+ units.add(unit); |
+ } |
+ |
+ private void recordNodeNameForElement(Element element) { |
+ String name = getElementName(element); |
+ int nameId = stringCodec.encode(name); |
+ nameToNodeNames.add(nameId, currentNodeNameId); |
+ } |
+ |
+ private void recordRelationshipUniverse(Relationship relationship, Location location) { |
+ // in current context |
+ Map<Integer, Map<Relationship, List<LocationData>>> nodeRelations = contextNodeRelations.get(currentContextId); |
+ if (nodeRelations == null) { |
+ nodeRelations = Maps.newHashMap(); |
+ contextNodeRelations.put(currentContextId, nodeRelations); |
+ } |
+ // in current node |
+ Map<Relationship, List<LocationData>> relations = nodeRelations.get(currentNodeNameId); |
+ if (relations == null) { |
+ relations = Maps.newHashMap(); |
+ nodeRelations.put(currentNodeNameId, relations); |
+ } |
+ // for the given relationship |
+ List<LocationData> locations = relations.get(relationship); |
+ if (locations == null) { |
+ locations = Lists.newArrayList(); |
+ relations.put(relationship, locations); |
+ } |
+ // record LocationData |
+ locations.add(new LocationData(elementCodec, location)); |
+ } |
+ |
+ private void recordUnitInLibrary(AnalysisContext context, Source library, Source unit) { |
+ Map<Source, Set<Source>> unitToLibraries = contextToUnitToLibraries.get(context); |
+ if (unitToLibraries == null) { |
+ unitToLibraries = Maps.newHashMap(); |
+ contextToUnitToLibraries.put(context, unitToLibraries); |
+ } |
+ Set<Source> libraries = unitToLibraries.get(unit); |
+ if (libraries == null) { |
+ libraries = Sets.newHashSet(); |
+ unitToLibraries.put(unit, libraries); |
+ } |
+ libraries.add(library); |
+ } |
+ |
+ /** |
+ * Removes locations recorded in the given library/unit pair. |
+ */ |
+ private void removeLocations(AnalysisContext context, Source library, Source unit) { |
+ // remove node |
+ String libraryName = library != null ? library.getFullName() : null; |
+ String unitName = unit.getFullName(); |
+ int libraryNameIndex = stringCodec.encode(libraryName); |
+ int unitNameIndex = stringCodec.encode(unitName); |
+ String nodeName = libraryNameIndex + "_" + unitNameIndex + ".index"; |
+ nodeManager.removeNode(nodeName); |
+ // remove source |
+ sources.remove(library); |
+ sources.remove(unit); |
+ } |
+ |
+ /** |
+ * When logging is on, {@link AnalysisEngine} actually creates |
+ * {@link InstrumentedAnalysisContextImpl}, which wraps {@link AnalysisContextImpl} used to create |
+ * actual {@link Element}s. So, in index we have to unwrap {@link InstrumentedAnalysisContextImpl} |
+ * when perform any operation. |
+ */ |
+ private AnalysisContext unwrapContext(AnalysisContext context) { |
+ if (context instanceof InstrumentedAnalysisContextImpl) { |
+ context = ((InstrumentedAnalysisContextImpl) context).getBasis(); |
+ } |
+ return context; |
+ } |
+} |
Property changes on: dart/editor/tools/plugins/com.google.dart.engine/src/com/google/dart/engine/internal/index/file/SplitIndexStoreImpl.java |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |