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

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

Issue 1400473008: Roll Observatory packages and add a roll script (Closed) Base URL: git@github.com:dart-lang/observatory_pub_packages.git@master
Patch Set: Created 5 years, 2 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/cancelable_future.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/analyzer/lib/src/context/cache.dart b/packages/analyzer/lib/src/context/cache.dart
similarity index 86%
rename from analyzer/lib/src/context/cache.dart
rename to packages/analyzer/lib/src/context/cache.dart
index 0d67817f80ab56763b9737666b361f1640b8b793..4535ca4ce1d4cea4079b9eafa45152bce0f267f5 100644
--- a/analyzer/lib/src/context/cache.dart
+++ b/packages/analyzer/lib/src/context/cache.dart
@@ -12,7 +12,6 @@ import 'package:analyzer/src/generated/engine.dart'
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_collection.dart';
-import 'package:analyzer/src/generated/utilities_general.dart';
import 'package:analyzer/src/task/model.dart';
import 'package:analyzer/task/model.dart';
@@ -39,8 +38,8 @@ class AnalysisCache {
/**
* The [StreamController] reporting [InvalidatedResult]s.
*/
- final StreamController<InvalidatedResult> _onResultInvalidated =
- new StreamController<InvalidatedResult>.broadcast(sync: true);
+ final ReentrantSynchronousStream<InvalidatedResult> onResultInvalidated =
+ new ReentrantSynchronousStream<InvalidatedResult>();
/**
* Initialize a newly created cache to have the given [partitions]. The
@@ -51,17 +50,11 @@ class AnalysisCache {
AnalysisCache(this._partitions) {
for (CachePartition partition in _partitions) {
partition.onResultInvalidated.listen((InvalidatedResult event) {
- _onResultInvalidated.add(event);
+ onResultInvalidated.add(event);
});
}
}
- /**
- * Return the stream that is notified when a value is invalidated.
- */
- Stream<InvalidatedResult> get onResultInvalidated =>
- _onResultInvalidated.stream;
-
// TODO(brianwilkerson) Implement or delete this.
// /**
// * Return information about each of the partitions in this cache.
@@ -173,14 +166,17 @@ class AnalysisCache {
/**
* Return an iterator returning all of the map entries mapping targets to
- * cache entries.
+ * cache entries. If the [context] is not `null`, then only entries that are
+ * owned by the given context will be returned.
*/
- MapIterator<AnalysisTarget, CacheEntry> iterator() {
- int count = _partitions.length;
+ MapIterator<AnalysisTarget, CacheEntry> iterator(
+ {InternalAnalysisContext context: null}) {
List<Map<AnalysisTarget, CacheEntry>> maps =
- new List<Map<AnalysisTarget, CacheEntry>>(count);
- for (int i = 0; i < count; i++) {
- maps[i] = _partitions[i].map;
+ <Map<AnalysisTarget, CacheEntry>>[];
+ for (CachePartition partition in _partitions) {
+ if (context == null || partition.context == context) {
+ maps.add(partition.map);
+ }
}
return new MultipleMapIterator<AnalysisTarget, CacheEntry>(maps);
}
@@ -216,8 +212,10 @@ class AnalysisCache {
/**
* Remove all information related to the given [target] from this cache.
+ * Return the entry associated with the target, or `null` if there was cache
+ * entry for the target.
*/
- void remove(AnalysisTarget target) {
+ CacheEntry remove(AnalysisTarget target) {
int count = _partitions.length;
for (int i = 0; i < count; i++) {
CachePartition partition = _partitions[i];
@@ -226,10 +224,10 @@ class AnalysisCache {
AnalysisEngine.instance.logger
.logInformation('Removed the cache entry for $target.');
}
- partition.remove(target);
- return;
+ return partition.remove(target);
}
}
+ return null;
}
/**
@@ -257,6 +255,11 @@ class CacheEntry {
static int _EXPLICITLY_ADDED_FLAG = 0;
/**
+ * The next invalidation process identifier.
+ */
+ static int nextInvalidateId = 0;
+
+ /**
* The target this entry is about.
*/
final AnalysisTarget target;
@@ -445,7 +448,7 @@ class CacheEntry {
if (state == CacheState.INVALID) {
ResultData data = _resultMap[descriptor];
if (data != null) {
- _invalidate(descriptor, delta);
+ _invalidate(nextInvalidateId++, descriptor, delta, 0);
}
} else {
ResultData data = getResultData(descriptor);
@@ -464,8 +467,11 @@ 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, List<TargetedResult> dependedOn) {
+ /*<V>*/ void setValue(
+ ResultDescriptor /*<V>*/ descriptor,
+ dynamic /*V*/
+ value,
+ List<TargetedResult> dependedOn) {
// {
// String valueStr = '$value';
// if (valueStr.length > 20) {
@@ -490,11 +496,14 @@ class CacheEntry {
* Set the value of the result represented by the given [descriptor] to the
* given [value], keep its dependency, invalidate all the dependent result.
*/
- void setValueIncremental(ResultDescriptor descriptor, dynamic value) {
+ void setValueIncremental(
+ ResultDescriptor descriptor, dynamic value, bool invalidateDependent) {
ResultData data = getResultData(descriptor);
- List<TargetedResult> dependedOn = data.dependedOnResults;
- _invalidate(descriptor, null);
- setValue(descriptor, value, dependedOn);
+ data.state = CacheState.VALID;
+ data.value = value;
+ if (invalidateDependent) {
+ _invalidateDependentResults(nextInvalidateId++, data, null, 0);
+ }
}
@override
@@ -513,50 +522,57 @@ class CacheEntry {
* Invalidate the result represented by the given [descriptor] and propagate
* invalidation to other results that depend on it.
*/
- void _invalidate(ResultDescriptor descriptor, Delta delta) {
+ void _invalidate(
+ int id, ResultDescriptor descriptor, Delta delta, int level) {
+ ResultData thisData = _resultMap[descriptor];
+ if (thisData == null) {
+ return;
+ }
+ // Stop if already validated.
+ if (delta != null) {
+ if (thisData.invalidateId == id) {
+ return;
+ }
+ thisData.invalidateId = id;
+ }
+ // Ask the delta to validate.
DeltaResult deltaResult = null;
if (delta != null) {
deltaResult = delta.validate(_partition.context, target, descriptor);
if (deltaResult == DeltaResult.STOP) {
-// print('not-invalidate $descriptor for $target');
return;
}
}
-// print('invalidate $descriptor for $target');
- ResultData thisData;
- if (deltaResult == null || deltaResult == DeltaResult.INVALIDATE) {
- thisData = _resultMap.remove(descriptor);
- }
- if (deltaResult == DeltaResult.KEEP_CONTINUE) {
- thisData = _resultMap[descriptor];
+ if (deltaResult == DeltaResult.INVALIDATE_NO_DELTA) {
+ delta = null;
}
- if (thisData == null) {
- return;
+ if (deltaResult == null ||
+ deltaResult == DeltaResult.INVALIDATE ||
+ deltaResult == DeltaResult.INVALIDATE_NO_DELTA) {
+ _resultMap.remove(descriptor);
+// {
+// 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) {
+ if (data != null && deltaResult != DeltaResult.KEEP_CONTINUE) {
data.dependentResults.remove(thisResult);
}
}
// Invalidate results that depend on this result.
- List<TargetedResult> dependentResults = thisData.dependentResults.toList();
- for (TargetedResult dependentResult in dependentResults) {
- CacheEntry entry = _partition.get(dependentResult.target);
- if (entry != null) {
- entry._invalidate(dependentResult.result, delta);
- }
- }
+ _invalidateDependentResults(id, thisData, delta, level + 1);
// If empty, remove the entry altogether.
if (_resultMap.isEmpty) {
_partition._targetMap.remove(target);
_partition._removeIfSource(target);
}
// Notify controller.
- _partition._onResultInvalidated
- .add(new InvalidatedResult(this, descriptor));
+ _partition.onResultInvalidated
+ .add(new InvalidatedResult(this, descriptor, thisData.value));
}
/**
@@ -565,7 +581,21 @@ class CacheEntry {
void _invalidateAll() {
List<ResultDescriptor> results = _resultMap.keys.toList();
for (ResultDescriptor result in results) {
- _invalidate(result, null);
+ _invalidate(nextInvalidateId++, result, null, 0);
+ }
+ }
+
+ /**
+ * Invalidate results that depend on [thisData].
+ */
+ void _invalidateDependentResults(
+ int id, ResultData thisData, Delta delta, int level) {
+ 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);
+ }
}
}
@@ -803,8 +833,8 @@ abstract class CachePartition {
/**
* The [StreamController] reporting [InvalidatedResult]s.
*/
- final StreamController<InvalidatedResult> _onResultInvalidated =
- new StreamController<InvalidatedResult>.broadcast(sync: true);
+ final ReentrantSynchronousStream<InvalidatedResult> onResultInvalidated =
+ new ReentrantSynchronousStream<InvalidatedResult>();
/**
* A table mapping the targets belonging to this partition to the information
@@ -839,12 +869,6 @@ abstract class CachePartition {
Map<AnalysisTarget, CacheEntry> get map => _targetMap;
/**
- * Return the stream that is notified when a value is invalidated.
- */
- Stream<InvalidatedResult> get onResultInvalidated =>
- _onResultInvalidated.stream;
-
- /**
* Notifies the partition that the client is going to stop using it.
*/
void dispose() {
@@ -896,9 +920,11 @@ abstract class CachePartition {
}
/**
- * Remove all information related to the given [target] from this cache.
+ * Remove all information related to the given [target] from this partition.
+ * Return the entry associated with the target, or `null` if there was cache
+ * entry for the target.
*/
- void remove(AnalysisTarget target) {
+ CacheEntry remove(AnalysisTarget target) {
for (CacheFlushManager flushManager in _flushManagerMap.values) {
flushManager.targetRemoved(target);
}
@@ -907,6 +933,7 @@ abstract class CachePartition {
entry._invalidateAll();
}
_removeIfSource(target);
+ return entry;
}
/**
@@ -948,10 +975,8 @@ abstract class CachePartition {
void _addIfSource(AnalysisTarget target) {
if (target is Source) {
_sources.add(target);
- {
- String fullName = target.fullName;
- _pathToSources.putIfAbsent(fullName, () => <Source>[]).add(target);
- }
+ String fullName = target.fullName;
+ _pathToSources.putIfAbsent(fullName, () => <Source>[]).add(target);
}
}
@@ -981,19 +1006,17 @@ abstract class CachePartition {
}
/**
- * If the given [target] is a [Source], removes it from [_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);
- }
+ String fullName = target.fullName;
+ List<Source> sources = _pathToSources[fullName];
+ if (sources != null) {
+ sources.remove(target);
+ if (sources.isEmpty) {
+ _pathToSources.remove(fullName);
}
}
}
@@ -1021,7 +1044,30 @@ class Delta {
/**
* The possible results of validating analysis results againt a [Delta].
*/
-enum DeltaResult { INVALIDATE, KEEP_CONTINUE, STOP }
+enum DeltaResult {
+ /**
+ * Invalidate this result and continue visiting dependent results
+ * with this [Delta].
+ */
+ INVALIDATE,
+
+ /**
+ * Invalidate this result and stop using this [Delta], so unconditionally
+ * invalidate all the dependent results.
+ */
+ INVALIDATE_NO_DELTA,
+
+ /**
+ * Keep this result and continue validating dependent results
+ * with this [Delta].
+ */
+ KEEP_CONTINUE,
+
+ /**
+ * Keep this result and stop visiting results that depend on this one.
+ */
+ STOP
+}
/**
* [InvalidatedResult] describes an invalidated result.
@@ -1037,13 +1083,47 @@ class InvalidatedResult {
*/
final ResultDescriptor descriptor;
- InvalidatedResult(this.entry, this.descriptor);
+ /**
+ * The value of the result which was invalidated.
+ */
+ final Object value;
+
+ InvalidatedResult(this.entry, this.descriptor, this.value);
@override
String toString() => '$descriptor of ${entry.target}';
}
/**
+ * A Stream-like interface, which broadcasts events synchronously.
+ * If a second event is fired while delivering a first event, then the second
+ * event will be delivered first, and then delivering of the first will be
+ * continued.
+ */
+class ReentrantSynchronousStream<T> {
+ final List<Function> listeners = <Function>[];
+
+ /**
+ * Send the given [event] to the stream.
+ */
+ void add(T event) {
+ List<Function> listeners = this.listeners.toList();
+ for (Function listener in listeners) {
+ listener(event);
+ }
+ }
+
+ /**
+ * Listen for the events in this stream.
+ * 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)) {
+ listeners.add(listener);
+ }
+}
+
+/**
* The data about a single analysis result that is stored in a [CacheEntry].
*/
// TODO(brianwilkerson) Consider making this a generic class so that the value
@@ -1066,6 +1146,13 @@ 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).
+ */
+ int invalidateId = -1;
+
+ /**
* A list of the results on which this result depends.
*/
List<TargetedResult> dependedOnResults = <TargetedResult>[];
@@ -1114,46 +1201,6 @@ class SdkCachePartition extends CachePartition {
}
/**
- * A specification of a specific result computed for a specific target.
- */
-class TargetedResult {
- /**
- * An empty list of results.
- */
- static final List<TargetedResult> EMPTY_LIST = const <TargetedResult>[];
-
- /**
- * The target with which the result is associated.
- */
- final AnalysisTarget target;
-
- /**
- * The result associated with the target.
- */
- final ResultDescriptor result;
-
- /**
- * Initialize a new targeted result.
- */
- TargetedResult(this.target, this.result);
-
- @override
- int get hashCode {
- return JenkinsSmiHash.combine(target.hashCode, result.hashCode);
- }
-
- @override
- bool operator ==(other) {
- return other is TargetedResult &&
- other.target == target &&
- other.result == result;
- }
-
- @override
- String toString() => '$result for $target';
-}
-
-/**
* A cache partition that contains all targets not contained in other partitions.
*/
class UniversalCachePartition extends CachePartition {
« no previous file with comments | « packages/analyzer/lib/src/cancelable_future.dart ('k') | packages/analyzer/lib/src/context/context.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698