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

Unified Diff: packages/analyzer/lib/src/context/cache.dart

Issue 2990843002: Removed fixed dependencies (Closed)
Patch Set: Created 3 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « packages/analyzer/lib/src/context/builder.dart ('k') | packages/analyzer/lib/src/context/context.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: packages/analyzer/lib/src/context/cache.dart
diff --git a/packages/analyzer/lib/src/context/cache.dart b/packages/analyzer/lib/src/context/cache.dart
index 4535ca4ce1d4cea4079b9eafa45152bce0f267f5..ef780314a2ee2c4f4decd1415f00ebc3fb6e83c3 100644
--- a/packages/analyzer/lib/src/context/cache.dart
+++ b/packages/analyzer/lib/src/context/cache.dart
@@ -7,14 +7,25 @@ library analyzer.src.context.cache;
import 'dart:async';
import 'dart:collection';
-import 'package:analyzer/src/generated/engine.dart'
- show AnalysisEngine, CacheState, InternalAnalysisContext, RetentionPriority;
-import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/exception/exception.dart';
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_collection.dart';
import 'package:analyzer/src/task/model.dart';
import 'package:analyzer/task/model.dart';
+/**
+ * The cache results visiting function type.
+ */
+typedef void CacheResultVisitor(AnalysisTarget target, ResultData data);
+
+/**
+ * Return `true` if the [result] of the [target] should be flushed.
+ */
+typedef bool FlushResultFilter<V>(
+ AnalysisTarget target, ResultDescriptor<V> result);
+
/**
* Return `true` if the given [target] is a priority one.
*/
@@ -41,20 +52,36 @@ class AnalysisCache {
final ReentrantSynchronousStream<InvalidatedResult> onResultInvalidated =
new ReentrantSynchronousStream<InvalidatedResult>();
+ final List<ReentrantSynchronousStreamSubscription>
+ onResultInvalidatedPartitionSubscriptions =
+ <ReentrantSynchronousStreamSubscription>[];
+
/**
- * Initialize a newly created cache to have the given [partitions]. The
+ * Initialize a newly created cache to have the given [_partitions]. The
* partitions will be searched in the order in which they appear in the array,
* so the most specific partition (usually an [SdkCachePartition]) should be
* first and the most general (usually a [UniversalCachePartition]) last.
*/
AnalysisCache(this._partitions) {
for (CachePartition partition in _partitions) {
- partition.onResultInvalidated.listen((InvalidatedResult event) {
+ partition.containingCaches.add(this);
+ ReentrantSynchronousStreamSubscription<InvalidatedResult> subscription =
+ partition.onResultInvalidated.listen((InvalidatedResult event) {
onResultInvalidated.add(event);
});
+ onResultInvalidatedPartitionSubscriptions.add(subscription);
}
}
+ /**
+ * Return an iterator returning all of the [Source] targets.
+ */
+ Iterable<Source> get sources {
+ return _partitions
+ .map((CachePartition partition) => partition.sources)
+ .expand((Iterable<Source> sources) => sources);
+ }
+
// TODO(brianwilkerson) Implement or delete this.
// /**
// * Return information about each of the partitions in this cache.
@@ -73,12 +100,25 @@ class AnalysisCache {
// }
/**
- * Return an iterator returning all of the [Source] targets.
+ * Free any allocated resources and references.
*/
- Iterable<Source> get sources {
- return _partitions
- .map((CachePartition partition) => partition._sources)
- .expand((Iterable<Source> sources) => sources);
+ void dispose() {
+ for (ReentrantSynchronousStreamSubscription subscription
+ in onResultInvalidatedPartitionSubscriptions) {
+ subscription.cancel();
+ }
+ for (CachePartition partition in _partitions) {
+ partition.containingCaches.remove(this);
+ }
+ }
+
+ /**
+ * Flush results that satisfy the given [filter].
+ */
+ void flush(FlushResultFilter filter) {
+ for (CachePartition partition in _partitions) {
+ partition.flush(filter);
+ }
}
/**
@@ -156,7 +196,8 @@ class AnalysisCache {
* It does not update the cache, if the corresponding [CacheEntry] does not
* exist, then the default value is returned.
*/
- Object getValue(AnalysisTarget target, ResultDescriptor result) {
+ Object/*=V*/ getValue/*<V>*/(
+ AnalysisTarget target, ResultDescriptor/*<V>*/ result) {
CacheEntry entry = get(target);
if (entry == null) {
return result.defaultValue;
@@ -175,7 +216,7 @@ class AnalysisCache {
<Map<AnalysisTarget, CacheEntry>>[];
for (CachePartition partition in _partitions) {
if (context == null || partition.context == context) {
- maps.add(partition.map);
+ maps.add(partition.entryMap);
}
}
return new MultipleMapIterator<AnalysisTarget, CacheEntry>(maps);
@@ -224,7 +265,11 @@ class AnalysisCache {
AnalysisEngine.instance.logger
.logInformation('Removed the cache entry for $target.');
}
- return partition.remove(target);
+ CacheEntry entry = partition.remove(target);
+ if (entry != null) {
+ entry.dispose();
+ }
+ return entry;
}
}
return null;
@@ -255,9 +300,16 @@ class CacheEntry {
static int _EXPLICITLY_ADDED_FLAG = 0;
/**
- * The next invalidation process identifier.
+ * The next visit process identifier.
+ */
+ static int nextVisitId = 0;
+
+ /**
+ * A table containing the number of times the value of a result descriptor was
+ * recomputed after having been flushed.
*/
- static int nextInvalidateId = 0;
+ static final Map<ResultDescriptor, int> recomputedCounts =
+ new HashMap<ResultDescriptor, int>();
/**
* The target this entry is about.
@@ -325,12 +377,18 @@ class CacheEntry {
* Notifies the entry that the client is going to stop using it.
*/
void dispose() {
- _resultMap.forEach((descriptor, data) {
+ _resultMap.forEach((ResultDescriptor descriptor, ResultData data) {
TargetedResult result = new TargetedResult(target, descriptor);
for (TargetedResult dependedOnResult in data.dependedOnResults) {
- ResultData dependedOnData = _partition._getDataFor(dependedOnResult);
- if (dependedOnData != null) {
- dependedOnData.dependentResults.remove(result);
+ for (AnalysisCache cache in _partition.containingCaches) {
+ CacheEntry entry = cache.get(dependedOnResult.target);
+ if (entry != null) {
+ ResultData data =
+ entry.getResultDataOrNull(dependedOnResult.result);
+ if (data != null) {
+ data.dependentResults.remove(result);
+ }
+ }
}
}
});
@@ -347,13 +405,31 @@ class CacheEntry {
}
/**
- * Look up the [ResultData] of [descriptor], or add a new one if it isn't
- * there.
+ * Flush results that satisfy the given [filter].
+ */
+ void flush(FlushResultFilter filter) {
+ _resultMap.forEach((ResultDescriptor result, ResultData data) {
+ if (filter(target, result)) {
+ data.flush();
+ }
+ });
+ }
+
+ /**
+ * Return the result data associated with the [descriptor], creating one if it
+ * isn't there.
*/
ResultData getResultData(ResultDescriptor descriptor) {
return _resultMap.putIfAbsent(descriptor, () => new ResultData(descriptor));
}
+ /**
+ * Return the result data associated with the [descriptor], or `null` if there
+ * is no data currently associated with the descriptor.
+ */
+ ResultData getResultDataOrNull(ResultDescriptor descriptor) =>
+ _resultMap[descriptor];
+
/**
* Return the state of the result represented by the given [descriptor].
*/
@@ -369,7 +445,7 @@ class CacheEntry {
* Return the value of the result represented by the given [descriptor], or
* the default value for the result if this entry does not have a valid value.
*/
- /*<V>*/ dynamic /*V*/ getValue(ResultDescriptor /*<V>*/ descriptor) {
+ dynamic/*=V*/ getValue/*<V>*/(ResultDescriptor/*<V>*/ descriptor) {
ResultData data = _resultMap[descriptor];
if (data == null) {
return descriptor.defaultValue;
@@ -377,7 +453,7 @@ class CacheEntry {
if (_partition != null) {
_partition.resultAccessed(target, descriptor);
}
- return data.value;
+ return data.value as Object/*=V*/;
}
/**
@@ -448,7 +524,12 @@ class CacheEntry {
if (state == CacheState.INVALID) {
ResultData data = _resultMap[descriptor];
if (data != null) {
- _invalidate(nextInvalidateId++, descriptor, delta, 0);
+ bool canUseDelta =
+ _gatherResultsInvalidatedByDelta(descriptor, delta, 0);
+ if (!canUseDelta) {
+ delta = null;
+ }
+ _invalidate(nextVisitId++, descriptor, delta, 0);
}
} else {
ResultData data = getResultData(descriptor);
@@ -467,10 +548,7 @@ class CacheEntry {
* Set the value of the result represented by the given [descriptor] to the
* given [value].
*/
- /*<V>*/ void setValue(
- ResultDescriptor /*<V>*/ descriptor,
- dynamic /*V*/
- value,
+ void setValue/*<V>*/(ResultDescriptor/*<V>*/ descriptor, dynamic/*=V*/ value,
List<TargetedResult> dependedOn) {
// {
// String valueStr = '$value';
@@ -479,7 +557,7 @@ class CacheEntry {
// }
// valueStr = valueStr.replaceAll('\n', '\\n');
// print(
-// 'setValue $descriptor for $target value=$valueStr deps=$dependedOn');
+// 'setValue $descriptor for $target value=$valueStr dependedOn=$dependedOn');
// }
_validateStateChange(descriptor, CacheState.VALID);
TargetedResult thisResult = new TargetedResult(target, descriptor);
@@ -488,21 +566,27 @@ class CacheEntry {
}
ResultData data = getResultData(descriptor);
_setDependedOnResults(data, thisResult, dependedOn);
+ if (data.state == CacheState.FLUSHED) {
+ int count = recomputedCounts[descriptor] ?? 0;
+ recomputedCounts[descriptor] = count + 1;
+ }
data.state = CacheState.VALID;
- data.value = value == null ? descriptor.defaultValue : value;
+ data.value = value ?? descriptor.defaultValue;
}
/**
- * Set the value of the result represented by the given [descriptor] to the
- * given [value], keep its dependency, invalidate all the dependent result.
+ * If the result represented by the given [descriptor] is valid, set
+ * it to the given [value], keep its dependency, and if [invalidateDependent]
+ * invalidate all the dependent result.
*/
void setValueIncremental(
ResultDescriptor descriptor, dynamic value, bool invalidateDependent) {
ResultData data = getResultData(descriptor);
- data.state = CacheState.VALID;
- data.value = value;
+ if (data.state == CacheState.VALID || data.state == CacheState.FLUSHED) {
+ data.value = value;
+ }
if (invalidateDependent) {
- _invalidateDependentResults(nextInvalidateId++, data, null, 0);
+ _invalidateDependentResults(nextVisitId++, data, null, 0);
}
}
@@ -513,6 +597,38 @@ class CacheEntry {
return buffer.toString();
}
+ /**
+ * Visit the given [result] and all results that depend on it, and
+ * ask [delta] to gather changes. Return `true` if the [delta] can be used
+ * to perform limited invalidation, or `false` if the changes collection
+ * process does not stop (should not happen).
+ */
+ bool _gatherResultsInvalidatedByDelta(
+ ResultDescriptor result, Delta delta, int level) {
+ if (delta == null) {
+ return false;
+ }
+ if (!delta.shouldGatherChanges) {
+ return true;
+ }
+ for (int i = 0; i < 64; i++) {
+ bool hasVisitChanges = false;
+ _visitResults(nextVisitId++, result,
+ (AnalysisTarget target, ResultData data) {
+ bool hasDeltaChanges = delta.gatherChanges(
+ _partition.context, target, data.descriptor, data.value);
+ if (hasDeltaChanges) {
+ hasVisitChanges = true;
+ }
+ });
+ delta.gatherEnd();
+ if (!hasVisitChanges) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Return the value of the flag with the given [index].
*/
@@ -530,49 +646,77 @@ class CacheEntry {
}
// Stop if already validated.
if (delta != null) {
- if (thisData.invalidateId == id) {
+ if (thisData.visitId == id) {
return;
}
- thisData.invalidateId = id;
+ thisData.visitId = id;
}
// Ask the delta to validate.
DeltaResult deltaResult = null;
if (delta != null) {
- deltaResult = delta.validate(_partition.context, target, descriptor);
+ deltaResult = delta.validate(
+ _partition.context, target, descriptor, thisData.value);
if (deltaResult == DeltaResult.STOP) {
return;
}
}
+// if (deltaResult != null) {
+// String indent = ' ' * level;
+// String deltaResultName = deltaResult.toString().split('.').last;
+// print('[$id]$indent$deltaResultName $descriptor for $target');
+// }
if (deltaResult == DeltaResult.INVALIDATE_NO_DELTA) {
delta = null;
}
- if (deltaResult == null ||
+ if (deltaResult == DeltaResult.INVALIDATE_KEEP_DEPENDENCIES) {
+ thisData.value = descriptor.defaultValue;
+ thisData.state = CacheState.INVALID;
+ } else if (deltaResult == null ||
deltaResult == DeltaResult.INVALIDATE ||
deltaResult == DeltaResult.INVALIDATE_NO_DELTA) {
_resultMap.remove(descriptor);
-// {
+ // Stop depending on other results.
+ {
+ TargetedResult thisResult = new TargetedResult(target, descriptor);
+ List<AnalysisCache> caches = _partition.containingCaches;
+ int cacheLength = caches.length;
+ List<TargetedResult> results = thisData.dependedOnResults;
+ int resultLength = results.length;
+ for (int i = 0; i < resultLength; i++) {
+ TargetedResult dependedOnResult = results[i];
+ for (int j = 0; j < cacheLength; j++) {
+ AnalysisCache cache = caches[j];
+ CacheEntry entry = cache.get(dependedOnResult.target);
+ if (entry != null) {
+ ResultData data =
+ entry.getResultDataOrNull(dependedOnResult.result);
+ if (data != null) {
+ data.dependentResults.remove(thisResult);
+ }
+ }
+ }
+ }
+ }
+// if (deltaResult == null) {
// String indent = ' ' * level;
// print('[$id]$indent invalidate $descriptor for $target');
// }
}
- // Stop depending on other results.
- TargetedResult thisResult = new TargetedResult(target, descriptor);
- for (TargetedResult dependedOnResult in thisData.dependedOnResults) {
- ResultData data = _partition._getDataFor(dependedOnResult);
- if (data != null && deltaResult != DeltaResult.KEEP_CONTINUE) {
- data.dependentResults.remove(thisResult);
- }
- }
// Invalidate results that depend on this result.
_invalidateDependentResults(id, thisData, delta, level + 1);
- // If empty, remove the entry altogether.
- if (_resultMap.isEmpty) {
- _partition._targetMap.remove(target);
+ // If empty and not explicitly added, remove the entry altogether.
+ if (_resultMap.isEmpty && !explicitlyAdded) {
+ CacheEntry entry = _partition.entryMap.remove(target);
+ if (entry != null) {
+ entry.dispose();
+ }
_partition._removeIfSource(target);
}
// Notify controller.
- _partition.onResultInvalidated
- .add(new InvalidatedResult(this, descriptor, thisData.value));
+ if (deltaResult != DeltaResult.KEEP_CONTINUE) {
+ _partition.onResultInvalidated
+ .add(new InvalidatedResult(this, descriptor, thisData.value));
+ }
}
/**
@@ -580,8 +724,10 @@ class CacheEntry {
*/
void _invalidateAll() {
List<ResultDescriptor> results = _resultMap.keys.toList();
- for (ResultDescriptor result in results) {
- _invalidate(nextInvalidateId++, result, null, 0);
+ int length = results.length;
+ for (int i = 0; i < length; i++) {
+ ResultDescriptor result = results[i];
+ _invalidate(nextVisitId++, result, null, 0);
}
}
@@ -590,11 +736,20 @@ class CacheEntry {
*/
void _invalidateDependentResults(
int id, ResultData thisData, Delta delta, int level) {
+ // It is necessary to copy the results to a list to avoid a concurrent
+ // modification of the set of dependent results.
+ List<AnalysisCache> caches = _partition.containingCaches;
+ int cacheLength = caches.length;
List<TargetedResult> dependentResults = thisData.dependentResults.toList();
- for (TargetedResult dependentResult in dependentResults) {
- CacheEntry entry = _partition.get(dependentResult.target);
- if (entry != null) {
- entry._invalidate(id, dependentResult.result, delta, level);
+ int resultLength = dependentResults.length;
+ for (int i = 0; i < resultLength; i++) {
+ TargetedResult dependentResult = dependentResults[i];
+ for (int j = 0; j < cacheLength; j++) {
+ AnalysisCache cache = caches[j];
+ CacheEntry entry = cache.get(dependentResult.target);
+ if (entry != null) {
+ entry._invalidate(id, dependentResult.result, delta, level);
+ }
}
}
}
@@ -604,19 +759,37 @@ class CacheEntry {
*/
void _setDependedOnResults(ResultData thisData, TargetedResult thisResult,
List<TargetedResult> dependedOn) {
- thisData.dependedOnResults.forEach((TargetedResult dependedOnResult) {
- ResultData data = _partition._getDataFor(dependedOnResult);
- if (data != null) {
- data.dependentResults.remove(thisResult);
+ List<AnalysisCache> caches = _partition.containingCaches;
+ int cacheLength = caches.length;
+
+ List<TargetedResult> oldResults = thisData.dependedOnResults;
+ int oldLength = oldResults.length;
+ for (int i = 0; i < oldLength; i++) {
+ TargetedResult dependedOnResult = oldResults[i];
+ for (int j = 0; j < cacheLength; j++) {
+ AnalysisCache cache = caches[j];
+ CacheEntry entry = cache.get(dependedOnResult.target);
+ if (entry != null) {
+ ResultData data = entry.getResultDataOrNull(dependedOnResult.result);
+ if (data != null) {
+ data.dependentResults.remove(thisResult);
+ }
+ }
}
- });
+ }
thisData.dependedOnResults = dependedOn;
- thisData.dependedOnResults.forEach((TargetedResult dependedOnResult) {
- ResultData data = _partition._getDataFor(dependedOnResult);
- if (data != null) {
- data.dependentResults.add(thisResult);
+ int newLength = dependedOn.length;
+ for (int i = 0; i < newLength; i++) {
+ TargetedResult dependedOnResult = dependedOn[i];
+ for (int j = 0; j < cacheLength; j++) {
+ AnalysisCache cache = caches[j];
+ CacheEntry entry = cache.get(dependedOnResult.target);
+ if (entry != null) {
+ ResultData data = entry.getResultData(dependedOnResult.result);
+ data.dependentResults.add(thisResult);
+ }
}
- });
+ }
}
/**
@@ -630,9 +803,16 @@ class CacheEntry {
thisData.state = CacheState.ERROR;
thisData.value = descriptor.defaultValue;
// Propagate the error state.
+ List<AnalysisCache> caches = _partition.containingCaches;
+ int cacheLength = caches.length;
thisData.dependentResults.forEach((TargetedResult dependentResult) {
- CacheEntry entry = _partition.get(dependentResult.target);
- entry._setErrorState(dependentResult.result, exception);
+ for (int i = 0; i < cacheLength; i++) {
+ AnalysisCache cache = caches[i];
+ CacheEntry entry = cache.get(dependentResult.target);
+ if (entry != null) {
+ entry._setErrorState(dependentResult.result, exception);
+ }
+ }
});
}
@@ -666,6 +846,41 @@ class CacheEntry {
// }
}
+ /**
+ * Call [visitor] for the result described by the given [descriptor] and all
+ * results that depend on directly or indirectly. Each result is visited
+ * only once.
+ */
+ void _visitResults(
+ int id, ResultDescriptor descriptor, CacheResultVisitor visitor) {
+ ResultData thisData = _resultMap[descriptor];
+ if (thisData == null) {
+ return;
+ }
+ // Stop if already visited.
+ if (thisData.visitId == id) {
+ return;
+ }
+ thisData.visitId = id;
+ // Visit this result.
+ visitor(target, thisData);
+ // Visit results that depend on this result.
+ List<AnalysisCache> caches = _partition.containingCaches;
+ int cacheLength = caches.length;
+ List<TargetedResult> dependentResults = thisData.dependentResults.toList();
+ int resultLength = dependentResults.length;
+ for (int i = 0; i < resultLength; i++) {
+ TargetedResult dependentResult = dependentResults[i];
+ for (int j = 0; j < cacheLength; j++) {
+ AnalysisCache cache = caches[j];
+ CacheEntry entry = cache.get(dependentResult.target);
+ if (entry != null) {
+ entry._visitResults(id, dependentResult.result, visitor);
+ }
+ }
+ }
+ }
+
/**
* Write a textual representation of this entry to the given [buffer]. The
* result should only be used for debugging purposes.
@@ -725,7 +940,7 @@ class CacheFlushManager<T> {
: policy = policy,
maxActiveSize = policy.maxActiveSize,
maxIdleSize = policy.maxIdleSize,
- maxSize = policy.maxIdleSize;
+ maxSize = policy.maxActiveSize;
/**
* If [currentSize] is already less than [maxSize], returns an empty list.
@@ -824,6 +1039,12 @@ abstract class CachePartition {
*/
final InternalAnalysisContext context;
+ /**
+ * A list of the caches that contain this partition. This includes the cache
+ * associated with the context that owns this partition.
+ */
+ final List<AnalysisCache> containingCaches = <AnalysisCache>[];
+
/**
* A table mapping caching policies to the cache flush managers.
*/
@@ -840,18 +1061,18 @@ abstract class CachePartition {
* A table mapping the targets belonging to this partition to the information
* known about those targets.
*/
- HashMap<AnalysisTarget, CacheEntry> _targetMap =
+ final HashMap<AnalysisTarget, CacheEntry> entryMap =
new HashMap<AnalysisTarget, CacheEntry>();
/**
* A set of the [Source] targets.
*/
- final HashSet<Source> _sources = new HashSet<Source>();
+ final HashSet<Source> sources = new HashSet<Source>();
/**
* A table mapping full paths to lists of [Source]s with these full paths.
*/
- final Map<String, List<Source>> _pathToSources = <String, List<Source>>{};
+ final Map<String, List<Source>> pathToSource = <String, List<Source>>{};
/**
* Initialize a newly created cache partition, belonging to the given
@@ -860,36 +1081,52 @@ abstract class CachePartition {
CachePartition(this.context);
/**
- * Return a table mapping the targets known to the context to the information
- * known about the target.
- *
- * <b>Note:</b> This method is only visible for use by [AnalysisCache] and
- * should not be used for any other purpose.
+ * Specify whether a context that uses this partition is being analyzed.
*/
- Map<AnalysisTarget, CacheEntry> get map => _targetMap;
+ set isActive(bool active) {
+ for (CacheFlushManager manager in _flushManagerMap.values) {
+ if (active) {
+ manager.madeActive();
+ } else {
+ List<TargetedResult> resultsToFlush = manager.madeIdle();
+ _flushResults(resultsToFlush);
+ }
+ }
+ }
/**
* Notifies the partition that the client is going to stop using it.
*/
void dispose() {
- for (CacheEntry entry in _targetMap.values) {
+ for (CacheEntry entry in entryMap.values) {
entry.dispose();
}
- _targetMap.clear();
+ entryMap.clear();
+ sources.clear();
+ pathToSource.clear();
+ }
+
+ /**
+ * Flush results that satisfy the given [filter].
+ */
+ void flush(FlushResultFilter filter) {
+ for (CacheEntry entry in entryMap.values) {
+ entry.flush(filter);
+ }
}
/**
* Return the entry associated with the given [target].
*/
- CacheEntry get(AnalysisTarget target) => _targetMap[target];
+ CacheEntry get(AnalysisTarget target) => entryMap[target];
/**
* Return [Source]s whose full path is equal to the given [path].
* Maybe empty, but not `null`.
*/
List<Source> getSourcesWithFullName(String path) {
- List<Source> sources = _pathToSources[path];
- return sources != null ? sources : Source.EMPTY_LIST;
+ List<Source> sources = pathToSource[path];
+ return sources ?? Source.EMPTY_LIST;
}
/**
@@ -902,7 +1139,7 @@ abstract class CachePartition {
* cache entries.
*/
MapIterator<AnalysisTarget, CacheEntry> iterator() =>
- new SingleMapIterator<AnalysisTarget, CacheEntry>(_targetMap);
+ new SingleMapIterator<AnalysisTarget, CacheEntry>(entryMap);
/**
* Puts the given [entry] into the partition.
@@ -915,7 +1152,7 @@ abstract class CachePartition {
}
entry._partition = this;
entry.fixExceptionState();
- _targetMap[target] = entry;
+ entryMap[target] = entry;
_addIfSource(target);
}
@@ -928,7 +1165,7 @@ abstract class CachePartition {
for (CacheFlushManager flushManager in _flushManagerMap.values) {
flushManager.targetRemoved(target);
}
- CacheEntry entry = _targetMap.remove(target);
+ CacheEntry entry = entryMap.remove(target);
if (entry != null) {
entry._invalidateAll();
}
@@ -953,36 +1190,38 @@ abstract class CachePartition {
CacheFlushManager flushManager = _getFlushManager(result.result);
List<TargetedResult> resultsToFlush =
flushManager.resultStored(result, value);
- for (TargetedResult result in resultsToFlush) {
- CacheEntry entry = get(result.target);
- if (entry != null) {
- ResultData data = entry._resultMap[result.result];
- if (data != null) {
- data.flush();
- }
- }
- }
+ _flushResults(resultsToFlush);
}
/**
* Return the number of targets that are mapped to cache entries.
*/
- int size() => _targetMap.length;
+ int size() => entryMap.length;
/**
- * If the given [target] is a [Source], adds it to [_sources].
+ * If the given [target] is a [Source], adds it to [sources].
*/
void _addIfSource(AnalysisTarget target) {
if (target is Source) {
- _sources.add(target);
+ sources.add(target);
String fullName = target.fullName;
- _pathToSources.putIfAbsent(fullName, () => <Source>[]).add(target);
+ pathToSource.putIfAbsent(fullName, () => <Source>[]).add(target);
}
}
- ResultData _getDataFor(TargetedResult result) {
- CacheEntry entry = context.analysisCache.get(result.target);
- return entry != null ? entry._resultMap[result.result] : null;
+ /**
+ * Flush the given [resultsToFlush].
+ */
+ void _flushResults(List<TargetedResult> resultsToFlush) {
+ for (TargetedResult result in resultsToFlush) {
+ CacheEntry entry = get(result.target);
+ if (entry != null) {
+ ResultData data = entry._resultMap[result.result];
+ if (data != null) {
+ data.flush();
+ }
+ }
+ }
}
/**
@@ -990,7 +1229,8 @@ abstract class CachePartition {
*/
CacheFlushManager _getFlushManager(ResultDescriptor descriptor) {
ResultCachingPolicy policy = descriptor.cachingPolicy;
- if (identical(policy, DEFAULT_CACHING_POLICY)) {
+ if (identical(policy, DEFAULT_CACHING_POLICY) ||
+ context.analysisOptions.disableCacheFlushing) {
return UnlimitedCacheFlushManager.INSTANCE;
}
CacheFlushManager manager = _flushManagerMap[policy];
@@ -1002,21 +1242,22 @@ abstract class CachePartition {
}
bool _isPriorityAnalysisTarget(AnalysisTarget target) {
- return context.priorityTargets.contains(target);
+ Source source = target.source;
+ return source != null && context.prioritySources.contains(source);
}
/**
- * If the given [target] is a [Source], remove it from the list of [_sources].
+ * If the given [target] is a [Source], remove it from the list of [sources].
*/
void _removeIfSource(AnalysisTarget target) {
if (target is Source) {
- _sources.remove(target);
- String fullName = target.fullName;
- List<Source> sources = _pathToSources[fullName];
- if (sources != null) {
- sources.remove(target);
- if (sources.isEmpty) {
- _pathToSources.remove(fullName);
+ sources.remove(target);
+ String path = target.fullName;
+ List<Source> pathSources = pathToSource[path];
+ if (pathSources != null) {
+ pathSources.remove(target);
+ if (pathSources.isEmpty) {
+ pathToSource.remove(path);
}
}
}
@@ -1031,26 +1272,57 @@ class Delta {
Delta(this.source);
+ /**
+ * Return `true` if this delta needs cache walking to gather additional
+ * changes before it can be used to [validate]. In this case [gatherChanges]
+ * is invoked for every targeted result in transitive dependencies, and
+ * [gatherEnd] is invoked after cache walking is done.
+ */
+ bool get shouldGatherChanges => false;
+
+ /**
+ * This method is called during a cache walk, so that the delta can gather
+ * additional changes to which are caused by the changes it already knows
+ * about. Return `true` if a new change was added, so that one more cache
+ * walk will be performed (to include changes that depend on results which we
+ * decided to be changed later in the previous cache walk).
+ */
+ bool gatherChanges(InternalAnalysisContext context, AnalysisTarget target,
+ ResultDescriptor descriptor, Object value) {
+ return false;
+ }
+
+ /**
+ * The current cache results visit is done.
+ */
+ void gatherEnd() {}
+
/**
* Check whether this delta affects the result described by the given
- * [descriptor] and [target].
+ * [descriptor] and [target]. The current [value] of the result is provided.
*/
DeltaResult validate(InternalAnalysisContext context, AnalysisTarget target,
- ResultDescriptor descriptor) {
+ ResultDescriptor descriptor, Object value) {
return DeltaResult.INVALIDATE;
}
}
/**
- * The possible results of validating analysis results againt a [Delta].
+ * The possible results of validating analysis results against a [Delta].
*/
enum DeltaResult {
/**
* Invalidate this result and continue visiting dependent results
- * with this [Delta].
+ * with this [Delta]. Remove the result and all its dependencies.
*/
INVALIDATE,
+ /**
+ * Invalidate this result and continue visiting dependent results
+ * with this [Delta]. Keep the dependencies of this result.
+ */
+ INVALIDATE_KEEP_DEPENDENCIES,
+
/**
* Invalidate this result and stop using this [Delta], so unconditionally
* invalidate all the dependent results.
@@ -1072,7 +1344,7 @@ enum DeltaResult {
/**
* [InvalidatedResult] describes an invalidated result.
*/
-class InvalidatedResult {
+class InvalidatedResult<V> {
/**
* The target in which the result was invalidated.
*/
@@ -1081,12 +1353,13 @@ class InvalidatedResult {
/**
* The descriptor of the result which was invalidated.
*/
- final ResultDescriptor descriptor;
+ final ResultDescriptor<V> descriptor;
/**
- * The value of the result which was invalidated.
+ * The value of the result before it was invalidated, may be the default
+ * value if the result was flushed.
*/
- final Object value;
+ final V value;
InvalidatedResult(this.entry, this.descriptor, this.value);
@@ -1094,6 +1367,29 @@ class InvalidatedResult {
String toString() => '$descriptor of ${entry.target}';
}
+/**
+ * A cache partition that contains all of the targets in a single package.
+ */
+class PackageCachePartition extends CachePartition {
+ /**
+ * The root of the directory representing the package.
+ */
+ final Folder packageRoot;
+
+ /**
+ * Initialize a newly created cache partition, belonging to the given
+ * [context].
+ */
+ PackageCachePartition(InternalAnalysisContext context, this.packageRoot)
+ : super(context);
+
+ @override
+ bool isResponsibleFor(AnalysisTarget target) {
+ Source source = target.source;
+ return source != null && packageRoot.contains(source.fullName);
+ }
+}
+
/**
* A Stream-like interface, which broadcasts events synchronously.
* If a second event is fired while delivering a first event, then the second
@@ -1118,8 +1414,27 @@ class ReentrantSynchronousStream<T> {
* Note that if the [listener] fires a new event, then the [listener] will be
* invoked again before returning from the [add] invocation.
*/
- void listen(void listener(T event)) {
+ ReentrantSynchronousStreamSubscription<T> listen(void listener(T event)) {
listeners.add(listener);
+ return new ReentrantSynchronousStreamSubscription<T>(this, listener);
+ }
+}
+
+/**
+ * A subscription on events from a [ReentrantSynchronousStream].
+ */
+class ReentrantSynchronousStreamSubscription<T> {
+ final ReentrantSynchronousStream<T> _stream;
+ final Function _listener;
+
+ ReentrantSynchronousStreamSubscription(this._stream, this._listener);
+
+ /**
+ * Cancels this subscription.
+ * It will no longer receive events.
+ */
+ void cancel() {
+ _stream.listeners.remove(_listener);
}
}
@@ -1146,11 +1461,10 @@ class ResultData {
Object value;
/**
- * The identifier of the invalidation process that most recently checked
- * this value. If it is the same as the current invalidation identifier,
- * then there is no reason to check it (and its subtree again).
+ * The identifier of the most recent visiting process. We use it to visit
+ * every result only once.
*/
- int invalidateId = -1;
+ int visitId = -1;
/**
* A list of the results on which this result depends.
« no previous file with comments | « packages/analyzer/lib/src/context/builder.dart ('k') | packages/analyzer/lib/src/context/context.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698