OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (c) 2014, the Dart project authors. |
| 3 * |
| 4 * Licensed under the Eclipse Public License v1.0 (the "License"); you may not u
se this file except |
| 5 * in compliance with the License. You may obtain a copy of the License at |
| 6 * |
| 7 * http://www.eclipse.org/legal/epl-v10.html |
| 8 * |
| 9 * Unless required by applicable law or agreed to in writing, software distribut
ed under the License |
| 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY K
IND, either express |
| 11 * or implied. See the License for the specific language governing permissions a
nd limitations under |
| 12 * the License. |
| 13 */ |
| 14 |
| 15 package com.google.dart.engine.internal.index.file; |
| 16 |
| 17 import com.google.common.collect.Lists; |
| 18 import com.google.common.collect.Maps; |
| 19 import com.google.common.collect.Sets; |
| 20 import com.google.dart.engine.AnalysisEngine; |
| 21 import com.google.dart.engine.context.AnalysisContext; |
| 22 import com.google.dart.engine.element.CompilationUnitElement; |
| 23 import com.google.dart.engine.element.Element; |
| 24 import com.google.dart.engine.element.ElementKind; |
| 25 import com.google.dart.engine.element.HtmlElement; |
| 26 import com.google.dart.engine.element.LibraryElement; |
| 27 import com.google.dart.engine.index.IndexStore; |
| 28 import com.google.dart.engine.index.Location; |
| 29 import com.google.dart.engine.index.Relationship; |
| 30 import com.google.dart.engine.index.UniverseElement; |
| 31 import com.google.dart.engine.internal.context.AnalysisContextImpl; |
| 32 import com.google.dart.engine.internal.context.InstrumentedAnalysisContextImpl; |
| 33 import com.google.dart.engine.source.Source; |
| 34 import com.google.dart.engine.source.SourceContainer; |
| 35 |
| 36 import org.apache.commons.lang3.ArrayUtils; |
| 37 |
| 38 import java.util.Collections; |
| 39 import java.util.List; |
| 40 import java.util.Map; |
| 41 import java.util.Map.Entry; |
| 42 import java.util.Set; |
| 43 |
| 44 /** |
| 45 * An {@link IndexStore} which keeps index information in separate nodes for eac
h unit. |
| 46 * |
| 47 * @coverage dart.engine.index |
| 48 */ |
| 49 public class SplitIndexStoreImpl implements IndexStore { |
| 50 /** |
| 51 * The {@link NodeManager} to get/put {@link IndexNode}s. |
| 52 */ |
| 53 private final NodeManager nodeManager; |
| 54 |
| 55 /** |
| 56 * The {@link ContextCodec} to encode/decode {@link AnalysisContext}s. |
| 57 */ |
| 58 private final ContextCodec contextCodec; |
| 59 |
| 60 /** |
| 61 * The {@link ElementCodec} to encode/decode {@link Element}s. |
| 62 */ |
| 63 private final ElementCodec elementCodec; |
| 64 |
| 65 /** |
| 66 * The {@link StringCodec} to encode/decode {@link String}s. |
| 67 */ |
| 68 private final StringCodec stringCodec; |
| 69 |
| 70 /** |
| 71 * A table mapping element names to the node names that may have relations wit
h elements with |
| 72 * these names. |
| 73 */ |
| 74 private final IntToIntSetMap nameToNodeNames = new IntToIntSetMap(10000, 0.75f
); |
| 75 |
| 76 /** |
| 77 * Information about "universe" elements. We need to keep them together to avo
id loading of all |
| 78 * index nodes. |
| 79 * <p> |
| 80 * Order of keys: contextId, nodeId, Relationship. |
| 81 */ |
| 82 private final Map<Integer, Map<Integer, Map<Relationship, List<LocationData>>>
> contextNodeRelations = Maps.newHashMap(); |
| 83 |
| 84 /** |
| 85 * The mapping of library {@link Source} to the {@link Source}s of part units. |
| 86 */ |
| 87 final Map<AnalysisContext, Map<Source, Set<Source>>> contextToLibraryToUnits =
Maps.newHashMap(); |
| 88 |
| 89 /** |
| 90 * The mapping of unit {@link Source} to the {@link Source}s of libraries it i
s used in. |
| 91 */ |
| 92 final Map<AnalysisContext, Map<Source, Set<Source>>> contextToUnitToLibraries
= Maps.newHashMap(); |
| 93 |
| 94 /** |
| 95 * The set of known {@link Source}s. |
| 96 */ |
| 97 private final Set<Source> sources = Sets.newHashSet(); |
| 98 |
| 99 private int currentContextId; |
| 100 private String currentNodeName; |
| 101 private int currentNodeNameId; |
| 102 private IndexNode currentNode; |
| 103 |
| 104 public SplitIndexStoreImpl(NodeManager nodeManager) { |
| 105 this.nodeManager = nodeManager; |
| 106 this.contextCodec = nodeManager.getContextCodec(); |
| 107 this.elementCodec = nodeManager.getElementCodec(); |
| 108 this.stringCodec = nodeManager.getStringCodec(); |
| 109 } |
| 110 |
| 111 @Override |
| 112 public boolean aboutToIndexDart(AnalysisContext context, CompilationUnitElemen
t unitElement) { |
| 113 context = unwrapContext(context); |
| 114 // may be already disposed in other thread |
| 115 if (context.isDisposed()) { |
| 116 return false; |
| 117 } |
| 118 // validate unit |
| 119 if (unitElement == null) { |
| 120 return false; |
| 121 } |
| 122 LibraryElement libraryElement = unitElement.getLibrary(); |
| 123 if (libraryElement == null) { |
| 124 return false; |
| 125 } |
| 126 CompilationUnitElement definingUnitElement = libraryElement.getDefiningCompi
lationUnit(); |
| 127 if (definingUnitElement == null) { |
| 128 return false; |
| 129 } |
| 130 // prepare sources |
| 131 Source library = definingUnitElement.getSource(); |
| 132 Source unit = unitElement.getSource(); |
| 133 // special handling for the defining library unit |
| 134 if (unit.equals(library)) { |
| 135 // prepare new parts |
| 136 Set<Source> newParts = Sets.newHashSet(); |
| 137 for (CompilationUnitElement part : libraryElement.getParts()) { |
| 138 newParts.add(part.getSource()); |
| 139 } |
| 140 // prepare old parts |
| 141 Map<Source, Set<Source>> libraryToUnits = contextToLibraryToUnits.get(cont
ext); |
| 142 if (libraryToUnits == null) { |
| 143 libraryToUnits = Maps.newHashMap(); |
| 144 contextToLibraryToUnits.put(context, libraryToUnits); |
| 145 } |
| 146 Set<Source> oldParts = libraryToUnits.get(library); |
| 147 // check if some parts are not in the library now |
| 148 if (oldParts != null) { |
| 149 Set<Source> noParts = Sets.difference(oldParts, newParts); |
| 150 for (Source noPart : noParts) { |
| 151 removeLocations(context, library, noPart); |
| 152 } |
| 153 } |
| 154 // remember new parts |
| 155 libraryToUnits.put(library, newParts); |
| 156 } |
| 157 // remember library/unit relations |
| 158 recordUnitInLibrary(context, library, unit); |
| 159 recordLibraryWithUnit(context, library, unit); |
| 160 sources.add(library); |
| 161 sources.add(unit); |
| 162 // prepare node |
| 163 String libraryName = library.getFullName(); |
| 164 String unitName = unit.getFullName(); |
| 165 int libraryNameIndex = stringCodec.encode(libraryName); |
| 166 int unitNameIndex = stringCodec.encode(unitName); |
| 167 currentNodeName = libraryNameIndex + "_" + unitNameIndex + ".index"; |
| 168 currentNodeNameId = stringCodec.encode(currentNodeName); |
| 169 currentNode = nodeManager.newNode(context); |
| 170 currentContextId = contextCodec.encode(context); |
| 171 // remove Universe information for the current node |
| 172 for (Map<Integer, ?> nodeRelations : contextNodeRelations.values()) { |
| 173 nodeRelations.remove(currentNodeNameId); |
| 174 } |
| 175 // done |
| 176 return true; |
| 177 } |
| 178 |
| 179 @Override |
| 180 public boolean aboutToIndexHtml(AnalysisContext context, HtmlElement htmlEleme
nt) { |
| 181 context = unwrapContext(context); |
| 182 // may be already disposed in other thread |
| 183 if (context.isDisposed()) { |
| 184 return false; |
| 185 } |
| 186 // remove locations |
| 187 Source source = htmlElement.getSource(); |
| 188 removeLocations(context, null, source); |
| 189 // remember library/unit relations |
| 190 recordUnitInLibrary(context, null, source); |
| 191 // prepare node |
| 192 String sourceName = source.getFullName(); |
| 193 int sourceNameIndex = stringCodec.encode(sourceName); |
| 194 currentNodeName = sourceNameIndex + ".index"; |
| 195 currentNodeNameId = stringCodec.encode(currentNodeName); |
| 196 currentNode = nodeManager.newNode(context); |
| 197 return true; |
| 198 } |
| 199 |
| 200 @Override |
| 201 public void clear() { |
| 202 nodeManager.clear(); |
| 203 nameToNodeNames.clear(); |
| 204 } |
| 205 |
| 206 @Override |
| 207 public void doneIndex() { |
| 208 if (currentNode != null) { |
| 209 nodeManager.putNode(currentNodeName, currentNode); |
| 210 currentNodeName = null; |
| 211 currentNodeNameId = -1; |
| 212 currentNode = null; |
| 213 currentContextId = -1; |
| 214 } |
| 215 } |
| 216 |
| 217 @Override |
| 218 public Location[] getRelationships(Element element, Relationship relationship)
{ |
| 219 // special support for UniverseElement |
| 220 if (element == UniverseElement.INSTANCE) { |
| 221 return getRelationshipsUniverse(relationship); |
| 222 } |
| 223 // prepare node names |
| 224 String name = getElementName(element); |
| 225 int nameId = stringCodec.encode(name); |
| 226 int[] nodeNameIds = nameToNodeNames.get(nameId); |
| 227 // check each node |
| 228 List<Location> locations = Lists.newArrayList(); |
| 229 for (int i = 0; i < nodeNameIds.length; i++) { |
| 230 int nodeNameId = nodeNameIds[i]; |
| 231 String nodeName = stringCodec.decode(nodeNameId); |
| 232 IndexNode node = nodeManager.getNode(nodeName); |
| 233 if (node != null) { |
| 234 Collections.addAll(locations, node.getRelationships(element, relationshi
p)); |
| 235 } else { |
| 236 nodeNameIds = ArrayUtils.removeElement(nodeNameIds, nodeNameId); |
| 237 i--; |
| 238 } |
| 239 } |
| 240 // done |
| 241 return locations.toArray(new Location[locations.size()]); |
| 242 } |
| 243 |
| 244 @Override |
| 245 public String getStatistics() { |
| 246 return "[" + nodeManager.getLocationCount() + " locations, " + sources.size(
) + " sources, " |
| 247 + nameToNodeNames.size() + " names]"; |
| 248 } |
| 249 |
| 250 @Override |
| 251 public void recordRelationship(Element element, Relationship relationship, Loc
ation location) { |
| 252 if (element == null || element.getKind() == ElementKind.ERROR) { |
| 253 return; |
| 254 } |
| 255 if (location == null) { |
| 256 return; |
| 257 } |
| 258 // special support for UniverseElement |
| 259 if (element == UniverseElement.INSTANCE) { |
| 260 recordRelationshipUniverse(relationship, location); |
| 261 return; |
| 262 } |
| 263 // other elements |
| 264 recordNodeNameForElement(element); |
| 265 currentNode.recordRelationship(element, relationship, location); |
| 266 } |
| 267 |
| 268 @Override |
| 269 public void removeContext(AnalysisContext context) { |
| 270 context = unwrapContext(context); |
| 271 if (context == null) { |
| 272 return; |
| 273 } |
| 274 // remove sources |
| 275 removeSources(context, null); |
| 276 // remove context information |
| 277 contextToLibraryToUnits.remove(context); |
| 278 contextToUnitToLibraries.remove(context); |
| 279 contextNodeRelations.remove(contextCodec.encode(context)); |
| 280 // remove context from codec |
| 281 contextCodec.removeContext(context); |
| 282 } |
| 283 |
| 284 @Override |
| 285 public void removeSource(AnalysisContext context, Source source) { |
| 286 context = unwrapContext(context); |
| 287 if (context == null) { |
| 288 return; |
| 289 } |
| 290 // remove nodes for unit/library pairs |
| 291 Map<Source, Set<Source>> unitToLibraries = contextToUnitToLibraries.get(cont
ext); |
| 292 if (unitToLibraries != null) { |
| 293 Set<Source> libraries = unitToLibraries.remove(source); |
| 294 if (libraries != null) { |
| 295 for (Source library : libraries) { |
| 296 removeLocations(context, library, source); |
| 297 } |
| 298 } |
| 299 } |
| 300 // remove nodes for library/unit pairs |
| 301 Map<Source, Set<Source>> libraryToUnits = contextToLibraryToUnits.get(contex
t); |
| 302 if (libraryToUnits != null) { |
| 303 Set<Source> units = libraryToUnits.remove(source); |
| 304 if (units != null) { |
| 305 for (Source unit : units) { |
| 306 removeLocations(context, source, unit); |
| 307 } |
| 308 } |
| 309 } |
| 310 } |
| 311 |
| 312 @Override |
| 313 public void removeSources(AnalysisContext context, SourceContainer container)
{ |
| 314 context = unwrapContext(context); |
| 315 if (context == null) { |
| 316 return; |
| 317 } |
| 318 // remove nodes for unit/library pairs |
| 319 Map<Source, Set<Source>> unitToLibraries = contextToUnitToLibraries.get(cont
ext); |
| 320 if (unitToLibraries != null) { |
| 321 List<Source> units = Lists.newArrayList(unitToLibraries.keySet()); |
| 322 for (Source source : units) { |
| 323 if (container == null || container.contains(source)) { |
| 324 removeSource(context, source); |
| 325 } |
| 326 } |
| 327 } |
| 328 // remove nodes for library/unit pairs |
| 329 Map<Source, Set<Source>> libraryToUnits = contextToLibraryToUnits.get(contex
t); |
| 330 if (libraryToUnits != null) { |
| 331 List<Source> libraries = Lists.newArrayList(libraryToUnits.keySet()); |
| 332 for (Source source : libraries) { |
| 333 if (container == null || container.contains(source)) { |
| 334 removeSource(context, source); |
| 335 } |
| 336 } |
| 337 } |
| 338 } |
| 339 |
| 340 private String getElementName(Element element) { |
| 341 return element.getName(); |
| 342 } |
| 343 |
| 344 private Location[] getRelationshipsUniverse(Relationship relationship) { |
| 345 List<Location> locations = Lists.newArrayList(); |
| 346 for (Entry<Integer, Map<Integer, Map<Relationship, List<LocationData>>>> con
textEntry : contextNodeRelations.entrySet()) { |
| 347 int contextId = contextEntry.getKey(); |
| 348 AnalysisContext context = contextCodec.decode(contextId); |
| 349 if (context != null) { |
| 350 for (Map<Relationship, List<LocationData>> nodeRelations : contextEntry.
getValue().values()) { |
| 351 List<LocationData> nodeLocations = nodeRelations.get(relationship); |
| 352 if (nodeLocations != null) { |
| 353 for (LocationData locationData : nodeLocations) { |
| 354 Location location = locationData.getLocation(context, elementCodec
); |
| 355 if (location != null) { |
| 356 locations.add(location); |
| 357 } |
| 358 } |
| 359 } |
| 360 } |
| 361 } |
| 362 } |
| 363 return locations.toArray(new Location[locations.size()]); |
| 364 } |
| 365 |
| 366 private void recordLibraryWithUnit(AnalysisContext context, Source library, So
urce unit) { |
| 367 Map<Source, Set<Source>> libraryToUnits = contextToLibraryToUnits.get(contex
t); |
| 368 if (libraryToUnits == null) { |
| 369 libraryToUnits = Maps.newHashMap(); |
| 370 contextToLibraryToUnits.put(context, libraryToUnits); |
| 371 } |
| 372 Set<Source> units = libraryToUnits.get(library); |
| 373 if (units == null) { |
| 374 units = Sets.newHashSet(); |
| 375 libraryToUnits.put(library, units); |
| 376 } |
| 377 units.add(unit); |
| 378 } |
| 379 |
| 380 private void recordNodeNameForElement(Element element) { |
| 381 String name = getElementName(element); |
| 382 int nameId = stringCodec.encode(name); |
| 383 nameToNodeNames.add(nameId, currentNodeNameId); |
| 384 } |
| 385 |
| 386 private void recordRelationshipUniverse(Relationship relationship, Location lo
cation) { |
| 387 // in current context |
| 388 Map<Integer, Map<Relationship, List<LocationData>>> nodeRelations = contextN
odeRelations.get(currentContextId); |
| 389 if (nodeRelations == null) { |
| 390 nodeRelations = Maps.newHashMap(); |
| 391 contextNodeRelations.put(currentContextId, nodeRelations); |
| 392 } |
| 393 // in current node |
| 394 Map<Relationship, List<LocationData>> relations = nodeRelations.get(currentN
odeNameId); |
| 395 if (relations == null) { |
| 396 relations = Maps.newHashMap(); |
| 397 nodeRelations.put(currentNodeNameId, relations); |
| 398 } |
| 399 // for the given relationship |
| 400 List<LocationData> locations = relations.get(relationship); |
| 401 if (locations == null) { |
| 402 locations = Lists.newArrayList(); |
| 403 relations.put(relationship, locations); |
| 404 } |
| 405 // record LocationData |
| 406 locations.add(new LocationData(elementCodec, location)); |
| 407 } |
| 408 |
| 409 private void recordUnitInLibrary(AnalysisContext context, Source library, Sour
ce unit) { |
| 410 Map<Source, Set<Source>> unitToLibraries = contextToUnitToLibraries.get(cont
ext); |
| 411 if (unitToLibraries == null) { |
| 412 unitToLibraries = Maps.newHashMap(); |
| 413 contextToUnitToLibraries.put(context, unitToLibraries); |
| 414 } |
| 415 Set<Source> libraries = unitToLibraries.get(unit); |
| 416 if (libraries == null) { |
| 417 libraries = Sets.newHashSet(); |
| 418 unitToLibraries.put(unit, libraries); |
| 419 } |
| 420 libraries.add(library); |
| 421 } |
| 422 |
| 423 /** |
| 424 * Removes locations recorded in the given library/unit pair. |
| 425 */ |
| 426 private void removeLocations(AnalysisContext context, Source library, Source u
nit) { |
| 427 // remove node |
| 428 String libraryName = library != null ? library.getFullName() : null; |
| 429 String unitName = unit.getFullName(); |
| 430 int libraryNameIndex = stringCodec.encode(libraryName); |
| 431 int unitNameIndex = stringCodec.encode(unitName); |
| 432 String nodeName = libraryNameIndex + "_" + unitNameIndex + ".index"; |
| 433 nodeManager.removeNode(nodeName); |
| 434 // remove source |
| 435 sources.remove(library); |
| 436 sources.remove(unit); |
| 437 } |
| 438 |
| 439 /** |
| 440 * When logging is on, {@link AnalysisEngine} actually creates |
| 441 * {@link InstrumentedAnalysisContextImpl}, which wraps {@link AnalysisContext
Impl} used to create |
| 442 * actual {@link Element}s. So, in index we have to unwrap {@link Instrumented
AnalysisContextImpl} |
| 443 * when perform any operation. |
| 444 */ |
| 445 private AnalysisContext unwrapContext(AnalysisContext context) { |
| 446 if (context instanceof InstrumentedAnalysisContextImpl) { |
| 447 context = ((InstrumentedAnalysisContextImpl) context).getBasis(); |
| 448 } |
| 449 return context; |
| 450 } |
| 451 } |
OLD | NEW |